/* Formatter for user's mailbox path */ /* Public domain; written by Eugene G. Crosser September 1999 */ /* this is developed for Zmailer (http://www.zmailer.org/) but do not include Zmailer's headers so the same file may be used with other products (notably IMAP/POP servers) */ #include "mailer.h" #include #ifdef STDC_HEADERS # include #else # ifdef HAVE_STRINGS_H # include # endif #endif #include #ifdef TEST #include #include #endif #ifndef __ # ifdef __STDC__ # define __(x) x # else # define __(x) /* */ # endif #endif #define DEFAULTDOMAIN "defaultdomain" /******** int fmtmbox (char *buf, int size, const char *format, const char *userid, const struct Zpasswd *pwd); format specifiers: %% - '%' alone %a - address as is %u - userid %U - long user name (userid if not supported) %d - first element of domain name %D - full domain name %x - next character derived from PJW hash of userid %X - next character derived from crc32 hash of userid %h - userid's home directory %n - least number guaranteening unique filename (for MH style boxes) *UNIMPL* %N - the same padded by leading zeroes to fixed length *UNIMPL* %(any other character) - substitute with "_bad_%_subst_" Examples: "/var/mail/%u" - standard mail directory "/var/mail/%x/%x/%u - hashed directory "%h/Mail/INBOX" - mailbox in user's home "/var/virtual/%D/mail/%X/%X/%u" - hashed spool with virtual domain ********/ extern int pjwhash32 __((const char *)); extern int crc32 __((const char *)); static int put_c __((char **, char *, int)); static int put_c(q,ebuf,c) char **q; char *ebuf; char c; { if (*q >= ebuf) return 1; *((*q)++)=(c); return 0; } static int put_s __((char **, char *, const char *)); static int put_s(q,ebuf,s) char **q; char *ebuf; const char *s; { char c; for (c=*s;c;c=*(++s)) { if (*q >= ebuf) return 1; *((*q)++)=c; } return 0; } int fmtmbox __((char *, int, const char *, const char *, const struct Zpasswd *)); int fmtmbox (buf, size, format, address, pwd) char *buf; int size; const char *format; const char *address; const struct Zpasswd *pwd; { char *q,*at,*dom,*dot; const char *p; char c; enum {norm,percentseen} state; int overflow=0; int phash=0, chash=0; char *ebuf=buf+size; if ((at=strrchr(address,'@'))) { *at='\0'; dom=at+1; } else dom=DEFAULTDOMAIN; state=norm; p=format; q=buf; for (c=*p;c;c=*(++p)) switch (state) { case norm: if (c == '%') state=percentseen; else overflow |= put_c(&q,ebuf,*p); break; case percentseen: switch (c) { case '%': overflow |= put_c(&q,ebuf,*p); break; case 'a': overflow |= put_s(&q,ebuf,address); if (at) { overflow |= put_c(&q,ebuf,'@'); overflow |= put_s(&q,ebuf,dom); } break; case 'u': overflow |= put_s(&q,ebuf,address); /* dom cut off */ break; case 'U': overflow |= put_s(&q,ebuf,pwd->pw_gecos); break; case 'd': if ((dot=strchr(dom,'.'))) *dot='\0'; overflow |= put_s(&q,ebuf,dom); if (dot) *dot='.'; break; case 'D': overflow |= put_s(&q,ebuf,dom); break; case 'x': if (!phash) phash=pjwhash32(address); overflow |= put_c(&q, ebuf, 'A' + (phash % 26)); phash /= 26; break; case 'X': if (!chash) chash=crc32(address); overflow |= put_c(&q, ebuf, 'A' + (chash % 26)); chash /= 26; break; case 'h': overflow |= put_s(&q,ebuf,pwd->pw_dir); break; case 'n': overflow |= put_s(&q,ebuf,"_%n_unimpl_"); break; case 'N': overflow |= put_s(&q,ebuf,"_%N_unimpl_"); break; default: overflow |= put_s(&q,ebuf,"_bad_%_subst_"); break; } state=norm; break; } *q='\0'; if (at) *at='@'; return overflow; } #ifdef TEST int main(argc, argv) int argc; char *argv[]; { struct Zpasswd *pwd; char buf[1024]; int rc; if (argc < 3) { fprintf(stderr,"usage: fmtmbox format user\n"); exit(1); } pwd = zgetpwnam(argv[2]); if (pwd == NULL) { if (errno) perror("getpwnam"); else fprintf(stderr,"no such user\n"); exit(1); } rc=fmtmbox(buf,sizeof(buf),argv[1],argv[2],pwd); printf("rc=%d, result=\"%s\"\n",rc,buf); return 0; } #endif