📄 efax_controller.cpp
字号:
// being tested can be changed by efax_controller_childexit_handler() if (state == close_child_connections || state == restart_standby) { if (*prog_config.receive_dirname) { // now delete receive_dirname if it is empty std::string full_dirname; if (!prog_config.homedir.empty()) { full_dirname = prog_config.homedir; full_dirname += "/faxin/"; } full_dirname += prog_config.receive_dirname; int result = rmdir(full_dirname.c_str()); // only deletes the directory if it is empty if (result == -1 && errno == ENOTEMPTY) { // before assuming a fax has been successfully received, check to see // if [fax_name].001 is of 0 size (if it is delete it) struct stat statinfo; std::string file_name(full_dirname); file_name += '/'; file_name += prog_config.receive_dirname; file_name += ".001"; if (!stat(file_name.c_str(), &statinfo) && !statinfo.st_size) { unlink(file_name.c_str()); rmdir(full_dirname.c_str()); } else fax_received_notify(); } // lock the Prog_config object while we modify it Glib::Mutex::Lock lock(*prog_config.mutex_p); *prog_config.receive_dirname = 0; } unjoin_child(); int state_val = state; state = inactive; // this is needed even if we are going to call receive() // now restart if in standby mode if (state_val == restart_standby) receive(receive_standby); } else if (state == send_success || state == send_fail) { if (state == send_success) { save_sent_fax(); if (last_fax_item_sent.is_socket_file) { // if we are sending a print job via the socket server, notify the // Socket_server object which created the temporary file (the server // object will clean up by deleting it and also cause the socket // file list to be updated - we do not need to do that here) remove_from_socket_server_filelist(last_fax_item_sent.file_list[0]); } } else cleanup_fax_send_fail(); unjoin_child(); state = inactive; } // Note: there is a possible race condition at this point immediately before // we operate on change_state_count. It is theoretically possible (though // very unlikely) that efax_controller_childexit_handler() could fire between us // testing state above and us operating on change_state_count below, because // of, say, an exec() failure in executing efax to send or receive a // fax. To avoid this we increment change_state_count (including in // efax_controller_childexit_handler()) instead of just setting it to true // and decrement it (as below) instead of setting it to false. This means that // even if efax_controller_childexit_handler() fires at this precise point in // the code, when it has finished change_state_count will hold the value 2 and // not 1, so after being decremented below it will still hold the value 1, so // causing this function to be called again recursively at the end of this // function, so operating correctly on the values of state set up in // efax_controller_childexit_handler() change_state_count--; display_state(); if (change_state_count > 0) timer_event(); }}void EfaxController::display_state(void) { write_state(state_messages[state].c_str());}void EfaxController::join_child(void) { // we do not need a mutex for this - join_child() and unjoin_child() are // only called in the initial (GUI) thread stdout_connection = Glib::signal_io().connect(sigc::mem_fun(*this, &EfaxController::read_pipe_slot), stdout_pipe.get_read_fd(), Glib::IO_IN);}void EfaxController::unjoin_child(void) { // we do not need a mutex for this - join_child() and unjoin_child() are // only called in the initial (GUI) thread, and stdout_pipe is only manipulated // in that thread or after a new single-threaded process has been launched with fork() stdout_pipe.close(); stdout_connection.disconnect();}void EfaxController::kill_child(void) { if (child_pid) kill(child_pid, SIGTERM); Glib::usleep(500000); // now really make sure if (child_pid) kill(child_pid, SIGKILL);}void EfaxController::save_sent_fax(void) { // get a time value to create the directory name into which the fax is to be saved struct std::tm* time_p; std::time_t time_count; std::time(&time_count); time_p = std::localtime(&time_count); // now create the directory into which the fax files to be saved std::string fileout_name; if (!prog_config.homedir.empty()) { fileout_name = prog_config.homedir; fileout_name += "/faxsent/"; } else { write_error("You don't have the $HOME environmental variable set.\n" "You may need to search for the directory in which\n" "the fax is saved, and it probably won't appear in\n" "the fax list!\n"); } const char dirname_format[] = "%y%m%d%H%M%S"; char top_dirname[MAX_TEMP_NAME + 1]; std::strftime(top_dirname, MAX_TEMP_NAME + 1, dirname_format, time_p); std::string temp(fileout_name); temp += top_dirname; // check whether directory already exists or can't be created int count; for (count = 0; count < 4 && mkdir(temp.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); count++) { sleep(1); // wait a second to get a different time std::time(&time_count); time_p = std::localtime(&time_count); std::strftime(top_dirname, MAX_TEMP_NAME + 1, dirname_format, time_p); temp = fileout_name + top_dirname; } if (count == 4) { write_error("Can't create directory to save fax\n"); return; } // now make fileout_name the same as the directory name for the saved faxes // that we have just created fileout_name += top_dirname; const std::string fileout_dirname(fileout_name); // keep for later to enter a description // and now complete the unsuffixed file name of the destination files fileout_name += '/'; fileout_name += top_dirname; // now create a string containing the date for the fax description // glibc has const struct tm* as last param of strftime() // but the const does not appear to be guaranteed by POSIX // so do localtime() again just in case time_p = std::localtime(&time_count); const char date_description_format[] = "(%H%M %Z %d %b %Y)"; const int max_description_datesize = 126; char date_description[max_description_datesize]; std::strftime(date_description, max_description_datesize, date_description_format, time_p); // now copy files into the relevant directory for the fax pages to be saved std::vector<std::string> file_basename_vec; // this is used in making the fax description int out_partnumber = 1; // in order to generate the suffix for each fax page as saved std::vector<std::string>::const_iterator sentname_iter; for (sentname_iter = last_fax_item_sent.file_list.begin(); sentname_iter != last_fax_item_sent.file_list.end(); ++sentname_iter) { std::string::size_type pos = sentname_iter->find_last_of('/'); if (pos == std::string::npos || pos + 2 > sentname_iter->size()) { write_error("Not valid file name to save -- can't save sent fax\n"); } else { // save the file base name for later use in making the fax description pos++; file_basename_vec.push_back(sentname_iter->substr(pos)); // make the suffixes int in_partnumber = 1;#ifdef HAVE_STRINGSTREAM std::ostringstream in_suffix_strm; in_suffix_strm << '.' << std::setfill('0') << std::setw(3) << in_partnumber; std::ostringstream out_suffix_strm; out_suffix_strm << '.' << std::setfill('0') << std::setw(3) << out_partnumber; // make the suffixed source and destination files std::string suffixed_inname = *sentname_iter + in_suffix_strm.str(); std::string suffixed_outname = fileout_name + out_suffix_strm.str();#else std::ostrstream in_suffix_strm; in_suffix_strm << '.' << std::setfill('0') << std::setw(3) << in_partnumber << std::ends; const char* in_suffix = in_suffix_strm.str(); std::ostrstream out_suffix_strm; out_suffix_strm << '.' << std::setfill('0') << std::setw(3) << out_partnumber << std::ends; const char* out_suffix = out_suffix_strm.str(); // make the suffixed source and destination files std::string suffixed_inname = *sentname_iter + in_suffix; std::string suffixed_outname = fileout_name + out_suffix; delete[] in_suffix; delete[] out_suffix;#endif std::ifstream filein; std::ofstream fileout; const int BLOCKSIZE = 1024; char block[BLOCKSIZE]; while (!access(suffixed_inname.c_str(), R_OK) && (filein.open(suffixed_inname.c_str(), std::ios::in), filein) // use comma operator to check filein && (fileout.open(suffixed_outname.c_str(), std::ios::out), fileout)) { // ditto for fileout while (filein) { filein.read(block, BLOCKSIZE); fileout.write(block, filein.gcount()); } filein.clear(); filein.close(); fileout.clear(); fileout.close(); unlink(suffixed_inname.c_str()); in_partnumber++; out_partnumber++;#ifdef HAVE_STRINGSTREAM in_suffix_strm.str(""); in_suffix_strm << '.' << std::setfill('0') << std::setw(3) << in_partnumber; out_suffix_strm.str(""); out_suffix_strm << '.' << std::setfill('0') << std::setw(3) << out_partnumber; // make the suffixed source and destination files suffixed_inname = *sentname_iter + in_suffix_strm.str(); suffixed_outname = fileout_name + out_suffix_strm.str();#else std::ostrstream in_suffix_strm; in_suffix_strm << '.' << std::setfill('0') << std::setw(3) << in_partnumber << std::ends; in_suffix = in_suffix_strm.str(); std::ostrstream out_suffix_strm; out_suffix_strm << '.' << std::setfill('0') << std::setw(3) << out_partnumber << std::ends; out_suffix = out_suffix_strm.str(); // make the suffixed source and destination files suffixed_inname = *sentname_iter + in_suffix; suffixed_outname = fileout_name + out_suffix; delete[] in_suffix; delete[] out_suffix;#endif } fileout.clear(); if (in_partnumber < 2) write_error("There was a problem saving all or part of the sent fax\n"); } } // now save the sent fax description if (out_partnumber > 1) { const std::string description_filename(fileout_dirname + "/Description"); std::ofstream fileout(description_filename.c_str(), std::ios::out); if (fileout) { if (last_fax_item_sent.is_socket_file) fileout << gettext("PRINT JOB"); else { std::vector<std::string>::const_iterator filename_iter; for (filename_iter = file_basename_vec.begin(); filename_iter != file_basename_vec.end(); ++filename_iter) { if (filename_iter != file_basename_vec.begin()) fileout << '+'; fileout << *filename_iter; } } if (!last_fax_item_sent.number.empty()) { fileout << " --> " << last_fax_item_sent.number; } fileout << ' ' << date_description; } else write_error("Cannot save sent fax description\n"); }}void EfaxController::cleanup_fax_send_fail(void) { std::vector<std::string>::const_iterator filename_iter; for (filename_iter = last_fax_item_sent.file_list.begin(); filename_iter != last_fax_item_sent.file_list.end(); ++filename_iter) { // make the suffix int partnumber = 1;#ifdef HAVE_STRINGSTREAM std::ostringstream strm; strm << '.' << std::setfill('0') << std::setw(3) << partnumber; // make the suffixed file name std::string filename = *filename_iter + strm.str(); while (!access(filename.c_str(), R_OK)) { unlink(filename.c_str()); partnumber++; strm.str(""); strm << '.' << std::setfill('0') << std::setw(3) << partnumber; filename = *filename_iter + strm.str(); }#else std::ostrstream strm; strm << '.' << std::setfill('0') << std::setw(3) << partnumber << std::ends; const char* suffix = strm.str(); // make the suffixed file name std::string filename = *filename_iter + suffix; delete[] suffix; while (!access(filename.c_str(), R_OK)) { unlink(filename.c_str()); partnumber++; std::ostrstream strm; strm << '.' << std::setfill('0') << std::setw(3) << partnumber << std::ends; suffix = strm.str(); filename = *filename_iter + suffix; delete[] suffix; }#endif }}bool efax_controller_childexit_handler(pid_t pid, int exit_code) { /* * in order to avoid race conditions or unexpected results, it is enough * (i) to end this function by incrementing change_state_count * (ii) to test for change_state_count at the beginning of EfaxController::timer_event() * (iii) to set state to inactive in EfaxController::timer_event() after that function * has finished acting on the value of state set in this handler * (iv) to decrement change_state_count at the end of EfaxController::timer_event() * * this is because only this signal handler sets state to restart_standby, * send_success, send_fail and close_child_connections, and until * EfaxController::timer_event() has changed the value of state from * these values to inactive, then the program cannot launch another * child process to exec() efax which would (when terminating) cause * this handler to be invoked */ if (pid == child_pid) { child_pid = 0; // this won't work if efax is suid root and we are not root if (prog_config.lock_file) unlink(prog_config.lock_file); if (state == EfaxController::closedown) // tell EfaxController::efax_closedown() the child is now dead state = EfaxController::inactive; else if (state == EfaxController::receive_standby && (!exit_code || exit_code == 3)) // get EfaxController::timer_event() to restart efax() state = EfaxController::restart_standby; else if (state == EfaxController::sending) { if(!exit_code) // get EfaxController::timer_event() to save the file in sent fax list state = EfaxController::send_success; else state = EfaxController::send_fail; } else if (state != EfaxController::inactive) // get EfaxController::timer_event() to close dead file descriptors and dead SigC connections state = EfaxController::close_child_connections; change_state_count++; return true; } return false;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -