#include #include #include #include #include "mailconf.h" #include #include "mailconf.m" #include "internal.h" #include #include #include #include "alias.h" #include "../paths.h" static MAILCONF_HELP_FILE help_aliascomng ("aliascomng"); class ALIAS_COMNG: public USERACCT_COMNG{ SSTRINGS aliases; // Redirect those aliases to this account SSTRING redir; // Redirect email for this account to another // account or email address bool redir_other; // Is there a redir of this account to an // alias filter or alias file SSTRING domain; bool is_new; // This is a new account, does not exist // yet (and may never exist) int first_field; int quota; // Email quota. Unrelated to alias, but nice to // have at the same place in the user account // dialog. /*~PROTOBEG~ ALIAS_COMNG */ public: ALIAS_COMNG (DICTIONARY&_dict); int deluser (PRIVILEGE *priv); int save (PRIVILEGE *priv); private: void setup_uquotap (char uquotap[PATH_MAX]); public: void setupdia (DIALOG&dia); int validate (DIALOG&, int &nof); /*~PROTOEND~ ALIAS_COMNG */ }; PRIVATE void ALIAS_COMNG::setup_uquotap(char uquotap[PATH_MAX]) { snprintf (uquotap,PATH_MAX-1,"%s/%s/%s.quota" ,VAR_SPOOL_VMAIL,domain.get(),dict.get_str ("name")); } PUBLIC ALIAS_COMNG::ALIAS_COMNG( DICTIONARY &_dict) : USERACCT_COMNG (_dict) { quota = 0; domain.setfrom (dict.get_str ("domain")); this->is_new = dict.get_bool ("is_new"); redir_other = false; if (!is_new){ char path[PATH_MAX]; const char *ptname = dict.get_str ("name"); if (domain.cmp("/")==0){ extern CONFIG_FILE f_virtuser; VIEWITEMS vitems; vitems.read (f_virtuser); int n = vitems.getnb(); for (int i=0; iline.get() ,sizeof(word)-1); pt = str_skip(pt); if (stricmp(pt,ptname)==0){ aliases.add (new SSTRING(word)); } } strcpy (path,ETC_ALIASES); }else{ sprintf (path,"%s/aliases.%s",ETC_VMAIL,domain.get()); char uquotap[PATH_MAX]; setup_uquotap(uquotap); FILE *fin = fopen (uquotap,"r"); if (fin != NULL){ fscanf (fin,"%d","a); fclose (fin); } } CONFIG_FILE f_cfg (path,help_nil,CONFIGF_MANAGED|CONFIGF_OPTIONAL); ALIASES faliases (f_cfg,NULL,0); int n=faliases.getnb(); // We process the aliases to find out which aliases point to this // account and if this account messages are redirect for (int i=0; ivalues; int nv = values->getnb(); if (al->name.cmp(ptname) != 0){ for (int j=0; jgetitem(j)->icmp(ptname)==0){ aliases.add (new SSTRING(al->name.get())); break; } } }else{ redir_other = al->file.is_filled() || al->filter.is_filled(); for (int j=0; jgetitem(j)->get(); if (j > 0) redir.append (" "); redir.append (s); } } } } } PUBLIC void ALIAS_COMNG::setupdia ( DIALOG &dia) { dia.addhelp (help_aliascomng,MSG_U(T_MSETTINGS,"Mail settings")); dia.newf_title (MSG_R(T_MSETTINGS),1 ,"",MSG_R(T_MSETTINGS)); if (domain.cmp("/")!=0){ if (perm_getuid()==0 || policies_mayeditquota()){ static const char *tb[]={ MSG_U(I_DOMDEF,"Domain default"),NULL }; static const int tbv[]={0,0}; dia.newf_chkm_num (MSG_U(F_INBOXQUOTA,"Inbox max. size(k)"),quota ,tbv,tb); } } first_field = dia.getnb(); int nb_empty = 0; for (int i=0; iis_empty()) nb_empty++; } for (int e=nb_empty; e<3; e++){ aliases.add (new SSTRING); } dia.newf_str (MSG_U(F_REDIR,"Redirect messages to"),redir); for (int j=0; jline.get() ,sizeof(word)-1); pt = str_skip(pt); if (stricmp(pt,ptname)==0){ int lk = aliases.lookup(word); if (lk == -1){ vitems.remove_del (it); savevitems = true; i--; n--; }else{ mustadd[lk] = false; } } } strcpy (path,ETC_ALIASES); }else{ sprintf (path,"%s/aliases.%s",ETC_VMAIL,domain.get()); dodb = false; char uquotap[PATH_MAX]; setup_uquotap(uquotap); if (quota <= 0){ unlink (uquotap); }else{ FILE *fout = fopen (uquotap,"w"); if (fout != NULL){ fprintf (fout,"%d\n",quota); fclose (fout); } } group = "mail"; perms = 0640; } CONFIG_FILE f_cfg (path,help_nil,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,"root",group,perms); ALIASES faliases (f_cfg,priv,dodb); int n=faliases.getnb(); bool user_seen = false; ALIAS *redir_alias = new ALIAS; redir_alias->name.setfrom (ptname); str_splitline (redir.get(),' ',redir_alias->values); // We are updating both the redirections and the aliases for (int i=0; ivalues.getnb(); if (al->name.cmp(ptname)==0){ // This alias is the account, so we are plugging redirection // here. redir_alias->file = al->file; redir_alias->filter = al->filter; if (nv!=redir_alias->values.getnb()){ // No match, remove the old aliase remove_al = true; }else{ user_seen = true; for (int j=0; jvalues.getitem(j)->cmp (*redir_alias->values.getitem(j))!=0){ user_seen = false; remove_al = true; break; } } } }else{ // Other aliases. They may point to this account SSTRINGS *values = &al->values; int nv = values->getnb(); for (int j=0; jgetitem(j)->icmp(ptname)==0){ int lk = aliases.lookup(al->name.get()); if (lk == -1){ if (nv == 1){ // Remove the alias completly remove_al = true; }else{ // This is a list, remove the member values->remove_del(j); } savealiases = true; }else{ mustadd[lk] = false; } break; } } } if (remove_al){ faliases.remove_del(al); i--; n--; savealiases = true; } } if (!user_seen && redir.is_filled()){ // Ok, we must add an alias to redirect email for that user // We get here either because there were no aliase for that user // or because it was changed (The old record was deleted). savealiases = true; faliases.add (redir_alias); redir_alias = NULL; } delete redir_alias; for (int j=0; jget(); if (s[0] != '\0'){ if (strchr(s,'@')!=NULL){ char tmp[400]; snprintf (tmp,sizeof(tmp)-1,"%s\t%s",s,ptname); VIEWITEM *it = new VIEWITEM (tmp); /* #Specification: email aliases / virtusertable / adding new entries When we add an entry to redirect one virtual email account to a user account, we insert it at the beginning of the file. When the entry redirects a whole domain (start with @), we put it at the end, so user redirection has precedence over domain redirection. */ if (s[0] == '@'){ vitems.add (it); }else{ vitems.insert (0,it); } savevitems = true; }else{ int ali = faliases.locate(s); ALIAS *al = NULL; if (ali == -1){ al = new ALIAS; al->name.setfrom (s); faliases.add (al); }else{ al = faliases.getitem(ali); } al->values.add (new SSTRING(ptname)); savealiases = true; } } } } int ret = 0; if (savealiases && faliases.write()==-1){ ret = -1; }else if (savevitems){ if (vitems.write(f_virtuser,priv)==-1){ ret = -1; }else{ mtable_makemap(f_virtuser); } } return ret; } /* Check if the email alias do not contain special shell characters Return true is the alias is fine */ static bool alias_lexvalid (const char *s) { bool ret = true; static const char tb[]={'*','?','|','"','\'','`'}; for (unsigned i=0; iget(); int field = i + first_field +1; if (strcasecmp(ali,ptname)==0){ xconf_error (MSG_U(E_REDEUNDANT ,"Useless alias: alias %s points to account %s") ,ali,ali); nof = field; ret = -1; break; }else if (domain.cmp("/")!=0 && strchr(ali,'@')!=NULL){ xconf_error (MSG_U(E_NOVIRTALIAS ,"no fully qualified aliase for virtual domains")); nof = field; ret = -1; break; } if (!alias_lexvalid(ali)){ nof = field; ret = -1; xconf_error (MSG_U(E_IVLDCHAR,"Invalid character in aliase")); break; } } if (redir.icmp(ptname)==0 && !redir_other){ nof = first_field; ret = -1; xconf_error (MSG_U(E_LOOPING ,"Can't redirect emails to the same account\n" "(Alias looping)")); }else if (!alias_lexvalid(redir.get())){ nof = first_field; ret = -1; xconf_error (MSG_R(E_IVLDCHAR)); } return ret; } PUBLIC int ALIAS_COMNG::deluser ( PRIVILEGE *priv) { char uquotap[PATH_MAX]; setup_uquotap(uquotap); unlink (uquotap); aliases.remove_all(); redir.setfrom (""); return save (priv); } USERACCT_COMNG *alias_newcomng( const char *key, DICTIONARY &dict) { USERACCT_COMNG *ret = NULL; if (strcmp(key,"user")==0){ ret = new ALIAS_COMNG (dict); } return ret; }