/* Returns TRUE if we are done */ int parser(struct protstream *sieved_out, struct protstream *sieved_in) { int token = EOL; const char *error_msg = "Generic Error"; struct buf mechanism_name = BUF_INITIALIZER; struct buf initial_challenge = BUF_INITIALIZER; struct buf sieve_name = BUF_INITIALIZER; struct buf sieve_data = BUF_INITIALIZER; unsigned long num; int ret = FALSE; /* get one token from the lexer */ while(token == EOL) token = timlex(NULL, NULL, sieved_in); if (!authenticated && (token > 255) && (token!=AUTHENTICATE) && (token!=LOGOUT) && (token!=CAPABILITY) && (token!=NOOP) && (token!=CHECKSCRIPT) && (!tls_enabled() || (token!=STARTTLS))) { error_msg = "Authenticate first"; if (token!=EOL) lex_setrecovering(); goto error; } if (verify_only && (token > 255) && (token!=CHECKSCRIPT) && (token!=PUTSCRIPT) && (token!=LOGOUT)) { error_msg = "Script verification only"; if (token!=EOL) lex_setrecovering(); goto error; } switch (token) { case EOF: /* timlex() will return EOF when the remote disconnects badly */ syslog(LOG_WARNING, "Lost connection to client -- exiting"); prot_printf(sieved_out, "BYE \"Shutdown TCP timeout\"\r\n"); ret = TRUE; goto done; break; case AUTHENTICATE: if (sieved_tls_required) { error_msg = "AUTHENTICATE only available under a layer"; goto error; } if (timlex(NULL, NULL, sieved_in)!=SPACE) { error_msg = "SPACE must occur after AUTHENTICATE"; goto error; } if (timlex(&mechanism_name, NULL, sieved_in)!=STRING) { error_msg = "Did not specify mechanism name"; goto error; } token = timlex(NULL, NULL, sieved_in); if (token != EOL) { /* optional client first challenge */ if (token!=SPACE) { error_msg = "Expected SPACE"; goto error; } if (timlex(&initial_challenge, NULL, sieved_in)!=STRING) { error_msg = "Expected string"; goto error; } token = timlex(NULL, NULL, sieved_in); } if (token != EOL) { error_msg = "Expected EOL"; goto error; } if (authenticated) prot_printf(sieved_out, "NO \"Already authenticated\"\r\n"); else if (cmd_authenticate(sieved_out, sieved_in, mechanism_name.s, &initial_challenge, &error_msg)==FALSE) { error_msg = "Authentication Error"; goto error; } #if 0 /* XXX - not implemented in sieveshell*/ /* referral_host is non-null only once we are authenticated */ if(referral_host) goto do_referral; #endif break; case CAPABILITY: if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } if(referral_host) goto do_referral; capabilities(sieved_out, sieved_saslconn, starttls_done, authenticated, sasl_ssf); break; case CHECKSCRIPT: if (timlex(NULL, NULL, sieved_in)!=SPACE) { error_msg = "SPACE must occur after CHECKSCRIPT"; goto error; } if (timlex(&sieve_data, NULL, sieved_in)!=STRING) { error_msg = "Expected script content as second parameter"; goto error; } if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } /* f stands for "f"aked name, it could be any valid script name */ buf_reset(&sieve_name); buf_appendcstr(&sieve_name, "f"); putscript(sieved_out, &sieve_name, &sieve_data, /* verify_only */ 1); break; case HAVESPACE: if (timlex(NULL, NULL, sieved_in)!=SPACE) { error_msg = "SPACE must occur after HAVESPACE"; goto error; } if (timlex(&sieve_name, NULL, sieved_in)!=STRING) { error_msg = "Did not specify script name"; goto error; } if (timlex(NULL, NULL, sieved_in)!=SPACE) { error_msg = "Expected SPACE after SCRIPTNAME"; goto error; } if (timlex(NULL, &num, sieved_in)!=NUMBER) { error_msg = "Expected Number"; goto error; } if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } if(referral_host) goto do_referral; cmd_havespace(sieved_out, &sieve_name, num); break; case LOGOUT: token = timlex(NULL, NULL, sieved_in); /* timlex() will return LOGOUT when the remote disconnects badly */ if (token!=EOL && token!=EOF && token!=LOGOUT) { error_msg = "Garbage after logout command"; goto error; } /* no referral for logout */ cmd_logout(sieved_out, sieved_in); ret = TRUE; goto done; break; case GETSCRIPT: if (timlex(NULL, NULL, sieved_in)!=SPACE) { error_msg = "SPACE must occur after GETSCRIPT"; goto error; } if (timlex(&sieve_name, NULL, sieved_in)!=STRING) { error_msg = "Did not specify script name"; goto error; } if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } if(referral_host) goto do_referral; getscript(sieved_out, &sieve_name); break; case PUTSCRIPT: if (timlex(NULL, NULL, sieved_in)!=SPACE) { error_msg = "SPACE must occur after PUTSCRIPT"; goto error; } if (timlex(&sieve_name, NULL, sieved_in)!=STRING) { error_msg = "Did not specify script name"; goto error; } if (timlex(NULL, NULL, sieved_in)!=SPACE) { error_msg = "Expected SPACE"; goto error; } if (timlex(&sieve_data, NULL, sieved_in)!=STRING) { error_msg = "Did not specify legal script data length"; goto error; } if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } if(referral_host) goto do_referral; putscript(sieved_out, &sieve_name, &sieve_data, verify_only); break; case SETACTIVE: if (timlex(NULL, NULL, sieved_in)!=SPACE) { error_msg = "SPACE must occur after SETACTIVE"; goto error; } if (timlex(&sieve_name, NULL, sieved_in)!=STRING) { error_msg = "Did not specify script name"; goto error; } if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } if(referral_host) goto do_referral; setactive(sieved_out, &sieve_name); break; case DELETESCRIPT: if (timlex(NULL, NULL, sieved_in)!=SPACE) { error_msg = "SPACE must occur after DELETESCRIPT"; goto error; } if (timlex(&sieve_name, NULL, sieved_in)!=STRING) { error_msg = "Did not specify script name"; goto error; } if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } if(referral_host) goto do_referral; deletescript(sieved_out, &sieve_name); break; case LISTSCRIPTS: if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } if(referral_host) goto do_referral; listscripts(sieved_out); break; case STARTTLS: if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } /* XXX discard any input pipelined after STARTTLS */ prot_flush(sieved_in); if(referral_host) goto do_referral; cmd_starttls(sieved_out, sieved_in); break; case NOOP: token = timlex(NULL, NULL, sieved_in); if (token != EOL) { /* optional string parameter */ if (token!=SPACE) { error_msg = "Expected SPACE"; goto error; } if (timlex(&sieve_name, NULL, sieved_in)!=STRING) { error_msg = "Expected string"; goto error; } token = timlex(NULL, NULL, sieved_in); } if (token != EOL) { error_msg = "Expected EOL"; goto error; } if (sieve_name.len) { prot_printf(sieved_out, "OK (TAG "); prot_printliteral(sieved_out, sieve_name.s, sieve_name.len); prot_printf(sieved_out, ") \"Done\"\r\n"); } else prot_printf(sieved_out, "OK \"Done\"\r\n"); break; case UNAUTHENTICATE: if (timlex(NULL, NULL, sieved_in)!=EOL) { error_msg = "Expected EOL"; goto error; } cmd_unauthenticate(sieved_out, sieved_in); break; default: error_msg="Expected a command. Got something else."; goto error; break; } done: /* free memory */ buf_free(&mechanism_name); buf_free(&initial_challenge); buf_free(&sieve_name); buf_free(&sieve_data); prot_flush(sieved_out); return ret; error: /* free memory */ buf_free(&mechanism_name); buf_free(&initial_challenge); buf_free(&sieve_name); buf_free(&sieve_data); prot_printf(sieved_out, "NO \"%s\"\r\n",error_msg); prot_flush(sieved_out); return FALSE; do_referral: { char buf[4096]; char *c; /* Truncate the hostname if necessary */ strlcpy(buf, referral_host, sizeof(buf)); c = strchr(buf, '!'); if(c) *c = '\0'; prot_printf(sieved_out, "BYE (REFERRAL \"sieve://%s\") \"Try Remote.\"\r\n", buf); ret = TRUE; goto done; } }
int main(int argc, char *argv[]) { const char *errstr; struct sigaction sact; int ch, EFlag = 0; while ((ch = getopt(argc, argv, "dEf:i:")) != -1) switch (ch) { case 'd': debug = 1; break; case 'E': EFlag = 1; break; case 'f': script = optarg; break; case 'i': interval = strtonum(optarg, 1, 60, &errstr); if (errstr) errx(1, "interval is %s: %s", errstr, optarg); break; default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; if (argc > 0 || (EFlag && optind > 2)) usage(); if ((dpy = XOpenDisplay(NULL)) == NULL) errx(1, "can't open display"); if (!XRRQueryExtension(dpy, &rr_event_base, &rr_event_error)) errx(1, "randr extension not available"); current_edidhash = getedidhash(); if (EFlag) { if (current_edidhash == NULL) return (1); printf("%s\n", current_edidhash); return (0); } if (script == NULL) script = getscript(); memset(&sact, 0, sizeof(sact)); sigemptyset(&sact.sa_mask); sact.sa_flags = 0; sact.sa_handler = sigquit; sigaction(SIGINT, &sact, NULL); sigaction(SIGQUIT, &sact, NULL); sigaction(SIGTERM, &sact, NULL); sact.sa_handler = SIG_IGN; sigaction(SIGHUP, &sact, NULL); sact.sa_handler = sigchild; sact.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &sact, NULL); openlog(_LOG_TAG, _LOG_OPT, _LOG_FACILITY); if (!debug && daemon(0, 0) == -1) err(1, "daemon"); syslog(LOG_INFO, "started"); randrd(); syslog(LOG_INFO, "terminated"); XCloseDisplay(dpy); closelog(); return (0); }