#pragma implementation #include #include #include #include #include #include #include #include #include #include /* * class DAEMON_FETCHMAIL */ #include #include #include #include "fetchmailconf.h" #include "fetchmailconf.m" #include "keyword.h" #include "basicsedit.h" static HELP_FILE help_basics ("fetchmailconf","basics"); static PRIVILEGE p_basics ("fetchmailconf_basics" ,P_MSG_U(T_PRIVFETCHMAILBASICS,"Basics") ,P_MSG_U(T_PRIVILEGE,"9-Fetchmail")); static const char *subsys; static int previous_schedule = -1; // On change from K_SCHEDULE_DAEMON // to some thing else // fetchmail will be killed at probe // time. /* * DAEMON_FETCHMAIL */ class PROC; class DAEMON_FETCHMAIL { PROC *myProcess; private: public: DAEMON_FETCHMAIL(); PROC *getdaemonprocess( void ); int killdaemon( void ); int startdaemon( int daemon ); }; /* * BASICS */ PRIVATE void BASICS::init() { syslog = 0; daemon = 0; no_bouncemail = 0; schedule = (char)linuxconf_getvalnum( K_BASICS, K_SCHEDULE, K_SCHEDULE_MANUAL ); if ( previous_schedule == -1 ) { previous_schedule = schedule; } log_details = (char)linuxconf_getvalnum( K_BASICS, K_LOG, K_LOG_STANDARD ); } PUBLIC BASICS::BASICS( const char *s ) { init(); subsys = s; } PUBLIC int BASICS::write( ) { //fprintf(stderr,"BASICS::write()\n"); int ret = -1; VIEWITEMS items; VIEWITEM *item; items.read( *f_config_file ); // Read current version of config file char line[1000]; item = items.locate( "set", "daemon" ); if ( item == NULL ) { item = new VIEWITEM( "" ); items.insert( 0, item ); } snprintf( line, sizeof(line), "set daemon %d", daemon ); item->line.setfrom( line ); item = items.locate( "set", "postmaster" ); if ( item == NULL ) { item = new VIEWITEM( "" ); items.insert( 0, item ); } snprintf( line, sizeof(line), "set postmaster \"%s\"", postmaster.get() ); item->line.setfrom( line ); if ( syslog ) { item = items.locate( "set", "nosyslog" ); if ( item != NULL ) { items.remove( item ); item = NULL; } item = items.locate( "set", "syslog" ); if ( item == NULL ) { item = new VIEWITEM( "" ); items.insert( 0, item ); } snprintf( line, sizeof(line), "set syslog" ); item->line.setfrom( line ); } else { item = items.locate( "set", "syslog" ); if ( item != NULL ) { items.remove( item ); item = NULL; } #if 0 /* * "set nosyslog" causes syntax error (fetchmail 5.1.0) * "set no syslog" also incorrect * Disabled for now */ item = items.locate( "set", "nosyslog" ); if ( item == NULL ) { item = new VIEWITEM( "" ); items.insert( 0, item ); } snprintf( line, sizeof(line), "set nosyslog" ); item->line.setfrom( line ); #endif } item = items.locate( "set", "logfile" ); if ( item == NULL ) { item = new VIEWITEM( "" ); items.insert( 0, item ); } snprintf( line, sizeof(line), "set logfile \"%s\"", logfile.get() ); item->line.setfrom( line ); item = items.locate( "set", "no" ); if ( item == NULL ) { if ( no_bouncemail ) { item = new VIEWITEM( "" ); items.insert( 0, item ); snprintf( line, sizeof(line), "set no bouncemail" ); item->line.setfrom( line ); } } else if ( strcmp( "set no bouncemail", item->line.get() ) == 0 ) { if ( no_bouncemail == 0 ) { items.remove( item ); item = NULL; } } if ( ! perm_access( &p_basics, MSG_U(P_EDITBASICS, "change basic configuration") ) ) { return( ret ); } items.write( *f_config_file, &p_basics ); /* * Update crontab */ char *logstring = NULL; switch ( log_details ) { case K_LOG_STANDARD: logstring = ""; break; case K_LOG_SILENT: logstring = "--silent"; break; case K_LOG_VERBOSE: logstring = "-v -v"; break; } char cmd[1000]; snprintf( cmd, sizeof(cmd), "%s %s -f %s", daemon_findpath( "fetchmail" ), logstring, f_config_file->getpath()); switch ( schedule ) { case K_SCHEDULE_MANUAL: // Manually cron_delcmd ("root",cmd); break; case K_SCHEDULE_CRON: // By cron cron_addcmd ("root",cmd ,"0","8-17","*","1-5","*"); static const char *tb[][2]={ { "fetchmail", MSG_U(O_FETCHMAIL, "Schedule mail retrieval") }, {NULL,NULL} }; cron_edit( "root", tb ); break; case K_SCHEDULE_DAEMON: // Init cron_delcmd ("root",cmd); break; default: cron_delcmd ("root",cmd); break; } /* * Update linuxconf database */ linuxconf_setcursys( subsys ); linuxconf_replace( K_BASICS, K_SCHEDULE, schedule ); linuxconf_replace( K_BASICS, K_LOG, log_details ); linuxconf_save( &p_basics ); return( ret ); } static int input_error( char daemon, char schedule ) { switch( schedule ) { case K_SCHEDULE_MANUAL: break; case K_SCHEDULE_CRON: if ( daemon > 0 ) { xconf_error(MSG_U(E_SCHEDULE_CRON, "You can't schedule a continually\n" "running process")); return( 1 ); } break; case K_SCHEDULE_DAEMON: if ( daemon == 0 ) { xconf_error(MSG_U(E_SCHEDULE_DAEMON, "Sorry, it is not possible to have\n" "a boot time start up without interval\n" "specified" )); return( 1 ); } break; } return( 0 ); } PUBLIC void BASICS::execute() { DIALOG dia; char fetch = 0; { static const char *fetch_use[]={ MSG_U(F_CHECKONLY,"Check only"), MSG_U(F_CHECKFETCH,"Fetch mail"), NULL }; dia.newf_chkm (MSG_U(F_CHECKACTION,"Action"), fetch, fetch_use); } { static const char *log_use[]={ MSG_U(F_LOG_STANDARD,"Normal"), MSG_U(F_LOG_SILENT,"Silent"), MSG_U(F_LOG_VERBOSE,"Verbose"), NULL }; dia.newf_chkm (MSG_U(F_LOG,"Details"), log_details, log_use); } dia.setbutinfo (MENU_ACCEPT,MSG_U(B_CHECKACCEPT,"Activate"),MSG_R(B_CHECKACCEPT)); int ret = 0; int nof = 0; while( 1 ) { MENU_STATUS code = dia.edit( MSG_U(T_EXECUTE,"Remote mail retreival execution") ,MSG_U(I_EXECUTE, "This dialog let you check your configuration or activate\n" "your configuration and fetch mail.\n" "\n" "Log output will appear on screen.\n" "\n" "In case of a dialup connection a complete log may not\n" "appear if the connection time is too long.\n" ) ,help_basics ,nof ,MENUBUT_CANCEL|MENUBUT_ACCEPT); if (code == MENU_CANCEL || code == MENU_ESCAPE){ ret = -1; break; } else if ( code == MENU_ACCEPT ){ char *logstring = NULL; switch ( log_details ) { case K_LOG_STANDARD: logstring = ""; break; case K_LOG_SILENT: logstring = "--silent"; break; case K_LOG_VERBOSE: logstring = "-v -v"; break; } if ( fetch ) { fetchmail_execute( "", logstring ); } else { fetchmail_execute( "--check", logstring ); } continue; } } } /** * Edit basics entry */ PUBLIC int BASICS::edit() { DIALOG dia; dia.newf_num (MSG_U(F_DAEMON,"Poll interval in seconds"),daemon); { static const char *schedule_use[]={ MSG_U(F_SCHEDULE_MANUAL,"Manually"), MSG_U(F_SCHEDULE_CRON,"By cron"), MSG_U(F_SCHEDULE_DAEMON,"At boot"), NULL }; dia.newf_chkm (MSG_U(F_SCHEDULE,"Start fetchmail"), schedule, schedule_use); } dia.newf_title ("",MSG_U(T_OPTIONAL,"Optional information")); dia.newf_title (MSG_U(T_LOG,"Log configuration"),1,"",MSG_R(T_LOG)); dia.newf_str (MSG_U(F_LOGFILE,"To file"),logfile); dia.newf_chk (MSG_U(F_SYSLOG,"To system log"),syslog,""); { static const char *log_use[]={ MSG_R(F_LOG_STANDARD), MSG_R(F_LOG_SILENT), MSG_R(F_LOG_VERBOSE), NULL }; dia.newf_chkm (MSG_R(F_LOG), log_details, log_use); } dia.newf_title (MSG_U(T_POSTMASTER,"Postmaster"),1,"", MSG_R(T_POSTMASTER)); { static const char *bouncemail_use[]={ MSG_U(F_BOUNCEMAIL,"Return to sender"), MSG_U(F_FORWARD_POSTMASTER,"Forward to postmaster"), NULL }; dia.newf_chkm (MSG_U(F_BOUNCEMAILPROMPT, "Incorrect mail address"),no_bouncemail,bouncemail_use); } dia.newf_str (MSG_U(F_POSTMASTER,"Postmaster"),postmaster); dia.newf_info (MSG_U(F_CREATE,"Configuration file"), f_config_file->getpath()); dia.setbutinfo (MENU_USR1,MSG_U(B_EXECUTE,"Check"),MSG_R(B_EXECUTE)); int ret = 0; int nof = 0; while( 1 ) { MENU_STATUS code = dia.edit( MSG_U(T_BASICS,"Remote mail retreival basics") ,MSG_U(I_BASICS, "This is where you enter basic information for mail\n" "retreival from one or more remote mail servers.\n" "\n" "If poll interval is zero fetchmail must be scheduled\n" "to run automatically, started manually or automatically\n" "started at boot time for a one time retreival.\n" "\n" "If poll interval is greater than zero fetchmail runs\n" "continuously and fetches mail every interval. Fetchmail\n" "should be started at boot time in this case.\n" ) ,help_basics ,nof ,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_USR1); if (code == MENU_CANCEL || code == MENU_ESCAPE){ ret = -1; break; } else if ( code == MENU_USR1 ){ if ( input_error( daemon, schedule ) ) { continue; } execute(); continue; } else if ( code == MENU_ACCEPT ){ if ( input_error( daemon, schedule ) ) { continue; } write ( ); ret = 0; break; } } return ret; } /** * Read config file and parse basicss */ PUBLIC void BASICS::read() { //fprintf(stderr,"BASICS::read() subsys=%s\n", subsys); SSTRING string; VIEWITEMS items; items.read( *f_config_file ); // Read config file for ( int i=0; iline.get() ); // Concatenate all lines string.append( " " ); // with spaces } KEYWORD *null = NULL; KEYWORD *keyword; KEYWORDLIST keywordlist; const char *config = string.get(); char word[WORD]; while ( 1 ) { keyword = keywordlist.option( word, config, WORD ); if ( keyword == null ) break; //fprintf(stderr,"read:keyword->id=%d keyword->word=%s: %s %s\n", keyword->id,keyword->word.get(), word, keyword->value?"":""); switch ( keyword->id ) { case KEY_DAEMON: daemon = atoi( word ); break; case KEY_POSTMASTER: postmaster.setfrom( word ); break; case KEY_NO_BOUNCEMAIL: if ( keyword->value ) no_bouncemail = 0; else no_bouncemail = 1; break; case KEY_LOGFILE: logfile.setfrom( word ); break; case KEY_SYSLOG: syslog = 1; break; case KEY_NOSYSLOG: syslog = 0; break; default: break; } } keywordlist.clean_option( ); } /* * probe() is the function that will see to that fetchmail is running * when it should. */ PUBLIC int BASICS::probe( int level, int target, int simulation ) { //fprintf(stderr,"BASICS::probe() level=%d target=%d schedule=%d previous_schedule=%d daemon=%d %s\n", level, target, (int)schedule, previous_schedule, daemon, simulation?"(simulation)":"" ); DAEMON_FETCHMAIL myFetchmail; schedule = (char)linuxconf_getvalnum( K_BASICS, K_SCHEDULE, 0 ); switch ( schedule ) { case K_SCHEDULE_MANUAL: if ( previous_schedule == K_SCHEDULE_DAEMON ) { myFetchmail.killdaemon(); } break; case K_SCHEDULE_CRON: if ( previous_schedule == K_SCHEDULE_DAEMON ) { myFetchmail.killdaemon(); } break; case K_SCHEDULE_DAEMON: if ( level == 2 && target == 2 && daemon > 0 ) { myFetchmail.startdaemon( daemon ); } break; } if ( ! simulation ) previous_schedule = (int)schedule; return( 0 ); } /* * class DAEMON_FETCHMAIL */ PUBLIC DAEMON_FETCHMAIL::DAEMON_FETCHMAIL() { //fprintf(stderr,"DAEMON_FETCHMAIL::DAEMON_FETCHMAIL()\n"); myProcess = getdaemonprocess(); } PUBLIC PROC *DAEMON_FETCHMAIL::getdaemonprocess() { //fprintf(stderr,"DAEMON_FETCHMAIL::getdaemonprocess(): "); PROC *myProcess = NULL; char pidpath[PATH_MAX]; sprintf (pidpath,"%s.pid","/var/run/fetchmail"); CONFIG_FILE f_pid ( pidpath, help_nil ,CONFIGF_OPTIONAL|CONFIGF_MANAGED ,"root","root",0600); if ( f_pid.exist ()){ myProcess = process_find ("fetchmail", &f_pid); //fprintf(stderr,"found"); } //fprintf(stderr,"\n"); return( myProcess ); } PUBLIC int DAEMON_FETCHMAIL::killdaemon() { //fprintf(stderr,"DAEMON_FETCHMAIL::killdaemon(): "); int ret = 0; if (myProcess != NULL){ net_prtlog (NETLOG_CMD,MSG_U(X_KILLFETCHMAIL ,"Killing fetchmail\n") ); ret = myProcess->kill( SIGTERM ); //fprintf(stderr,"killed"); } //fprintf(stderr,"\n"); return( ret ); } PUBLIC int DAEMON_FETCHMAIL::startdaemon( int daemon ) { //fprintf(stderr,"DAEMON_FETCHMAIL::startdaemon()\n"); int ret = 0; long modified_time = file_date (f_config_file->getpath()); if (myProcess != NULL && myProcess->getstarttime() < modified_time){ /* * The process is older than the config file */ killdaemon(); myProcess = NULL; } if (myProcess == NULL){ /* * Not running: Start fetchmail * * If daemon==0 fetchmail will do a one time retreival and then * exit. * Therefore this kind of start should only occur at boot time * and never more. The problem is: How to recognize boot? * Leave this problem for now. Stop this function by diabling * configuration boot time start + interval = 0. */ DAEMON_INTERNAL *myDaemon = daemon_find ("fetchmail"); if ( myDaemon->is_managed() ) { char *logstring = NULL; int log_details = linuxconf_getvalnum( K_BASICS, K_LOG, K_LOG_STANDARD ); switch ( log_details ) { case K_LOG_STANDARD: logstring = ""; break; case K_LOG_SILENT: logstring = "--silent"; break; case K_LOG_VERBOSE: logstring = "-v -v"; break; } char cmd[500]; sprintf(cmd,"%s %s -f %s", myDaemon->getpath(), logstring, f_config_file->getpath() ); //fprintf(stderr,"DAEMON_FETCHMAIL::startdaemon() cmd=%s\n", cmd); netconf_system(5 ,cmd); } } return ret; }