// -*- C++ -*- // Ossama Othman #include "ace/FILE_Connector.h" #include "ace/Log_Msg.h" #include "ace/Process_Manager.h" #include "Callback_i.h" #include "ace/OS_NS_strings.h" #include "ace/OS_NS_string.h" Callback_i::Callback_i (int *request_count) : file_ (ACE_sap_any_cast (ACE_FILE_Addr &)), file_io_ (), ami_handler_ (), metadata_ (), last_chunk_ (0), lock_ (), request_count_ (request_count) { // Create a temporary file to store the retrieved data. ACE_FILE_Connector connector; if (connector.connect (this->file_io_, this->file_, 0, ACE_Addr::sap_any, 0, O_CREAT | O_TRUNC | O_WRONLY, ACE_DEFAULT_FILE_PERMS) == -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("Could not open file \"%s\"%p\n"), this->file_.get_path_name ())); } else (*this->request_count_)++; } Callback_i::~Callback_i (void) { (void) this->file_io_.close (); } void Callback_i::next_chunk (const Web_Server::Chunk_Type & chunk_data, CORBA::Boolean last_chunk) { if (!last_chunk) { Web_Server::Chunk_Type_var chunk = chunk_data; // Append the received data to the corresponding // buffer/temporary file. if (this->file_io_.send (chunk->get_buffer (), chunk->length ()) == -1) { (*this->request_count_)--; // Don't wait for more data. ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Unable to write retrieved data to ") ACE_TEXT ("file <%s>"), this->file_.get_path_name ())); return; } } else { { ACE_MT (ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->lock_)); this->last_chunk_ = 1; // Received entire content. } ACE_DEBUG ((LM_INFO, ACE_TEXT ("Wrote retrieved data to file <%s>\n"), this->file_.get_path_name ())); (*this->request_count_)--; // No more data. // File retrieval has completed, so spawn an external viewer to // display its contents. // If the entire metadata has been received, then spawn an // external viewer to display the received file. if (this->metadata_received ()) { (void) this->file_io_.close (); this->deactivate (); (void) this->spawn_viewer (); } } } void Callback_i::metadata (const Web_Server::Metadata_Type &metadata) { try { { ACE_MT (ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->lock_)); this->metadata_ = metadata; } ACE_DEBUG ((LM_INFO, ACE_TEXT ("Retrieved file has the following ") ACE_TEXT ("characteristics:\n") ACE_TEXT (" Modification Date: %s\n") ACE_TEXT (" Content Type: %s\n"), this->metadata_.modification_date.in (), this->metadata_.content_type.in ())); // If the entire content of the data has been received, then spawn // an external viewer to display it. if (this->content_received ()) { this->deactivate (); (void) this->spawn_viewer (); } } catch (const CORBA::Exception& ex) { ex._tao_print_exception ( ACE_TEXT ("Caught unexpected exception ") ACE_TEXT ("in Callback_i::metdata(...):")); } } int Callback_i::metadata_received (void) { ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->lock_, 0)); return (this->metadata_.content_type.in () != 0); } int Callback_i::content_received (void) { ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->lock_, 0)); return this->last_chunk_; } int Callback_i::get_viewer (char *viewer, size_t length) { const char *content_type = this->metadata_.content_type.in (); if (ACE_OS::strcasecmp (content_type, "text/html") == 0) { const char lynx[] = "lynx"; if (length <= sizeof (lynx)) return -1; else ACE_OS::strcpy (viewer, lynx); } else if (ACE_OS::strcasecmp (content_type, "text/plain") == 0) { const char more[] = "more"; if (length <= sizeof (more)) return -1; else ACE_OS::strcpy (viewer, more); } else if (ACE_OS::strcasecmp (content_type, "application/postscript") == 0) { const char ghostview[] = "ghostview"; if (length <= sizeof (ghostview)) return -1; else ACE_OS::strcpy (viewer, ghostview); } else if (ACE_OS::strcasecmp (content_type, "application/pdf") == 0) { const char acroread[] = "acroread"; if (length <= sizeof (acroread)) return -1; else ACE_OS::strcpy (viewer, acroread); } else if (ACE_OS::strcasecmp (content_type, "image/jpeg") == 0 || ACE_OS::strcasecmp (content_type, "image/gif") == 0 || ACE_OS::strcasecmp (content_type, "image/tiff") == 0 || ACE_OS::strcasecmp (content_type, "image/png") == 0) { const char xv[] = "xv"; if (length <= sizeof (xv)) return -1; else ACE_OS::strcpy (viewer, xv); } else ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Unsupported MIME type: <%s>\n"), content_type), -1); return 0; } int Callback_i::spawn_viewer (void) { char viewer[BUFSIZ]; if (this->get_viewer (viewer, sizeof (viewer)) != 0) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Problem determining which external ") ACE_TEXT ("viewer to use.\n")), -1); // Set up the command line that will be used when spawning the // external viewer. ACE_Process_Options opts; opts.command_line (ACE_TEXT ("%s %s"), viewer, this->file_.get_path_name ()); pid_t result = ACE_Process_Manager::instance ()->spawn (opts); switch (result) { case 0: // Child return 0; case ACE_INVALID_PID: ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Error during viewer spawn of %p\n"), opts.command_line_buf ()), -1); default: // Parent ACE_DEBUG ((LM_INFO, ACE_TEXT ("Spawned viewer <%s> with PID <%d>.\n"), viewer, result)); break; } return 0; } void Callback_i::deactivate (void) { // Get the POA used when activating the Reply Handler object. PortableServer::POA_var poa = this->_default_POA (); // Get the object ID associated with this servant. PortableServer::ObjectId_var oid = poa->servant_to_id (this); // Now deactivate the iterator object. poa->deactivate_object (oid.in ()); }