/* 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"; mystring_t *mechanism_name = NULL; mystring_t *initial_challenge = NULL; mystring_t *sieve_name = NULL; mystring_t *sieve_data = NULL; 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"); ret = TRUE; goto done; break; case AUTHENTICATE: 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, 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 = "Did not specify legal script data length"; 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 */ string_allocate(1, "f", &sieve_name); 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"; 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); mystring_t *noop_param = NULL; if (token != EOL) { /* optional string parameter */ if (token!=SPACE) { error_msg = "Expected SPACE"; goto error; } if (timlex(&noop_param, NULL, sieved_in)!=STRING) { error_msg = "Expected string"; free(noop_param); goto error; } token = timlex(NULL, NULL, sieved_in); } if (token != EOL) { error_msg = "Expected EOL"; free(noop_param); goto error; } if (noop_param != NULL) { int temp; char* dataptr = string_DATAPTR(noop_param); prot_printf(sieved_out, "OK (TAG {%d}\r\n", noop_param->len); for (temp = 0; temp < noop_param->len; temp++) prot_putc(dataptr[temp], sieved_out); prot_printf(sieved_out, ") \"Done\"\r\n"); free(noop_param); } 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 */ free(mechanism_name); free(initial_challenge); free(sieve_name); free(sieve_data); prot_flush(sieved_out); return ret; error: /* free memory */ free(mechanism_name); free(initial_challenge); free(sieve_name); 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; } }
static int fetch(char *msgid, int bymsgid, struct protstream *pin, struct protstream *pout, struct protstream *sin, struct protstream *sout, int *rejected, int *accepted, int *failed) { char buf[4096]; /* see if we want this article */ prot_printf(sout, "IHAVE %s\r\n", msgid); if (!prot_fgets(buf, sizeof(buf), sin)) { syslog(LOG_ERR, "IHAVE terminated abnormally"); return -1; } else if (strncmp("335", buf, 3)) { /* don't want it */ (*rejected)++; return 0; } /* fetch the article */ if (bymsgid) prot_printf(pout, "ARTICLE %s\r\n", msgid); else prot_printf(pout, "ARTICLE\r\n"); if (!prot_fgets(buf, sizeof(buf), pin)) { syslog(LOG_ERR, "ARTICLE terminated abnormally"); return -1; } else if (strncmp("220", buf, 3)) { /* doh! the article doesn't exist, terminate IHAVE */ prot_printf(sout, ".\r\n"); } else { /* store the article */ while (prot_fgets(buf, sizeof(buf), pin)) { if (buf[0] == '.') { if (buf[1] == '\r' && buf[2] == '\n') { /* End of message */ prot_printf(sout, ".\r\n"); break; } else if (buf[1] != '.') { /* Add missing dot-stuffing */ prot_putc('.', sout); } } do { /* look for malformed lines with NUL CR LF */ if (buf[strlen(buf)-1] != '\n' && strlen(buf)+2 < sizeof(buf)-1 && buf[strlen(buf)+2] == '\n') { strlcat(buf, "\r\n", sizeof(buf)); } prot_printf(sout, "%s", buf); } while (buf[strlen(buf)-1] != '\n' && prot_fgets(buf, sizeof(buf), pin)); } if (buf[0] != '.') { syslog(LOG_ERR, "ARTICLE terminated abnormally"); return -1; } } /* see how we did */ if (!prot_fgets(buf, sizeof(buf), sin)) { syslog(LOG_ERR, "IHAVE terminated abnormally"); return -1; } else if (!strncmp("235", buf, 3)) (*accepted)++; else (*failed)++; return 0; }
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; } }