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; }
/* delete a sieve script */ int deletescript(struct protstream *conn, const struct buf *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", name->s); if (isactive(name->s)) { prot_printf(conn, "NO (ACTIVE) \"Active script cannot be deleted\"\r\n"); return TIMSIEVE_FAIL; } result = unlink(path); if (result != 0) { if (result == ENOENT) prot_printf(conn, "NO (NONEXISTENT) \"Script %s does not exist.\"\r\n", name->s); else prot_printf(conn,"NO \"Error deleting script\"\r\n"); return TIMSIEVE_FAIL; } snprintf(path, 1023, "%s.bc", name->s); 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 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; }
/* 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; }
/* 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; }
/* 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; }