#include #include #include "mailconf.h" #include "mailconf.m" #include "internal.h" #include #include #include #include #include #include static MAILCONF_HELP_FILE help_vacation ("vacation"); void vacation_drawinfo (DIALOG &dia, const char *msg) { SSTRINGS tb; str_cnv2lines (msg,tb); for (int i=0; iget()); } } struct VACATION_INFO{ SSTRING text; SSTRING subject; SSTRING dir,msgfile,dbfile; char enable; char reset; SSTRING oldtext; SSTRING oldsubject; PRIVATE_MESSAGE msg; SSTRING nbinlist; int noinlist; }; /* Set the number of email address in the vacation db */ static void vacation_countaddr (VACATION_INFO &info) { int nblines = (info.dbfile.get(),true); return 0; if (nblines == -1) nblines = 0; info.nbinlist.setfromf (MSG_U(I_NBEMAILINDB,"%d correspondent(s) in list"),nblines); } static void vacation_setupinfo ( VACATION_INFO &info, const char *user, const char *domain) { info.dir.setfromf ("/var/spool/vmail/files/%s",domain); info.msgfile.setfromf ("/var/spool/vmail/files/%s/%s.vacation",domain,user); info.dbfile.setfromf ("/var/spool/vmail/files/%s/%s.vacation.db",domain,user); } static int vacation_setup( DIALOG &dia, const char *user, const char *domain, VACATION_INFO &info, bool verbose) // Put various help text in the dialog { glocal VACATION_INFO *info = &info; vacation_setupinfo (info,user,domain); info.enable = 0; info.reset = 0; if (file_exist (info.dbfile.get()) && file_exist(info.msgfile.get())){ info.enable = 1; } (info.msgfile.get(),true); if (noline == 0 && strncasecmp(line,"Subject:",8)==0){ glocal.info->subject.setfrom (str_skip(line+8)); }else if (noline != 1 && line[0] != '\0'){ glocal.info->text.appendf ("%s\n",line); } return 0; info.text.strip_end(); info.oldtext.setfrom (info.text); info.oldsubject.setfrom (info.subject); if (verbose){ vacation_drawinfo (dia,MSG_U(I_ENABLEVACINFO,"You can turn the vacation mechanism on or off")); } int nof = dia.getnb(); dia.newf_chk (MSG_U(F_ENABLEVAC,"Enable"),info.enable,MSG_U(I_ENABLEVAC,"the vacation service")); if (verbose){ dia.newf_info ("",""); vacation_drawinfo (dia,MSG_U(I_RESETVACINFO ,"The vacation mechanism send one message per correspondent\n" "The correspondent list is kept in a database\n" "You may want to reset (empty) the database\n" "if you change the message for example")); } dia.newf_chk (MSG_U(F_RESETVAC,"Reset"),info.reset,MSG_U(I_RESETVAC,"the correspondent list")); vacation_countaddr (info); info.noinlist = dia.getnb(); dia.newf_str ("",info.nbinlist); dia.set_lastreadonly(); dia.new_button (MSG_U(B_EDITLIST,"Edit list"),MSG_R(B_EDITLIST),info.msg); dia.waitfor (info.msg); dia.newf_str (MSG_U(F_SUBJECT,"Message subject"),info.subject); if (verbose){ vacation_drawinfo (dia,MSG_U(I_TEXT,"Enter the text to send to every correspondent while you are away")); } dia.newf_textarea (MSG_U(F_TEXT,"Vacation text"),info.text,60,10); return nof; } static void vacation_apply ( VACATION_INFO &info, SSTRING &msg, const char *domain, const char *user) { info.text.strip_end(); file_mkdirp (info.dir.get(),"root","root",0755); if (info.text.cmp(info.oldtext)!=0 || info.subject.cmp(info.oldsubject)!=0){ const char *msgfile = info.msgfile.get(); if (info.text.is_empty() && info.subject.is_empty()){ unlink (msgfile); msg.appendf (MSG_U(I_RMTEXT,"Vacation message deleted.\n")); net_prtlog (NETLOG_VERB,MSG_U(N_DELVACATION,"domain %s, user %s: Vacation message deleted: %s\n") ,domain,user,msgfile); }else{ msg.appendf (MSG_U(I_TEXTUPD,"Vacation message updated.\n")); VACATION_INFO *info; glocal.info = &info; net_prtlog (NETLOG_VERB,MSG_U(N_UPDVACATION,"domain %s, user %s: Vacation message updated: %s\n") ,domain,user,msgfile); (msgfile,false); fprintf (fout,"Subject: %s\n\n",glocal.info->subject.get()); fputs (glocal.info->text.get(),fout); return 0; } } // msg.appendf ("debug: %d %d %d\n",file_exist(dbfile.get()),enable,reset); if (!file_exist(info.dbfile.get())){ if (info.enable){ file_create (info.dbfile.get(),"root","root",0660); msg.appendf (MSG_U(I_DBCREATED,"Database initialised, vacation service active.\n")); net_prtlog (NETLOG_VERB,MSG_U(N_DBCREATED,"domain %s, user %s: Vacation db initialised: %s\n") ,domain,user,info.dbfile.get()); } }else{ if (!info.enable){ unlink (info.dbfile.get()); msg.appendf (MSG_U(I_VACDISABLED,"Vacation service disabled.\n")); net_prtlog (NETLOG_VERB,MSG_U(N_DBDELETED,"domain %s, user %s: Vacation db deleted: %s\n") ,domain,user,info.dbfile.get()); }else if (info.reset){ unlink (info.dbfile.get()); file_create (info.dbfile.get(),"root","root",0660); msg.appendf (MSG_U(I_RESETDB,"Database cleared.\n")); net_prtlog (NETLOG_VERB,MSG_U(N_DBRESET,"domain %s, user %s: Vacation db reset: %s\n") ,domain,user,info.dbfile.get()); } } } static void vacation_edit(const char *user, const char *domain) { DIALOG dia; VACATION_INFO info; int nof = vacation_setup (dia,user,domain,info,true); while (1){ MENU_STATUS code = dia.edit (MSG_U(T_VACATION,"Vacation configuration") ,MSG_U(I_VACATION,"") ,help_vacation ,nof); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else{ perm_setbypass (true); SSTRING msg; vacation_apply (info,msg,domain,user); perm_setbypass (false); if (msg.is_empty()) msg.setfrom (MSG_U(I_NOTHINGDONE,"No changed performed")); xconf_notice (msg.get()); break; } } } /* Check the password of a user when provided with the email address. The vdomain is identified from the email address. */ int vdomain_checkpass ( const SSTRING &addr, const SSTRING &passwd, USERS *&users, // Will contain the user list // The call must delete this USER *&user, // Will contain the user record CONFIG_FILE *&file, CONFIG_FILE *&file_shadow, SSTRING &uid, SSTRING &domain) { int ret = -1; users = NULL; user = NULL; file = NULL; file_shadow = NULL; const char *ptaddr = addr.get(); const char *pt = strchr(ptaddr,'@'); if (pt == NULL){ xconf_error (MSG_U(E_NOATSIGN ,"You must supply a complete email address\n" "of the form user@some_domain.xxx")); }else{ const char *ptdomain = pt+1; VDOMAINS vdom; VDOMAIN *dom = vdom.locate (ptdomain); if (dom == NULL){ xconf_error (MSG_U(E_IVLDEMAIL ,"Invalid email address")); sleep(3); }else{ domain = ptdomain; CONFIG_FILE *file,*file_shadow; users = dom->getusers (file,file_shadow); uid.setfrom (ptaddr,(int)(pt-ptaddr)); user = users->getitem(uid.get()); if (user == NULL){ xconf_error (MSG_U(E_IVLDPASSWD ,"Invalid email address or password")); sleep(3); }else if (!perm_validpass (*users,uid.get(),passwd.get())){ xconf_error (MSG_R(E_IVLDPASSWD)); sleep(3); }else{ // Ok we know the domain, the password is good ret = 0; } } } if (ret != 0){ delete users; users = NULL; user = NULL; delete file; delete file_shadow; file = NULL; file_shadow = NULL; } return ret; } void vacation_login() { DIALOG dia; SSTRING addr,passwd; vacation_drawinfo (dia,MSG_U(I_EMAILADRINFO,"user + domain: joe@some-domain.com")); int nof = dia.getnb(); dia.newf_str (MSG_U(F_EMAILADR,"Your email address"),addr); dia.newf_pass (MSG_U(F_PASSWORD,"Your password"),passwd); while (1){ MENU_STATUS code = dia.edit (MSG_U(T_USERAUTH,"Email user authentication") ,MSG_U(I_USERAUTH,"Please identify yourself") ,help_vacation ,nof); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else{ USERS *users; USER *user; CONFIG_FILE *file,*file_shadow; SSTRING domain,uid; if (vdomain_checkpass (addr,passwd,users,user ,file,file_shadow,uid,domain)!=-1){ // Ok we know the domain, the password is good vacation_edit (uid.get(),domain.get()); passwd.setempty(); addr.setempty(); dia.reload(); delete users; delete file; delete file_shadow; } } } } static void vacation_editlist(const char *fname) { SSTRING text; (fname,true); glocal.text.appendf ("%s\n",line); return 0; DIALOG dia; dia.newf_textarea (NULL,glocal.text,50,15); int nof = 0; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_VACATIONLIST,"Vacation list") ,MSG_U(I_VACATIONLIST ,"Here is the email address list collected so far\n" "by the vacation process. You have received at least\n" "one message from those address since you have enabled\n" "your vacation message.") ,help_nil ,nof); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else{ (fname,false); fputs (glocal.text.get(),fout); return 0; break; } } } class VACATION_COMNG: public USERACCT_COMNG{ bool is_new; SSTRING domain; VACATION_INFO info; /*~PROTOBEG~ VACATION_COMNG */ public: VACATION_COMNG (DICTIONARY&_dict); int deluser (PRIVILEGE *priv); void message (DIALOG&dia); int save (PRIVILEGE *priv); void setupdia (DIALOG&dia); int validate (DIALOG&, int &nof); /*~PROTOEND~ VACATION_COMNG */ }; PUBLIC VACATION_COMNG::VACATION_COMNG( DICTIONARY &_dict) : USERACCT_COMNG (_dict) { domain.setfrom (dict.get_str ("domain")); this->is_new = dict.get_bool ("is_new"); } PUBLIC void VACATION_COMNG::setupdia ( DIALOG &dia) { dia.addhelp (help_vacation,MSG_U(T_VSETTINGS,"Vacation settings")); dia.newf_title (MSG_R(T_VSETTINGS),1 ,"",MSG_R(T_VSETTINGS)); const char *ptname = dict.get_str ("name"); vacation_setup (dia,ptname,domain.get(),info,false); } PUBLIC void VACATION_COMNG::message ( DIALOG &dia) { if (dialog_testmessage(info.msg)){ vacation_editlist(info.dbfile.get()); vacation_countaddr (info); dia.reload (info.noinlist); } } PUBLIC int VACATION_COMNG::save( PRIVILEGE *priv) { SSTRING msg; perm_setbypass (true); const char *user = dict.get_str ("name"); vacation_setupinfo (info,user,domain.get()); vacation_apply (info,msg,domain.get(),user); perm_setbypass (false); if (msg.is_filled()) xconf_notice (msg.get()); return 0; } PUBLIC int VACATION_COMNG::validate( DIALOG &, int &nof) { return 0; } PUBLIC int VACATION_COMNG::deluser ( PRIVILEGE *priv) { unlink (info.dbfile.get()); unlink (info.msgfile.get()); return 0; } USERACCT_COMNG *vacation_newcomng( const char *key, DICTIONARY &dict) { USERACCT_COMNG *ret = NULL; const char *domain = dict.get_str("domain"); if (strcmp(key,"user")==0 && domain != NULL && strcmp(domain,"/")!=0){ ret = new VACATION_COMNG (dict); } return ret; }