int setactive(struct protstream *conn, mystring_t *name) { int result; char filename[1024]; /* if string name is empty, disable active script */ if (!strlen(string_DATAPTR(name))) { if (deleteactive(conn) != TIMSIEVE_OK) return TIMSIEVE_FAIL; prot_printf(conn,"OK\r\n"); return TIMSIEVE_OK; } result = scriptname_valid(name); if (result!=TIMSIEVE_OK) { prot_printf(conn,"NO \"Invalid script name\"\r\n"); return result; } if (exists(string_DATAPTR(name))==FALSE) { prot_printf(conn,"NO \"Script does not exist\"\r\n"); return TIMSIEVE_NOEXIST; } /* if script already is the active one just say ok */ if (isactive(string_DATAPTR(name))==TRUE) { prot_printf(conn,"OK\r\n"); return TIMSIEVE_OK; } /* get the name of the active sieve script */ snprintf(filename, sizeof(filename), "%s.bc", string_DATAPTR(name)); /* ok we want to do this atomically so let's - make <activesieve>.NEW as a hard link - rename it to <activesieve> */ result = symlink(filename, "defaultbc.NEW"); if (result) { syslog(LOG_ERR, "symlink(%s, defaultbc.NEW): %m", filename); prot_printf(conn, "NO \"Can't make link\"\r\n"); return TIMSIEVE_FAIL; } result = rename("defaultbc.NEW", "defaultbc"); if (result) { unlink("defaultbc.NEW"); syslog(LOG_ERR, "rename(defaultbc.NEW, defaultbc): %m"); prot_printf(conn,"NO \"Error renaming\"\r\n"); return TIMSIEVE_FAIL; } sync_log_sieve(sieved_userid); prot_printf(conn,"OK\r\n"); return TIMSIEVE_OK; }
int installdata(int version,struct protstream *pout, struct protstream *pin, char *scriptname, char *data, int len, char **refer_to, char **errstrp) { int res; int ret; mystring_t *errstr=NULL; lexstate_t state; prot_printf(pout, "PUTSCRIPT \"%s\" ",scriptname); prot_printf(pout, "{%d+}\r\n",len); prot_write(pout, data, len); prot_printf(pout,"\r\n"); prot_flush(pout); /* now let's see what the server said */ res=yylex(&state,pin); ret = handle_response(res,version,pin,refer_to,&errstr); /* if command failed */ if(ret == -2 && *refer_to) { return -2; } else if (ret!=0) { *errstrp = strconcat("Putting script: ", string_DATAPTR(errstr), (char *)NULL); return -1; } return 0; }
int setscriptactive(int version, struct protstream *pout, struct protstream *pin,char *name, char **refer_to, char **errstrp) { lexstate_t state; int res; int ret; mystring_t *errstr=NULL; /* tell server we want "name" to be the active script */ prot_printf(pout, "SETACTIVE \"%s\"\r\n",name); prot_flush(pout); /* now let's see what the server said */ res=yylex(&state, pin); ret = handle_response(res, version, pin, refer_to, &errstr); /* if command failed */ if(ret == -2 && *refer_to) { return -2; } else if (ret != 0) { *errstrp = strconcat("Setting script active: ", string_DATAPTR(errstr), (char *)NULL); return -1; } return 0; }
int deleteascript(int version, struct protstream *pout, struct protstream *pin, char *name, char **refer_to, char **errstrp) { lexstate_t state; int res; int ret; mystring_t *errstr; prot_printf(pout,"DELETESCRIPT \"%s\"\r\n",name); prot_flush(pout); res=yylex(&state, pin); ret = handle_response(res,version,pin,refer_to,&errstr); if(ret == -2 && *refer_to) { return -2; } else if (ret!=0) { *errstrp = strconcat("Deleting script: ", string_DATAPTR(errstr), (char *)NULL); return -1; } return 0; }
int list_wcb(int version, struct protstream *pout, struct protstream *pin,isieve_listcb_t *cb ,void *rock, char **refer_to) { lexstate_t state; int end=0; int res; int ret = 0; prot_printf(pout, "LISTSCRIPTS\r\n"); prot_flush(pout); do { if ((res=yylex(&state, pin))==STRING) { char *str=string_DATAPTR(state.str); if (yylex(&state, pin)==' ') { if (yylex(&state, pin)!=TOKEN_ACTIVE) printf("Expected ACTIVE\n"); if (yylex(&state, pin)!=EOL) printf("Expected EOL\n"); cb(str, 1, rock); } else { /* in old version we had that '*' means active script thing */ if (version == OLD_VERSION) { if (str[strlen(str)-1]=='*') { str[strlen(str)-1]='\0'; cb(str, 1, rock); } else { cb(str, 0, rock); } } else { /* NEW_VERSION */ /* assume it's a EOL */ cb(str, 0, rock); } } } else { ret = handle_response(res,version,pin,refer_to,NULL); end=1; } } while (end==0); return ret; }
/* delete a sieve script */ int deletescript(struct protstream *conn, mystring_t *name) { int result; char path[1024]; result = scriptname_valid(name); if (result!=TIMSIEVE_OK) { prot_printf(conn,"NO \"Invalid script name\"\r\n"); return result; } snprintf(path, 1023, "%s.script", string_DATAPTR(name)); if (isactive(string_DATAPTR(name)) && (deleteactive(conn)!=TIMSIEVE_OK)) { return TIMSIEVE_FAIL; } result = unlink(path); if (result != 0) { prot_printf(conn,"NO \"Error deleting script\"\r\n"); return TIMSIEVE_FAIL; } snprintf(path, 1023, "%s.bc", string_DATAPTR(name)); result = unlink(path); if (result != 0) { prot_printf(conn,"NO \"Error deleting bytecode\"\r\n"); return TIMSIEVE_FAIL; } sync_log_sieve(sieved_userid); prot_printf(conn,"OK\r\n"); return TIMSIEVE_OK; }
int scriptname_valid(mystring_t *name) { int lup; char *ptr; /* must be at least one character long */ if (name->len < 1) return TIMSIEVE_FAIL; ptr=string_DATAPTR(name); for (lup=0;lup<name->len;lup++) { if ((ptr[lup]=='/') || (ptr[lup]=='\0')) return TIMSIEVE_FAIL; } return TIMSIEVE_OK; }
int cmd_havespace(struct protstream *conn, mystring_t *sieve_name, unsigned long num) { int result; int maxscripts; unsigned long maxscriptsize; result = scriptname_valid(sieve_name); if (result!=TIMSIEVE_OK) { prot_printf(conn,"NO \"Invalid script name\"\r\n"); return result; } /* see if the size of the script is too big */ maxscriptsize = config_getint(IMAPOPT_SIEVE_MAXSCRIPTSIZE); maxscriptsize *= 1024; if (num > maxscriptsize) { prot_printf(conn, "NO (\"QUOTA\") \"Script size is too large. " "Max script size is %ld bytes\"\r\n", maxscriptsize); return TIMSIEVE_FAIL; } /* see if this would put the user over quota */ maxscripts = config_getint(IMAPOPT_SIEVE_MAXSCRIPTS); if (countscripts(string_DATAPTR(sieve_name))+1 > maxscripts) { prot_printf(conn, "NO (\"QUOTA\") \"You are only allowed %d scripts on this server\"\r\n", maxscripts); return TIMSIEVE_FAIL; } prot_printf(conn,"OK\r\n"); return TIMSIEVE_OK; }
int yylex(lexstate_t * lvalp, void * client) { int ch; char buffer[ACAP_MAX_QSTR_LEN]; /* big enough for everything */ char *buff_ptr = buffer; /* ptr into the buffer */ char *buff_end = buffer + ACAP_MAX_QSTR_LEN -1; unsigned long count=0; int result = SIEVE_OK; int synchronizing; /* wheather we are in the process of reading a synchronizing string or not */ struct protstream *stream=(struct protstream *) client; while (1) { /* get a character this may block on a read if there is nothing in the buffer */ ch = prot_getc(stream); if (ch == -1) return SIEVE_FAIL; switch (lexer_state) { case LEXER_STATE_RECOVER: if (ch == '\r') lexer_state=LEXER_STATE_RECOVER_CR; break; case LEXER_STATE_RECOVER_CR: if (ch == '\n') lexer_state=LEXER_STATE_NORMAL; return EOL; case LEXER_STATE_CR: if (ch == '\n') { lexer_state=LEXER_STATE_NORMAL; return EOL; } /* otherwise, life is bad */ ERR_PUSHBACK(); case LEXER_STATE_QSTR: if (ch == '\"') { /* End of the string */ lvalp->str = NULL; result = string_allocate(buff_ptr - buffer, buffer, &lvalp->str); if (result != SIEVE_OK) ERR_PUSHBACK(); lexer_state=LEXER_STATE_NORMAL; return STRING; } if (ch == '\0' || 0x7F < ((unsigned char)ch)) ERR_PUSHBACK(); /* Otherwise, we're appending a character */ if (buff_end <= buff_ptr) ERR_PUSHBACK(); /* too long! */ if (ch == '\\') { ch=prot_getc(stream); if (result != SIEVE_OK) ERR(); if (ch != '\"' && ch != '\\') ERR_PUSHBACK(); } *buff_ptr++ = ch; break; case LEXER_STATE_LITERAL: if (('0' <= ch) && (ch <= '9')) { unsigned long newcount = count * 10 + (ch - '0'); if (newcount < count) ERR_PUSHBACK(); /* overflow */ /* * XXX This should be fatal if non-synchronizing. */ count = newcount; break; } synchronizing = FALSE; if (ch != '}') ERR_PUSHBACK(); ch=prot_getc(stream); if (ch < 0) ERR(); if (ch != '\r') ERR_PUSHBACK(); ch=prot_getc(stream); if (ch < 0) ERR(); if (ch != '\n') ERR_PUSHBACK(); lvalp->str = NULL; result = string_allocate(count, NULL, &lvalp->str); if (result != SIEVE_OK) ERR_PUSHBACK(); /* there is a literal string on the wire. let's read it */ { char *it = string_DATAPTR(lvalp->str), *end = it + count; while (it < end) { *it=prot_getc(stream); it++; } *it = '\0'; } lexer_state=LEXER_STATE_NORMAL; return STRING; case LEXER_STATE_NUMBER: if (('0' <= ch) && (ch <= '9')) { unsigned long newcount = count * 10 + (ch - '0'); if (newcount < count) ERR_PUSHBACK(); /* overflow */ count = newcount; } else { lvalp->number = count; lexer_state=LEXER_STATE_NORMAL; prot_ungetc(ch, stream); return NUMBER; } break; case LEXER_STATE_NORMAL: if (isalpha((unsigned char) ch)) { lexer_state=LEXER_STATE_ATOM; *buff_ptr++ = tolower(ch); break; } switch (ch) { case '(': return '('; case ')': return ')'; case ' ': return ' '; case '\"': lexer_state=LEXER_STATE_QSTR; break; case '*': return '*'; case '0': /* fall through all numbers */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': count = ch - '0'; lexer_state=LEXER_STATE_NUMBER; break; case '{': count = 0; synchronizing = TRUE; lexer_state=LEXER_STATE_LITERAL; break; case '\r': lexer_state=LEXER_STATE_CR; break; case '\n': lexer_state=LEXER_STATE_NORMAL; return EOL; break; default: ERR_PUSHBACK(); } break; case LEXER_STATE_ATOM: if (!isalpha((unsigned char) ch)) { int token; buffer[ buff_ptr - buffer] = '\0'; /* We've got the atom. */ token = token_lookup((char *) buffer, (int) (buff_ptr - buffer)); if (token!=-1) { lexer_state=LEXER_STATE_NORMAL; prot_ungetc(ch, stream); return token; } else ERR_PUSHBACK(); } if (buff_end <= buff_ptr) ERR_PUSHBACK(); /* atom too long */ *buff_ptr++ = tolower(ch); break; } } /* while (1) */ /* never reached */ }
int timlex(mystring_t **outstr, unsigned long *outnum, struct protstream *stream) { int ch; char *buff_ptr; char *buff_end; unsigned long tmpnum = 0; unsigned long count=0; int result = TIMSIEVE_OK; buff_ptr = buffer; /* ptr into the buffer */ buff_end = buffer + maxscriptsize - 10; /* ptr to end of buffer */ while (1) { /* get a character this may block on a read if there is nothing in the buffer */ ch=prot_getc(stream); if (ch==EOF) { /* Lost connection */ return EOF; } switch (lexer_state) { case LEXER_STATE_RECOVER: if (ch == '\n') { lexer_state=LEXER_STATE_NORMAL; } if (ch == '\r') lexer_state=LEXER_STATE_RECOVER_CR; break; case LEXER_STATE_RECOVER_CR: if (ch == '\n') lexer_state=LEXER_STATE_NORMAL; break; case LEXER_STATE_CR: if (ch == '\n') { lexer_state=LEXER_STATE_NORMAL; return EOL; } /* otherwise, life is bad */ ERR_PUSHBACK(); case LEXER_STATE_QSTR: if (ch == '\"') { /* End of the string */ if (outstr!=NULL) { *outstr = NULL; result = string_allocate(buff_ptr - buffer, buffer, outstr); if (result != TIMSIEVE_OK) ERR_PUSHBACK(); } /*} */ lexer_state=LEXER_STATE_NORMAL; return STRING; } /* illegal character */ if (ch == '\0' || ch == '\r' || ch == '\n' || 0x7F < ((unsigned char)ch)) { ERR_PUSHBACK(); } /* Otherwise, we're appending a character */ if (buff_end <= buff_ptr) ERR_PUSHBACK(); /* too long! */ if (ch == '\\') { ch=prot_getc(stream); if (result != TIMSIEVE_OK) ERR(); if (ch != '\"' && ch != '\\') ERR_PUSHBACK(); } *buff_ptr++ = ch; break; case LEXER_STATE_LITERAL: if (('0' <= ch) && (ch <= '9')) { unsigned long newcount = count * 10 + (ch - '0'); if (newcount < count) ERR_PUSHBACK(); /* overflow */ /* * XXX This should be fatal if non-synchronizing. */ count = newcount; break; } if (ch != '+') ERR_PUSHBACK(); ch=prot_getc(stream); if (ch != '}') ERR_PUSHBACK(); ch=prot_getc(stream); if (ch < 0) ERR(); if (ch != '\r') ERR_PUSHBACK(); ch=prot_getc(stream); if (ch < 0) ERR(); if (ch != '\n') ERR_PUSHBACK(); if (count > maxscriptsize) { /* too big, eat the input */ for(;count > 0;count--) { if(prot_getc(stream)==EOF) break; } ERR(); } if (outstr!=NULL) { *outstr = NULL; result = string_allocate(count, NULL, outstr); if (result != TIMSIEVE_OK) ERR_PUSHBACK(); } /* there is a literal string on the wire. let's read it */ if (outstr!=NULL) { char *it = string_DATAPTR(*outstr), *end = it + count; while (it < end) { *it=prot_getc(stream); it++; } } else { /* just read the chars and throw them away */ unsigned long lup; for (lup=0;lup<count;lup++) (void)prot_getc(stream); } lexer_state=LEXER_STATE_NORMAL; return STRING; case LEXER_STATE_NUMBER: if (Uisdigit(ch)) { unsigned long newcount = tmpnum * 10 + (ch - '0'); if (newcount < tmpnum) ERR_PUSHBACK(); /* overflow */ tmpnum = newcount; } else { lexer_state=LEXER_STATE_NORMAL; prot_ungetc(ch, stream); if (outnum) *outnum = tmpnum; return NUMBER; } break; case LEXER_STATE_NORMAL: if (Uisalpha(ch)) { lexer_state=LEXER_STATE_ATOM; *buff_ptr++ = tolower(ch); break; } if (Uisdigit(ch)) { lexer_state=LEXER_STATE_NUMBER; tmpnum = ch -'0'; break; } switch (ch) { case '(': return '('; case ')': return ')'; case ' ': return ' '; case '\"': lexer_state=LEXER_STATE_QSTR; break; case '*': return '*'; case '{': count = 0; lexer_state=LEXER_STATE_LITERAL; break; case '\r': lexer_state=LEXER_STATE_CR; break; case '\n': lexer_state=LEXER_STATE_NORMAL; return EOL; break; default: return ch; } break; case LEXER_STATE_ATOM: if (!Uisalpha(ch)) { int token; buffer[ buff_ptr - buffer] = '\0'; /* We've got the atom. */ token = token_lookup((char *) buffer, (int) (buff_ptr - buffer)); if (token!=-1) { lexer_state=LEXER_STATE_NORMAL; prot_ungetc(ch, stream); return token; } else ERR_PUSHBACK(); } if (buff_end <= buff_ptr) ERR_PUSHBACK(); /* atom too long */ *buff_ptr++ = tolower(ch); break; } } /* while (1) */ /* never reached */ }
/* save name as a sieve script */ int putscript(struct protstream *conn, mystring_t *name, mystring_t *data, int verify_only) { FILE *stream; char *dataptr; char *errstr; int lup; int result; char path[1024], p2[1024]; char bc_path[1024], bc_p2[1024]; int maxscripts; sieve_script_t *s; result = scriptname_valid(name); if (result!=TIMSIEVE_OK) { prot_printf(conn,"NO \"Invalid script name\"\r\n"); return result; } if (verify_only) stream = tmpfile(); else { /* see if this would put the user over quota */ maxscripts = config_getint(IMAPOPT_SIEVE_MAXSCRIPTS); if (countscripts(string_DATAPTR(name))+1 > maxscripts) { prot_printf(conn, "NO (\"QUOTA\") \"You are only allowed %d scripts on this server\"\r\n", maxscripts); return TIMSIEVE_FAIL; } snprintf(path, 1023, "%s.script.NEW", string_DATAPTR(name)); stream = fopen(path, "w+"); } if (stream == NULL) { prot_printf(conn, "NO \"Unable to open script for writing (%s)\"\r\n", path); return TIMSIEVE_NOEXIST; } dataptr = string_DATAPTR(data); for (lup=0;lup<= data->len / BLOCKSIZE; lup++) { int amount = BLOCKSIZE; if (lup*BLOCKSIZE+BLOCKSIZE > data->len) amount=data->len % BLOCKSIZE; fwrite(dataptr, 1, amount, stream); dataptr += amount; } /* let's make sure this is a valid script (no parse errors) */ result = is_script_parsable(stream, &errstr, &s); if (result != TIMSIEVE_OK) { if (errstr && *errstr) { prot_printf(conn, "NO {" SIZE_T_FMT "}\r\n%s\r\n", strlen(errstr), errstr); free(errstr); } else { if (errstr) free(errstr); prot_printf(conn, "NO \"parse failed\"\r\n"); } fclose(stream); unlink(path); return result; } fflush(stream); fclose(stream); if (!verify_only) { int fd; bytecode_info_t *bc; /* Now, generate the bytecode */ if(sieve_generate_bytecode(&bc, s) == -1) { unlink(path); sieve_script_free(&s); prot_printf(conn, "NO \"bytecode generate failed\"\r\n"); return TIMSIEVE_FAIL; } /* Now, open the new file */ snprintf(bc_path, 1023, "%s.bc.NEW", string_DATAPTR(name)); fd = open(bc_path, O_CREAT | O_TRUNC | O_WRONLY, 0600); if(fd < 0) { unlink(path); sieve_free_bytecode(&bc); sieve_script_free(&s); prot_printf(conn, "NO \"couldn't open bytecode file\"\r\n"); return TIMSIEVE_FAIL; } /* Now, emit the bytecode */ if(sieve_emit_bytecode(fd, bc) == -1) { close(fd); unlink(path); unlink(bc_path); sieve_free_bytecode(&bc); sieve_script_free(&s); prot_printf(conn, "NO \"bytecode emit failed\"\r\n"); return TIMSIEVE_FAIL; } sieve_free_bytecode(&bc); sieve_script_free(&s); close(fd); /* Now, rename! */ snprintf(p2, 1023, "%s.script", string_DATAPTR(name)); snprintf(bc_p2, 1023, "%s.bc", string_DATAPTR(name)); rename(path, p2); rename(bc_path, bc_p2); } prot_printf(conn, "OK\r\n"); sync_log_sieve(sieved_userid); return TIMSIEVE_OK; }
int getscript(struct protstream *conn, mystring_t *name) { FILE *stream; struct stat filestats; /* returned by stat */ int size; /* size of the file */ int result; int cnt; char path[1024]; result = scriptname_valid(name); if (result!=TIMSIEVE_OK) { prot_printf(conn,"NO \"Invalid script name\"\r\n"); return result; } snprintf(path, 1023, "%s.script", string_DATAPTR(name)); result = stat(path, &filestats); if (result != 0) { prot_printf(conn,"NO \"Script doesn't exist\"\r\n"); return TIMSIEVE_NOEXIST; } size = filestats.st_size; stream = fopen(path, "r"); if (stream == NULL) { prot_printf(conn,"NO \"fopen failed\"\r\n"); return TIMSIEVE_NOEXIST; } prot_printf(conn, "{%d}\r\n", size); cnt = 0; while (cnt < size) { char buf[BLOCKSIZE]; int amount=BLOCKSIZE; if (size-cnt < BLOCKSIZE) amount=size-cnt; if (fread(buf, 1, BLOCKSIZE, stream) == 0) { if (ferror(stream)) { fatal("fatal error (fread)", 0); } } prot_write(conn, buf, amount); cnt += amount; } prot_printf(conn,"\r\n"); prot_printf(conn, "OK\r\n"); fclose(stream); return TIMSIEVE_OK; }
int handle_response(int res,int version,struct protstream *pin, char **refer_to, mystring_t **errstr) { lexstate_t state; int r = 0; *refer_to = NULL; if (res == -1) parseerror("lost connection"); if ((res!=TOKEN_OK) && (res!=TOKEN_NO) && (res!=TOKEN_BYE)) parseerror("ATOM"); if(res == TOKEN_BYE) { if (yylex(&state, pin)!=' ') parseerror("expected space"); res = yylex(&state, pin); /* additional error response */ if (res == '(') { /* '(' string [SP string] ')' */ /* we only support the REFERRAL response with BYE */ if (yylex(&state, pin)==TOKEN_REFERRAL) { if (yylex(&state, pin)!=' ') parseerror("expected space"); if (yylex(&state, pin)!=STRING) parseerror("expected string"); *refer_to = xstrdup(string_DATAPTR(state.str)); if (yylex(&state, pin)!=')') parseerror("expected RPAREN"); } else { res = 0; while(res != ')' && res != -1) { res = yylex(&state, pin); } if(res != ')') { parseerror("expected RPARAN"); } } res = yylex(&state, pin); if (res == ' ') res = yylex(&state, pin); } if (res != STRING && res != EOL) parseerror("expected string2"); if (errstr) *errstr = state.str; r = -2; } else if (res==TOKEN_NO) { if (yylex(&state, pin)!=' ') parseerror("expected space"); res = yylex(&state, pin); /* additional error response */ if (res == '(') { /* '(' string [SP string] ')' */ res = 0; while(res != ')' && res != -1) { res = yylex(&state, pin); } if(res != ')') { parseerror("expected RPARAN"); } res = yylex(&state, pin); if (res == ' ') res = yylex(&state, pin); } if (res != STRING) parseerror("expected string"); if (errstr) *errstr = state.str; r = -1; } else { /* ok */ int res; /* SASL response */ res = yylex(&state, pin); if(res == ' ') { if (yylex(&state, pin) != '(') parseerror("expected LPAREN"); if (yylex(&state, pin)==TOKEN_SASL) { if (yylex(&state, pin)!=' ') parseerror("expected space"); if (yylex(&state, pin)!=STRING) parseerror("expected string"); *refer_to = xstrdup(string_DATAPTR(state.str)); if (yylex(&state, pin)!=')') parseerror("expected RPAREN"); } else { parseerror("unexpected response code with OK response"); } } else if (version != OLD_VERSION && res == EOL) { return r; } /* old version of protocol had strings with ok responses too */ if (version == OLD_VERSION) { if (res !=' ') parseerror("expected sp"); if (yylex(&state, pin)!=STRING) parseerror("expected string"); } } if (yylex(&state, pin)!=EOL) parseerror("expected EOL"); return r; }
int installafile(int version,struct protstream *pout, struct protstream *pin, char *filename, char *destname, char **refer_to, char **errstrp) { FILE *stream; struct stat filestats; /* returned by stat */ int size; /* size of the file */ int result; int cnt; int res; int ret; mystring_t *errstr=NULL; lexstate_t state; char *sievename; if(!destname) destname = filename; result=stat(filename,&filestats); if (result!=0) { *errstrp = xstrdup(strerror(errno)); return -1; } size=filestats.st_size; stream=fopen(filename, "r"); if (stream==NULL) { *errstrp = xstrdup( "put script: internal error: couldn't open temporary file"); return -1; } sievename=getsievename(destname); prot_printf(pout, "PUTSCRIPT \"%s\" ",sievename); prot_printf(pout, "{%d+}\r\n",size); cnt=0; while (cnt < size) { char buf[BLOCKSIZE]; int amount=BLOCKSIZE; int n; if (size-cnt < BLOCKSIZE) amount=size-cnt; n = fread(buf, 1, BLOCKSIZE, stream); if (!n) { *errstrp = xstrdup("put script: failed to finish reading"); fclose(stream); free(sievename); return -1; } prot_write(pout, buf, n); cnt+=amount; } prot_printf(pout,"\r\n"); prot_flush(pout); fclose(stream); free(sievename); /* now let's see what the server said */ res=yylex(&state,pin); ret = handle_response(res,version,pin,refer_to,&errstr); /* if command failed */ if(ret == -2 && *refer_to) { return -2; } else if (ret!=0) { *errstrp = strconcat("put script: ", string_DATAPTR(errstr), (char *)NULL); return -1; } return 0; }
/* if command failed */ if(ret == -2 && *refer_to) { return -2; } else if (ret != 0) { *errstrp = strconcat("Setting script active: ", string_DATAPTR(errstr), (char *)NULL); return -1; } return 0; } #if 0 static int viewafile(mystring_t *data, char *name __attribute__((unused))) { printf("%s\r\n", string_DATAPTR(data)); return 0; } #endif #if 0 static int writefile(mystring_t *data, char *name, char **errstrp) { FILE *stream; char *scrname; char *dp; /* this is only necessary to shut up gcc */ scrname = strconcat(name, ".script", (char *)NULL);
/* 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; } }