/* 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; } }
EXPORTED void dlist_print(const struct dlist *dl, int printkeys, struct protstream *out) { struct dlist *di; if (printkeys) { prot_printastring(out, dl->name); prot_putc(' ', out); } switch (dl->type) { case DL_NIL: prot_printf(out, "NIL"); break; case DL_ATOM: prot_printastring(out, dl->sval); break; case DL_FLAG: prot_printf(out, "%s", dl->sval); break; case DL_NUM: case DL_DATE: /* for now, we will format it later */ prot_printf(out, "%llu", dl->nval); break; case DL_FILE: printfile(out, dl); break; case DL_BUF: if (strlen(dl->sval) == dl->nval) prot_printastring(out, dl->sval); else prot_printliteral(out, dl->sval, dl->nval); break; case DL_GUID: prot_printf(out, "%s", message_guid_encode(dl->gval)); break; case DL_HEX: { char buf[17]; snprintf(buf, 17, "%016llx", dl->nval); prot_printf(out, "%s", buf); } break; case DL_KVLIST: prot_printf(out, "%%("); for (di = dl->head; di; di = di->next) { dlist_print(di, 1, out); if (di->next) { prot_printf(out, " "); } } prot_printf(out, ")"); break; case DL_ATOMLIST: prot_printf(out, "("); for (di = dl->head; di; di = di->next) { dlist_print(di, dl->nval, out); if (di->next) prot_printf(out, " "); } prot_printf(out, ")"); break; } }