#pragma implementation #include #include #include #include #include #include #include "postfixconf.h" #include #include #include #include "postfixconf.m" #include "virtuals.h" PUBLIC VIRT::VIRT(VIRTUALS *_vrtls) { vrtls = _vrtls; } PUBLIC VIRT::VIRT(char *line, VIRTUALS *_vrtls) { vrtls = _vrtls; char *p = str_skip(line); if (p[0] == '#'){ comment.setfrom (p); }else{ char buffer[1000]; int j=0; for (; *p!=' ' && *p!='\t' && *p!='\0'; j++,p++) buffer[j] = *p; buffer[j] = '\0'; if (!is_address(buffer)){ type = DOMAIN; adrsdom.setfrom(buffer); buffer[0] = '\0'; p = str_skip(p); anything.setfrom(p); }else{ type = ADDRESS; adrsdom.setfrom(buffer); buffer[0] = '\0'; for (j=0; *p!='\0';p++){ //add address if (isspace(*p)) continue; if (*p == ','){ buffer[j] = '\0'; j = 0; redcom.add(new SSTRING(buffer)); continue; } buffer[j] = *p; j++; } buffer[j] = '\0'; if (j>0) redcom.add(new SSTRING(buffer)); } } } PRIVATE bool VIRT::is_address(const char *t){ bool a = false; if (strstr(t,(const char*)"@")){ a = true; } return a; } PUBLIC bool VIRT::is_comment(char *t){ for (; *t!='\0'; t++) if (*t==',') return false; return true; } PUBLIC const char *VIRT::getname() { return adrsdom.get(); } PUBLIC int VIRT::is_valid() { return !adrsdom.is_empty(); } /* Edit an virtual table item definition. Return -1 if the user abort the edition (The record is left unchanged then). Return 0 if the user accepted changes Return 1 if the user request the deletion of this record */ PUBLIC int VIRT::editdomain(PRIVILEGE *privi, char anew) { DIALOG dia; dia.newf_str (MSG_U(F_VRTDOM,"Domain"),adrsdom); dia.newf_title ("",""); dia.newf_str (MSG_U(F_ANYTHING,"Comment"),anything); int no = 0; int ret = -1; int but_opt = MENUBUT_ACCEPT|MENUBUT_CANCEL; if (anew==0) but_opt |= MENUBUT_DEL; while (1){ MENU_STATUS code = dia.edit ( MSG_U(T_ONEVIRTUAL, "One domain table item definition"), MSG_U(I_ONEVIRTUAL, "Here, you can edit/delete a domain name.\n" "This domain will be used for address\n" "redirections.") ,help_postfix_virtual ,no ,but_opt); if (code == MENU_ESCAPE || code == MENU_CANCEL){ break; }else if (code == MENU_DEL){ if (xconf_delok ()){ // Test if this domain have redirections // if yes, the user must delete its redirections first if (vrtls->have_reddom (adrsdom.get())){ xconf_notice (MSG_U(N_DELDOMAIN,"You are attempting to delete a domain that\n" "still contains redirections. You must erase them\n" "before deleting the domain completely")); continue; } ret = 1; break; } }else if (code == MENU_ACCEPT && perm_access(privi,MSG_U(P_EDITVIRTUAL,"edit a virtual"))){ if (adrsdom.is_empty()){ no = 0; xconf_error (MSG_R(E_NONAME)); }else if (adrsdom.strstr("@")){ no = 0; xconf_error(MSG_R(E_NOAT)); }else if (anything.is_empty()){ anything.setfrom("virtual"); }else{ ret = 0; break; } } } if (ret == 0){ setmodified(); }else{ dia.restore(); } return ret; } PUBLIC int VIRTUALS::have_reddom (const char *domain){ for (int i=0; itype==ADDRESS && v->adrsdom.strstr(domain)) // if is address and domain is found return 1; } return 0; } PUBLIC int VIRT::editaddress(PRIVILEGE *privi, SSTRINGS *dom, char anew) { DIALOG dia; SSTRING name; SSTRING domcurr; int l=0; int ret = -1; if (dom!=NULL && dom->getnb()>0){ // There must be a domain list with at least one domain if (!adrsdom.is_empty()){ // There is an address. Pick only the first part of it const char *address = adrsdom.get(); char *end = strstr(address,"@"); if (end!=NULL){ // test if digit '@' is found l = end - address; name.setfrom(adrsdom.get(),l); domcurr.setfrom(++end); }else{ // invalid address xconf_error (MSG_U(E_FINDADRS,"Can't find address")); delete (dom); return ret; } }// checks, whenever it's not a new domain, if this domain is present in the domain list dia.newf_str (MSG_U(F_USERNAME,"Username"),name); FIELD_COMBO *combo = dia.newf_combo(MSG_R(F_DOMAIN),domcurr); for (int i=0; igetnb(); i++) // add the domain combos combo->addopt(dom->getitem(i)->get()); dia.newf_title ("",""); // add the redirections list for (int i=0; i<10; i++) redcom.add (new SSTRING); int vnb = redcom.getnb(); for (int i=0; istrip_end(); } int i; for (i=0; iis_empty()){ break; } } if (i == vnb){ xconf_error (MSG_R(E_ALLEMPTY)); no = 4; }else{ // do changes adrsdom.setfrom(name); adrsdom.append("@"); adrsdom.append(domcurr.get()); ret = 0; break; } } } } } if (ret == 0){ setmodified(); }else{ dia.restore(); } redcom.remove_empty(); }else{ xconf_error (MSG_U(E_NODOMAINS,"You don't have any domain!\n" "You must have at least one domain\n" "in your table")); } delete (dom); return ret; } PRIVATE int VIRT::have_domain(const char *d, SSTRINGS* doms) { int ret = 0; for (int i=0; igetnb(); i++){ if(doms->getitem(i)->cmp(d)==0){ ret = 1; } } return ret; } PRIVATE SSTRINGS *VIRTUALS::populatedomains() { SSTRINGS *dom = new SSTRINGS(); dom->neverdelete(); for (int i=0; itype==DOMAIN && v->is_valid()){ dom->add(&(v->adrsdom)); } } dom->remove_dups(); dom->sort(); return dom; } // save the content of instance variables in file PUBLIC void VIRT::write (FILE_CFG *fout) { if (type==ADDRESS){ if (!adrsdom.is_empty()){ fprintf (fout, "%s ",adrsdom.get()); int nb = redcom.getnb(); char *comma = ","; bool needcomas = 0; for (int i=0; iget()); else fprintf (fout,"%s",s->get()); needcomas = 1; } } }else{ if (!adrsdom.is_empty()){ char buffer[256]; sprintf(buffer,"%s %s",adrsdom.get(),anything.get()); fprintf (fout, "%s ",buffer); } } fprintf (fout, "%s\n",comment.get()); } PUBLIC VIRT *VIRTUALS::getitem(int no) { return (VIRT*)ARRAY::getitem(no); } PUBLIC VIRTUALS::VIRTUALS( const char *config, PRIVILEGE *_privi, bool _dodb, int _btype) : f(config,help_postfix_virtual, CONFIGF_OPTIONAL|CONFIGF_MANAGED, subsys_postfix) { privi = _privi; dodb = _dodb; btype = _btype; FILE_CFG *fin = f.fopen ("r"); if (fin != NULL){ char line[10000]; line[0] = '\0'; while (fgets(line,sizeof(line)-1,fin)!=NULL){ strip_end (line); if (line[0] != '\0'){ add (new VIRT(line, this)); } } fclose (fin); rstmodified(); } } PUBLIC int VIRTUALS::edit() { int choice = 0; int modified = 0; DIALOG dia; static const char *domnames = MSG_U(M_DOMAINNAMES,"Domain names"); static const char *redirections = MSG_U(M_REDIRECTIONS,"Redirections"); static const char *menuopt[]={ "", domnames, "", redirections, NULL }; dia.new_menuitems (menuopt); while (1){ MENU_STATUS code = dia.editmenu ( MSG_U(T_VIRTTABLEEDITPRINC,"Virtual table") ,MSG_U(I_VIRTTABLEEDITPRINC, "The optional virtual table specifies redirections\n" "for local and non-local recipients or domains.\n" "You are allowed to edit/add/delete domain names\n" "or address redirections") ,help_postfix_virtual ,choice,0); if (code == MENU_ESCAPE || code == MENU_QUIT){ break; }else{ const char *key = dia.getmenustr (choice); if (key == domnames){ modified |= editdomain(); }else if (key == redirections){ modified |= editaddress(); } } } if (dodb && modified){ SSTRING notice; const char *cmd = "postmap"; char *buf = type(btype); char path[50]; sprintf (path,"%s%s",buf,f.getpath()); if (execute (cmd,path,notice)){ xconf_notice ("%s",notice.get()); }else xconf_error (MSG_U(E_EXECCOMM,"Can't execute command %s %s"),cmd,path); } if (f.exist()) return nb; else return -1; } // Construct DIALOG with domain list and edit PRIVATE int VIRTUALS::editdomain() { int ret = 0; int choice = 0; DIALOG_LISTE *dia = NULL; SSTRINGS domnames; SSTRINGS domcomments; domnames.neverdelete(); domcomments.neverdelete(); while (1){ if (dia == NULL){ dia = new DIALOG_LISTE; dia->newf_head("", MSG_U(X_DOMAINS_COMMENTS,"Domains\tComments")); domnames.remove_all(); domcomments.remove_all(); for (int i=0; itype==DOMAIN && v->is_valid()){ domnames.add(&(v->adrsdom)); domcomments.add(&(v->anything)); } } for (int i=0; inew_menuitem(domnames.getitem(i)->get(), domcomments.getitem(i)->get()); } dia->addwhat (MSG_U(I_NEWDOMAIN,"Select [Add] to add a new domain item")); } MENU_STATUS code = dia->editmenu ( MSG_U(T_VIRTTABLEEDITDOMAIN,"Here, you can find a list of domains.") ,MSG_U(I_VIRTTABLEEDITDOMAIN, "You are allowed to edit/add/delete\n" "domain address") ,help_postfix_virtual ,choice,0); VIRT *item = NULL; if (choice >=0 && choice get(); item = getitemsel(str, DOMAIN); } bool must_delete = false; if (code == MENU_ESCAPE || code == MENU_QUIT){ break; }else if (code == MENU_OK){ ret = 1; if (item != NULL){ int ok; while(1){ ok = item->editdomain(privi, 0); if (ok==1 || locatedups(item->getname())<1) break; xconf_error (MSG_R(E_DUPVRTITEM)); } if (manage_edit (item,ok) >= 0){ must_delete = true; } } }else if (perm_access(privi,MSG_R(P_WRITE),f.getpath())){ ret = 1; if (code == MENU_ADD){ addnewdomain(); must_delete = true; } } if (must_delete){ delete dia; dia = NULL; } } delete dia; return ret; } PRIVATE int VIRTUALS::editaddress() { int ret = 0; int choice = 0; DIALOG_LISTE *dia = NULL; SSTRINGS addrsnames; SSTRINGS addrsred; addrsnames.neverdelete(); while (1){ if (dia == NULL){ dia = new DIALOG_LISTE; dia->newf_head("", MSG_U(X_ADDRESS_REDIRS,"Addresses\tRedirections")); addrsnames.remove_all(); addrsred.remove_all(); for (int i=0; itype==ADDRESS && v->is_valid()){ addrsnames.add(&(v->adrsdom)); SSTRING *t = new SSTRING(); bool needcommas = 0; for (int j=0; jredcom.getnb(); j++){ if (needcommas){ t->append(","); t->append (" "); } t->appendf ("%s",v->redcom.getitem(j)->get()); needcommas = 1; } addrsred.add(t); } } for (int i=0; inew_menuitem(addrsnames.getitem(i)->get(), addrsred.getitem(i)->get()); } dia->addwhat (MSG_U(I_NEWREDIRECTION,"Select [Add] to add a new redirection item")); } MENU_STATUS code = dia->editmenu ( MSG_U(T_VIRTTABLEEDITREDIRECTIONS,"Redirections") ,MSG_U(I_VIRTTABLEEDITREDIRECTIONS, "You are allowed to edit\n" "address redirections") ,help_postfix_virtual ,choice,0); VIRT *item = NULL; if (choice >=0 && choice get(); item = getitemsel(str, ADDRESS); } bool must_delete = false; if (code == MENU_ESCAPE || code == MENU_QUIT){ break; }else if (code == MENU_OK){ ret = 1; if (item != NULL){ int ok; while(1){ ok = item->editaddress(privi, populatedomains(),0); if (ok==1 || locatedups(item->getname())<1) break; xconf_error (MSG_R(E_DUPREDITEM)); } if (manage_edit (item,ok) >= 0){ must_delete = true; } } }else if (perm_access(privi,MSG_R(P_WRITE),f.getpath())){ if (code == MENU_ADD){ ret = 1; addnewaddress(); must_delete = true; } } if (must_delete){ delete dia; dia = NULL; } } delete dia; return ret; } PRIVATE VIRT *VIRTUALS::getitemsel(const char *str, int tp){ VIRT *v = NULL; for (int i=0; itype==tp && strcmp(str,s->adrsdom.get())==0){ v = s; } } return v; } /* Find an virtual item in the table. Return -1 if not found. Return the index otherwise. */ PUBLIC int VIRTUALS::locate (const char *name) { int ret = -1; int nb = getnb(); for (int i=0; igetname(),name)==0){ ret = i; break; } } return ret; } PUBLIC int VIRTUALS::locatedups (const char *name) { int ret = -1; int nb = getnb(); for (int i=0; igetname(),name)==0){ ret++; } } return ret; } PUBLIC void VIRTUALS::addnewdomain() { VIRT *a = new VIRT(this); a->type = DOMAIN; while (a->editdomain(privi,1)==0){ // verify if domains exist if ( locate(a->getname())!=-1 ){ xconf_error (MSG_U(E_DUPVRTITEM,"Duplicate domain item, rejected")); }else{ add (a); write(); a = NULL; break; } } delete a; } PUBLIC void VIRTUALS::addnewaddress() { VIRT *a = new VIRT(this); a->type = ADDRESS; while (a->editaddress(privi, populatedomains(), 1)==0){//verify if domain exist if ( locate(a->getname())!=-1 ){ xconf_error (MSG_U(E_DUPREDITEM,"Duplicate redirection item, rejected")); }else{ add (a); write(); a = NULL; break; } } delete a; } PUBLIC int VIRTUALS::write () { int ret = -1; FILE_CFG *fout = f.fopen (privi,"w"); if (fout != NULL){ for (int i=0; iwrite(fout); } ret = fclose (fout); rstmodified(); } return ret; } PRIVATE char *VIRTUALS::type (int nametable) { char *buf; switch (nametable){ case BTREE_DATABASE: buf = "btree:"; break; case DBM_DATABASE: buf = "dbm:"; break; case HASH_DATABASE: buf = "hash:"; break; default: buf = ""; } return buf; }