#include #include #include #include #include "internal.h" #include #include "../paths.h" #include "mailconf.h" #include "mailconf.m" #include static MAILCONF_HELP_FILE help_mailtable ("mailtable"); CONFIG_FILE f_mailtable (VAR_LIB_MAILERTABLE,help_mailtable ,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,subsys_mail); PUBLIC SPC_ROUTE::SPC_ROUTE() { subdomain = 0; } PUBLIC void SPC_ROUTE::write (FILE_CFG *fout) { fprintf (fout,"%s %s:%s\n",to.get(),mailer.get(),forwarder.get()); if (subdomain){ fprintf (fout,".%s %s:%s\n",to.get(),mailer.get() ,forwarder.get()); } } /* Edit one routing and return 0 if edit was success Return 1 if the entry must be deleted. */ PUBLIC int SPC_ROUTE::edit() { DIALOG dia; dia.newf_str (MSG_U(F_DEST,"Destination"),to); dia.newf_str (MSG_U(F_FORWARD,"Forwader"),forwarder); dia.newf_chk ("",subdomain,MSG_U(F_MANAGE,"Manage sub-domain identically")); FIELD_COMBO *com = dia.newf_combo (MSG_U(F_MAILER,"Mailer"),mailer); basic_setmailer (com); int ret = -1; int nof = 0; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_SPECIAL,"Special routing") ,MSG_U(I_SPECIAL ,"Enter a destination (host) and the\n" "forwarder (another host) used to reach it\n" "and the mailer (transport) needed") ,help_mailtable ,nof ,MENUBUT_DEL|MENUBUT_ACCEPT|MENUBUT_CANCEL); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_DEL){ ret = 1; break; }else{ if (to.is_empty() || forwarder.is_empty() || mailer.is_empty()){ xconf_error (MSG_U(E_EMPTYF,"All field must be filled")); }else{ ret = 0; break; } } } if (ret != 0) dia.restore(); return ret; } PUBLIC SPC_ROUTES::SPC_ROUTES() { /* #Specification: mailconf / special routing A lookup file may be used by sendmail to managed the routing of certain site. This file is called the mailer table. Mostly, if the destination match one entry of this table, the value pair mailer:forwarder will be used. This ascii file must be turned into a database so sendmail can use it efficiently. This is normally done using the makemap utility. mailconf will always generate this file even if it is empty. One reason is to simplify the generation of the sendmail.cf file. */ FILE_CFG *fin = f_mailtable.fopen ("r"); if (fin != NULL){ char buf[500]; int noline = 0; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ noline++; strip_end (buf); char *pt = str_skip (buf); if (pt[0] != '\0'){ char word[300]; pt = str_copyword(word,pt,sizeof(word)); SPC_ROUTE *rt = new SPC_ROUTE; rt->to.setfrom (word); pt = str_skip(pt); if (pt[0] != '\0'){ str_copyword(word,pt,sizeof(word)); pt = strchr(word,':'); if (pt != NULL){ *pt++ = '\0'; rt->mailer.setfrom(word); rt->forwarder.setfrom(pt); add (rt); } } } } fclose (fin); /* #Specification: mailconf / mailertable / domain and subdomain We can specify a different special routing for a domain, and for subdomain in the mailer table. This is done with two separate line: # foo.com mailer:forwarder .foo.com mailer:forwarder # The first line manage foo.com and the other everything else under it. mailconf present this information in a single record. A checkbox let specify if we want to manage the subdomain identically. This is simpler to understand for administrator. The information is still written as two separate line in the mailertable and fold back into a single one when read */ for (int i=0; ito.get(); if (to[0] != '.'){ for (int j=0; jto.get(); if (tof[0] == '.' && strcmp(to,tof+1)==0 && rt->mailer.cmp(rtf->mailer)==0 && rt->forwarder.cmp(rtf->forwarder)==0){ // Ok, we have found the same record, but applying // to subdomain. // We set the subdomain flag in rt and delete // this record rt->subdomain = 1; remove_del (rtf); if (j < i) i--; break; } } } } } } /* Write the mailertable back. */ PUBLIC int SPC_ROUTES::save() { int ret = -1; FILE_CFG *fout = f_mailtable.fopen ("w"); if (fout != NULL){ int nb = getnb(); for (int i=0; iwrite(fout); fclose (fout); } return ret; } int mtable_makemap(CONFIG_FILE &conf) { int ret = -1; const char *type = confread_getdbformat(); if (conf.exist() && type != NULL){ static const char K_KMAILDBTYPE[]="kmaildbtype"; const char *typeext = "db"; if (strcmp(type,"dbm")==0){ typeext = "dbm"; } const char *path = conf.getpath(); char dbpath[PATH_MAX]; snprintf (dbpath,PATH_MAX-1,"%s.%s",path,typeext); long date = conf.getdate (); long dbdate = file_date (dbpath); const char *lasttype = linuxconf_getval (K_KMAILDBTYPE,path); if (date > dbdate || lasttype == NULL || strcmp(lasttype,type)!=0){ char buf[PATH_MAX*2]; sprintf (buf,"%s %s <%s",type,path,path); ret = netconf_system_if ("makemap",buf); if (ret == 0 && !simul_ison()){ linuxconf_replace (K_KMAILDBTYPE,path,type); linuxconf_save(); } }else{ ret = 0; } } return ret; } /* Write the mailertable back and rebuild the database */ PUBLIC int SPC_ROUTES::build() { // This save simply insure that the file exist // The constructor of SPC_ROUTES will manage a missing // mailertable as an empty one. Given that the sendmail.cf // refer to it all the time, we force a generation of the file save(); return mtable_makemap(f_mailtable); } PUBLIC SPC_ROUTE *SPC_ROUTES::getitem(int no) { return (SPC_ROUTE *)ARRAY::getitem(no); } static int cmp(const ARRAY_OBJ *p1, const ARRAY_OBJ *p2) { SPC_ROUTE *r1 = (SPC_ROUTE *)p1; SPC_ROUTE *r2 = (SPC_ROUTE *)p2; return r1->to.cmp(r2->to); } PUBLIC void SPC_ROUTES::sort() { ARRAY::sort (cmp); } /* Edit the special routings database. Return 0 if the something was changed in the database. */ PUBLIC int SPC_ROUTES::edit () { int ret = -1; while (1){ sort(); int nb = getnb(); MENU_STATUS code; int choice = 0; { DIALOG dia; for (int i=0; ito.get()); } dia.addwhat (MSG_U(I_ADDONE,"Select [Add] to add one routing spec")); code = dia.editmenu ( MSG_U(T_SPECIALS,"Special routings") ,MSG_U(I_SPECIALS,"You are allowed to edit/add/remove routings\n") ,help_mailtable ,choice ,MENUBUT_ADD); } if (code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (code == MENU_ADD){ SPC_ROUTE *spc = new SPC_ROUTE; if (spc->edit()==0){ add (spc); save(); ret = 0; }else{ delete spc; } }else if (nb > 0){ SPC_ROUTE *spc = getitem(choice); int status = spc->edit(); if (status != -1){ if (status == 1) remove_del(spc); save(); ret = 0; } } } return ret; }