17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <auth.h>
47dd7cddfSDavid du Colombier #include <bio.h>
57dd7cddfSDavid du Colombier #include "imap4d.h"
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier /*
87dd7cddfSDavid du Colombier * these should be in libraries
97dd7cddfSDavid du Colombier */
107dd7cddfSDavid du Colombier char *csquery(char *attr, char *val, char *rattr);
117dd7cddfSDavid du Colombier
127dd7cddfSDavid du Colombier /*
137dd7cddfSDavid du Colombier * /lib/rfc/rfc2060 imap4rev1
147dd7cddfSDavid du Colombier * /lib/rfc/rfc2683 is implementation advice
157dd7cddfSDavid du Colombier * /lib/rfc/rfc2342 is namespace capability
167dd7cddfSDavid du Colombier * /lib/rfc/rfc2222 is security protocols
177dd7cddfSDavid du Colombier * /lib/rfc/rfc1731 is security protocols
187dd7cddfSDavid du Colombier * /lib/rfc/rfc2221 is LOGIN-REFERRALS
197dd7cddfSDavid du Colombier * /lib/rfc/rfc2193 is MAILBOX-REFERRALS
207dd7cddfSDavid du Colombier * /lib/rfc/rfc2177 is IDLE capability
217dd7cddfSDavid du Colombier * /lib/rfc/rfc2195 is CRAM-MD5 authentication
227dd7cddfSDavid du Colombier * /lib/rfc/rfc2088 is LITERAL+ capability
237dd7cddfSDavid du Colombier * /lib/rfc/rfc1760 is S/Key authentication
247dd7cddfSDavid du Colombier *
257dd7cddfSDavid du Colombier * outlook uses "Secure Password Authentication" aka ntlm authentication
267dd7cddfSDavid du Colombier *
277dd7cddfSDavid du Colombier * capabilities from nslocum
287dd7cddfSDavid du Colombier * CAPABILITY IMAP4 IMAP4REV1 NAMESPACE IDLE SCAN SORT MAILBOX-REFERRALS LOGIN-REFERRALS AUTH=LOGIN THREAD=ORDEREDSUBJECT
297dd7cddfSDavid du Colombier */
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier typedef struct ParseCmd ParseCmd;
327dd7cddfSDavid du Colombier
337dd7cddfSDavid du Colombier enum
347dd7cddfSDavid du Colombier {
357dd7cddfSDavid du Colombier UlongMax = 4294967295,
367dd7cddfSDavid du Colombier };
377dd7cddfSDavid du Colombier
387dd7cddfSDavid du Colombier struct ParseCmd
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier char *name;
417dd7cddfSDavid du Colombier void (*f)(char *tg, char *cmd);
427dd7cddfSDavid du Colombier };
437dd7cddfSDavid du Colombier
447dd7cddfSDavid du Colombier static void appendCmd(char *tg, char *cmd);
457dd7cddfSDavid du Colombier static void authenticateCmd(char *tg, char *cmd);
467dd7cddfSDavid du Colombier static void capabilityCmd(char *tg, char *cmd);
477dd7cddfSDavid du Colombier static void closeCmd(char *tg, char *cmd);
487dd7cddfSDavid du Colombier static void copyCmd(char *tg, char *cmd);
497dd7cddfSDavid du Colombier static void createCmd(char *tg, char *cmd);
507dd7cddfSDavid du Colombier static void deleteCmd(char *tg, char *cmd);
517dd7cddfSDavid du Colombier static void expungeCmd(char *tg, char *cmd);
527dd7cddfSDavid du Colombier static void fetchCmd(char *tg, char *cmd);
537dd7cddfSDavid du Colombier static void idleCmd(char *tg, char *cmd);
547dd7cddfSDavid du Colombier static void listCmd(char *tg, char *cmd);
557dd7cddfSDavid du Colombier static void loginCmd(char *tg, char *cmd);
567dd7cddfSDavid du Colombier static void logoutCmd(char *tg, char *cmd);
577dd7cddfSDavid du Colombier static void namespaceCmd(char *tg, char *cmd);
587dd7cddfSDavid du Colombier static void noopCmd(char *tg, char *cmd);
597dd7cddfSDavid du Colombier static void renameCmd(char *tg, char *cmd);
607dd7cddfSDavid du Colombier static void searchCmd(char *tg, char *cmd);
617dd7cddfSDavid du Colombier static void selectCmd(char *tg, char *cmd);
627dd7cddfSDavid du Colombier static void statusCmd(char *tg, char *cmd);
637dd7cddfSDavid du Colombier static void storeCmd(char *tg, char *cmd);
647dd7cddfSDavid du Colombier static void subscribeCmd(char *tg, char *cmd);
657dd7cddfSDavid du Colombier static void uidCmd(char *tg, char *cmd);
667dd7cddfSDavid du Colombier static void unsubscribeCmd(char *tg, char *cmd);
677dd7cddfSDavid du Colombier
687dd7cddfSDavid du Colombier static void copyUCmd(char *tg, char *cmd, int uids);
697dd7cddfSDavid du Colombier static void fetchUCmd(char *tg, char *cmd, int uids);
707dd7cddfSDavid du Colombier static void searchUCmd(char *tg, char *cmd, int uids);
717dd7cddfSDavid du Colombier static void storeUCmd(char *tg, char *cmd, int uids);
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier static void imap4(int);
747dd7cddfSDavid du Colombier static void status(int expungeable, int uids);
757dd7cddfSDavid du Colombier static void cleaner(void);
767dd7cddfSDavid du Colombier static void check(void);
7759cc4ca5SDavid du Colombier static int catcher(void*, char*);
787dd7cddfSDavid du Colombier
797dd7cddfSDavid du Colombier static Search *searchKey(int first);
807dd7cddfSDavid du Colombier static Search *searchKeys(int first, Search *tail);
817dd7cddfSDavid du Colombier static char *astring(void);
827dd7cddfSDavid du Colombier static char *atomString(char *disallowed, char *initial);
837dd7cddfSDavid du Colombier static char *atom(void);
847dd7cddfSDavid du Colombier static void badsyn(void);
857dd7cddfSDavid du Colombier static void clearcmd(void);
867dd7cddfSDavid du Colombier static char *command(void);
877dd7cddfSDavid du Colombier static void crnl(void);
887dd7cddfSDavid du Colombier static Fetch *fetchAtt(char *s, Fetch *f);
897dd7cddfSDavid du Colombier static Fetch *fetchWhat(void);
907dd7cddfSDavid du Colombier static int flagList(void);
917dd7cddfSDavid du Colombier static int flags(void);
927dd7cddfSDavid du Colombier static int getc(void);
937dd7cddfSDavid du Colombier static char *listmbox(void);
947dd7cddfSDavid du Colombier static char *literal(void);
957dd7cddfSDavid du Colombier static ulong litlen(void);
96becaf2abSDavid du Colombier static MsgSet *msgSet(int);
977dd7cddfSDavid du Colombier static void mustBe(int c);
987dd7cddfSDavid du Colombier static ulong number(int nonzero);
997dd7cddfSDavid du Colombier static int peekc(void);
1007dd7cddfSDavid du Colombier static char *quoted(void);
1017dd7cddfSDavid du Colombier static void sectText(Fetch *f, int mimeOk);
1027dd7cddfSDavid du Colombier static ulong seqNo(void);
1037dd7cddfSDavid du Colombier static Store *storeWhat(void);
1047dd7cddfSDavid du Colombier static char *tag(void);
105becaf2abSDavid du Colombier static ulong uidNo(void);
1067dd7cddfSDavid du Colombier static void ungetc(void);
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier static ParseCmd SNonAuthed[] =
1097dd7cddfSDavid du Colombier {
1107dd7cddfSDavid du Colombier {"capability", capabilityCmd},
1117dd7cddfSDavid du Colombier {"logout", logoutCmd},
1127dd7cddfSDavid du Colombier {"x-exit", logoutCmd},
1137dd7cddfSDavid du Colombier {"noop", noopCmd},
1147dd7cddfSDavid du Colombier
1157dd7cddfSDavid du Colombier {"login", loginCmd},
1167dd7cddfSDavid du Colombier {"authenticate", authenticateCmd},
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier nil
1197dd7cddfSDavid du Colombier };
1207dd7cddfSDavid du Colombier
1217dd7cddfSDavid du Colombier static ParseCmd SAuthed[] =
1227dd7cddfSDavid du Colombier {
1237dd7cddfSDavid du Colombier {"capability", capabilityCmd},
1247dd7cddfSDavid du Colombier {"logout", logoutCmd},
1257dd7cddfSDavid du Colombier {"x-exit", logoutCmd},
1267dd7cddfSDavid du Colombier {"noop", noopCmd},
1277dd7cddfSDavid du Colombier
1287dd7cddfSDavid du Colombier {"append", appendCmd},
1297dd7cddfSDavid du Colombier {"create", createCmd},
1307dd7cddfSDavid du Colombier {"delete", deleteCmd},
1317dd7cddfSDavid du Colombier {"examine", selectCmd},
1327dd7cddfSDavid du Colombier {"select", selectCmd},
1337dd7cddfSDavid du Colombier {"idle", idleCmd},
1347dd7cddfSDavid du Colombier {"list", listCmd},
1357dd7cddfSDavid du Colombier {"lsub", listCmd},
1367dd7cddfSDavid du Colombier {"namespace", namespaceCmd},
1377dd7cddfSDavid du Colombier {"rename", renameCmd},
1387dd7cddfSDavid du Colombier {"status", statusCmd},
1397dd7cddfSDavid du Colombier {"subscribe", subscribeCmd},
1407dd7cddfSDavid du Colombier {"unsubscribe", unsubscribeCmd},
1417dd7cddfSDavid du Colombier
1427dd7cddfSDavid du Colombier nil
1437dd7cddfSDavid du Colombier };
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier static ParseCmd SSelected[] =
1467dd7cddfSDavid du Colombier {
1477dd7cddfSDavid du Colombier {"capability", capabilityCmd},
1487dd7cddfSDavid du Colombier {"logout", logoutCmd},
1497dd7cddfSDavid du Colombier {"x-exit", logoutCmd},
1507dd7cddfSDavid du Colombier {"noop", noopCmd},
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier {"append", appendCmd},
1537dd7cddfSDavid du Colombier {"create", createCmd},
1547dd7cddfSDavid du Colombier {"delete", deleteCmd},
1557dd7cddfSDavid du Colombier {"examine", selectCmd},
1567dd7cddfSDavid du Colombier {"select", selectCmd},
1577dd7cddfSDavid du Colombier {"idle", idleCmd},
1587dd7cddfSDavid du Colombier {"list", listCmd},
1597dd7cddfSDavid du Colombier {"lsub", listCmd},
1607dd7cddfSDavid du Colombier {"namespace", namespaceCmd},
1617dd7cddfSDavid du Colombier {"rename", renameCmd},
1627dd7cddfSDavid du Colombier {"status", statusCmd},
1637dd7cddfSDavid du Colombier {"subscribe", subscribeCmd},
1647dd7cddfSDavid du Colombier {"unsubscribe", unsubscribeCmd},
1657dd7cddfSDavid du Colombier
1667dd7cddfSDavid du Colombier {"check", noopCmd},
1677dd7cddfSDavid du Colombier {"close", closeCmd},
1687dd7cddfSDavid du Colombier {"copy", copyCmd},
1697dd7cddfSDavid du Colombier {"expunge", expungeCmd},
1707dd7cddfSDavid du Colombier {"fetch", fetchCmd},
1717dd7cddfSDavid du Colombier {"search", searchCmd},
1727dd7cddfSDavid du Colombier {"store", storeCmd},
1737dd7cddfSDavid du Colombier {"uid", uidCmd},
1747dd7cddfSDavid du Colombier
1757dd7cddfSDavid du Colombier nil
1767dd7cddfSDavid du Colombier };
1777dd7cddfSDavid du Colombier
1787dd7cddfSDavid du Colombier static char *atomStop = "(){%*\"\\";
1799a747e4fSDavid du Colombier static Chalstate *chal;
1807dd7cddfSDavid du Colombier static int chaled;
1817dd7cddfSDavid du Colombier static ParseCmd *imapState;
1827dd7cddfSDavid du Colombier static jmp_buf parseJmp;
1837dd7cddfSDavid du Colombier static char *parseMsg;
1847dd7cddfSDavid du Colombier static int allowPass;
185d9306527SDavid du Colombier static int allowCR;
18659cc4ca5SDavid du Colombier static int exiting;
18759cc4ca5SDavid du Colombier static QLock imaplock;
18859cc4ca5SDavid du Colombier static int idlepid = -1;
1897dd7cddfSDavid du Colombier
1907dd7cddfSDavid du Colombier Biobuf bout;
1917dd7cddfSDavid du Colombier Biobuf bin;
1929a747e4fSDavid du Colombier char username[UserNameLen];
1939a747e4fSDavid du Colombier char mboxDir[MboxNameLen];
1947dd7cddfSDavid du Colombier char *servername;
1957dd7cddfSDavid du Colombier char *site;
19680ee5cbfSDavid du Colombier char *remote;
1977dd7cddfSDavid du Colombier Box *selected;
19880ee5cbfSDavid du Colombier Bin *parseBin;
1999a747e4fSDavid du Colombier int debug;
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier void
main(int argc,char * argv[])2027dd7cddfSDavid du Colombier main(int argc, char *argv[])
2037dd7cddfSDavid du Colombier {
2047dd7cddfSDavid du Colombier char *s, *t;
2057dd7cddfSDavid du Colombier int preauth, n;
2067dd7cddfSDavid du Colombier
20780ee5cbfSDavid du Colombier Binit(&bin, 0, OREAD);
20880ee5cbfSDavid du Colombier Binit(&bout, 1, OWRITE);
20980ee5cbfSDavid du Colombier
2107dd7cddfSDavid du Colombier preauth = 0;
2117dd7cddfSDavid du Colombier allowPass = 0;
212d9306527SDavid du Colombier allowCR = 0;
2137dd7cddfSDavid du Colombier ARGBEGIN{
2147dd7cddfSDavid du Colombier case 'a':
2157dd7cddfSDavid du Colombier preauth = 1;
2167dd7cddfSDavid du Colombier break;
21780ee5cbfSDavid du Colombier case 'd':
21880ee5cbfSDavid du Colombier site = ARGF();
21980ee5cbfSDavid du Colombier break;
220d9306527SDavid du Colombier case 'c':
221d9306527SDavid du Colombier allowCR = 1;
222d9306527SDavid du Colombier break;
2237dd7cddfSDavid du Colombier case 'p':
2247dd7cddfSDavid du Colombier allowPass = 1;
2257dd7cddfSDavid du Colombier break;
22680ee5cbfSDavid du Colombier case 'r':
22780ee5cbfSDavid du Colombier remote = ARGF();
2287dd7cddfSDavid du Colombier break;
2297dd7cddfSDavid du Colombier case 's':
2307dd7cddfSDavid du Colombier servername = ARGF();
2317dd7cddfSDavid du Colombier break;
2329a747e4fSDavid du Colombier case 'v':
2339a747e4fSDavid du Colombier debug = 1;
2349a747e4fSDavid du Colombier debuglog("imap4d debugging enabled\n");
2359a747e4fSDavid du Colombier break;
2367dd7cddfSDavid du Colombier default:
237d9306527SDavid du Colombier fprint(2, "usage: ip/imap4d [-acpv] [-d site] [-r remotehost] [-s servername]\n");
2387dd7cddfSDavid du Colombier bye("usage");
2397dd7cddfSDavid du Colombier break;
2407dd7cddfSDavid du Colombier }ARGEND
2417dd7cddfSDavid du Colombier
242d9306527SDavid du Colombier if(allowPass && allowCR){
243d9306527SDavid du Colombier fprint(2, "%s: -c and -p are mutually exclusive\n", argv0);
244d9306527SDavid du Colombier bye("usage");
245d9306527SDavid du Colombier }
246d9306527SDavid du Colombier
2479a747e4fSDavid du Colombier if(preauth)
2489a747e4fSDavid du Colombier setupuser(nil);
2497dd7cddfSDavid du Colombier
2507dd7cddfSDavid du Colombier if(servername == nil){
2517dd7cddfSDavid du Colombier servername = csquery("sys", sysname(), "dom");
2527dd7cddfSDavid du Colombier if(servername == nil)
2537dd7cddfSDavid du Colombier servername = sysname();
25480ee5cbfSDavid du Colombier if(servername == nil){
25580ee5cbfSDavid du Colombier fprint(2, "ip/imap4d can't find server name: %r\n");
2567dd7cddfSDavid du Colombier bye("can't find system name");
2577dd7cddfSDavid du Colombier }
25880ee5cbfSDavid du Colombier }
2597dd7cddfSDavid du Colombier if(site == nil){
2607dd7cddfSDavid du Colombier t = getenv("site");
2617dd7cddfSDavid du Colombier if(t == nil)
2627dd7cddfSDavid du Colombier site = servername;
2637dd7cddfSDavid du Colombier else{
2647dd7cddfSDavid du Colombier n = strlen(t);
2657dd7cddfSDavid du Colombier s = strchr(servername, '.');
2667dd7cddfSDavid du Colombier if(s == nil)
2677dd7cddfSDavid du Colombier s = servername;
2687dd7cddfSDavid du Colombier else
2697dd7cddfSDavid du Colombier s++;
2707dd7cddfSDavid du Colombier n += strlen(s) + 2;
2717dd7cddfSDavid du Colombier site = emalloc(n);
2727dd7cddfSDavid du Colombier snprint(site, n, "%s.%s", t, s);
2737dd7cddfSDavid du Colombier }
2747dd7cddfSDavid du Colombier }
2757dd7cddfSDavid du Colombier
2767dd7cddfSDavid du Colombier rfork(RFNOTEG|RFREND);
2777dd7cddfSDavid du Colombier
27859cc4ca5SDavid du Colombier atnotify(catcher, 1);
27959cc4ca5SDavid du Colombier qlock(&imaplock);
2807dd7cddfSDavid du Colombier atexit(cleaner);
2817dd7cddfSDavid du Colombier imap4(preauth);
2827dd7cddfSDavid du Colombier }
2837dd7cddfSDavid du Colombier
2847dd7cddfSDavid du Colombier static void
imap4(int preauth)2857dd7cddfSDavid du Colombier imap4(int preauth)
2867dd7cddfSDavid du Colombier {
2877dd7cddfSDavid du Colombier char *volatile tg;
2887dd7cddfSDavid du Colombier char *volatile cmd;
2897dd7cddfSDavid du Colombier ParseCmd *st;
2907dd7cddfSDavid du Colombier
2917dd7cddfSDavid du Colombier if(preauth){
2927dd7cddfSDavid du Colombier Bprint(&bout, "* preauth %s IMAP4rev1 server ready user %s authenticated\r\n", servername, username);
2937dd7cddfSDavid du Colombier imapState = SAuthed;
2947dd7cddfSDavid du Colombier }else{
295d9306527SDavid du Colombier Bprint(&bout, "* OK %s IMAP4rev1 server ready\r\n", servername);
2967dd7cddfSDavid du Colombier imapState = SNonAuthed;
2977dd7cddfSDavid du Colombier }
2987dd7cddfSDavid du Colombier if(Bflush(&bout) < 0)
2997dd7cddfSDavid du Colombier writeErr();
3007dd7cddfSDavid du Colombier
3017dd7cddfSDavid du Colombier chaled = 0;
3027dd7cddfSDavid du Colombier
3037dd7cddfSDavid du Colombier tg = nil;
3047dd7cddfSDavid du Colombier cmd = nil;
3057dd7cddfSDavid du Colombier if(setjmp(parseJmp)){
3067dd7cddfSDavid du Colombier if(tg == nil)
3077dd7cddfSDavid du Colombier Bprint(&bout, "* bad empty command line: %s\r\n", parseMsg);
3087dd7cddfSDavid du Colombier else if(cmd == nil)
309d9306527SDavid du Colombier Bprint(&bout, "%s BAD no command: %s\r\n", tg, parseMsg);
3107dd7cddfSDavid du Colombier else
311d9306527SDavid du Colombier Bprint(&bout, "%s BAD %s %s\r\n", tg, cmd, parseMsg);
3127dd7cddfSDavid du Colombier clearcmd();
3137dd7cddfSDavid du Colombier if(Bflush(&bout) < 0)
3147dd7cddfSDavid du Colombier writeErr();
31580ee5cbfSDavid du Colombier binfree(&parseBin);
3167dd7cddfSDavid du Colombier }
3177dd7cddfSDavid du Colombier for(;;){
3187dd7cddfSDavid du Colombier if(mbLocked())
3197dd7cddfSDavid du Colombier bye("internal error: mailbox lock held");
3207dd7cddfSDavid du Colombier tg = nil;
3217dd7cddfSDavid du Colombier cmd = nil;
3227dd7cddfSDavid du Colombier tg = tag();
3237dd7cddfSDavid du Colombier mustBe(' ');
3247dd7cddfSDavid du Colombier cmd = atom();
3257dd7cddfSDavid du Colombier
3267dd7cddfSDavid du Colombier /*
3277dd7cddfSDavid du Colombier * note: outlook express is broken: it requires echoing the
3287dd7cddfSDavid du Colombier * command as part of matching response
3297dd7cddfSDavid du Colombier */
3307dd7cddfSDavid du Colombier for(st = imapState; st->name != nil; st++){
3317dd7cddfSDavid du Colombier if(cistrcmp(cmd, st->name) == 0){
3327dd7cddfSDavid du Colombier (*st->f)(tg, cmd);
3337dd7cddfSDavid du Colombier break;
3347dd7cddfSDavid du Colombier }
3357dd7cddfSDavid du Colombier }
3367dd7cddfSDavid du Colombier if(st->name == nil){
3377dd7cddfSDavid du Colombier clearcmd();
338d9306527SDavid du Colombier Bprint(&bout, "%s BAD %s illegal command\r\n", tg, cmd);
3397dd7cddfSDavid du Colombier }
3407dd7cddfSDavid du Colombier
3417dd7cddfSDavid du Colombier if(Bflush(&bout) < 0)
3427dd7cddfSDavid du Colombier writeErr();
34380ee5cbfSDavid du Colombier binfree(&parseBin);
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier void
bye(char * fmt,...)3487dd7cddfSDavid du Colombier bye(char *fmt, ...)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier va_list arg;
3517dd7cddfSDavid du Colombier
3527dd7cddfSDavid du Colombier va_start(arg, fmt);
3539a747e4fSDavid du Colombier Bprint(&bout, "* bye ");
3549a747e4fSDavid du Colombier Bvprint(&bout, fmt, arg);
3559a747e4fSDavid du Colombier Bprint(&bout, "\r\n");
3569a747e4fSDavid du Colombier Bflush(&bout);
3579a747e4fSDavid du Colombier exits("rob2");
3587dd7cddfSDavid du Colombier exits(0);
3597dd7cddfSDavid du Colombier }
3607dd7cddfSDavid du Colombier
3617dd7cddfSDavid du Colombier void
parseErr(char * msg)3627dd7cddfSDavid du Colombier parseErr(char *msg)
3637dd7cddfSDavid du Colombier {
3647dd7cddfSDavid du Colombier parseMsg = msg;
3657dd7cddfSDavid du Colombier longjmp(parseJmp, 1);
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier /*
3697dd7cddfSDavid du Colombier * an error occured while writing to the client
3707dd7cddfSDavid du Colombier */
3717dd7cddfSDavid du Colombier void
writeErr(void)3727dd7cddfSDavid du Colombier writeErr(void)
3737dd7cddfSDavid du Colombier {
3747dd7cddfSDavid du Colombier cleaner();
3757dd7cddfSDavid du Colombier _exits("connection closed");
3767dd7cddfSDavid du Colombier }
3777dd7cddfSDavid du Colombier
37859cc4ca5SDavid du Colombier static int
catcher(void * v,char * msg)37959cc4ca5SDavid du Colombier catcher(void *v, char *msg)
38059cc4ca5SDavid du Colombier {
38159cc4ca5SDavid du Colombier USED(v);
38259cc4ca5SDavid du Colombier if(strstr(msg, "closed pipe") != nil)
38359cc4ca5SDavid du Colombier return 1;
38459cc4ca5SDavid du Colombier return 0;
38559cc4ca5SDavid du Colombier }
38659cc4ca5SDavid du Colombier
3877dd7cddfSDavid du Colombier /*
38859cc4ca5SDavid du Colombier * wipes out the idleCmd backgroung process if it is around.
38959cc4ca5SDavid du Colombier * this can only be called if the current proc has qlocked imaplock.
39059cc4ca5SDavid du Colombier * it must be the last piece of imap4d code executed.
3917dd7cddfSDavid du Colombier */
3927dd7cddfSDavid du Colombier static void
cleaner(void)3937dd7cddfSDavid du Colombier cleaner(void)
3947dd7cddfSDavid du Colombier {
3957dd7cddfSDavid du Colombier int i;
3967dd7cddfSDavid du Colombier
39759cc4ca5SDavid du Colombier if(idlepid < 0)
39859cc4ca5SDavid du Colombier return;
39959cc4ca5SDavid du Colombier exiting = 1;
40059cc4ca5SDavid du Colombier close(0);
40159cc4ca5SDavid du Colombier close(1);
40259cc4ca5SDavid du Colombier close(2);
40359cc4ca5SDavid du Colombier
40459cc4ca5SDavid du Colombier /*
40559cc4ca5SDavid du Colombier * the other proc is either stuck in a read, a sleep,
40659cc4ca5SDavid du Colombier * or is trying to lock imap4lock.
40759cc4ca5SDavid du Colombier * get him out of it so he can exit cleanly
40859cc4ca5SDavid du Colombier */
40959cc4ca5SDavid du Colombier qunlock(&imaplock);
4107dd7cddfSDavid du Colombier for(i = 0; i < 4; i++)
4117dd7cddfSDavid du Colombier postnote(PNGROUP, getpid(), "die");
4127dd7cddfSDavid du Colombier }
4137dd7cddfSDavid du Colombier
4147dd7cddfSDavid du Colombier /*
4157dd7cddfSDavid du Colombier * send any pending status updates to the client
4167dd7cddfSDavid du Colombier * careful: shouldn't exit, because called by idle polling proc
4177dd7cddfSDavid du Colombier *
4187dd7cddfSDavid du Colombier * can't always send pending info
4197dd7cddfSDavid du Colombier * in particular, can't send expunge info
4207dd7cddfSDavid du Colombier * in response to a fetch, store, or search command.
4217dd7cddfSDavid du Colombier *
4227dd7cddfSDavid du Colombier * rfc2060 5.2: server must send mailbox size updates
4237dd7cddfSDavid du Colombier * rfc2060 5.2: server may send flag updates
4247dd7cddfSDavid du Colombier * rfc2060 5.5: servers prohibited from sending expunge while fetch, store, search in progress
4257dd7cddfSDavid du Colombier * rfc2060 7: in selected state, server checks mailbox for new messages as part of every command
4267dd7cddfSDavid du Colombier * sends untagged EXISTS and RECENT respsonses reflecting new size of the mailbox
4277dd7cddfSDavid du Colombier * should also send appropriate untagged FETCH and EXPUNGE messages if another agent
4287dd7cddfSDavid du Colombier * changes the state of any message flags or expunges any messages
4297dd7cddfSDavid du Colombier * rfc2060 7.4.1 expunge server response must not be sent when no command is in progress,
4307dd7cddfSDavid du Colombier * nor while responding to a fetch, stort, or search command (uid versions are ok)
4317dd7cddfSDavid du Colombier * command only "in progress" after entirely parsed.
4327dd7cddfSDavid du Colombier *
4337dd7cddfSDavid du Colombier * strategy for third party deletion of messages or of a mailbox
4347dd7cddfSDavid du Colombier *
4357dd7cddfSDavid du Colombier * deletion of a selected mailbox => act like all message are expunged
4367dd7cddfSDavid du Colombier * not strictly allowed by rfc2180, but close to method 3.2.
4377dd7cddfSDavid du Colombier *
4387dd7cddfSDavid du Colombier * renaming same as deletion
4397dd7cddfSDavid du Colombier *
4407dd7cddfSDavid du Colombier * copy
4417dd7cddfSDavid du Colombier * reject iff a deleted message is in the request
4427dd7cddfSDavid du Colombier *
4437dd7cddfSDavid du Colombier * search, store, fetch operations on expunged messages
4447dd7cddfSDavid du Colombier * ignore the expunged messages
4457dd7cddfSDavid du Colombier * return tagged no if referenced
4467dd7cddfSDavid du Colombier */
4477dd7cddfSDavid du Colombier static void
status(int expungeable,int uids)4487dd7cddfSDavid du Colombier status(int expungeable, int uids)
4497dd7cddfSDavid du Colombier {
4507dd7cddfSDavid du Colombier int tell;
4517dd7cddfSDavid du Colombier
4527dd7cddfSDavid du Colombier if(!selected)
4537dd7cddfSDavid du Colombier return;
4547dd7cddfSDavid du Colombier tell = 0;
4557dd7cddfSDavid du Colombier if(expungeable)
4567dd7cddfSDavid du Colombier tell = expungeMsgs(selected, 1);
4577dd7cddfSDavid du Colombier if(selected->sendFlags)
4587dd7cddfSDavid du Colombier sendFlags(selected, uids);
4597dd7cddfSDavid du Colombier if(tell || selected->toldMax != selected->max){
46040fe8d0dSDavid du Colombier Bprint(&bout, "* %lud EXISTS\r\n", selected->max);
4617dd7cddfSDavid du Colombier selected->toldMax = selected->max;
4627dd7cddfSDavid du Colombier }
4637dd7cddfSDavid du Colombier if(tell || selected->toldRecent != selected->recent){
46440fe8d0dSDavid du Colombier Bprint(&bout, "* %lud RECENT\r\n", selected->recent);
4657dd7cddfSDavid du Colombier selected->toldRecent = selected->recent;
4667dd7cddfSDavid du Colombier }
46759cc4ca5SDavid du Colombier if(tell)
46859cc4ca5SDavid du Colombier closeImp(selected, checkBox(selected, 1));
4697dd7cddfSDavid du Colombier }
4707dd7cddfSDavid du Colombier
4717dd7cddfSDavid du Colombier /*
4727dd7cddfSDavid du Colombier * careful: can't exit, because called by idle polling proc
4737dd7cddfSDavid du Colombier */
4747dd7cddfSDavid du Colombier static void
check(void)4757dd7cddfSDavid du Colombier check(void)
4767dd7cddfSDavid du Colombier {
4777dd7cddfSDavid du Colombier if(!selected)
4787dd7cddfSDavid du Colombier return;
4797dd7cddfSDavid du Colombier checkBox(selected, 0);
4807dd7cddfSDavid du Colombier status(1, 0);
4817dd7cddfSDavid du Colombier }
4827dd7cddfSDavid du Colombier
4837dd7cddfSDavid du Colombier static void
appendCmd(char * tg,char * cmd)4847dd7cddfSDavid du Colombier appendCmd(char *tg, char *cmd)
4857dd7cddfSDavid du Colombier {
4867dd7cddfSDavid du Colombier char *mbox, head[128];
4877dd7cddfSDavid du Colombier ulong t, n, now;
4887dd7cddfSDavid du Colombier int flags, ok;
4897dd7cddfSDavid du Colombier
4907dd7cddfSDavid du Colombier mustBe(' ');
4917dd7cddfSDavid du Colombier mbox = astring();
4927dd7cddfSDavid du Colombier mustBe(' ');
4937dd7cddfSDavid du Colombier flags = 0;
4947dd7cddfSDavid du Colombier if(peekc() == '('){
4957dd7cddfSDavid du Colombier flags = flagList();
4967dd7cddfSDavid du Colombier mustBe(' ');
4977dd7cddfSDavid du Colombier }
4987dd7cddfSDavid du Colombier now = time(nil);
4997dd7cddfSDavid du Colombier if(peekc() == '"'){
5007dd7cddfSDavid du Colombier t = imap4DateTime(quoted());
5017dd7cddfSDavid du Colombier if(t == ~0)
5027dd7cddfSDavid du Colombier parseErr("illegal date format");
5037dd7cddfSDavid du Colombier mustBe(' ');
5047dd7cddfSDavid du Colombier if(t > now)
5057dd7cddfSDavid du Colombier t = now;
5067dd7cddfSDavid du Colombier }else
5077dd7cddfSDavid du Colombier t = now;
5087dd7cddfSDavid du Colombier n = litlen();
5097dd7cddfSDavid du Colombier
5107dd7cddfSDavid du Colombier mbox = mboxName(mbox);
5117dd7cddfSDavid du Colombier if(mbox == nil || !okMbox(mbox)){
5127dd7cddfSDavid du Colombier check();
513d9306527SDavid du Colombier Bprint(&bout, "%s NO %s bad mailbox\r\n", tg, cmd);
5147dd7cddfSDavid du Colombier return;
5157dd7cddfSDavid du Colombier }
5169a747e4fSDavid du Colombier if(!cdExists(mboxDir, mbox)){
5177dd7cddfSDavid du Colombier check();
518d9306527SDavid du Colombier Bprint(&bout, "%s NO [TRYCREATE] %s mailbox does not exist\r\n", tg, cmd);
5197dd7cddfSDavid du Colombier return;
5207dd7cddfSDavid du Colombier }
5217dd7cddfSDavid du Colombier
5227dd7cddfSDavid du Colombier snprint(head, sizeof(head), "From %s %s", username, ctime(t));
5237dd7cddfSDavid du Colombier ok = appendSave(mbox, flags, head, &bin, n);
5247dd7cddfSDavid du Colombier crnl();
52580ee5cbfSDavid du Colombier check();
52680ee5cbfSDavid du Colombier if(ok)
527d9306527SDavid du Colombier Bprint(&bout, "%s OK %s completed\r\n", tg, cmd);
52880ee5cbfSDavid du Colombier else
529d9306527SDavid du Colombier Bprint(&bout, "%s NO %s message save failed\r\n", tg, cmd);
5307dd7cddfSDavid du Colombier }
5317dd7cddfSDavid du Colombier
5327dd7cddfSDavid du Colombier static void
authenticateCmd(char * tg,char * cmd)5337dd7cddfSDavid du Colombier authenticateCmd(char *tg, char *cmd)
5347dd7cddfSDavid du Colombier {
5357dd7cddfSDavid du Colombier char *s, *t;
5367dd7cddfSDavid du Colombier
5377dd7cddfSDavid du Colombier mustBe(' ');
5387dd7cddfSDavid du Colombier s = atom();
5397dd7cddfSDavid du Colombier crnl();
5409a747e4fSDavid du Colombier auth_freechal(chal);
5419a747e4fSDavid du Colombier chal = nil;
5427dd7cddfSDavid du Colombier if(cistrcmp(s, "cram-md5") == 0){
5437dd7cddfSDavid du Colombier t = cramauth();
5447dd7cddfSDavid du Colombier if(t == nil){
545d9306527SDavid du Colombier Bprint(&bout, "%s OK %s\r\n", tg, cmd);
5467dd7cddfSDavid du Colombier imapState = SAuthed;
5477dd7cddfSDavid du Colombier }else
548d9306527SDavid du Colombier Bprint(&bout, "%s NO %s failed %s\r\n", tg, cmd, t);
5497dd7cddfSDavid du Colombier }else
550d9306527SDavid du Colombier Bprint(&bout, "%s NO %s unsupported authentication protocol\r\n", tg, cmd);
5517dd7cddfSDavid du Colombier }
5527dd7cddfSDavid du Colombier
5537dd7cddfSDavid du Colombier static void
capabilityCmd(char * tg,char * cmd)5547dd7cddfSDavid du Colombier capabilityCmd(char *tg, char *cmd)
5557dd7cddfSDavid du Colombier {
5567dd7cddfSDavid du Colombier crnl();
5577dd7cddfSDavid du Colombier check();
5586b6b9ac8SDavid du Colombier // nslocum's capabilities
5596b6b9ac8SDavid du Colombier // Bprint(&bout, "* CAPABILITY IMAP4 IMAP4REV1 NAMESPACE IDLE SCAN SORT MAILBOX-REFERRALS LOGIN-REFERRALS AUTH=LOGIN THREAD=ORDEREDSUBJECT\r\n");
560d9306527SDavid du Colombier Bprint(&bout, "* CAPABILITY IMAP4REV1 IDLE NAMESPACE AUTH=CRAM-MD5\r\n");
561d9306527SDavid du Colombier Bprint(&bout, "%s OK %s\r\n", tg, cmd);
5627dd7cddfSDavid du Colombier }
5637dd7cddfSDavid du Colombier
5647dd7cddfSDavid du Colombier static void
closeCmd(char * tg,char * cmd)5657dd7cddfSDavid du Colombier closeCmd(char *tg, char *cmd)
5667dd7cddfSDavid du Colombier {
5677dd7cddfSDavid du Colombier crnl();
5687dd7cddfSDavid du Colombier imapState = SAuthed;
5697dd7cddfSDavid du Colombier closeBox(selected, 1);
5707dd7cddfSDavid du Colombier selected = nil;
571d9306527SDavid du Colombier Bprint(&bout, "%s OK %s mailbox closed, now in authenticated state\r\n", tg, cmd);
5727dd7cddfSDavid du Colombier }
5737dd7cddfSDavid du Colombier
5747dd7cddfSDavid du Colombier /*
5757dd7cddfSDavid du Colombier * note: message id's are before any pending expunges
5767dd7cddfSDavid du Colombier */
5777dd7cddfSDavid du Colombier static void
copyCmd(char * tg,char * cmd)5787dd7cddfSDavid du Colombier copyCmd(char *tg, char *cmd)
5797dd7cddfSDavid du Colombier {
5807dd7cddfSDavid du Colombier copyUCmd(tg, cmd, 0);
5817dd7cddfSDavid du Colombier }
5827dd7cddfSDavid du Colombier
5837dd7cddfSDavid du Colombier static void
copyUCmd(char * tg,char * cmd,int uids)5847dd7cddfSDavid du Colombier copyUCmd(char *tg, char *cmd, int uids)
5857dd7cddfSDavid du Colombier {
5867dd7cddfSDavid du Colombier MsgSet *ms;
5877dd7cddfSDavid du Colombier char *uid, *mbox;
5887dd7cddfSDavid du Colombier ulong max;
5897dd7cddfSDavid du Colombier int ok;
5907dd7cddfSDavid du Colombier
5917dd7cddfSDavid du Colombier mustBe(' ');
592becaf2abSDavid du Colombier ms = msgSet(uids);
5937dd7cddfSDavid du Colombier mustBe(' ');
5947dd7cddfSDavid du Colombier mbox = astring();
5957dd7cddfSDavid du Colombier crnl();
5967dd7cddfSDavid du Colombier
5977dd7cddfSDavid du Colombier uid = "";
5987dd7cddfSDavid du Colombier if(uids)
5997dd7cddfSDavid du Colombier uid = "uid ";
6007dd7cddfSDavid du Colombier
6017dd7cddfSDavid du Colombier mbox = mboxName(mbox);
6027dd7cddfSDavid du Colombier if(mbox == nil || !okMbox(mbox)){
6037dd7cddfSDavid du Colombier status(1, uids);
604d9306527SDavid du Colombier Bprint(&bout, "%s NO %s%s bad mailbox\r\n", tg, uid, cmd);
6057dd7cddfSDavid du Colombier return;
6067dd7cddfSDavid du Colombier }
60748207d97SDavid du Colombier if(cistrcmp(mbox, "inbox") == 0)
60848207d97SDavid du Colombier mbox = "mbox";
6099a747e4fSDavid du Colombier if(!cdExists(mboxDir, mbox)){
6107dd7cddfSDavid du Colombier check();
611d9306527SDavid du Colombier Bprint(&bout, "%s NO [TRYCREATE] %s mailbox does not exist\r\n", tg, cmd);
6127dd7cddfSDavid du Colombier return;
6137dd7cddfSDavid du Colombier }
6147dd7cddfSDavid du Colombier
6157dd7cddfSDavid du Colombier max = selected->max;
6167dd7cddfSDavid du Colombier checkBox(selected, 0);
6177dd7cddfSDavid du Colombier ok = forMsgs(selected, ms, max, uids, copyCheck, nil);
6187dd7cddfSDavid du Colombier if(ok)
6197dd7cddfSDavid du Colombier ok = forMsgs(selected, ms, max, uids, copySave, mbox);
6207dd7cddfSDavid du Colombier
6217dd7cddfSDavid du Colombier status(1, uids);
6227dd7cddfSDavid du Colombier if(ok)
623d9306527SDavid du Colombier Bprint(&bout, "%s OK %s%s completed\r\n", tg, uid, cmd);
6247dd7cddfSDavid du Colombier else
625d9306527SDavid du Colombier Bprint(&bout, "%s NO %s%s failed\r\n", tg, uid, cmd);
6267dd7cddfSDavid du Colombier }
6277dd7cddfSDavid du Colombier
6287dd7cddfSDavid du Colombier static void
createCmd(char * tg,char * cmd)6297dd7cddfSDavid du Colombier createCmd(char *tg, char *cmd)
6307dd7cddfSDavid du Colombier {
6317dd7cddfSDavid du Colombier char *mbox, *m;
6327dd7cddfSDavid du Colombier int fd, slash;
6337dd7cddfSDavid du Colombier
6347dd7cddfSDavid du Colombier mustBe(' ');
6357dd7cddfSDavid du Colombier mbox = astring();
6367dd7cddfSDavid du Colombier crnl();
6377dd7cddfSDavid du Colombier check();
6387dd7cddfSDavid du Colombier
6397dd7cddfSDavid du Colombier m = strchr(mbox, '\0');
6407dd7cddfSDavid du Colombier slash = m != mbox && m[-1] == '/';
6417dd7cddfSDavid du Colombier mbox = mboxName(mbox);
6427dd7cddfSDavid du Colombier if(mbox == nil || !okMbox(mbox)){
643d9306527SDavid du Colombier Bprint(&bout, "%s NO %s bad mailbox\r\n", tg, cmd);
6447dd7cddfSDavid du Colombier return;
6457dd7cddfSDavid du Colombier }
6467dd7cddfSDavid du Colombier if(cistrcmp(mbox, "inbox") == 0){
647d9306527SDavid du Colombier Bprint(&bout, "%s NO %s cannot remotely create INBOX\r\n", tg, cmd);
6487dd7cddfSDavid du Colombier return;
6497dd7cddfSDavid du Colombier }
6507dd7cddfSDavid du Colombier if(access(mbox, AEXIST) >= 0){
651d9306527SDavid du Colombier Bprint(&bout, "%s NO %s mailbox already exists\r\n", tg, cmd);
6527dd7cddfSDavid du Colombier return;
6537dd7cddfSDavid du Colombier }
6547dd7cddfSDavid du Colombier
6557dd7cddfSDavid du Colombier fd = createBox(mbox, slash);
6567dd7cddfSDavid du Colombier close(fd);
6577dd7cddfSDavid du Colombier if(fd < 0)
658d9306527SDavid du Colombier Bprint(&bout, "%s NO %s cannot create mailbox %s\r\n", tg, cmd, mbox);
6597dd7cddfSDavid du Colombier else
660d9306527SDavid du Colombier Bprint(&bout, "%s OK %s %s completed\r\n", tg, mbox, cmd);
6617dd7cddfSDavid du Colombier }
6627dd7cddfSDavid du Colombier
6637dd7cddfSDavid du Colombier static void
deleteCmd(char * tg,char * cmd)6647dd7cddfSDavid du Colombier deleteCmd(char *tg, char *cmd)
6657dd7cddfSDavid du Colombier {
6667dd7cddfSDavid du Colombier char *mbox, *imp;
6677dd7cddfSDavid du Colombier
6687dd7cddfSDavid du Colombier mustBe(' ');
6697dd7cddfSDavid du Colombier mbox = astring();
6707dd7cddfSDavid du Colombier crnl();
6717dd7cddfSDavid du Colombier check();
6727dd7cddfSDavid du Colombier
6737dd7cddfSDavid du Colombier mbox = mboxName(mbox);
6747dd7cddfSDavid du Colombier if(mbox == nil || !okMbox(mbox)){
675d9306527SDavid du Colombier Bprint(&bout, "%s NO %s bad mailbox\r\n", tg, cmd);
6767dd7cddfSDavid du Colombier return;
6777dd7cddfSDavid du Colombier }
6787dd7cddfSDavid du Colombier
6797dd7cddfSDavid du Colombier imp = impName(mbox);
6807dd7cddfSDavid du Colombier if(cistrcmp(mbox, "inbox") == 0
6819a747e4fSDavid du Colombier || imp != nil && cdRemove(mboxDir, imp) < 0 && cdExists(mboxDir, imp)
6827dd7cddfSDavid du Colombier || cdRemove(mboxDir, mbox) < 0)
683d9306527SDavid du Colombier Bprint(&bout, "%s NO %s cannot delete mailbox %s\r\n", tg, cmd, mbox);
6847dd7cddfSDavid du Colombier else
685d9306527SDavid du Colombier Bprint(&bout, "%s OK %s %s completed\r\n", tg, mbox, cmd);
6867dd7cddfSDavid du Colombier }
6877dd7cddfSDavid du Colombier
6887dd7cddfSDavid du Colombier static void
expungeCmd(char * tg,char * cmd)6897dd7cddfSDavid du Colombier expungeCmd(char *tg, char *cmd)
6907dd7cddfSDavid du Colombier {
6917dd7cddfSDavid du Colombier int ok;
6927dd7cddfSDavid du Colombier
6937dd7cddfSDavid du Colombier crnl();
6947dd7cddfSDavid du Colombier ok = deleteMsgs(selected);
6957dd7cddfSDavid du Colombier check();
6967dd7cddfSDavid du Colombier if(ok)
697d9306527SDavid du Colombier Bprint(&bout, "%s OK %s messages erased\r\n", tg, cmd);
6987dd7cddfSDavid du Colombier else
699d9306527SDavid du Colombier Bprint(&bout, "%s NO %s some messages not expunged\r\n", tg, cmd);
7007dd7cddfSDavid du Colombier }
7017dd7cddfSDavid du Colombier
7027dd7cddfSDavid du Colombier static void
fetchCmd(char * tg,char * cmd)7037dd7cddfSDavid du Colombier fetchCmd(char *tg, char *cmd)
7047dd7cddfSDavid du Colombier {
7057dd7cddfSDavid du Colombier fetchUCmd(tg, cmd, 0);
7067dd7cddfSDavid du Colombier }
7077dd7cddfSDavid du Colombier
7087dd7cddfSDavid du Colombier static void
fetchUCmd(char * tg,char * cmd,int uids)7097dd7cddfSDavid du Colombier fetchUCmd(char *tg, char *cmd, int uids)
7107dd7cddfSDavid du Colombier {
7117dd7cddfSDavid du Colombier Fetch *f;
7127dd7cddfSDavid du Colombier MsgSet *ms;
7137dd7cddfSDavid du Colombier MbLock *ml;
7147dd7cddfSDavid du Colombier char *uid;
7157dd7cddfSDavid du Colombier ulong max;
7167dd7cddfSDavid du Colombier int ok;
7177dd7cddfSDavid du Colombier
7187dd7cddfSDavid du Colombier mustBe(' ');
719becaf2abSDavid du Colombier ms = msgSet(uids);
7207dd7cddfSDavid du Colombier mustBe(' ');
7217dd7cddfSDavid du Colombier f = fetchWhat();
7227dd7cddfSDavid du Colombier crnl();
7237dd7cddfSDavid du Colombier uid = "";
7247dd7cddfSDavid du Colombier if(uids)
7257dd7cddfSDavid du Colombier uid = "uid ";
7267dd7cddfSDavid du Colombier max = selected->max;
7277dd7cddfSDavid du Colombier ml = checkBox(selected, 1);
7287dd7cddfSDavid du Colombier if(ml != nil)
7297dd7cddfSDavid du Colombier forMsgs(selected, ms, max, uids, fetchSeen, f);
7307dd7cddfSDavid du Colombier closeImp(selected, ml);
7317dd7cddfSDavid du Colombier ok = ml != nil && forMsgs(selected, ms, max, uids, fetchMsg, f);
7327dd7cddfSDavid du Colombier status(uids, uids);
7337dd7cddfSDavid du Colombier if(ok)
734d9306527SDavid du Colombier Bprint(&bout, "%s OK %s%s completed\r\n", tg, uid, cmd);
7357dd7cddfSDavid du Colombier else
736d9306527SDavid du Colombier Bprint(&bout, "%s NO %s%s failed\r\n", tg, uid, cmd);
7377dd7cddfSDavid du Colombier }
7387dd7cddfSDavid du Colombier
7397dd7cddfSDavid du Colombier static void
idleCmd(char * tg,char * cmd)7407dd7cddfSDavid du Colombier idleCmd(char *tg, char *cmd)
7417dd7cddfSDavid du Colombier {
74259cc4ca5SDavid du Colombier int c, pid;
7437dd7cddfSDavid du Colombier
7447dd7cddfSDavid du Colombier crnl();
7457dd7cddfSDavid du Colombier Bprint(&bout, "+ idling, waiting for done\r\n");
7467dd7cddfSDavid du Colombier if(Bflush(&bout) < 0)
7477dd7cddfSDavid du Colombier writeErr();
7487dd7cddfSDavid du Colombier
74959cc4ca5SDavid du Colombier if(idlepid < 0){
7507dd7cddfSDavid du Colombier pid = rfork(RFPROC|RFMEM|RFNOWAIT);
7517dd7cddfSDavid du Colombier if(pid == 0){
7527dd7cddfSDavid du Colombier for(;;){
7537dd7cddfSDavid du Colombier qlock(&imaplock);
75459cc4ca5SDavid du Colombier if(exiting)
75559cc4ca5SDavid du Colombier break;
75659cc4ca5SDavid du Colombier
75759cc4ca5SDavid du Colombier /*
75859cc4ca5SDavid du Colombier * parent may have changed curDir, but it doesn't change our .
75959cc4ca5SDavid du Colombier */
76059cc4ca5SDavid du Colombier resetCurDir();
76159cc4ca5SDavid du Colombier
7627dd7cddfSDavid du Colombier check();
7637dd7cddfSDavid du Colombier if(Bflush(&bout) < 0)
7647dd7cddfSDavid du Colombier writeErr();
7657dd7cddfSDavid du Colombier qunlock(&imaplock);
7667dd7cddfSDavid du Colombier sleep(15*1000);
76780ee5cbfSDavid du Colombier enableForwarding();
7687dd7cddfSDavid du Colombier }
7699a747e4fSDavid du Colombier _exits("rob3");
7707dd7cddfSDavid du Colombier _exits(0);
7717dd7cddfSDavid du Colombier }
77259cc4ca5SDavid du Colombier idlepid = pid;
77359cc4ca5SDavid du Colombier }
7747dd7cddfSDavid du Colombier
7757dd7cddfSDavid du Colombier qunlock(&imaplock);
7767dd7cddfSDavid du Colombier
77759cc4ca5SDavid du Colombier /*
77859cc4ca5SDavid du Colombier * clear out the next line, which is supposed to contain (case-insensitive)
77959cc4ca5SDavid du Colombier * done\n
78059cc4ca5SDavid du Colombier * this is special code since it has to dance with the idle polling proc
78159cc4ca5SDavid du Colombier * and handle exiting correctly.
78259cc4ca5SDavid du Colombier */
78359cc4ca5SDavid du Colombier for(;;){
78459cc4ca5SDavid du Colombier c = getc();
78559cc4ca5SDavid du Colombier if(c < 0){
78659cc4ca5SDavid du Colombier qlock(&imaplock);
78759cc4ca5SDavid du Colombier if(!exiting)
78859cc4ca5SDavid du Colombier cleaner();
7899a747e4fSDavid du Colombier _exits("rob4");
79059cc4ca5SDavid du Colombier _exits(0);
79159cc4ca5SDavid du Colombier }
79259cc4ca5SDavid du Colombier if(c == '\n')
79359cc4ca5SDavid du Colombier break;
79459cc4ca5SDavid du Colombier }
79559cc4ca5SDavid du Colombier
79659cc4ca5SDavid du Colombier qlock(&imaplock);
79759cc4ca5SDavid du Colombier if(exiting)
7989a747e4fSDavid du Colombier {_exits("rob5");
79959cc4ca5SDavid du Colombier _exits(0);
8009a747e4fSDavid du Colombier }
8017dd7cddfSDavid du Colombier
8027dd7cddfSDavid du Colombier /*
8037dd7cddfSDavid du Colombier * child may have changed curDir, but it doesn't change our .
8047dd7cddfSDavid du Colombier */
8057dd7cddfSDavid du Colombier resetCurDir();
8067dd7cddfSDavid du Colombier
8077dd7cddfSDavid du Colombier check();
808d9306527SDavid du Colombier Bprint(&bout, "%s OK %s terminated\r\n", tg, cmd);
8097dd7cddfSDavid du Colombier }
8107dd7cddfSDavid du Colombier
8117dd7cddfSDavid du Colombier static void
listCmd(char * tg,char * cmd)8127dd7cddfSDavid du Colombier listCmd(char *tg, char *cmd)
8137dd7cddfSDavid du Colombier {
8147dd7cddfSDavid du Colombier char *s, *t, *ss, *ref, *mbox;
8157dd7cddfSDavid du Colombier int n;
8167dd7cddfSDavid du Colombier
8177dd7cddfSDavid du Colombier mustBe(' ');
8187dd7cddfSDavid du Colombier s = astring();
8197dd7cddfSDavid du Colombier mustBe(' ');
8207dd7cddfSDavid du Colombier t = listmbox();
8217dd7cddfSDavid du Colombier crnl();
8227dd7cddfSDavid du Colombier check();
8237dd7cddfSDavid du Colombier ref = mutf7str(s);
8247dd7cddfSDavid du Colombier mbox = mutf7str(t);
8257dd7cddfSDavid du Colombier if(ref == nil || mbox == nil){
826d9306527SDavid du Colombier Bprint(&bout, "%s BAD %s mailbox name not in modified utf-7\r\n", tg, cmd);
8277dd7cddfSDavid du Colombier return;
8287dd7cddfSDavid du Colombier }
8297dd7cddfSDavid du Colombier
8307dd7cddfSDavid du Colombier /*
8317dd7cddfSDavid du Colombier * special request for hierarchy delimiter and root name
8327dd7cddfSDavid du Colombier * root name appears to be name up to and including any delimiter,
8337dd7cddfSDavid du Colombier * or the empty string, if there is no delimiter.
8347dd7cddfSDavid du Colombier *
8357dd7cddfSDavid du Colombier * this must change if the # namespace convention is supported.
8367dd7cddfSDavid du Colombier */
8377dd7cddfSDavid du Colombier if(*mbox == '\0'){
8387dd7cddfSDavid du Colombier s = strchr(ref, '/');
8397dd7cddfSDavid du Colombier if(s == nil)
8407dd7cddfSDavid du Colombier ref = "";
8417dd7cddfSDavid du Colombier else
8427dd7cddfSDavid du Colombier s[1] = '\0';
8437dd7cddfSDavid du Colombier Bprint(&bout, "* %s (\\Noselect) \"/\" \"%s\"\r\n", cmd, ref);
844d9306527SDavid du Colombier Bprint(&bout, "%s OK %s\r\n", tg, cmd);
8457dd7cddfSDavid du Colombier return;
8467dd7cddfSDavid du Colombier }
8477dd7cddfSDavid du Colombier
8487dd7cddfSDavid du Colombier
8497dd7cddfSDavid du Colombier /*
8507dd7cddfSDavid du Colombier * massage the listing name:
8517dd7cddfSDavid du Colombier * clean up the components individually,
8527dd7cddfSDavid du Colombier * then rip off componenets from the ref to
8537dd7cddfSDavid du Colombier * take care of leading ..'s in the mbox.
8547dd7cddfSDavid du Colombier *
8557dd7cddfSDavid du Colombier * the cleanup can wipe out * followed by a ..
8567dd7cddfSDavid du Colombier * tough luck if such a stupid pattern is given.
8577dd7cddfSDavid du Colombier */
8587dd7cddfSDavid du Colombier cleanname(mbox);
8597dd7cddfSDavid du Colombier if(strcmp(mbox, ".") == 0)
8607dd7cddfSDavid du Colombier *mbox = '\0';
8617dd7cddfSDavid du Colombier if(mbox[0] == '/')
8627dd7cddfSDavid du Colombier *ref = '\0';
8637dd7cddfSDavid du Colombier else if(*ref != '\0'){
8647dd7cddfSDavid du Colombier cleanname(ref);
8657dd7cddfSDavid du Colombier if(strcmp(ref, ".") == 0)
8667dd7cddfSDavid du Colombier *ref = '\0';
8677dd7cddfSDavid du Colombier }else
8687dd7cddfSDavid du Colombier *ref = '\0';
8697dd7cddfSDavid du Colombier while(*ref && isdotdot(mbox)){
8707dd7cddfSDavid du Colombier s = strrchr(ref, '/');
8717dd7cddfSDavid du Colombier if(s == nil)
8727dd7cddfSDavid du Colombier s = ref;
8737dd7cddfSDavid du Colombier if(isdotdot(s))
8747dd7cddfSDavid du Colombier break;
8757dd7cddfSDavid du Colombier *s = '\0';
8767dd7cddfSDavid du Colombier mbox += 2;
8777dd7cddfSDavid du Colombier if(*mbox == '/')
8787dd7cddfSDavid du Colombier mbox++;
8797dd7cddfSDavid du Colombier }
8807dd7cddfSDavid du Colombier if(*ref == '\0'){
8817dd7cddfSDavid du Colombier s = mbox;
8827dd7cddfSDavid du Colombier ss = s;
8837dd7cddfSDavid du Colombier }else{
8847dd7cddfSDavid du Colombier n = strlen(ref) + strlen(mbox) + 2;
88580ee5cbfSDavid du Colombier t = binalloc(&parseBin, n, 0);
8867dd7cddfSDavid du Colombier if(t == nil)
8877dd7cddfSDavid du Colombier parseErr("out of memory");
8887dd7cddfSDavid du Colombier snprint(t, n, "%s/%s", ref, mbox);
8897dd7cddfSDavid du Colombier s = t;
8907dd7cddfSDavid du Colombier ss = s + strlen(ref);
8917dd7cddfSDavid du Colombier }
8927dd7cddfSDavid du Colombier
8937dd7cddfSDavid du Colombier /*
8947dd7cddfSDavid du Colombier * only allow activity in /mail/box
8957dd7cddfSDavid du Colombier */
8967dd7cddfSDavid du Colombier if(s[0] == '/' || isdotdot(s)){
897d9306527SDavid du Colombier Bprint(&bout, "%s NO illegal mailbox pattern\r\n", tg);
8987dd7cddfSDavid du Colombier return;
8997dd7cddfSDavid du Colombier }
9007dd7cddfSDavid du Colombier
9017dd7cddfSDavid du Colombier if(cistrcmp(cmd, "lsub") == 0)
9027dd7cddfSDavid du Colombier lsubBoxes(cmd, s, ss);
9037dd7cddfSDavid du Colombier else
9047dd7cddfSDavid du Colombier listBoxes(cmd, s, ss);
905d9306527SDavid du Colombier Bprint(&bout, "%s OK %s completed\r\n", tg, cmd);
906d9306527SDavid du Colombier }
907d9306527SDavid du Colombier
908d9306527SDavid du Colombier static char*
passCR(char * u,char * p)909d9306527SDavid du Colombier passCR(char*u, char*p)
910d9306527SDavid du Colombier {
911d9306527SDavid du Colombier static char Ebadch[] = "can't get challenge";
912d9306527SDavid du Colombier static char nchall[64];
913d9306527SDavid du Colombier static char response[64];
914d9306527SDavid du Colombier static Chalstate *ch = nil;
915d9306527SDavid du Colombier AuthInfo *ai;
916d9306527SDavid du Colombier
917d9306527SDavid du Colombier again:
918d9306527SDavid du Colombier if (ch == nil){
919d9306527SDavid du Colombier if(!(ch = auth_challenge("proto=p9cr role=server user=%q", u)))
920d9306527SDavid du Colombier return Ebadch;
921d9306527SDavid du Colombier snprint(nchall, 64, " encrypt challenge: %s", ch->chal);
922d9306527SDavid du Colombier return nchall;
923d9306527SDavid du Colombier } else {
924d9306527SDavid du Colombier strncpy(response, p, 64);
925d9306527SDavid du Colombier ch->resp = response;
926d9306527SDavid du Colombier ch->nresp = strlen(response);
927d9306527SDavid du Colombier ai = auth_response(ch);
928d9306527SDavid du Colombier auth_freechal(ch);
929d9306527SDavid du Colombier ch = nil;
930d9306527SDavid du Colombier if (ai == nil)
931d9306527SDavid du Colombier goto again;
932d9306527SDavid du Colombier setupuser(ai);
933d9306527SDavid du Colombier return nil;
934d9306527SDavid du Colombier }
935d9306527SDavid du Colombier
9367dd7cddfSDavid du Colombier }
9377dd7cddfSDavid du Colombier
9387dd7cddfSDavid du Colombier static void
loginCmd(char * tg,char * cmd)9397dd7cddfSDavid du Colombier loginCmd(char *tg, char *cmd)
9407dd7cddfSDavid du Colombier {
9417dd7cddfSDavid du Colombier char *s, *t;
9429a747e4fSDavid du Colombier AuthInfo *ai;
943d9306527SDavid du Colombier char*r;
9447dd7cddfSDavid du Colombier mustBe(' ');
9457dd7cddfSDavid du Colombier s = astring(); /* uid */
9467dd7cddfSDavid du Colombier mustBe(' ');
9477dd7cddfSDavid du Colombier t = astring(); /* password */
9487dd7cddfSDavid du Colombier crnl();
949d9306527SDavid du Colombier if(allowCR){
950d9306527SDavid du Colombier if ((r = passCR(s, t)) == nil){
951d9306527SDavid du Colombier Bprint(&bout, "%s OK %s succeeded\r\n", tg, cmd);
9527dd7cddfSDavid du Colombier imapState = SAuthed;
953d9306527SDavid du Colombier } else {
954d9306527SDavid du Colombier Bprint(&bout, "* NO [ALERT] %s\r\n", r);
955d9306527SDavid du Colombier Bprint(&bout, "%s NO %s succeeded\r\n", tg, cmd);
956d9306527SDavid du Colombier }
9577dd7cddfSDavid du Colombier return;
9587dd7cddfSDavid du Colombier }
959d9306527SDavid du Colombier else if(allowPass){
960d9306527SDavid du Colombier if(ai = passLogin(s, t)){
961d9306527SDavid du Colombier setupuser(ai);
962d9306527SDavid du Colombier Bprint(&bout, "%s OK %s succeeded\r\n", tg, cmd);
963d9306527SDavid du Colombier imapState = SAuthed;
964d9306527SDavid du Colombier }else
965d9306527SDavid du Colombier Bprint(&bout, "%s NO %s failed check\r\n", tg, cmd);
966d9306527SDavid du Colombier return;
967d9306527SDavid du Colombier }
968d9306527SDavid du Colombier Bprint(&bout, "%s NO %s plaintext passwords disallowed\r\n", tg, cmd);
9697dd7cddfSDavid du Colombier }
9707dd7cddfSDavid du Colombier
9717dd7cddfSDavid du Colombier /*
9727dd7cddfSDavid du Colombier * logout or x-exit, which doesn't expunge the mailbox
9737dd7cddfSDavid du Colombier */
9747dd7cddfSDavid du Colombier static void
logoutCmd(char * tg,char * cmd)9757dd7cddfSDavid du Colombier logoutCmd(char *tg, char *cmd)
9767dd7cddfSDavid du Colombier {
9777dd7cddfSDavid du Colombier crnl();
9787dd7cddfSDavid du Colombier
9797dd7cddfSDavid du Colombier if(cmd[0] != 'x' && selected){
9807dd7cddfSDavid du Colombier closeBox(selected, 1);
9817dd7cddfSDavid du Colombier selected = nil;
9827dd7cddfSDavid du Colombier }
9837dd7cddfSDavid du Colombier Bprint(&bout, "* bye\r\n");
984d9306527SDavid du Colombier Bprint(&bout, "%s OK %s completed\r\n", tg, cmd);
9859a747e4fSDavid du Colombier exits("rob6");
9867dd7cddfSDavid du Colombier exits(0);
9877dd7cddfSDavid du Colombier }
9887dd7cddfSDavid du Colombier
9897dd7cddfSDavid du Colombier static void
namespaceCmd(char * tg,char * cmd)9907dd7cddfSDavid du Colombier namespaceCmd(char *tg, char *cmd)
9917dd7cddfSDavid du Colombier {
9927dd7cddfSDavid du Colombier crnl();
9937dd7cddfSDavid du Colombier check();
9947dd7cddfSDavid du Colombier
9957dd7cddfSDavid du Colombier /*
9967dd7cddfSDavid du Colombier * personal, other users, shared namespaces
9977dd7cddfSDavid du Colombier * send back nil or descriptions of (prefix heirarchy-delim) for each case
9987dd7cddfSDavid du Colombier */
99940fe8d0dSDavid du Colombier Bprint(&bout, "* NAMESPACE ((\"\" \"/\")) nil nil\r\n");
1000d9306527SDavid du Colombier Bprint(&bout, "%s OK %s completed\r\n", tg, cmd);
10017dd7cddfSDavid du Colombier }
10027dd7cddfSDavid du Colombier
10037dd7cddfSDavid du Colombier static void
noopCmd(char * tg,char * cmd)10047dd7cddfSDavid du Colombier noopCmd(char *tg, char *cmd)
10057dd7cddfSDavid du Colombier {
10067dd7cddfSDavid du Colombier crnl();
10077dd7cddfSDavid du Colombier check();
1008d9306527SDavid du Colombier Bprint(&bout, "%s OK %s completed\r\n", tg, cmd);
100980ee5cbfSDavid du Colombier enableForwarding();
10107dd7cddfSDavid du Colombier }
10117dd7cddfSDavid du Colombier
10127dd7cddfSDavid du Colombier /*
10137dd7cddfSDavid du Colombier * this is only a partial implementation
10147dd7cddfSDavid du Colombier * should copy files to other directories,
10157dd7cddfSDavid du Colombier * and copy & truncate inbox
10167dd7cddfSDavid du Colombier */
10177dd7cddfSDavid du Colombier static void
renameCmd(char * tg,char * cmd)10187dd7cddfSDavid du Colombier renameCmd(char *tg, char *cmd)
10197dd7cddfSDavid du Colombier {
10207dd7cddfSDavid du Colombier char *from, *to;
10217dd7cddfSDavid du Colombier int ok;
10227dd7cddfSDavid du Colombier
10237dd7cddfSDavid du Colombier mustBe(' ');
10247dd7cddfSDavid du Colombier from = astring();
10257dd7cddfSDavid du Colombier mustBe(' ');
10267dd7cddfSDavid du Colombier to = astring();
10277dd7cddfSDavid du Colombier crnl();
10287dd7cddfSDavid du Colombier check();
10297dd7cddfSDavid du Colombier
10307dd7cddfSDavid du Colombier to = mboxName(to);
10317dd7cddfSDavid du Colombier if(to == nil || !okMbox(to) || cistrcmp(to, "inbox") == 0){
1032d9306527SDavid du Colombier Bprint(&bout, "%s NO %s bad mailbox destination name\r\n", tg, cmd);
10337dd7cddfSDavid du Colombier return;
10347dd7cddfSDavid du Colombier }
10357dd7cddfSDavid du Colombier if(access(to, AEXIST) >= 0){
1036d9306527SDavid du Colombier Bprint(&bout, "%s NO %s mailbox already exists\r\n", tg, cmd);
10377dd7cddfSDavid du Colombier return;
10387dd7cddfSDavid du Colombier }
10397dd7cddfSDavid du Colombier from = mboxName(from);
10407dd7cddfSDavid du Colombier if(from == nil || !okMbox(from)){
1041d9306527SDavid du Colombier Bprint(&bout, "%s NO %s bad mailbox destination name\r\n", tg, cmd);
10427dd7cddfSDavid du Colombier return;
10437dd7cddfSDavid du Colombier }
10447dd7cddfSDavid du Colombier if(cistrcmp(from, "inbox") == 0)
10457dd7cddfSDavid du Colombier ok = copyBox(from, to, 0);
10467dd7cddfSDavid du Colombier else
10477dd7cddfSDavid du Colombier ok = moveBox(from, to);
10487dd7cddfSDavid du Colombier
10497dd7cddfSDavid du Colombier if(ok)
1050d9306527SDavid du Colombier Bprint(&bout, "%s OK %s completed\r\n", tg, cmd);
10517dd7cddfSDavid du Colombier else
1052d9306527SDavid du Colombier Bprint(&bout, "%s NO %s failed\r\n", tg, cmd);
10537dd7cddfSDavid du Colombier }
10547dd7cddfSDavid du Colombier
10557dd7cddfSDavid du Colombier static void
searchCmd(char * tg,char * cmd)10567dd7cddfSDavid du Colombier searchCmd(char *tg, char *cmd)
10577dd7cddfSDavid du Colombier {
10587dd7cddfSDavid du Colombier searchUCmd(tg, cmd, 0);
10597dd7cddfSDavid du Colombier }
10607dd7cddfSDavid du Colombier
10617dd7cddfSDavid du Colombier static void
searchUCmd(char * tg,char * cmd,int uids)10627dd7cddfSDavid du Colombier searchUCmd(char *tg, char *cmd, int uids)
10637dd7cddfSDavid du Colombier {
10647dd7cddfSDavid du Colombier Search rock;
10657dd7cddfSDavid du Colombier Msg *m;
10667dd7cddfSDavid du Colombier char *uid;
10677dd7cddfSDavid du Colombier ulong id;
10687dd7cddfSDavid du Colombier
10697dd7cddfSDavid du Colombier mustBe(' ');
10707dd7cddfSDavid du Colombier rock.next = nil;
10717dd7cddfSDavid du Colombier searchKeys(1, &rock);
10727dd7cddfSDavid du Colombier crnl();
10737dd7cddfSDavid du Colombier uid = "";
10747dd7cddfSDavid du Colombier if(uids)
10757dd7cddfSDavid du Colombier uid = "uid ";
10767dd7cddfSDavid du Colombier if(rock.next != nil && rock.next->key == SKCharset){
1077*58da3067SDavid du Colombier if(cistrcmp(rock.next->s, "utf-8") != 0
10787dd7cddfSDavid du Colombier && cistrcmp(rock.next->s, "us-ascii") != 0){
1079*58da3067SDavid du Colombier Bprint(&bout, "%s NO [BADCHARSET] (\"US-ASCII\" \"UTF-8\") %s%s failed\r\n",
1080*58da3067SDavid du Colombier tg, uid, cmd);
10817dd7cddfSDavid du Colombier checkBox(selected, 0);
10827dd7cddfSDavid du Colombier status(uids, uids);
10837dd7cddfSDavid du Colombier return;
10847dd7cddfSDavid du Colombier }
10857dd7cddfSDavid du Colombier rock.next = rock.next->next;
10867dd7cddfSDavid du Colombier }
10877dd7cddfSDavid du Colombier Bprint(&bout, "* search");
10887dd7cddfSDavid du Colombier for(m = selected->msgs; m != nil; m = m->next)
10897dd7cddfSDavid du Colombier m->matched = searchMsg(m, rock.next);
10907dd7cddfSDavid du Colombier for(m = selected->msgs; m != nil; m = m->next){
10917dd7cddfSDavid du Colombier if(m->matched){
10927dd7cddfSDavid du Colombier if(uids)
10937dd7cddfSDavid du Colombier id = m->uid;
10947dd7cddfSDavid du Colombier else
10957dd7cddfSDavid du Colombier id = m->seq;
10967dd7cddfSDavid du Colombier Bprint(&bout, " %lud", id);
10977dd7cddfSDavid du Colombier }
10987dd7cddfSDavid du Colombier }
10997dd7cddfSDavid du Colombier Bprint(&bout, "\r\n");
11007dd7cddfSDavid du Colombier checkBox(selected, 0);
11017dd7cddfSDavid du Colombier status(uids, uids);
1102d9306527SDavid du Colombier Bprint(&bout, "%s OK %s%s completed\r\n", tg, uid, cmd);
11037dd7cddfSDavid du Colombier }
11047dd7cddfSDavid du Colombier
11057dd7cddfSDavid du Colombier static void
selectCmd(char * tg,char * cmd)11067dd7cddfSDavid du Colombier selectCmd(char *tg, char *cmd)
11077dd7cddfSDavid du Colombier {
11087dd7cddfSDavid du Colombier Msg *m;
11097dd7cddfSDavid du Colombier char *s, *mbox;
11107dd7cddfSDavid du Colombier
11117dd7cddfSDavid du Colombier mustBe(' ');
11127dd7cddfSDavid du Colombier mbox = astring();
11137dd7cddfSDavid du Colombier crnl();
11147dd7cddfSDavid du Colombier
11157dd7cddfSDavid du Colombier if(selected){
11167dd7cddfSDavid du Colombier imapState = SAuthed;
11177dd7cddfSDavid du Colombier closeBox(selected, 1);
11187dd7cddfSDavid du Colombier selected = nil;
11197dd7cddfSDavid du Colombier }
11207dd7cddfSDavid du Colombier
11217dd7cddfSDavid du Colombier mbox = mboxName(mbox);
11227dd7cddfSDavid du Colombier if(mbox == nil || !okMbox(mbox)){
1123d9306527SDavid du Colombier Bprint(&bout, "%s NO %s bad mailbox\r\n", tg, cmd);
11247dd7cddfSDavid du Colombier return;
11257dd7cddfSDavid du Colombier }
11267dd7cddfSDavid du Colombier
11277dd7cddfSDavid du Colombier selected = openBox(mbox, "imap", cistrcmp(cmd, "select") == 0);
11287dd7cddfSDavid du Colombier if(selected == nil){
1129d9306527SDavid du Colombier Bprint(&bout, "%s NO %s can't open mailbox %s: %r\r\n", tg, cmd, mbox);
11307dd7cddfSDavid du Colombier return;
11317dd7cddfSDavid du Colombier }
11327dd7cddfSDavid du Colombier
11337dd7cddfSDavid du Colombier imapState = SSelected;
11347dd7cddfSDavid du Colombier
1135d9306527SDavid du Colombier Bprint(&bout, "* FLAGS (\\Seen \\Answered \\Flagged \\Deleted \\Draft)\r\n");
113640fe8d0dSDavid du Colombier Bprint(&bout, "* %lud EXISTS\r\n", selected->max);
11377dd7cddfSDavid du Colombier selected->toldMax = selected->max;
113840fe8d0dSDavid du Colombier Bprint(&bout, "* %lud RECENT\r\n", selected->recent);
11397dd7cddfSDavid du Colombier selected->toldRecent = selected->recent;
11407dd7cddfSDavid du Colombier for(m = selected->msgs; m != nil; m = m->next){
11417dd7cddfSDavid du Colombier if(!m->expunged && (m->flags & MSeen) != MSeen){
1142d9306527SDavid du Colombier Bprint(&bout, "* OK [UNSEEN %ld]\r\n", m->seq);
11437dd7cddfSDavid du Colombier break;
11447dd7cddfSDavid du Colombier }
11457dd7cddfSDavid du Colombier }
11466b6b9ac8SDavid du Colombier Bprint(&bout, "* OK [PERMANENTFLAGS (\\Seen \\Answered \\Flagged \\Draft \\Deleted)]\r\n");
1147d9306527SDavid du Colombier Bprint(&bout, "* OK [UIDNEXT %ld]\r\n", selected->uidnext);
1148d9306527SDavid du Colombier Bprint(&bout, "* OK [UIDVALIDITY %ld]\r\n", selected->uidvalidity);
11497dd7cddfSDavid du Colombier s = "READ-ONLY";
11507dd7cddfSDavid du Colombier if(selected->writable)
11517dd7cddfSDavid du Colombier s = "READ-WRITE";
1152d9306527SDavid du Colombier Bprint(&bout, "%s OK [%s] %s %s completed\r\n", tg, s, cmd, mbox);
11537dd7cddfSDavid du Colombier }
11547dd7cddfSDavid du Colombier
11557dd7cddfSDavid du Colombier static NamedInt statusItems[] =
11567dd7cddfSDavid du Colombier {
11577dd7cddfSDavid du Colombier {"MESSAGES", SMessages},
11587dd7cddfSDavid du Colombier {"RECENT", SRecent},
11597dd7cddfSDavid du Colombier {"UIDNEXT", SUidNext},
11607dd7cddfSDavid du Colombier {"UIDVALIDITY", SUidValidity},
11617dd7cddfSDavid du Colombier {"UNSEEN", SUnseen},
11627dd7cddfSDavid du Colombier {nil, 0}
11637dd7cddfSDavid du Colombier };
11647dd7cddfSDavid du Colombier
11657dd7cddfSDavid du Colombier static void
statusCmd(char * tg,char * cmd)11667dd7cddfSDavid du Colombier statusCmd(char *tg, char *cmd)
11677dd7cddfSDavid du Colombier {
11687dd7cddfSDavid du Colombier Box *box;
11697dd7cddfSDavid du Colombier Msg *m;
11707dd7cddfSDavid du Colombier char *s, *mbox;
11717dd7cddfSDavid du Colombier ulong v;
11727dd7cddfSDavid du Colombier int si, i;
11737dd7cddfSDavid du Colombier
11747dd7cddfSDavid du Colombier mustBe(' ');
11757dd7cddfSDavid du Colombier mbox = astring();
11767dd7cddfSDavid du Colombier mustBe(' ');
11777dd7cddfSDavid du Colombier mustBe('(');
11787dd7cddfSDavid du Colombier si = 0;
11797dd7cddfSDavid du Colombier for(;;){
11807dd7cddfSDavid du Colombier s = atom();
11817dd7cddfSDavid du Colombier i = mapInt(statusItems, s);
11827dd7cddfSDavid du Colombier if(i == 0)
11837dd7cddfSDavid du Colombier parseErr("illegal status item");
11847dd7cddfSDavid du Colombier si |= i;
11857dd7cddfSDavid du Colombier if(peekc() == ')')
11867dd7cddfSDavid du Colombier break;
11877dd7cddfSDavid du Colombier mustBe(' ');
11887dd7cddfSDavid du Colombier }
11897dd7cddfSDavid du Colombier mustBe(')');
11907dd7cddfSDavid du Colombier crnl();
11917dd7cddfSDavid du Colombier
11927dd7cddfSDavid du Colombier mbox = mboxName(mbox);
11937dd7cddfSDavid du Colombier if(mbox == nil || !okMbox(mbox)){
11947dd7cddfSDavid du Colombier check();
1195d9306527SDavid du Colombier Bprint(&bout, "%s NO %s bad mailbox\r\n", tg, cmd);
11967dd7cddfSDavid du Colombier return;
11977dd7cddfSDavid du Colombier }
11987dd7cddfSDavid du Colombier
11997dd7cddfSDavid du Colombier box = openBox(mbox, "status", 1);
12007dd7cddfSDavid du Colombier if(box == nil){
12017dd7cddfSDavid du Colombier check();
1202d9306527SDavid du Colombier Bprint(&bout, "%s NO [TRYCREATE] %s can't open mailbox %s: %r\r\n", tg, cmd, mbox);
12037dd7cddfSDavid du Colombier return;
12047dd7cddfSDavid du Colombier }
12057dd7cddfSDavid du Colombier
12068cf6001eSDavid du Colombier Bprint(&bout, "* STATUS %s (", mbox);
12077dd7cddfSDavid du Colombier s = "";
12087dd7cddfSDavid du Colombier for(i = 0; statusItems[i].name != nil; i++){
12097dd7cddfSDavid du Colombier if(si & statusItems[i].v){
12107dd7cddfSDavid du Colombier v = 0;
12117dd7cddfSDavid du Colombier switch(statusItems[i].v){
12127dd7cddfSDavid du Colombier case SMessages:
12137dd7cddfSDavid du Colombier v = box->max;
12147dd7cddfSDavid du Colombier break;
12157dd7cddfSDavid du Colombier case SRecent:
12167dd7cddfSDavid du Colombier v = box->recent;
12177dd7cddfSDavid du Colombier break;
12187dd7cddfSDavid du Colombier case SUidNext:
12197dd7cddfSDavid du Colombier v = box->uidnext;
12207dd7cddfSDavid du Colombier break;
12217dd7cddfSDavid du Colombier case SUidValidity:
12227dd7cddfSDavid du Colombier v = box->uidvalidity;
12237dd7cddfSDavid du Colombier break;
12247dd7cddfSDavid du Colombier case SUnseen:
12257dd7cddfSDavid du Colombier v = 0;
12267dd7cddfSDavid du Colombier for(m = box->msgs; m != nil; m = m->next)
12277dd7cddfSDavid du Colombier if((m->flags & MSeen) != MSeen)
12287dd7cddfSDavid du Colombier v++;
12297dd7cddfSDavid du Colombier break;
12307dd7cddfSDavid du Colombier default:
12317dd7cddfSDavid du Colombier Bprint(&bout, ")");
12327dd7cddfSDavid du Colombier bye("internal error: status item not implemented");
12337dd7cddfSDavid du Colombier break;
12347dd7cddfSDavid du Colombier }
12357dd7cddfSDavid du Colombier Bprint(&bout, "%s%s %lud", s, statusItems[i].name, v);
12367dd7cddfSDavid du Colombier s = " ";
12377dd7cddfSDavid du Colombier }
12387dd7cddfSDavid du Colombier }
12397dd7cddfSDavid du Colombier Bprint(&bout, ")\r\n");
12407dd7cddfSDavid du Colombier closeBox(box, 1);
12417dd7cddfSDavid du Colombier
12427dd7cddfSDavid du Colombier check();
1243d9306527SDavid du Colombier Bprint(&bout, "%s OK %s completed\r\n", tg, cmd);
12447dd7cddfSDavid du Colombier }
12457dd7cddfSDavid du Colombier
12467dd7cddfSDavid du Colombier static void
storeCmd(char * tg,char * cmd)12477dd7cddfSDavid du Colombier storeCmd(char *tg, char *cmd)
12487dd7cddfSDavid du Colombier {
12497dd7cddfSDavid du Colombier storeUCmd(tg, cmd, 0);
12507dd7cddfSDavid du Colombier }
12517dd7cddfSDavid du Colombier
12527dd7cddfSDavid du Colombier static void
storeUCmd(char * tg,char * cmd,int uids)12537dd7cddfSDavid du Colombier storeUCmd(char *tg, char *cmd, int uids)
12547dd7cddfSDavid du Colombier {
12557dd7cddfSDavid du Colombier Store *st;
12567dd7cddfSDavid du Colombier MsgSet *ms;
12577dd7cddfSDavid du Colombier MbLock *ml;
12587dd7cddfSDavid du Colombier char *uid;
12597dd7cddfSDavid du Colombier ulong max;
12607dd7cddfSDavid du Colombier int ok;
12617dd7cddfSDavid du Colombier
12627dd7cddfSDavid du Colombier mustBe(' ');
1263becaf2abSDavid du Colombier ms = msgSet(uids);
12647dd7cddfSDavid du Colombier mustBe(' ');
12657dd7cddfSDavid du Colombier st = storeWhat();
12667dd7cddfSDavid du Colombier crnl();
12677dd7cddfSDavid du Colombier uid = "";
12687dd7cddfSDavid du Colombier if(uids)
12697dd7cddfSDavid du Colombier uid = "uid ";
12707dd7cddfSDavid du Colombier max = selected->max;
12717dd7cddfSDavid du Colombier ml = checkBox(selected, 1);
12727dd7cddfSDavid du Colombier ok = ml != nil && forMsgs(selected, ms, max, uids, storeMsg, st);
12737dd7cddfSDavid du Colombier closeImp(selected, ml);
12747dd7cddfSDavid du Colombier status(uids, uids);
12757dd7cddfSDavid du Colombier if(ok)
1276d9306527SDavid du Colombier Bprint(&bout, "%s OK %s%s completed\r\n", tg, uid, cmd);
12777dd7cddfSDavid du Colombier else
1278d9306527SDavid du Colombier Bprint(&bout, "%s NO %s%s failed\r\n", tg, uid, cmd);
12797dd7cddfSDavid du Colombier }
12807dd7cddfSDavid du Colombier
12817dd7cddfSDavid du Colombier /*
12827dd7cddfSDavid du Colombier * minimal implementation of subscribe
12837dd7cddfSDavid du Colombier * all folders are automatically subscribed,
12847dd7cddfSDavid du Colombier * and can't be unsubscribed
12857dd7cddfSDavid du Colombier */
12867dd7cddfSDavid du Colombier static void
subscribeCmd(char * tg,char * cmd)12877dd7cddfSDavid du Colombier subscribeCmd(char *tg, char *cmd)
12887dd7cddfSDavid du Colombier {
12897dd7cddfSDavid du Colombier Box *box;
12907dd7cddfSDavid du Colombier char *mbox;
12917dd7cddfSDavid du Colombier int ok;
12927dd7cddfSDavid du Colombier
12937dd7cddfSDavid du Colombier mustBe(' ');
12947dd7cddfSDavid du Colombier mbox = astring();
12957dd7cddfSDavid du Colombier crnl();
12967dd7cddfSDavid du Colombier check();
12977dd7cddfSDavid du Colombier mbox = mboxName(mbox);
12987dd7cddfSDavid du Colombier ok = 0;
12997dd7cddfSDavid du Colombier if(mbox != nil && okMbox(mbox)){
13007dd7cddfSDavid du Colombier box = openBox(mbox, "subscribe", 0);
13017dd7cddfSDavid du Colombier if(box != nil){
13027dd7cddfSDavid du Colombier ok = subscribe(mbox, 's');
13037dd7cddfSDavid du Colombier closeBox(box, 1);
13047dd7cddfSDavid du Colombier }
13057dd7cddfSDavid du Colombier }
13067dd7cddfSDavid du Colombier if(!ok)
1307d9306527SDavid du Colombier Bprint(&bout, "%s NO %s bad mailbox\r\n", tg, cmd);
13087dd7cddfSDavid du Colombier else
1309d9306527SDavid du Colombier Bprint(&bout, "%s OK %s completed\r\n", tg, cmd);
13107dd7cddfSDavid du Colombier }
13117dd7cddfSDavid du Colombier
13127dd7cddfSDavid du Colombier static void
uidCmd(char * tg,char * cmd)13137dd7cddfSDavid du Colombier uidCmd(char *tg, char *cmd)
13147dd7cddfSDavid du Colombier {
13157dd7cddfSDavid du Colombier char *sub;
13167dd7cddfSDavid du Colombier
13177dd7cddfSDavid du Colombier mustBe(' ');
13187dd7cddfSDavid du Colombier sub = atom();
13197dd7cddfSDavid du Colombier if(cistrcmp(sub, "copy") == 0)
13207dd7cddfSDavid du Colombier copyUCmd(tg, sub, 1);
13217dd7cddfSDavid du Colombier else if(cistrcmp(sub, "fetch") == 0)
13227dd7cddfSDavid du Colombier fetchUCmd(tg, sub, 1);
13237dd7cddfSDavid du Colombier else if(cistrcmp(sub, "search") == 0)
13247dd7cddfSDavid du Colombier searchUCmd(tg, sub, 1);
13257dd7cddfSDavid du Colombier else if(cistrcmp(sub, "store") == 0)
13267dd7cddfSDavid du Colombier storeUCmd(tg, sub, 1);
13277dd7cddfSDavid du Colombier else{
13287dd7cddfSDavid du Colombier clearcmd();
1329d9306527SDavid du Colombier Bprint(&bout, "%s BAD %s illegal uid command %s\r\n", tg, cmd, sub);
13307dd7cddfSDavid du Colombier }
13317dd7cddfSDavid du Colombier }
13327dd7cddfSDavid du Colombier
13337dd7cddfSDavid du Colombier static void
unsubscribeCmd(char * tg,char * cmd)13347dd7cddfSDavid du Colombier unsubscribeCmd(char *tg, char *cmd)
13357dd7cddfSDavid du Colombier {
13367dd7cddfSDavid du Colombier char *mbox;
13377dd7cddfSDavid du Colombier
13387dd7cddfSDavid du Colombier mustBe(' ');
13397dd7cddfSDavid du Colombier mbox = astring();
13407dd7cddfSDavid du Colombier crnl();
13417dd7cddfSDavid du Colombier check();
13427dd7cddfSDavid du Colombier mbox = mboxName(mbox);
13437dd7cddfSDavid du Colombier if(mbox == nil || !okMbox(mbox) || !subscribe(mbox, 'u'))
1344d9306527SDavid du Colombier Bprint(&bout, "%s NO %s can't unsubscribe\r\n", tg, cmd);
13457dd7cddfSDavid du Colombier else
1346d9306527SDavid du Colombier Bprint(&bout, "%s OK %s completed\r\n", tg, cmd);
13477dd7cddfSDavid du Colombier }
13487dd7cddfSDavid du Colombier
13497dd7cddfSDavid du Colombier static void
badsyn(void)13507dd7cddfSDavid du Colombier badsyn(void)
13517dd7cddfSDavid du Colombier {
13527dd7cddfSDavid du Colombier parseErr("bad syntax");
13537dd7cddfSDavid du Colombier }
13547dd7cddfSDavid du Colombier
13557dd7cddfSDavid du Colombier static void
clearcmd(void)13567dd7cddfSDavid du Colombier clearcmd(void)
13577dd7cddfSDavid du Colombier {
13587dd7cddfSDavid du Colombier int c;
13597dd7cddfSDavid du Colombier
13607dd7cddfSDavid du Colombier for(;;){
13617dd7cddfSDavid du Colombier c = getc();
13627dd7cddfSDavid du Colombier if(c < 0)
13637dd7cddfSDavid du Colombier bye("end of input");
13647dd7cddfSDavid du Colombier if(c == '\n')
13657dd7cddfSDavid du Colombier return;
13667dd7cddfSDavid du Colombier }
13677dd7cddfSDavid du Colombier }
13687dd7cddfSDavid du Colombier
13697dd7cddfSDavid du Colombier static void
crnl(void)13707dd7cddfSDavid du Colombier crnl(void)
13717dd7cddfSDavid du Colombier {
13727dd7cddfSDavid du Colombier int c;
13737dd7cddfSDavid du Colombier
13747dd7cddfSDavid du Colombier c = getc();
13757dd7cddfSDavid du Colombier if(c == '\n')
13767dd7cddfSDavid du Colombier return;
13777dd7cddfSDavid du Colombier if(c != '\r' || getc() != '\n')
13787dd7cddfSDavid du Colombier badsyn();
13797dd7cddfSDavid du Colombier }
13807dd7cddfSDavid du Colombier
13817dd7cddfSDavid du Colombier static void
mustBe(int c)13827dd7cddfSDavid du Colombier mustBe(int c)
13837dd7cddfSDavid du Colombier {
13847dd7cddfSDavid du Colombier if(getc() != c){
13857dd7cddfSDavid du Colombier ungetc();
13867dd7cddfSDavid du Colombier badsyn();
13877dd7cddfSDavid du Colombier }
13887dd7cddfSDavid du Colombier }
13897dd7cddfSDavid du Colombier
13907dd7cddfSDavid du Colombier /*
13917dd7cddfSDavid du Colombier * flaglist : '(' ')' | '(' flags ')'
13927dd7cddfSDavid du Colombier */
13937dd7cddfSDavid du Colombier static int
flagList(void)13947dd7cddfSDavid du Colombier flagList(void)
13957dd7cddfSDavid du Colombier {
13967dd7cddfSDavid du Colombier int f;
13977dd7cddfSDavid du Colombier
13987dd7cddfSDavid du Colombier mustBe('(');
13997dd7cddfSDavid du Colombier f = 0;
14007dd7cddfSDavid du Colombier if(peekc() != ')')
14017dd7cddfSDavid du Colombier f = flags();
14027dd7cddfSDavid du Colombier
14037dd7cddfSDavid du Colombier mustBe(')');
14047dd7cddfSDavid du Colombier return f;
14057dd7cddfSDavid du Colombier }
14067dd7cddfSDavid du Colombier
14077dd7cddfSDavid du Colombier /*
14087dd7cddfSDavid du Colombier * flags : flag | flags ' ' flag
14097dd7cddfSDavid du Colombier * flag : '\' atom | atom
14107dd7cddfSDavid du Colombier */
14117dd7cddfSDavid du Colombier static int
flags(void)14127dd7cddfSDavid du Colombier flags(void)
14137dd7cddfSDavid du Colombier {
14147dd7cddfSDavid du Colombier int ff, flags;
14157dd7cddfSDavid du Colombier char *s;
14167dd7cddfSDavid du Colombier int c;
14177dd7cddfSDavid du Colombier
14187dd7cddfSDavid du Colombier flags = 0;
14197dd7cddfSDavid du Colombier for(;;){
14207dd7cddfSDavid du Colombier c = peekc();
14217dd7cddfSDavid du Colombier if(c == '\\'){
14227dd7cddfSDavid du Colombier mustBe('\\');
14237dd7cddfSDavid du Colombier s = atomString(atomStop, "\\");
14247dd7cddfSDavid du Colombier }else if(strchr(atomStop, c) != nil)
14257dd7cddfSDavid du Colombier s = atom();
14267dd7cddfSDavid du Colombier else
14277dd7cddfSDavid du Colombier break;
14287dd7cddfSDavid du Colombier ff = mapFlag(s);
14297dd7cddfSDavid du Colombier if(ff == 0)
14307dd7cddfSDavid du Colombier parseErr("flag not supported");
14317dd7cddfSDavid du Colombier flags |= ff;
14327dd7cddfSDavid du Colombier if(peekc() != ' ')
14337dd7cddfSDavid du Colombier break;
14347dd7cddfSDavid du Colombier mustBe(' ');
14357dd7cddfSDavid du Colombier }
14367dd7cddfSDavid du Colombier if(flags == 0)
14377dd7cddfSDavid du Colombier parseErr("no flags given");
14387dd7cddfSDavid du Colombier return flags;
14397dd7cddfSDavid du Colombier }
14407dd7cddfSDavid du Colombier
14417dd7cddfSDavid du Colombier /*
14427dd7cddfSDavid du Colombier * storeWhat : osign 'FLAGS' ' ' storeflags
14437dd7cddfSDavid du Colombier * | osign 'FLAGS.SILENT' ' ' storeflags
14447dd7cddfSDavid du Colombier * osign :
14457dd7cddfSDavid du Colombier * | '+' | '-'
14467dd7cddfSDavid du Colombier * storeflags : flagList | flags
14477dd7cddfSDavid du Colombier */
14487dd7cddfSDavid du Colombier static Store*
storeWhat(void)14497dd7cddfSDavid du Colombier storeWhat(void)
14507dd7cddfSDavid du Colombier {
14517dd7cddfSDavid du Colombier int f;
14527dd7cddfSDavid du Colombier char *s;
14537dd7cddfSDavid du Colombier int c, w;
14547dd7cddfSDavid du Colombier
14557dd7cddfSDavid du Colombier c = peekc();
14567dd7cddfSDavid du Colombier if(c == '+' || c == '-')
14577dd7cddfSDavid du Colombier mustBe(c);
14587dd7cddfSDavid du Colombier else
14597dd7cddfSDavid du Colombier c = 0;
14607dd7cddfSDavid du Colombier s = atom();
14617dd7cddfSDavid du Colombier w = 0;
14627dd7cddfSDavid du Colombier if(cistrcmp(s, "flags") == 0)
14637dd7cddfSDavid du Colombier w = STFlags;
14647dd7cddfSDavid du Colombier else if(cistrcmp(s, "flags.silent") == 0)
14657dd7cddfSDavid du Colombier w = STFlagsSilent;
14667dd7cddfSDavid du Colombier else
14677dd7cddfSDavid du Colombier parseErr("illegal store attribute");
14687dd7cddfSDavid du Colombier mustBe(' ');
14697dd7cddfSDavid du Colombier if(peekc() == '(')
14707dd7cddfSDavid du Colombier f = flagList();
14717dd7cddfSDavid du Colombier else
14727dd7cddfSDavid du Colombier f = flags();
14737dd7cddfSDavid du Colombier return mkStore(c, w, f);
14747dd7cddfSDavid du Colombier }
14757dd7cddfSDavid du Colombier
14767dd7cddfSDavid du Colombier /*
14777dd7cddfSDavid du Colombier * fetchWhat : "ALL" | "FULL" | "FAST" | fetchAtt | '(' fetchAtts ')'
14787dd7cddfSDavid du Colombier * fetchAtts : fetchAtt | fetchAtts ' ' fetchAtt
14797dd7cddfSDavid du Colombier */
14807dd7cddfSDavid du Colombier static char *fetchAtom = "(){}%*\"\\[]";
14817dd7cddfSDavid du Colombier static Fetch*
fetchWhat(void)14827dd7cddfSDavid du Colombier fetchWhat(void)
14837dd7cddfSDavid du Colombier {
14847dd7cddfSDavid du Colombier Fetch *f;
14857dd7cddfSDavid du Colombier char *s;
14867dd7cddfSDavid du Colombier
14877dd7cddfSDavid du Colombier if(peekc() == '('){
14887dd7cddfSDavid du Colombier getc();
14897dd7cddfSDavid du Colombier f = nil;
14907dd7cddfSDavid du Colombier for(;;){
14917dd7cddfSDavid du Colombier s = atomString(fetchAtom, "");
14927dd7cddfSDavid du Colombier f = fetchAtt(s, f);
14937dd7cddfSDavid du Colombier if(peekc() == ')')
14947dd7cddfSDavid du Colombier break;
14957dd7cddfSDavid du Colombier mustBe(' ');
14967dd7cddfSDavid du Colombier }
14977dd7cddfSDavid du Colombier getc();
14987dd7cddfSDavid du Colombier return revFetch(f);
14997dd7cddfSDavid du Colombier }
15007dd7cddfSDavid du Colombier
15017dd7cddfSDavid du Colombier s = atomString(fetchAtom, "");
15027dd7cddfSDavid du Colombier if(cistrcmp(s, "all") == 0)
15037dd7cddfSDavid du Colombier f = mkFetch(FFlags, mkFetch(FInternalDate, mkFetch(FRfc822Size, mkFetch(FEnvelope, nil))));
15047dd7cddfSDavid du Colombier else if(cistrcmp(s, "fast") == 0)
15057dd7cddfSDavid du Colombier f = mkFetch(FFlags, mkFetch(FInternalDate, mkFetch(FRfc822Size, nil)));
15067dd7cddfSDavid du Colombier else if(cistrcmp(s, "full") == 0)
15077dd7cddfSDavid du Colombier f = mkFetch(FFlags, mkFetch(FInternalDate, mkFetch(FRfc822Size, mkFetch(FEnvelope, mkFetch(FBody, nil)))));
15087dd7cddfSDavid du Colombier else
15097dd7cddfSDavid du Colombier f = fetchAtt(s, nil);
15107dd7cddfSDavid du Colombier return f;
15117dd7cddfSDavid du Colombier }
15127dd7cddfSDavid du Colombier
15137dd7cddfSDavid du Colombier /*
15147dd7cddfSDavid du Colombier * fetchAtt : "ENVELOPE" | "FLAGS" | "INTERNALDATE"
15157dd7cddfSDavid du Colombier * | "RFC822" | "RFC822.HEADER" | "RFC822.SIZE" | "RFC822.TEXT"
15167dd7cddfSDavid du Colombier * | "BODYSTRUCTURE"
15177dd7cddfSDavid du Colombier * | "UID"
15187dd7cddfSDavid du Colombier * | "BODY"
15197dd7cddfSDavid du Colombier * | "BODY" bodysubs
15207dd7cddfSDavid du Colombier * | "BODY.PEEK" bodysubs
15217dd7cddfSDavid du Colombier * bodysubs : sect
15227dd7cddfSDavid du Colombier * | sect '<' number '.' nz-number '>'
15237dd7cddfSDavid du Colombier * sect : '[' sectSpec ']'
15247dd7cddfSDavid du Colombier * sectSpec : sectMsgText
15257dd7cddfSDavid du Colombier * | sectPart
15267dd7cddfSDavid du Colombier * | sectPart '.' sectText
15277dd7cddfSDavid du Colombier * sectPart : nz-number
15287dd7cddfSDavid du Colombier * | sectPart '.' nz-number
15297dd7cddfSDavid du Colombier */
15307dd7cddfSDavid du Colombier static Fetch*
fetchAtt(char * s,Fetch * f)15317dd7cddfSDavid du Colombier fetchAtt(char *s, Fetch *f)
15327dd7cddfSDavid du Colombier {
15337dd7cddfSDavid du Colombier NList *sect;
15347dd7cddfSDavid du Colombier int c;
15357dd7cddfSDavid du Colombier
15367dd7cddfSDavid du Colombier if(cistrcmp(s, "envelope") == 0)
15377dd7cddfSDavid du Colombier return mkFetch(FEnvelope, f);
15387dd7cddfSDavid du Colombier if(cistrcmp(s, "flags") == 0)
15397dd7cddfSDavid du Colombier return mkFetch(FFlags, f);
15407dd7cddfSDavid du Colombier if(cistrcmp(s, "internaldate") == 0)
15417dd7cddfSDavid du Colombier return mkFetch(FInternalDate, f);
1542d9306527SDavid du Colombier if(cistrcmp(s, "RFC822") == 0)
15437dd7cddfSDavid du Colombier return mkFetch(FRfc822, f);
1544d9306527SDavid du Colombier if(cistrcmp(s, "RFC822.header") == 0)
15457dd7cddfSDavid du Colombier return mkFetch(FRfc822Head, f);
1546d9306527SDavid du Colombier if(cistrcmp(s, "RFC822.size") == 0)
15477dd7cddfSDavid du Colombier return mkFetch(FRfc822Size, f);
1548d9306527SDavid du Colombier if(cistrcmp(s, "RFC822.text") == 0)
15497dd7cddfSDavid du Colombier return mkFetch(FRfc822Text, f);
15507dd7cddfSDavid du Colombier if(cistrcmp(s, "bodystructure") == 0)
15517dd7cddfSDavid du Colombier return mkFetch(FBodyStruct, f);
15527dd7cddfSDavid du Colombier if(cistrcmp(s, "uid") == 0)
15537dd7cddfSDavid du Colombier return mkFetch(FUid, f);
15547dd7cddfSDavid du Colombier
15557dd7cddfSDavid du Colombier if(cistrcmp(s, "body") == 0){
15567dd7cddfSDavid du Colombier if(peekc() != '[')
15577dd7cddfSDavid du Colombier return mkFetch(FBody, f);
15587dd7cddfSDavid du Colombier f = mkFetch(FBodySect, f);
15597dd7cddfSDavid du Colombier }else if(cistrcmp(s, "body.peek") == 0)
15607dd7cddfSDavid du Colombier f = mkFetch(FBodyPeek, f);
15617dd7cddfSDavid du Colombier else
15627dd7cddfSDavid du Colombier parseErr("illegal fetch attribute");
15637dd7cddfSDavid du Colombier
15647dd7cddfSDavid du Colombier mustBe('[');
15657dd7cddfSDavid du Colombier c = peekc();
15667dd7cddfSDavid du Colombier if(c >= '1' && c <= '9'){
15677dd7cddfSDavid du Colombier sect = mkNList(number(1), nil);
15687dd7cddfSDavid du Colombier while(peekc() == '.'){
15697dd7cddfSDavid du Colombier getc();
15707dd7cddfSDavid du Colombier c = peekc();
15717dd7cddfSDavid du Colombier if(c >= '1' && c <= '9'){
15727dd7cddfSDavid du Colombier sect = mkNList(number(1), sect);
15737dd7cddfSDavid du Colombier }else{
15747dd7cddfSDavid du Colombier break;
15757dd7cddfSDavid du Colombier }
15767dd7cddfSDavid du Colombier }
15777dd7cddfSDavid du Colombier f->sect = revNList(sect);
15787dd7cddfSDavid du Colombier }
15797dd7cddfSDavid du Colombier if(peekc() != ']')
15807dd7cddfSDavid du Colombier sectText(f, f->sect != nil);
15817dd7cddfSDavid du Colombier mustBe(']');
15827dd7cddfSDavid du Colombier
15837dd7cddfSDavid du Colombier if(peekc() != '<')
15847dd7cddfSDavid du Colombier return f;
15857dd7cddfSDavid du Colombier
15867dd7cddfSDavid du Colombier f->partial = 1;
15877dd7cddfSDavid du Colombier mustBe('<');
15887dd7cddfSDavid du Colombier f->start = number(0);
15897dd7cddfSDavid du Colombier mustBe('.');
15907dd7cddfSDavid du Colombier f->size = number(1);
15917dd7cddfSDavid du Colombier mustBe('>');
15927dd7cddfSDavid du Colombier return f;
15937dd7cddfSDavid du Colombier }
15947dd7cddfSDavid du Colombier
15957dd7cddfSDavid du Colombier /*
15967dd7cddfSDavid du Colombier * sectText : sectMsgText | "MIME"
15977dd7cddfSDavid du Colombier * sectMsgText : "HEADER"
15987dd7cddfSDavid du Colombier * | "TEXT"
15997dd7cddfSDavid du Colombier * | "HEADER.FIELDS" ' ' hdrList
16007dd7cddfSDavid du Colombier * | "HEADER.FIELDS.NOT" ' ' hdrList
16017dd7cddfSDavid du Colombier * hdrList : '(' hdrs ')'
16027dd7cddfSDavid du Colombier * hdrs: : astring
16037dd7cddfSDavid du Colombier * | hdrs ' ' astring
16047dd7cddfSDavid du Colombier */
16057dd7cddfSDavid du Colombier static void
sectText(Fetch * f,int mimeOk)16067dd7cddfSDavid du Colombier sectText(Fetch *f, int mimeOk)
16077dd7cddfSDavid du Colombier {
16087dd7cddfSDavid du Colombier SList *h;
16097dd7cddfSDavid du Colombier char *s;
16107dd7cddfSDavid du Colombier
16117dd7cddfSDavid du Colombier s = atomString(fetchAtom, "");
16127dd7cddfSDavid du Colombier if(cistrcmp(s, "header") == 0){
16137dd7cddfSDavid du Colombier f->part = FPHead;
16147dd7cddfSDavid du Colombier return;
16157dd7cddfSDavid du Colombier }
16167dd7cddfSDavid du Colombier if(cistrcmp(s, "text") == 0){
16177dd7cddfSDavid du Colombier f->part = FPText;
16187dd7cddfSDavid du Colombier return;
16197dd7cddfSDavid du Colombier }
16207dd7cddfSDavid du Colombier if(mimeOk && cistrcmp(s, "mime") == 0){
16217dd7cddfSDavid du Colombier f->part = FPMime;
16227dd7cddfSDavid du Colombier return;
16237dd7cddfSDavid du Colombier }
16247dd7cddfSDavid du Colombier if(cistrcmp(s, "header.fields") == 0)
16257dd7cddfSDavid du Colombier f->part = FPHeadFields;
16267dd7cddfSDavid du Colombier else if(cistrcmp(s, "header.fields.not") == 0)
16277dd7cddfSDavid du Colombier f->part = FPHeadFieldsNot;
16287dd7cddfSDavid du Colombier else
16297dd7cddfSDavid du Colombier parseErr("illegal fetch section text");
16307dd7cddfSDavid du Colombier mustBe(' ');
16317dd7cddfSDavid du Colombier mustBe('(');
16327dd7cddfSDavid du Colombier h = nil;
16337dd7cddfSDavid du Colombier for(;;){
16347dd7cddfSDavid du Colombier h = mkSList(astring(), h);
16357dd7cddfSDavid du Colombier if(peekc() == ')')
16367dd7cddfSDavid du Colombier break;
16377dd7cddfSDavid du Colombier mustBe(' ');
16387dd7cddfSDavid du Colombier }
16397dd7cddfSDavid du Colombier mustBe(')');
16407dd7cddfSDavid du Colombier f->hdrs = revSList(h);
16417dd7cddfSDavid du Colombier }
16427dd7cddfSDavid du Colombier
16437dd7cddfSDavid du Colombier /*
16447dd7cddfSDavid du Colombier * searchWhat : "CHARSET" ' ' astring searchkeys | searchkeys
16457dd7cddfSDavid du Colombier * searchkeys : searchkey | searchkeys ' ' searchkey
16467dd7cddfSDavid du Colombier * searchkey : "ALL" | "ANSWERED" | "DELETED" | "FLAGGED" | "NEW" | "OLD" | "RECENT"
16477dd7cddfSDavid du Colombier * | "SEEN" | "UNANSWERED" | "UNDELETED" | "UNFLAGGED" | "DRAFT" | "UNDRAFT"
16487dd7cddfSDavid du Colombier * | astrkey ' ' astring
16497dd7cddfSDavid du Colombier * | datekey ' ' date
16507dd7cddfSDavid du Colombier * | "KEYWORD" ' ' flag | "UNKEYWORD" flag
16517dd7cddfSDavid du Colombier * | "LARGER" ' ' number | "SMALLER" ' ' number
16527dd7cddfSDavid du Colombier * | "HEADER" astring ' ' astring
16537dd7cddfSDavid du Colombier * | set | "UID" ' ' set
16547dd7cddfSDavid du Colombier * | "NOT" ' ' searchkey
16557dd7cddfSDavid du Colombier * | "OR" ' ' searchkey ' ' searchkey
16567dd7cddfSDavid du Colombier * | '(' searchkeys ')'
16577dd7cddfSDavid du Colombier * astrkey : "BCC" | "BODY" | "CC" | "FROM" | "SUBJECT" | "TEXT" | "TO"
16587dd7cddfSDavid du Colombier * datekey : "BEFORE" | "ON" | "SINCE" | "SENTBEFORE" | "SENTON" | "SENTSINCE"
16597dd7cddfSDavid du Colombier */
16607dd7cddfSDavid du Colombier static NamedInt searchMap[] =
16617dd7cddfSDavid du Colombier {
16627dd7cddfSDavid du Colombier {"ALL", SKAll},
16637dd7cddfSDavid du Colombier {"ANSWERED", SKAnswered},
16647dd7cddfSDavid du Colombier {"DELETED", SKDeleted},
16657dd7cddfSDavid du Colombier {"FLAGGED", SKFlagged},
16667dd7cddfSDavid du Colombier {"NEW", SKNew},
16677dd7cddfSDavid du Colombier {"OLD", SKOld},
16687dd7cddfSDavid du Colombier {"RECENT", SKRecent},
16697dd7cddfSDavid du Colombier {"SEEN", SKSeen},
16707dd7cddfSDavid du Colombier {"UNANSWERED", SKUnanswered},
16717dd7cddfSDavid du Colombier {"UNDELETED", SKUndeleted},
16727dd7cddfSDavid du Colombier {"UNFLAGGED", SKUnflagged},
16737dd7cddfSDavid du Colombier {"DRAFT", SKDraft},
16747dd7cddfSDavid du Colombier {"UNDRAFT", SKUndraft},
16757dd7cddfSDavid du Colombier {"UNSEEN", SKUnseen},
16767dd7cddfSDavid du Colombier {nil, 0}
16777dd7cddfSDavid du Colombier };
16787dd7cddfSDavid du Colombier
16797dd7cddfSDavid du Colombier static NamedInt searchMapStr[] =
16807dd7cddfSDavid du Colombier {
16817dd7cddfSDavid du Colombier {"CHARSET", SKCharset},
16827dd7cddfSDavid du Colombier {"BCC", SKBcc},
16837dd7cddfSDavid du Colombier {"BODY", SKBody},
16847dd7cddfSDavid du Colombier {"CC", SKCc},
16857dd7cddfSDavid du Colombier {"FROM", SKFrom},
16867dd7cddfSDavid du Colombier {"SUBJECT", SKSubject},
16877dd7cddfSDavid du Colombier {"TEXT", SKText},
16887dd7cddfSDavid du Colombier {"TO", SKTo},
16897dd7cddfSDavid du Colombier {nil, 0}
16907dd7cddfSDavid du Colombier };
16917dd7cddfSDavid du Colombier
16927dd7cddfSDavid du Colombier static NamedInt searchMapDate[] =
16937dd7cddfSDavid du Colombier {
16947dd7cddfSDavid du Colombier {"BEFORE", SKBefore},
16957dd7cddfSDavid du Colombier {"ON", SKOn},
16967dd7cddfSDavid du Colombier {"SINCE", SKSince},
16977dd7cddfSDavid du Colombier {"SENTBEFORE", SKSentBefore},
16987dd7cddfSDavid du Colombier {"SENTON", SKSentOn},
16997dd7cddfSDavid du Colombier {"SENTSINCE", SKSentSince},
17007dd7cddfSDavid du Colombier {nil, 0}
17017dd7cddfSDavid du Colombier };
17027dd7cddfSDavid du Colombier
17037dd7cddfSDavid du Colombier static NamedInt searchMapFlag[] =
17047dd7cddfSDavid du Colombier {
17057dd7cddfSDavid du Colombier {"KEYWORD", SKKeyword},
17067dd7cddfSDavid du Colombier {"UNKEYWORD", SKUnkeyword},
17077dd7cddfSDavid du Colombier {nil, 0}
17087dd7cddfSDavid du Colombier };
17097dd7cddfSDavid du Colombier
17107dd7cddfSDavid du Colombier static NamedInt searchMapNum[] =
17117dd7cddfSDavid du Colombier {
17127dd7cddfSDavid du Colombier {"SMALLER", SKSmaller},
17137dd7cddfSDavid du Colombier {"LARGER", SKLarger},
17147dd7cddfSDavid du Colombier {nil, 0}
17157dd7cddfSDavid du Colombier };
17167dd7cddfSDavid du Colombier
17177dd7cddfSDavid du Colombier static Search*
searchKeys(int first,Search * tail)17187dd7cddfSDavid du Colombier searchKeys(int first, Search *tail)
17197dd7cddfSDavid du Colombier {
17207dd7cddfSDavid du Colombier Search *s;
17217dd7cddfSDavid du Colombier
17227dd7cddfSDavid du Colombier for(;;){
17237dd7cddfSDavid du Colombier if(peekc() == '('){
17247dd7cddfSDavid du Colombier getc();
17257dd7cddfSDavid du Colombier tail = searchKeys(0, tail);
17267dd7cddfSDavid du Colombier mustBe(')');
17277dd7cddfSDavid du Colombier }else{
17287dd7cddfSDavid du Colombier s = searchKey(first);
17297dd7cddfSDavid du Colombier tail->next = s;
17307dd7cddfSDavid du Colombier tail = s;
17317dd7cddfSDavid du Colombier }
17327dd7cddfSDavid du Colombier first = 0;
17337dd7cddfSDavid du Colombier if(peekc() != ' ')
17347dd7cddfSDavid du Colombier break;
17357dd7cddfSDavid du Colombier getc();
17367dd7cddfSDavid du Colombier }
17377dd7cddfSDavid du Colombier return tail;
17387dd7cddfSDavid du Colombier }
17397dd7cddfSDavid du Colombier
17407dd7cddfSDavid du Colombier static Search*
searchKey(int first)17417dd7cddfSDavid du Colombier searchKey(int first)
17427dd7cddfSDavid du Colombier {
17437dd7cddfSDavid du Colombier Search *sr, rock;
17447dd7cddfSDavid du Colombier Tm tm;
17457dd7cddfSDavid du Colombier char *a;
17467dd7cddfSDavid du Colombier int i, c;
17477dd7cddfSDavid du Colombier
174880ee5cbfSDavid du Colombier sr = binalloc(&parseBin, sizeof(Search), 1);
17497dd7cddfSDavid du Colombier if(sr == nil)
17507dd7cddfSDavid du Colombier parseErr("out of memory");
17517dd7cddfSDavid du Colombier
17527dd7cddfSDavid du Colombier c = peekc();
17537dd7cddfSDavid du Colombier if(c >= '0' && c <= '9'){
17547dd7cddfSDavid du Colombier sr->key = SKSet;
1755becaf2abSDavid du Colombier sr->set = msgSet(0);
17567dd7cddfSDavid du Colombier return sr;
17577dd7cddfSDavid du Colombier }
17587dd7cddfSDavid du Colombier
17597dd7cddfSDavid du Colombier a = atom();
17607dd7cddfSDavid du Colombier if(i = mapInt(searchMap, a))
17617dd7cddfSDavid du Colombier sr->key = i;
17627dd7cddfSDavid du Colombier else if(i = mapInt(searchMapStr, a)){
17637dd7cddfSDavid du Colombier if(!first && i == SKCharset)
17647dd7cddfSDavid du Colombier parseErr("illegal search key");
17657dd7cddfSDavid du Colombier sr->key = i;
17667dd7cddfSDavid du Colombier mustBe(' ');
17677dd7cddfSDavid du Colombier sr->s = astring();
17687dd7cddfSDavid du Colombier }else if(i = mapInt(searchMapDate, a)){
17697dd7cddfSDavid du Colombier sr->key = i;
17707dd7cddfSDavid du Colombier mustBe(' ');
17717dd7cddfSDavid du Colombier c = peekc();
17727dd7cddfSDavid du Colombier if(c == '"')
17737dd7cddfSDavid du Colombier getc();
17747dd7cddfSDavid du Colombier a = atom();
17757dd7cddfSDavid du Colombier if(!imap4Date(&tm, a))
17767dd7cddfSDavid du Colombier parseErr("bad date format");
17777dd7cddfSDavid du Colombier sr->year = tm.year;
17787dd7cddfSDavid du Colombier sr->mon = tm.mon;
17797dd7cddfSDavid du Colombier sr->mday = tm.mday;
17807dd7cddfSDavid du Colombier if(c == '"')
17817dd7cddfSDavid du Colombier mustBe('"');
17827dd7cddfSDavid du Colombier }else if(i = mapInt(searchMapFlag, a)){
17837dd7cddfSDavid du Colombier sr->key = i;
17847dd7cddfSDavid du Colombier mustBe(' ');
17857dd7cddfSDavid du Colombier c = peekc();
17867dd7cddfSDavid du Colombier if(c == '\\'){
17877dd7cddfSDavid du Colombier mustBe('\\');
17887dd7cddfSDavid du Colombier a = atomString(atomStop, "\\");
17897dd7cddfSDavid du Colombier }else
17907dd7cddfSDavid du Colombier a = atom();
17917dd7cddfSDavid du Colombier i = mapFlag(a);
17927dd7cddfSDavid du Colombier if(i == 0)
17937dd7cddfSDavid du Colombier parseErr("flag not supported");
17947dd7cddfSDavid du Colombier sr->num = i;
17957dd7cddfSDavid du Colombier }else if(i = mapInt(searchMapNum, a)){
17967dd7cddfSDavid du Colombier sr->key = i;
17977dd7cddfSDavid du Colombier mustBe(' ');
17987dd7cddfSDavid du Colombier sr->num = number(0);
17997dd7cddfSDavid du Colombier }else if(cistrcmp(a, "HEADER") == 0){
18007dd7cddfSDavid du Colombier sr->key = SKHeader;
18017dd7cddfSDavid du Colombier mustBe(' ');
18027dd7cddfSDavid du Colombier sr->hdr = astring();
18037dd7cddfSDavid du Colombier mustBe(' ');
18047dd7cddfSDavid du Colombier sr->s = astring();
18057dd7cddfSDavid du Colombier }else if(cistrcmp(a, "UID") == 0){
18067dd7cddfSDavid du Colombier sr->key = SKUid;
18077dd7cddfSDavid du Colombier mustBe(' ');
1808becaf2abSDavid du Colombier sr->set = msgSet(0);
18097dd7cddfSDavid du Colombier }else if(cistrcmp(a, "NOT") == 0){
18107dd7cddfSDavid du Colombier sr->key = SKNot;
18117dd7cddfSDavid du Colombier mustBe(' ');
18127dd7cddfSDavid du Colombier rock.next = nil;
18137dd7cddfSDavid du Colombier searchKeys(0, &rock);
18147dd7cddfSDavid du Colombier sr->left = rock.next;
18157dd7cddfSDavid du Colombier }else if(cistrcmp(a, "OR") == 0){
18167dd7cddfSDavid du Colombier sr->key = SKOr;
18177dd7cddfSDavid du Colombier mustBe(' ');
18187dd7cddfSDavid du Colombier rock.next = nil;
18197dd7cddfSDavid du Colombier searchKeys(0, &rock);
18207dd7cddfSDavid du Colombier sr->left = rock.next;
18217dd7cddfSDavid du Colombier mustBe(' ');
18227dd7cddfSDavid du Colombier rock.next = nil;
18237dd7cddfSDavid du Colombier searchKeys(0, &rock);
18247dd7cddfSDavid du Colombier sr->right = rock.next;
18257dd7cddfSDavid du Colombier }else
18267dd7cddfSDavid du Colombier parseErr("illegal search key");
18277dd7cddfSDavid du Colombier return sr;
18287dd7cddfSDavid du Colombier }
18297dd7cddfSDavid du Colombier
18307dd7cddfSDavid du Colombier /*
18317dd7cddfSDavid du Colombier * set : seqno
18327dd7cddfSDavid du Colombier * | seqno ':' seqno
18337dd7cddfSDavid du Colombier * | set ',' set
18347dd7cddfSDavid du Colombier * seqno: nz-number
18357dd7cddfSDavid du Colombier * | '*'
18367dd7cddfSDavid du Colombier *
18377dd7cddfSDavid du Colombier */
18387dd7cddfSDavid du Colombier static MsgSet*
msgSet(int uids)1839becaf2abSDavid du Colombier msgSet(int uids)
18407dd7cddfSDavid du Colombier {
18417dd7cddfSDavid du Colombier MsgSet head, *last, *ms;
18427dd7cddfSDavid du Colombier ulong from, to;
18437dd7cddfSDavid du Colombier
18447dd7cddfSDavid du Colombier last = &head;
18457dd7cddfSDavid du Colombier head.next = nil;
18467dd7cddfSDavid du Colombier for(;;){
1847becaf2abSDavid du Colombier from = uids ? uidNo() : seqNo();
18487dd7cddfSDavid du Colombier to = from;
18497dd7cddfSDavid du Colombier if(peekc() == ':'){
18507dd7cddfSDavid du Colombier getc();
1851becaf2abSDavid du Colombier to = uids ? uidNo() : seqNo();
18527dd7cddfSDavid du Colombier }
185380ee5cbfSDavid du Colombier ms = binalloc(&parseBin, sizeof(MsgSet), 0);
18547dd7cddfSDavid du Colombier if(ms == nil)
18557dd7cddfSDavid du Colombier parseErr("out of memory");
18567dd7cddfSDavid du Colombier ms->from = from;
18577dd7cddfSDavid du Colombier ms->to = to;
18587dd7cddfSDavid du Colombier ms->next = nil;
18597dd7cddfSDavid du Colombier last->next = ms;
18607dd7cddfSDavid du Colombier last = ms;
18617dd7cddfSDavid du Colombier if(peekc() != ',')
18627dd7cddfSDavid du Colombier break;
18637dd7cddfSDavid du Colombier getc();
18647dd7cddfSDavid du Colombier }
18657dd7cddfSDavid du Colombier return head.next;
18667dd7cddfSDavid du Colombier }
18677dd7cddfSDavid du Colombier
18687dd7cddfSDavid du Colombier static ulong
seqNo(void)18697dd7cddfSDavid du Colombier seqNo(void)
18707dd7cddfSDavid du Colombier {
18717dd7cddfSDavid du Colombier if(peekc() == '*'){
18727dd7cddfSDavid du Colombier getc();
18737dd7cddfSDavid du Colombier return ~0UL;
18747dd7cddfSDavid du Colombier }
18757dd7cddfSDavid du Colombier return number(1);
18767dd7cddfSDavid du Colombier }
18777dd7cddfSDavid du Colombier
1878becaf2abSDavid du Colombier static ulong
uidNo(void)1879becaf2abSDavid du Colombier uidNo(void)
1880becaf2abSDavid du Colombier {
1881becaf2abSDavid du Colombier if(peekc() == '*'){
1882becaf2abSDavid du Colombier getc();
1883becaf2abSDavid du Colombier return ~0UL;
1884becaf2abSDavid du Colombier }
1885becaf2abSDavid du Colombier return number(0);
1886becaf2abSDavid du Colombier }
1887becaf2abSDavid du Colombier
18887dd7cddfSDavid du Colombier /*
18897dd7cddfSDavid du Colombier * 7 bit, non-ctl chars, no (){%*"\
18907dd7cddfSDavid du Colombier * NIL is special case for nstring or parenlist
18917dd7cddfSDavid du Colombier */
18927dd7cddfSDavid du Colombier static char *
atom(void)18937dd7cddfSDavid du Colombier atom(void)
18947dd7cddfSDavid du Colombier {
18957dd7cddfSDavid du Colombier return atomString(atomStop, "");
18967dd7cddfSDavid du Colombier }
18977dd7cddfSDavid du Colombier
18987dd7cddfSDavid du Colombier /*
18997dd7cddfSDavid du Colombier * like an atom, but no +
19007dd7cddfSDavid du Colombier */
19017dd7cddfSDavid du Colombier static char *
tag(void)19027dd7cddfSDavid du Colombier tag(void)
19037dd7cddfSDavid du Colombier {
19047dd7cddfSDavid du Colombier return atomString("+(){%*\"\\", "");
19057dd7cddfSDavid du Colombier }
19067dd7cddfSDavid du Colombier
19077dd7cddfSDavid du Colombier /*
19087dd7cddfSDavid du Colombier * string or atom allowing %*
19097dd7cddfSDavid du Colombier */
19107dd7cddfSDavid du Colombier static char *
listmbox(void)19117dd7cddfSDavid du Colombier listmbox(void)
19127dd7cddfSDavid du Colombier {
19137dd7cddfSDavid du Colombier int c;
19147dd7cddfSDavid du Colombier
19157dd7cddfSDavid du Colombier c = peekc();
19167dd7cddfSDavid du Colombier if(c == '{')
19177dd7cddfSDavid du Colombier return literal();
19187dd7cddfSDavid du Colombier if(c == '"')
19197dd7cddfSDavid du Colombier return quoted();
19207dd7cddfSDavid du Colombier return atomString("(){\"\\", "");
19217dd7cddfSDavid du Colombier }
19227dd7cddfSDavid du Colombier
19237dd7cddfSDavid du Colombier /*
19247dd7cddfSDavid du Colombier * string or atom
19257dd7cddfSDavid du Colombier */
19267dd7cddfSDavid du Colombier static char *
astring(void)19277dd7cddfSDavid du Colombier astring(void)
19287dd7cddfSDavid du Colombier {
19297dd7cddfSDavid du Colombier int c;
19307dd7cddfSDavid du Colombier
19317dd7cddfSDavid du Colombier c = peekc();
19327dd7cddfSDavid du Colombier if(c == '{')
19337dd7cddfSDavid du Colombier return literal();
19347dd7cddfSDavid du Colombier if(c == '"')
19357dd7cddfSDavid du Colombier return quoted();
19367dd7cddfSDavid du Colombier return atom();
19377dd7cddfSDavid du Colombier }
19387dd7cddfSDavid du Colombier
19397dd7cddfSDavid du Colombier /*
19407dd7cddfSDavid du Colombier * 7 bit, non-ctl chars, none from exception list
19417dd7cddfSDavid du Colombier */
19427dd7cddfSDavid du Colombier static char *
atomString(char * disallowed,char * initial)19437dd7cddfSDavid du Colombier atomString(char *disallowed, char *initial)
19447dd7cddfSDavid du Colombier {
19457dd7cddfSDavid du Colombier char *s;
19467dd7cddfSDavid du Colombier int c, ns, as;
19477dd7cddfSDavid du Colombier
19487dd7cddfSDavid du Colombier ns = strlen(initial);
194980ee5cbfSDavid du Colombier s = binalloc(&parseBin, ns + StrAlloc, 0);
19507dd7cddfSDavid du Colombier if(s == nil)
19517dd7cddfSDavid du Colombier parseErr("out of memory");
19527dd7cddfSDavid du Colombier strcpy(s, initial);
19537dd7cddfSDavid du Colombier as = ns + StrAlloc;
19547dd7cddfSDavid du Colombier for(;;){
19557dd7cddfSDavid du Colombier c = getc();
19567dd7cddfSDavid du Colombier if(c <= ' ' || c >= 0x7f || strchr(disallowed, c) != nil){
19577dd7cddfSDavid du Colombier ungetc();
19587dd7cddfSDavid du Colombier break;
19597dd7cddfSDavid du Colombier }
19607dd7cddfSDavid du Colombier s[ns++] = c;
19617dd7cddfSDavid du Colombier if(ns >= as){
196280ee5cbfSDavid du Colombier s = bingrow(&parseBin, s, as, as + StrAlloc, 0);
19637dd7cddfSDavid du Colombier if(s == nil)
19647dd7cddfSDavid du Colombier parseErr("out of memory");
19657dd7cddfSDavid du Colombier as += StrAlloc;
19667dd7cddfSDavid du Colombier }
19677dd7cddfSDavid du Colombier }
19687dd7cddfSDavid du Colombier if(ns == 0)
19697dd7cddfSDavid du Colombier badsyn();
19707dd7cddfSDavid du Colombier s[ns] = '\0';
19717dd7cddfSDavid du Colombier return s;
19727dd7cddfSDavid du Colombier }
19737dd7cddfSDavid du Colombier
19747dd7cddfSDavid du Colombier /*
19757dd7cddfSDavid du Colombier * quoted: '"' chars* '"'
19767dd7cddfSDavid du Colombier * chars: 1-128 except \r and \n
19777dd7cddfSDavid du Colombier */
19787dd7cddfSDavid du Colombier static char *
quoted(void)19797dd7cddfSDavid du Colombier quoted(void)
19807dd7cddfSDavid du Colombier {
19817dd7cddfSDavid du Colombier char *s;
19827dd7cddfSDavid du Colombier int c, ns, as;
19837dd7cddfSDavid du Colombier
19847dd7cddfSDavid du Colombier mustBe('"');
198580ee5cbfSDavid du Colombier s = binalloc(&parseBin, StrAlloc, 0);
19867dd7cddfSDavid du Colombier if(s == nil)
19877dd7cddfSDavid du Colombier parseErr("out of memory");
19887dd7cddfSDavid du Colombier as = StrAlloc;
19897dd7cddfSDavid du Colombier ns = 0;
19907dd7cddfSDavid du Colombier for(;;){
19917dd7cddfSDavid du Colombier c = getc();
19927dd7cddfSDavid du Colombier if(c == '"')
19937dd7cddfSDavid du Colombier break;
19947dd7cddfSDavid du Colombier if(c < 1 || c > 0x7f || c == '\r' || c == '\n')
19957dd7cddfSDavid du Colombier badsyn();
19967dd7cddfSDavid du Colombier if(c == '\\'){
19977dd7cddfSDavid du Colombier c = getc();
19987dd7cddfSDavid du Colombier if(c != '\\' && c != '"')
19997dd7cddfSDavid du Colombier badsyn();
20007dd7cddfSDavid du Colombier }
20017dd7cddfSDavid du Colombier s[ns++] = c;
20027dd7cddfSDavid du Colombier if(ns >= as){
200380ee5cbfSDavid du Colombier s = bingrow(&parseBin, s, as, as + StrAlloc, 0);
20047dd7cddfSDavid du Colombier if(s == nil)
20057dd7cddfSDavid du Colombier parseErr("out of memory");
20067dd7cddfSDavid du Colombier as += StrAlloc;
20077dd7cddfSDavid du Colombier }
20087dd7cddfSDavid du Colombier }
20097dd7cddfSDavid du Colombier s[ns] = '\0';
20107dd7cddfSDavid du Colombier return s;
20117dd7cddfSDavid du Colombier }
20127dd7cddfSDavid du Colombier
20137dd7cddfSDavid du Colombier /*
20147dd7cddfSDavid du Colombier * litlen: {number}\r\n
20157dd7cddfSDavid du Colombier */
20167dd7cddfSDavid du Colombier static ulong
litlen(void)20177dd7cddfSDavid du Colombier litlen(void)
20187dd7cddfSDavid du Colombier {
20197dd7cddfSDavid du Colombier ulong v;
20207dd7cddfSDavid du Colombier
20217dd7cddfSDavid du Colombier mustBe('{');
20227dd7cddfSDavid du Colombier v = number(0);
20237dd7cddfSDavid du Colombier mustBe('}');
20247dd7cddfSDavid du Colombier crnl();
20257dd7cddfSDavid du Colombier return v;
20267dd7cddfSDavid du Colombier }
20277dd7cddfSDavid du Colombier
20287dd7cddfSDavid du Colombier /*
20297dd7cddfSDavid du Colombier * literal: litlen data<0:litlen>
20307dd7cddfSDavid du Colombier */
20317dd7cddfSDavid du Colombier static char *
literal(void)20327dd7cddfSDavid du Colombier literal(void)
20337dd7cddfSDavid du Colombier {
20347dd7cddfSDavid du Colombier char *s;
20357dd7cddfSDavid du Colombier ulong v;
20367dd7cddfSDavid du Colombier
20377dd7cddfSDavid du Colombier v = litlen();
203880ee5cbfSDavid du Colombier s = binalloc(&parseBin, v+1, 0);
20397dd7cddfSDavid du Colombier if(s == nil)
20407dd7cddfSDavid du Colombier parseErr("out of memory");
20417dd7cddfSDavid du Colombier Bprint(&bout, "+ Ready for literal data\r\n");
20427dd7cddfSDavid du Colombier if(Bflush(&bout) < 0)
20437dd7cddfSDavid du Colombier writeErr();
20447dd7cddfSDavid du Colombier if(v != 0 && Bread(&bin, s, v) != v)
20457dd7cddfSDavid du Colombier badsyn();
20467dd7cddfSDavid du Colombier s[v] = '\0';
20477dd7cddfSDavid du Colombier return s;
20487dd7cddfSDavid du Colombier }
20497dd7cddfSDavid du Colombier
20507dd7cddfSDavid du Colombier /*
20517dd7cddfSDavid du Colombier * digits; number is 32 bits
20527dd7cddfSDavid du Colombier */
20537dd7cddfSDavid du Colombier static ulong
number(int nonzero)20547dd7cddfSDavid du Colombier number(int nonzero)
20557dd7cddfSDavid du Colombier {
20567dd7cddfSDavid du Colombier ulong v;
20577dd7cddfSDavid du Colombier int c, first;
20587dd7cddfSDavid du Colombier
20597dd7cddfSDavid du Colombier v = 0;
20607dd7cddfSDavid du Colombier first = 1;
20617dd7cddfSDavid du Colombier for(;;){
20627dd7cddfSDavid du Colombier c = getc();
20637dd7cddfSDavid du Colombier if(c < '0' || c > '9'){
20647dd7cddfSDavid du Colombier ungetc();
20657dd7cddfSDavid du Colombier if(first)
20667dd7cddfSDavid du Colombier badsyn();
20677dd7cddfSDavid du Colombier break;
20687dd7cddfSDavid du Colombier }
20697dd7cddfSDavid du Colombier if(nonzero && first && c == '0')
20707dd7cddfSDavid du Colombier badsyn();
20717dd7cddfSDavid du Colombier c -= '0';
20727dd7cddfSDavid du Colombier first = 0;
207359cc4ca5SDavid du Colombier if(v > UlongMax/10 || v == UlongMax/10 && c > UlongMax%10)
20747dd7cddfSDavid du Colombier parseErr("number out of range\r\n");
20757dd7cddfSDavid du Colombier v = v * 10 + c;
20767dd7cddfSDavid du Colombier }
20777dd7cddfSDavid du Colombier return v;
20787dd7cddfSDavid du Colombier }
20797dd7cddfSDavid du Colombier
20807dd7cddfSDavid du Colombier static int
getc(void)20817dd7cddfSDavid du Colombier getc(void)
20827dd7cddfSDavid du Colombier {
20837dd7cddfSDavid du Colombier return Bgetc(&bin);
20847dd7cddfSDavid du Colombier }
20857dd7cddfSDavid du Colombier
20867dd7cddfSDavid du Colombier static void
ungetc(void)20877dd7cddfSDavid du Colombier ungetc(void)
20887dd7cddfSDavid du Colombier {
20897dd7cddfSDavid du Colombier Bungetc(&bin);
20907dd7cddfSDavid du Colombier }
20917dd7cddfSDavid du Colombier
20927dd7cddfSDavid du Colombier static int
peekc(void)20937dd7cddfSDavid du Colombier peekc(void)
20947dd7cddfSDavid du Colombier {
20957dd7cddfSDavid du Colombier int c;
20967dd7cddfSDavid du Colombier
20977dd7cddfSDavid du Colombier c = Bgetc(&bin);
20987dd7cddfSDavid du Colombier Bungetc(&bin);
20997dd7cddfSDavid du Colombier return c;
21007dd7cddfSDavid du Colombier }
2101d9306527SDavid du Colombier
2102