📄 efax_controller.cpp
字号:
} else if (access(filename_iter->c_str(), R_OK)) { try { write_error(Glib::locale_from_utf8(gettext("User does not have read permission on the file\n")).c_str()); } catch (Glib::ConvertError&) { write_error("UTF-8 conversion error in EfaxController::make_fax_thread()\n"); } no_fax_made_notify(); // clean up and then end this worker thread return; } // unfortunately ghostscript does not handle long file names // so we need to separate the file name from the full path (we will chdir() to the directory later) // pos is already set to the position of the last '/' character std::string dirname(filename_iter->substr(0, pos)); pos++; std::string basename(filename_iter->substr(pos)); // get the arguments for the exec() call below (because this is a // multi-threaded program, we must do this before fork()ing because // we use functions to get the arguments which are not async-signal-safe) std::pair<const char*, char* const*> gs_parms(get_gs_parms(basename)); // create a synchronising pipe - we need to wait() on gs having completed executing // and then notify the parent process. To wait() successfully we need to fork() once, // reset the child signal handler, and then fork() again Sync_pipe sync_pipe; pid_t pid = fork(); if (pid == -1) { write_error("Fork error\n"); std::exit(FORK_ERROR); } if (!pid) { // child process // restore the default SIGCHLD signal handler with SA_RESTART // for systems (such as Linux) which require it. Also unblock // signals in case we are blocking them on launching a thread // elsewhere in this program (I cannot work out from IEEE 1003.1 // whether all masks are emptied on a fork() in any event) sigset_t sig_mask; sigemptyset(&sig_mask); sigaddset(&sig_mask, SIGCHLD); sigaddset(&sig_mask, SIGQUIT); sigaddset(&sig_mask, SIGTERM); sigaddset(&sig_mask, SIGINT); sigaddset(&sig_mask, SIGHUP); // this child process is single threaded, so we can use sigprocmask() // rather than pthread_sigmask() (and should do so as sigprocmask() // is guaranteed to be async-signal-safe) sigprocmask(SIG_UNBLOCK, &sig_mask, 0); struct sigaction sig_act; sig_act.sa_handler = SIG_DFL; sigemptyset(&sig_act.sa_mask);#ifdef SA_RESTART sig_act.sa_flags = SA_RESTART;#else sig_act.sa_flags = 0;#endif sigaction(SIGCHLD, &sig_act, 0); connect_to_stderr(); // now fork() again pid_t pid = fork(); if (pid == -1) { write_error("Fork error\n"); _exit(FORK_ERROR); // we have already forked, so use _exit() not exit() } if (!pid) { // child process - when everything is set up, we are going to do an exec() // we don't need sync_pipe in this process - ignore it by calling release() sync_pipe.release(); // now start up ghostscript // first we need to connect stdin to /dev/null to make ghostscript terminate int fd = open("/dev/null", O_RDWR); dup2(fd, 0); // now close stdout dup2(fd, 1); close(fd); // now stdin and stdout read/write to /dev/null, we can close the /dev/null file descriptor // unfortunately ghostscript does not handle long file names // so we need to chdir() chdir(dirname.c_str()); execvp(gs_parms.first, gs_parms.second); // if we reached this point, then the execvp() call must have failed write_error("Can't find the ghostscript program - please check your installation\n" "and the PATH environmental variable\n"); // this child process must end here - use _exit() not exit() _exit(EXEC_ERROR); } // end of child process // this is the parent process // wait until ghostscript has produced the fax tiffg3 fax file. // Note that we have already fork()ed before the fork() by this process // so childexit_signalhandler in mainwindow.cpp will not pick up // the end of the child process, so this wait() will work OK wait(0); // release the waiting parent process sync_pipe.release(); // now end the process - use _exit() not exit() _exit(0); } // wait on sync_pipe until we know gs has made all the files in tiffg3 format sync_pipe.wait(); // release the memory allocated on the heap for // the redundant gs_parms // we are in the main parent process here - no worries about // only being able to use async-signal-safe functions delete_parms(gs_parms); // now enter the names of the created files in sendfax_parms_vec bool valid_file = false; int partnumber = 1;#ifdef HAVE_STRINGSTREAM std::ostringstream strm; strm << *filename_iter << '.' << std::setfill('0') << std::setw(3) << partnumber; int result = access(strm.str().c_str(), R_OK); while (!result) { // file OK // valid_file only needs to be set true once, but it is more // convenient to do it in this loop valid_file = true; // we do not need a mutex to protect sendfax_parms_vec - until // EfaxController::timer_event() resets state to inactive, we cannot invoke // sendfax() again sendfax_parms_vec.push_back(strm.str()); partnumber++; strm.str(""); strm << *filename_iter << '.' << std::setfill('0') << std::setw(3) << partnumber; result = access(strm.str().c_str(), R_OK); }#else std::ostrstream strm; strm << filename_iter->c_str() << '.' << std::setfill('0') << std::setw(3) << partnumber << std::ends; const char* test_name = strm.str(); int result = access(test_name, R_OK); while (!result) { // file OK // valid_file only needs to be set true once, but it is more // convenient to do it in this loop valid_file = true; sendfax_parms_vec.push_back(test_name); delete[] test_name; partnumber++; std::ostrstream strm; strm << filename_iter->c_str() << '.' << std::setfill('0') << std::setw(3) << partnumber << std::ends; test_name = strm.str(); result = access(test_name, R_OK); } delete[] test_name;#endif if (!valid_file) { try { write_error(Glib::locale_from_utf8(gettext("Not valid postscript file\n")).c_str()); } catch (Glib::ConvertError&) { write_error("UTF-8 conversion error in EfaxController::make_fax_thread()\n"); } // clean up and then end this worker thread no_fax_made_notify(); return; } } // we have now made the fax pages in tiffg3 format and entered them into sendfax_parms_vec. // At the end of this method this worker thread will end, and emitting fax_made_notify // will cause sendfax_slot() to be executed in the initial (GUI) thread fax_made_notify();}std::pair<const char*, char* const*> EfaxController::get_receive_parms(int mode) { std::vector<std::string> efax_parms(prog_config.parms); std::string temp("-r"); temp += prog_config.receive_dirname; efax_parms.push_back(temp); if (mode == receive_takeover) efax_parms.push_back("-w"); else if (mode == receive_standby) { temp = "-jS0="; temp += prog_config.rings; efax_parms.push_back(temp); efax_parms.push_back("-s"); efax_parms.push_back("-w"); } char** exec_parms = new char*[efax_parms.size() + 1]; std::vector<std::string>::const_iterator iter; char** temp_pp = exec_parms; for (iter = efax_parms.begin(); iter != efax_parms.end(); ++iter, ++temp_pp) { *temp_pp = new char[iter->size() + 1]; std::strcpy(*temp_pp, iter->c_str()); } *temp_pp = 0; char* prog_name = new char[std::strlen("efax-0.9a") + 1]; std::strcpy(prog_name, "efax-0.9a"); return std::pair<const char*, char* const*>(prog_name, exec_parms);}void EfaxController::receive(int mode) { if (state != inactive) beep(); else { // get a time value to create the directory name into which the fax is to be saved // and to insert in prog_config.receive_dirname for parent and child struct std::tm* time_p; std::time_t time_count; std::time(&time_count); time_p = std::localtime(&time_count); std::string fax_pathname; if (!prog_config.homedir.empty()) { fax_pathname = prog_config.homedir; fax_pathname += "/faxin/"; } 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 received fax is saved, and it probably won't\n" "appear in the fax list!\n"); } const char format[] = "%y%m%d%H%M%S"; { // lock the Prog_config object while we modify it Glib::Mutex::Lock lock(*prog_config.mutex_p); std::strftime(prog_config.receive_dirname, MAX_TEMP_NAME + 1, format, time_p); } std::string temp(fax_pathname); temp += prog_config.receive_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); { // lock the Prog_config object while we modify it Glib::Mutex::Lock lock(*prog_config.mutex_p); std::strftime(prog_config.receive_dirname, MAX_TEMP_NAME + 1, format, time_p); } temp = fax_pathname + prog_config.receive_dirname; } if (count == 4) { write_error("Can't create directory to save fax\n"); { // lock the Prog_config object while we modify it Glib::Mutex::Lock lock(*prog_config.mutex_p); *prog_config.receive_dirname = 0; } return; } fax_pathname += prog_config.receive_dirname; stdout_pipe.open(Pipe_fifo::non_block); // efax is sensitive to timing, so set pipe write to non-block also stdout_pipe.make_write_non_block(); state = mode; change_state_count++; // get the arguments for the exec() call below (because this is a // multi-threaded program, we must do this before fork()ing because // we use functions to get the arguments which are not async-signal-safe) std::pair<const char*, char* const*> receive_parms(get_receive_parms(mode)); // set up a synchronising pipe in case the child process finishes before // fork() in parent space has returned (yes, with an exec() error that can // happen with Linux kernel 2.6) - this is important because we test child_pid // in efax_controller_childexit_handler() Sync_pipe sync_pipe; child_pid = fork(); if (child_pid == -1) { write_error("Fork error - exiting\n"); std::exit(FORK_ERROR); } if (!child_pid) { // child process - as soon as everything is set up we are going to do an exec() // now we have forked, we can connect stdout_pipe to stdout // and connect MainWindow::error_pipe to stderr stdout_pipe.connect_to_stdout(); connect_to_stderr(); chdir(fax_pathname.c_str()); // wait before we call execvp() until the parent process has set itself up // and releases this process sync_pipe.wait(); // now start up efax in receive mode execvp(receive_parms.first, receive_parms.second); // if we reached this point, then the execvp() call must have failed // report the error and end this process - use _exit() and not exit() write_error("Can't find the efax-0.9a program - please check your installation\n" "and the PATH environmental variable\n"); _exit(EXEC_ERROR); } // end of child process // this is the parent process stdout_pipe.make_readonly(); // since the pipe is unidirectional, we can close the write fd join_child(); // now we have set up, release the child process sync_pipe.release(); // release the memory allocated on the heap for // the redundant receive_parms // we are in the main parent process here - no worries about // only being able to use async-signal-safe functions delete_parms(receive_parms); }}void EfaxController::delete_parms(std::pair<const char*, char* const*> parms_pair) { delete[] parms_pair.first; char* const* temp_pp = parms_pair.second; for(; *temp_pp != 0; ++temp_pp) { delete[] *temp_pp; } delete[] parms_pair.second;}bool EfaxController::read_pipe_slot(Glib::IOCondition) { char pipe_buffer[PIPE_BUF + 1]; ssize_t result; while ((result = stdout_pipe.read(pipe_buffer, PIPE_BUF)) > 0) { pipe_buffer[result] = 0; stdout_message(pipe_buffer); } if (result == -1 // as this is a non-blocking pipe, result should && (errno == EAGAIN || errno == EINTR)) {// end up being -1 with errno == EAGAIN return true; // retain SigC connection } return false; // something has gone wrong (probably the pipe has been destroyed), so disconnect}void EfaxController::stop_slot(void) { if (state != inactive && state != close_child_connections) { // else we need to deal with it here stdout_message(gettext("\n*** Stopping send/receive session ***\n\n")); kill_child(); } else beep();}void EfaxController::timer_event(void) { if (change_state_count) { // we only really need to test change_state_count to trigger // a call to display_state(), but we need to test here at the outset to make sure // that timer_event() is atomic for all further tests below, as all the variables
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -