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; }
/* 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; }
/* save name as a sieve script */ int putscript(struct protstream *conn, const struct buf *name, const struct buf *data, int verify_only) { FILE *stream; const char *dataptr; char *errstr; unsigned int i; int last_was_r = 0; 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(name->s)+1 > maxscripts) { prot_printf(conn, "NO (QUOTA/MAXSCRIPTS) \"You are only allowed %d scripts on this server\"\r\n", maxscripts); return TIMSIEVE_FAIL; } snprintf(path, 1023, "%s.script.NEW", name->s); 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 = data->s; /* copy data to file - replacing any lone \r or \n with the * \r\n pair so notify messages are SMTP compatible */ for (i = 0; i < data->len; i++) { if (last_was_r) { if (dataptr[i] != '\n') putc('\n', stream); } else { if (dataptr[i] == '\n') putc('\r', stream); } putc(dataptr[i], stream); last_was_r = (dataptr[i] == '\r'); } if (last_was_r) putc('\n', stream); /* 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 "); prot_printstring(conn, errstr); prot_printf(conn, "\r\n"); } else { prot_printf(conn, "NO \"parse failed\"\r\n"); } free(errstr); 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", name->s); 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", name->s); snprintf(bc_p2, 1023, "%s.bc", name->s); rename(path, p2); rename(bc_path, bc_p2); } prot_printf(conn, "OK\r\n"); sync_log_sieve(sieved_userid); return TIMSIEVE_OK; }