./prayer-1.3.5/0000755006513000651300000000000011775262635011607 5ustar dpc22dpc22./prayer-1.3.5/servers/0000755006513000651300000000000011775262602013272 5ustar dpc22dpc22./prayer-1.3.5/servers/prayer_shared.h0000644006513000651300000000220511063701635016264 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/prayer_shared.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* System header files needed by other headers */ #ifndef PRAYER_FULL_HDRS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #endif #include "lib.h" #include "common.h" #include "config.h" #include "user_agent.h" #include "request.h" #include "response.h" #include "gzip.h" #include "html_common.h" #include "setproctitle.h" #include "mymutex.h" #include "log.h" #include "utf8.h" ./prayer-1.3.5/servers/session_exchange.h0000644006513000651300000000065011063701635016763 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_exchange.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ BOOL session_exchange(struct session *session); ./prayer-1.3.5/servers/prayer_login.c0000644006513000651300000003520411243215763016130 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/prayer_login.c,v 1.15 2009/08/20 09:48:35 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_shared.h" #include "prayer.h" #include "prayer_login.h" #include "prayer_server.h" char *read_file(struct pool *pool, char *filename) { struct buffer *b = buffer_create(pool, 4096); FILE *file; int c; if (!(file = fopen(filename, "r"))) return(""); while ((c = fgetc(file)) != EOF) { if (c == '\n') bputs(b, ""CRLF); else bputc(b, c); } fclose(file); return (buffer_fetch(b, 0, buffer_size(b), NIL)); } /* prayer_login_generate() *********************************************** * * Generate login screen * prayer: Global state * request: HTTP request that initiated this action * user: Default username for login scren. * form: Whether to include the login form. ************************************************************************/ static void prayer_login_generate(struct prayer *prayer, struct request *request, char *user, BOOL form) { struct config *config = prayer->config; struct buffer *b = request->write_buffer; struct pool *pool = request->pool; struct template_vals *tvals = NIL; char *hostname; if (!prayer->use_ssl && config->ssl_required) { response_error(request, 403); /* Forbidden */ return; } prayer_template_setup(prayer); /* Adds $url_prefix automatically */ tvals = prayer->template_vals; hostname = config->hostname_service ? config->hostname_service : config->hostname; template_vals_string(tvals, "$service_name", config->login_service_name); template_vals_string(tvals, "$hostname", hostname); template_vals_string(tvals, "$user", user); if (config->raven_enable) { template_vals_ulong(tvals, "$raven_enable", 1); } if (config->login_banner) { template_vals_string(tvals, "$login_banner", config->login_banner); } if (config->motd_path) { template_vals_string(tvals, "$motd", read_file(pool, config->motd_path)); } if (config->login_insert1_path) { template_vals_string(tvals, "$login_insert1", read_file(pool, config->login_insert1_path)); } if (config->login_insert2_path) { template_vals_string(tvals, "$login_insert2", read_file(pool, config->login_insert2_path)); } if ((prayer->use_ssl == NIL) && (config->ssl_default_port > 0)) { template_vals_ulong(tvals, "$ssl_available", 1); template_vals_ulong(tvals, "$ssl_port", config->ssl_default_port); } template_expand(config->login_template, tvals, b); response_html(request, 200); } /* ====================================================================== */ /* ====================================================================== */ /* prayer_login_attempt() ************************************************ * * Attempt login to prayer-session backend * prayer: Global state * username: Username to send to IMAP server * password: Password to send to IMAP server * statusp: Returns Server status code * valuep: Returns Descritive text or URL, depending on status code * * Connection/protocol error if either *statusp and *valuep NIL on return ************************************************************************/ static BOOL prayer_login_attempt(struct prayer *prayer, char *username, char *password, char **statusp, char **valuep) { struct config *config = prayer->config; struct request *request = prayer->request; struct pool *pool = request->pool; struct user_agent *user_agent = request->user_agent; struct iostream *iostream; char *socketname; int sockfd; struct buffer *b = buffer_create(pool, 0L); int c; char *line, *status = "NO", *value = ""; char *ua_options; *statusp = NIL; *valuep = NIL; if (!(username && username[0])) { *statusp = "NO"; *valuep = "No username supplied"; return(NIL); } if (!(password && password[0])) { *statusp = "NO"; *valuep = "No password supplied"; return(NIL); } socketname = pool_printf(pool, "%s/%s", config->socket_dir, config->init_socket_name); if ((sockfd = os_connect_unix_socket(socketname)) < 0) return(NIL); if ((iostream = iostream_create(pool, sockfd, 0)) == NIL) { log_misc("[process_login_request()] iostream_create() failed"); return(NIL); } iostream_set_timeout(iostream, config->session_timeout); ua_options = user_agent_options(user_agent); ioprintf(iostream, "%s %s %s %d %d %s" CRLF, string_canon_encode(pool, username), string_canon_encode(pool, password), string_canon_encode(pool, ua_options), prayer->port, prayer->use_ssl, ipaddr_text(prayer->ipaddr)); ioflush(iostream); while (((c = iogetc(iostream)) != EOF) && (c != '\015') && (c != '\012')) bputc(b, c); if (c == EOF) { log_misc("[process_login_request()] iogetc() got end of file"); return(NIL); } line = buffer_fetch(b, 0, buffer_size(b), NIL); status = string_get_token(&line); value = string_next_token(&line); if (!(status && value)) { log_misc("[process_login_request()] Invalid response from server"); return(NIL); } *statusp = status; *valuep = value; return(T); } /* Couple of support functions shared between prayer_login_process() * and prayer_login_raven() */ static void prayer_login_connect_error(struct prayer *prayer, char *username) { struct request *request = prayer->request; struct buffer *b = request->write_buffer; struct template_vals *tvals = NIL; prayer_template_setup(prayer); /* Adds $url_prefix automatically */ tvals = prayer->template_vals; template_vals_string(tvals, "$user", username); template_expand("frontend_session", tvals, b); response_html(request, 200); } static void prayer_login_error(struct prayer *prayer, char *username, char *value) { struct request *request = prayer->request; struct buffer *b = request->write_buffer; struct template_vals *tvals = NIL; prayer_template_setup(prayer); /* Adds $url_prefix automatically */ tvals = prayer->template_vals; template_vals_string(tvals, "$user", username); template_vals_string(tvals, "$value", value); template_expand("frontend_login_error", tvals, b); response_html(request, 200); } /* ====================================================================== */ /* prayer_login_raven() ************************************************** * * Process Raven login request * prayer: Global state * username: Default login name. ************************************************************************/ #ifdef RAVEN_ENABLE void prayer_login_raven(struct prayer *prayer) { struct request *request = prayer->request; struct config *config = request->config; struct pool *pool = request->pool; char *username = NIL; char *password = NIL; char *status = "NO"; char *value = ""; char *url_prefix = prayer_url_prefix(prayer, request->pool); char *raven_prefix = pool_strcat(request->pool, url_prefix, "/raven"); char *wls_token; struct raven_wls_response *wls; if (request->argc != 1) { response_error(request, 404); return; } if (!(config->raven_enable && config->raven_key_path && config->raven_key_path[0])) { response_error(request, 404); return; } request_decode_form(request); wls_token = assoc_lookup(request->form, "WLS-Response"); if (!(wls_token && wls_token[0])) { char *callback_url = pool_strcat(pool, url_prefix, "/raven"); char *service_name = "Prayer Webmail Service"; char *login_url; if (config->login_service_name) service_name = pool_printf(pool, "%s Webmail Service", config->login_service_name); login_url = pool_printf (pool, "%s?ver=1&url=%s&date=%s&desc=%s", "https://raven.cam.ac.uk/auth/authenticate.html", string_url_encode(pool, callback_url), string_url_encode(pool, raven_wls_response_now()), string_url_encode(pool, service_name)); response_redirect(request, login_url); return; } wls = raven_wls_response_parse(wls_token, config->raven_key_path, &value); if (!wls) { /* error provided by parse routine */ } else if (strcmp(wls->status, "200") != 0) { if (wls->msg && wls->msg[0]) { value = pool_printf(pool, "%s: %s", wls->status, wls->msg); } else { value = pool_printf(pool, "%s: %s", wls->status, raven_wls_response_status_message(wls)); } } else if (strcmp(wls->url, raven_prefix) != 0) { value = "Authentication response for wrong system"; } else if (!raven_wls_response_check_timestamp (wls, RAVEN_WLS_TICKET_MAXSKEW, RAVEN_WLS_TICKET_TIMEOUT)) { value = "Authentication response timed out"; } else { username = pool_strdup(pool, wls->principal); password = wls_token; } if (wls) { request->log_entry = pool_printf (pool, "GET /raven?WLS-Response=%s!...", wls->lhs); raven_wls_response_free(wls); } if (username && password && !prayer_login_attempt(prayer, username, password, &status, &value)) { if (status && value) { prayer_login_error(prayer, username, value); } else { prayer_login_connect_error(prayer, username); } return; } if (status && !strcmp(status, "OK")) response_redirect(request, value); else /* Should never happen... */ prayer_login_error(prayer, username, value); } #else void prayer_login_raven(struct prayer *prayer) { struct request *request = prayer->request; response_error(request, 404); return; } #endif /* ====================================================================== */ /* prayer_login_process() ************************************************ * * Process login request (static internal fn). * prayer: Global state * request: HTTP request that initiated this action ************************************************************************/ static void prayer_login_process(struct prayer *prayer, struct request *request) { struct config *config = request->config; struct buffer *b = request->write_buffer; char *username; char *password; char *status = "NO"; char *value; /* Decode information from post request */ request_decode_form(request); username = assoc_lookup(request->form, "username"); password = assoc_lookup(request->form, "password"); if (username) username = string_trim_whitespace(username); if ((config->referer_log_invalid || config->referer_block_invalid) && !request_test_referer(request, config->hostname_service) && !request_test_referer(request, config->hostname)) { if (config->referer_log_invalid) log_misc("[prayer_login_process()] Invalid Referer: %s", assoc_lookup(request->hdrs, "referer")); if (config->referer_block_invalid) { prayer_template_setup(prayer); /* Adds $url_prefix automatically */ template_expand("frontend_security", prayer->template_vals, b); response_html(request, 200); return; } } if ((config->raven_enable) && (password) && (strlen(password) > 256)) { prayer_login_error(prayer, username, "Password too long"); return; } if (!prayer_login_attempt(prayer, username, password, &status, &value)) { if (status && value) { prayer_login_error(prayer, username, value); } else { prayer_login_connect_error(prayer, username); } return; } if (status && !strcmp(status, "OK")) response_redirect(request, value); else /* Should never happen... */ prayer_login_error(prayer, username, value); } /* ====================================================================== */ /* ====================================================================== */ /* prayer_login() ******************************************************** * * Process login URLs: POST => login request, GET => display login screen * prayer: Global state * username: Default login name. ************************************************************************/ void prayer_login(struct prayer *prayer, char *username) { struct request *request = prayer->request; if (request->method == POST) prayer_login_process(prayer, request); else prayer_login_generate(prayer, request, username, T); } /* prayer_login_preamble() *********************************************** * * Handle pre-login actions for insecure connections, either a warning * banner or a redirect to the secure server, depending on configuration. * prayer: Global state ************************************************************************/ void prayer_login_preamble(struct prayer *prayer) { struct config *config = prayer->config; struct request *request = prayer->request; char *hostname, *url; /* Normal login if we are secure */ if (prayer->use_ssl) { prayer_login(prayer, NIL); return; } /* Redirect to the secure login url */ if (config->ssl_redirect) { hostname = config->hostname_service ? config->hostname_service : config->hostname; if (config->ssl_default_port != 443) url = pool_printf(request->pool, "https://%s:%lu", hostname, config->ssl_default_port); else url = pool_printf(request->pool, "https://%s", hostname); response_redirect(prayer->request, url); return; } if (config->ssl_encouraged) { /* Produce a pre-login warning page */ prayer_login_generate(prayer, request, NIL, NIL); } else { /* Configuration allows plaintext logins (e.g: testrig on magenta) */ prayer_login(prayer, NIL); } } ./prayer-1.3.5/servers/session_streams.c0000644006513000651300000007114011063701635016654 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_streams.c,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* session stream manipulation stuff amalgamated here. This is a bit of a * mess simply because struct session defines half a dozen independant * streams, and session idle mode, stream checking and folder change * affect a number of different streams. * * Putting it all here in one place to encourage rationalisation/cleanup at * some future point. However this probably isn't a high priority as the * mess is more or less invisible to the main body of the code which only * cares about session->stream. Thought: define abstraction, have ptrs from * struct session into abstraction so that all changes within this * abstraction transparent to other code */ #include "server.h" /* session_streams_idle() ************************************************ * * Shut down transient resources if session is idle ************************************************************************/ BOOL session_streams_idle(struct session *session) { unsigned long marked = msgmap_marked_count(session->zm); /* Will be reassigned when we wake up */ session->stream = NIL; if (session->inbox_stream) { if ((session->stream == session->inbox_stream) && (marked > 0)) /* Garbage collect inbox stream */ mail_gc(session->inbox_stream, GC_ENV | GC_TEXTS); else { /* Shut down inbox stream */ ml_close(session, session->inbox_stream); session->inbox_stream = NIL; } } if (session->other_stream) { if ((session->stream == session->other_stream) && (marked > 0)) { /* Garbage collect other stream */ mail_gc(session->other_stream, GC_ENV | GC_TEXTS); } else { /* Shut down other stream */ ml_close(session, session->other_stream); session->other_stream = NIL; } } if (session->draft_stream) { if ((session->stream == session->draft_stream) && (marked > 0)) { /* Garbage collect draft stream */ mail_gc(session->draft_stream, GC_ENV | GC_TEXTS); } else { /* Shut down other stream */ ml_close(session, session->draft_stream); session->draft_stream = NIL; } } /* Shut down preferences stream */ if (session->prefs_stream) { ml_close(session, session->prefs_stream); session->prefs_stream = NIL; } /* Shut down transfer stream */ if (session->xfer_stream) { ml_close(session, session->xfer_stream); session->xfer_stream = NIL; } /* Shut down account connections as well */ account_close(session->account); sieve_close(session->sieve); return (T); } /* ====================================================================== */ /* Some static utility routines for session_streams_check() */ static BOOL session_reopen_inbox_stream(struct session *session) { struct request *request = session->request; struct pool *pool = request->pool; session->inbox_stream = ml_open(session, NIL, session_mailbox(session, pool, "inbox"), 0); if (session->inbox_stream == NIL) { session_log(session, "[session_reopen_inbox_stream] Failed to reopen inbox"); return (NIL); } if (!strcasecmp(session->foldername, "inbox")) { session->stream = session->inbox_stream; msgmap_associate(session->zm, session, session->inbox_stream); } session_log(session, "[session_reopen_inbox_stream] Reopened inbox"); session->inbox_last_ping_time = time(NIL); return (T); } static BOOL session_reopen_other_stream(struct session *session) { struct request *request = session->request; struct pool *pool = request->pool; session->other_stream = ml_open(session, NIL, session_mailbox(session, pool, session->other_foldername), 0); if (session->other_stream == NIL) { session_log(session, "[session_reopen_other_stream] Failed to reopen %s", session->other_foldername); return (NIL); } if (!strcmp(session->foldername, session->other_foldername)) { session->stream = session->other_stream; msgmap_associate(session->zm, session, session->other_stream); } session_log(session, "[session_reopen_other_stream] Reopened %s", session->other_foldername); session->other_last_ping_time = time(NIL); return (T); } static BOOL session_reopen_draft_stream(struct session *session) { struct request *request = session->request; struct pool *pool = request->pool; session->draft_stream = ml_open(session, NIL, session_mailbox(session, pool, session->draft_foldername), 0); if (session->draft_stream == NIL) { session_log(session, "[session_reopen_draft_stream] Failed to reopen %s", session->draft_foldername); return (NIL); } if (!strcmp(session->foldername, session->draft_foldername)) { session->stream = session->draft_stream; msgmap_associate(session->zm, session, session->draft_stream); } session_log(session, "[session_reopen_draft_stream] Reopened %s", session->draft_foldername); session->draft_last_ping_time = time(NIL); return (T); } /* ====================================================================== */ static unsigned long *session_marked_list(struct pool *pool, MAILSTREAM * stream) { unsigned long count = 0; unsigned long msgno; unsigned long *result; for (msgno = 1; msgno <= stream->nmsgs; msgno++) { MESSAGECACHE *elt = mail_elt(stream, msgno); if (elt->spare) count++; } result = pool_alloc(pool, (count + 1) * sizeof(unsigned long)); count = 0; for (msgno = 1; msgno <= stream->nmsgs; msgno++) { MESSAGECACHE *elt = mail_elt(stream, msgno); if (elt->spare) result[count++] = mail_uid(stream, msgno); } result[count] = 0; return (result); } unsigned long session_apply_marked_list(MAILSTREAM * stream, unsigned long *list) { unsigned long count = 0; unsigned long msgno; for (msgno = 1; msgno <= stream->nmsgs; msgno++) { unsigned long uid = mail_uid(stream, msgno); if (uid == *list) { mail_elt(stream, msgno)->spare = T; count++; list++; } else if (uid > (*list)) { list++; if (*list == 0L) break; } } return (count); } /* ====================================================================== */ static BOOL session_check_inbox_stream(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; time_t now = time(NIL); BOOL use_check = config->stream_checkpoint; BOOL current = (session->stream == session->inbox_stream); unsigned long *marklist = NIL; if (use_check) { if (ml_check(session, session->inbox_stream)) { session_log(session, "[session_check_inbox_stream] Checkpoint inbox"); session->inbox_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } else { if (ml_ping(session, session->inbox_stream)) { session_log(session, "[session_check_inbox_stream] Pinged inbox"); session->inbox_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } /* Need to reopen inbox. First record current marked messages */ if (current) marklist = session_marked_list(pool, session->inbox_stream); ml_close(session, session->inbox_stream); session->inbox_stream = ml_open(session, NIL, session_mailbox(session, pool, "INBOX"), 0); if (session->inbox_stream == NIL) { session_log(session, "[session_check_inbox_stream] Failed to reopen inbox"); return (NIL); } if (current) { session->stream = session->inbox_stream; if (marklist) msgmap_marked_set(session->zm, session_apply_marked_list(session->stream, marklist)); msgmap_associate(session->zm, session, session->inbox_stream); } if (msgmap_marked_count(session->zm) > 0) session_log(session, ("[session_check_inbox_stream] " "Reopened inbox with %lu marked msgs"), msgmap_marked_count(session->zm)); else session_log(session, "[session_check_inbox_stream] Reopened inbox"); return (T); } static BOOL session_check_other_stream(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; time_t now = time(NIL); BOOL use_check = config->stream_checkpoint; BOOL current = (session->stream == session->other_stream); unsigned long *marklist = NIL; if (use_check) { if (ml_check(session, session->other_stream)) { session_log(session, "[session_check_other_stream] Checkpoint %s", session->other_foldername); session->other_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } else { if (ml_ping(session, session->other_stream)) { session_log(session, "[session_check_other_stream] Pinged %s", session->other_foldername); session->other_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } /* Need to reopen other stream. First record current marked messages */ if (current) marklist = session_marked_list(pool, session->other_stream); ml_close(session, session->other_stream); session->other_stream = ml_open(session, NIL, session_mailbox(session, pool, session->other_foldername), 0); if (session->other_stream == NIL) { session_log(session, "[session_check_other_stream] Failed to reopen %s", session->other_foldername); return (NIL); } if (current) { session->stream = session->other_stream; if (marklist) msgmap_marked_set(session->zm, session_apply_marked_list(session->stream, marklist)); msgmap_associate(session->zm, session, session->other_stream); } if (msgmap_marked_count(session->zm) > 0) session_log(session, ("[session_check_other_stream] " "Reopened %s with %lu marked msgs"), session->other_foldername, msgmap_marked_count(session->zm)); else session_log(session, "[session_check_other_stream] Reopened %s", session->other_foldername); session->other_last_ping_time = now; return (T); } static BOOL session_check_draft_stream(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; time_t now = time(NIL); BOOL use_check = config->stream_checkpoint; BOOL current = (session->stream == session->draft_stream); unsigned long *marklist = NIL; if (use_check) { if (ml_check(session, session->draft_stream)) { session_log(session, "[session_check_draft_stream] Checkpoint %s", session->draft_foldername); session->draft_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } else { if (ml_ping(session, session->draft_stream)) { session_log(session, "[session_check_draft_stream] Pinged %s", session->draft_foldername); session->draft_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } /* Need to reopen other stream. First record current marked messages */ if (current) marklist = session_marked_list(pool, session->draft_stream); ml_close(session, session->draft_stream); session->draft_stream = ml_open(session, NIL, session_mailbox(session, pool, session->draft_foldername), 0); if (session->draft_stream == NIL) { session_log(session, "[session_check_draft_stream] Failed to reopen %s", session->draft_foldername); return (NIL); } if (current) { session->stream = session->draft_stream; if (marklist) msgmap_marked_set(session->zm, session_apply_marked_list(session->stream, marklist)); msgmap_associate(session->zm, session, session->draft_stream); } if (msgmap_marked_count(session->zm) > 0) session_log(session, ("[session_check_draft_stream] " "Reopened %s with %lu marked msgs"), session->draft_foldername, msgmap_marked_count(session->zm)); else session_log(session, "[session_check_draft_stream] Reopened %s", session->draft_foldername); session->draft_last_ping_time = now; return (T); } /* ====================================================================== */ /* session_streams_check() *********************************************** * * Check to see if MAILSTREAM connections to IMAP server have timed out * Quietly reconnect connections which have timed out ************************************************************************/ BOOL session_streams_check(struct session * session) { struct config *config = session->config; time_t now = time(NIL); time_t interval; interval = (time_t) config->stream_ping_interval; /* IMAP server may time out after 30 minutes */ if ((interval == 0) || (interval > SESSION_DEFAULT_IMAP_TIMEOUT)) interval = SESSION_DEFAULT_IMAP_TIMEOUT; /* Check or reopen inbox stream if needed */ if (session->inbox_stream == NIL) { if (!session_reopen_inbox_stream(session)) return (NIL); } else if ((session->inbox_last_ping_time + interval) < now) { if (!session_check_inbox_stream(session)) return (NIL); } /* Check or reopen other stream if needed */ if (session->other_stream) { if (((session->other_last_ping_time + interval) < now) && !session_check_other_stream(session)) return (NIL); } else if (session->foldername && session->other_foldername && !strcmp(session->foldername, session->other_foldername) && !session_reopen_other_stream(session)) return (NIL); /* Check or reopen draft stream if needed */ if (session->draft_stream) { if (((session->draft_last_ping_time + interval) < now) && !session_check_draft_stream(session)) return (NIL); } else if (session->foldername && session->draft_foldername && !strcmp(session->foldername, session->draft_foldername) && !session_reopen_draft_stream(session)) return (NIL); interval = config->stream_misc_timeout; /* IMAP server may time out after 30 minutes */ if ((interval == 0) || (interval > SESSION_DEFAULT_IMAP_TIMEOUT)) interval = SESSION_DEFAULT_IMAP_TIMEOUT; /* Shut down preferences stream if it has been idle */ if (session->prefs_stream && ((session->prefs_last_ping_time + interval) < now)) { ml_close(session, session->prefs_stream); session->prefs_stream = NIL; } /* Shut down transfer stream if it has been idle */ if (session->xfer_stream && ((session->xfer_last_ping_time + interval) < now)) { ml_close(session, session->xfer_stream); session->xfer_stream = NIL; } /* Shut down account connections if they have been idle */ account_timeout_close(session->account); sieve_timeout_close(session->sieve, session); return (T); } /* ====================================================================== */ /* session_streams_change() ********************************************** * * Change to named folder, updating session stream stuff as required ************************************************************************/ BOOL session_streams_change(struct session * session, char *name) { struct request *request = session->request; struct msgmap *zm = session->zm; MAILSTREAM *stream; if (!strcasecmp(name, "inbox")) { /* Switch back to inbox stream */ string_strdup(&session->foldername, "INBOX"); session->stream = session->inbox_stream; } else if (session->other_stream && session->other_foldername && !strcmp(name, session->other_foldername)) { /* Switch to other stream */ string_strdup(&session->foldername, session->other_foldername); session->stream = session->other_stream; } else if (!strcmp(name, session->draft_foldername)) { /* Switch to draft stream, opening if required */ if (!session->draft_stream) { if (!(stream = ml_open(session, NIL, session_mailbox(session, request->pool, session-> draft_foldername), 0))) return (NIL); session->draft_stream = session->stream = stream; session->draft_last_ping_time = time(NIL); } else session->stream = stream = session->draft_stream; string_strdup(&session->foldername, session->draft_foldername); } else { /* Open fresh other_stream */ /* Just in case ml_open() fails */ stream = session->other_stream; session->other_stream = NIL; /* Open stream, reusing existing other stream if possible */ if (!(stream = ml_open(session, stream, session_mailbox(session, request->pool, name), 0))) return (NIL); string_strdup(&session->other_foldername, name); string_strdup(&session->foldername, name); session->other_stream = session->stream = stream; session->other_last_ping_time = time(NIL); } stream = session->stream; msgmap_associate(zm, session, stream); msgmap_update(zm); if (zm->nmsgs > 0) { if (zm->sort_reverse) session->current = msgmap_value(zm, 1); else session->current = msgmap_value(zm, zm->nmsgs); } else session->current = 0; session->last_displayed = session->current; /* Record current session sequence number: intercept browser back button */ session->sequence_last_change = session->sequence; return (T); } /* ====================================================================== */ /* session_streams_find() ************************************************ * * Work out if we have open connection to nominated mail folder already. ************************************************************************/ MAILSTREAM *session_streams_find(struct session * session, char *name) { if (!strcasecmp(name, "INBOX")) return (session->inbox_stream); if (session->other_foldername && !strcmp(name, session->other_foldername)) return (session->other_stream); if (session->draft_foldername && !strcmp(name, session->draft_foldername)) return (session->draft_stream); return (NIL); } /* ====================================================================== */ /* session_streams_ping() ************************************************ * * Ping stream associated with mailbox name if active ************************************************************************/ BOOL session_streams_ping(struct session * session, char *mailbox) { if (!strcasecmp(mailbox, "inbox") && session->inbox_stream) { if (!ml_ping(session, session->inbox_stream)) return (NIL); session->inbox_last_ping_time = time(NIL); if (session->stream == session->inbox_stream) msgmap_check(session->zm); return (T); } if (session->other_foldername && session->other_stream && !strcmp(mailbox, session->other_foldername)) { if (!ml_ping(session, session->other_stream)) return (NIL); session->other_last_ping_time = time(NIL); if (session->stream == session->other_stream) msgmap_check(session->zm); return (T); } if (!strcmp(mailbox, session->draft_foldername) && session->draft_stream) { if (!ml_ping(session, session->draft_stream)) return (NIL); session->draft_last_ping_time = time(NIL); if (session->stream == session->draft_stream) msgmap_check(session->zm); return (T); } return (T); } /* ====================================================================== */ /* session_save_options_to_stream() ************************************** * * Utility routine to help save user preferences. * session: Global state * stream Connection to preferences folder ************************************************************************/ static BOOL session_save_options_to_stream(struct session *session, MAILSTREAM * stream) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; struct options *options = session->options; unsigned long nmsgs = stream->nmsgs; STRING ms; char *data; unsigned long size; char *range; char *prayer_name = session_mailbox_prefs(session, pool); /* Create new status message */ data = options_create_message(options, config, pool); /* Convert simple "char *" string into c-client "STRING *" string */ INIT(&ms, mail_string, data, size = strlen(data)); /* Append new preferences message to end of folder */ if (!ml_append(session, stream, prayer_name, &ms)) return (NIL); /* Double check that append was successful: c-client ignores errors :( */ if (!ml_ping(session, stream) || (stream->nmsgs == nmsgs)) return (NIL); /* Clear out the old preferences if append was successful */ if (nmsgs > 0) { range = pool_strcat(pool, "1:", string_itoa_tmp(nmsgs)); if (!ml_flag(session, stream, range, "\\DELETED", ST_SET)) { session_log(session, ("[session_save_options_to_stream] " "Failed to clear out prefs file: %s"), ml_errmsg()); return (NIL); } } if (!ml_expunge(session, stream)) return (NIL); options->save = NIL; session->prefs_last_ping_time = time(NIL); return (T); } /* session_streams_save_options() **************************************** * * Save user preferences. Catch and report error condition. ************************************************************************/ BOOL session_streams_save_options(struct session * session) { struct request *request = session->request; struct pool *pool = request->pool; char *prayer_name = session_mailbox_prefs(session, pool); ml_clear_error(); if (!session->prefs_stream) session->prefs_stream = ml_open(session, NIL, prayer_name, 0); if (!session->prefs_stream || ml_have_error()) { ml_clear_error(); ml_create(session, session->prefs_stream, prayer_name); if (!ml_have_error()) session->prefs_stream = ml_open(session, session->prefs_stream, prayer_name, 0); } if (session->prefs_stream && !ml_have_error() && session->prefs_stream && session_save_options_to_stream(session, session->prefs_stream)) return (T); session_message(session, "Failed to save preferences: %s", ml_errmsg()); session_log(session, "[session_save_options] Failed to save preferences: %s", ml_errmsg()); if (session->prefs_stream) { ml_close(session, session->prefs_stream); session->prefs_stream = NIL; } return (T); } /* ====================================================================== */ /* session_save_options_and_close_inbox() ******************************* * * Shut down inbox stream, saving options if needed. ***********************************************************************/ static void session_save_options_and_close_inbox(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; MAILSTREAM *stream; char *name; char *prefs_folder_name = config->prefs_folder_name; char *prayer_name = session_mailbox_prefs(session, pool); /* Checkpoint inbox stream before recycle attempt */ ml_check(session, session->inbox_stream); ml_clear_error(); stream = ml_open(session, session->inbox_stream, prayer_name, 0); if (!stream) { if (ml_have_error()) { ml_clear_error(); ml_create(session, stream, prayer_name); if (!ml_have_error()) stream = ml_open(session, stream, prayer_name, 0); } if (!stream || ml_have_error() || !((name = stream->mailbox) && (strlen(name) >= strlen(prefs_folder_name)) && (!strcmp(name + strlen(name) - strlen(prefs_folder_name), prefs_folder_name)))) { session_log(session, ("[session_save_options_and_close_inbox]" " Unable to select/create prefs file on exit")); ml_close(session, stream); return; } } if (stream) { session_save_options_to_stream(session, stream); ml_close(session, stream); } } /* ====================================================================== */ /* session_streams_close() ********************************************** * * Shut down IMAP mailstreams associated with a login session ***********************************************************************/ void session_streams_close(struct session *session) { struct request *request = session->request; struct options *options = session->options; BOOL remove_drafts = NIL; /* Shut down transfer stream */ if (session->xfer_stream) { ml_close(session, session->xfer_stream); session->xfer_stream = NIL; } /* Shut down other stream */ if (session->other_stream) { ml_close(session, session->other_stream); session->other_stream = NIL; } /* Shut down drafts stream */ if (session->draft_stream) { if (session->draft_foldername && (session->draft_stream->nmsgs == 0)) remove_drafts = T; ml_close(session, session->draft_stream); session->draft_stream = NIL; } /* Shut down preferences stream, flushing options if dirty */ if (session->prefs_stream) { if (options->save) session_streams_save_options(session); ml_close(session, session->prefs_stream); session->prefs_stream = NIL; } /* Remove draft messages folder if empty */ if (remove_drafts) ml_delete(session, session->inbox_stream, session_mailbox(session, request->pool, session->draft_foldername)); /* Shut down inbox stream, flushing options if dirty (and no prefs stream) */ if (session->inbox_stream) { if (options->save) session_save_options_and_close_inbox(session); else ml_close(session, session->inbox_stream); session->inbox_stream = NIL; } } ./prayer-1.3.5/servers/prayer_server.h0000644006513000651300000000074511063701635016333 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/prayer_server.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ BOOL prayer_server(struct prayer *prayer, BOOL foreground); BOOL prayer_server_prefork(struct prayer *prayer); ./prayer-1.3.5/servers/portlist.h0000644006513000651300000000303611063701635015317 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/portlist.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Data structures which describe lists of internet domain sockets and * ports used for HTTP connects direct to Prayer in direct mode operation */ struct port { struct port *next; /* Linked list */ char *name; /* NIL */ int sockfd; /* Socket descriptor associated with this socket */ unsigned long inet_port; /* Internet domain port associated with socket */ pid_t pid; /* Process id associated with port if active */ }; struct portlist { struct list *idle; /* List of idle ports */ struct list *active; /* List of active ports */ unsigned long next; /* Range to draw fresh ports from */ unsigned long last; }; struct portlist *portlist_create(unsigned long first_port, unsigned long count); void portlist_free(struct portlist *pl); struct port *portlist_reserve_port(struct portlist *pl); BOOL portlist_free_port_bypid(struct portlist *pl, pid_t pid); BOOL portlist_free_port(struct portlist *pl, unsigned long inet_port); void portlist_close_all(struct portlist *pl); void portlist_close_all_except(struct portlist *pl, int except_fd); ./prayer-1.3.5/servers/session_config.h0000644006513000651300000000076311063701635016453 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_config.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ BOOL session_config_local_domain_open(struct config *config); BOOL session_config_local_domain_ping(struct config *config); ./prayer-1.3.5/servers/session_unix.h0000644006513000651300000000067111063701635016167 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_unix.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ BOOL session_unix(struct session *session, struct iostream *stream); ./prayer-1.3.5/servers/prayer_main.c0000644006513000651300000002572411063701635015750 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/prayer_main.c,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_shared.h" #include "prayer.h" #include "prayer_server.h" BOOL prayer_main_use_existing(struct prayer *prayer, char *ports) { char *use_ssl, *fd, *next; while (ports) { if ((next = strchr(ports, ','))) *next++ = '\0'; if (!(use_ssl = strchr(ports, ':'))) return (NIL); *use_ssl++ = '\0'; if (!(fd = strchr(use_ssl, ':'))) return (NIL); *fd++ = '\0'; if (((atoi(ports) == 0) || (atoi(fd) == 0))) return (NIL); if (!strcmp(use_ssl, "1")) prayer_http_port_alloc(prayer, atoi(ports), T, atoi(fd)); else prayer_http_port_alloc(prayer, atoi(ports), NIL, atoi(fd)); ports = next; } return (T); } BOOL prayer_main_exec(struct prayer * prayer, int argc, char *argv[]) { struct config *config = prayer->config; struct pool *p = pool_create(8192); struct buffer *b = buffer_create(p, 256); char *cmd; char **nargv = pool_alloc(p, (argc + 2) * sizeof(char *)); int i; struct list_item *li; bputs(b, "--ports="); for (li = prayer->http_port_list->head; li; li = li->next) { struct prayer_http_port *fhp = (struct prayer_http_port *) li; if (fhp->use_ssl) bprintf(b, "%lu:1:%lu,", fhp->port, fhp->sockfd); else bprintf(b, "%lu:0:%lu,", fhp->port, fhp->sockfd); } cmd = pool_printf(p, "%s/prayer", config->bin_dir); for (i = 0; i < argc; i++) nargv[i] = argv[i]; nargv[argc++] = buffer_fetch(b, 0, buffer_size(b) - 1, NIL); nargv[argc] = NIL; execv(cmd, nargv); prayer_fatal(prayer, "execv(%s) failed: %s", cmd, strerror(errno)); /* NOTREACHED */ return (NIL); } BOOL prayer_main_start_session(struct prayer * prayer, int argc, char *argv[]) { struct config *config = prayer->config; char *cmd = pool_printf(NIL, "%s/prayer-session", config->bin_dir); char **nargv = pool_alloc(NIL, (1 + argc) * sizeof(char *)); int i, j; nargv[0] = "prayer-session"; i = 1; j = 1; while (i < argc) { if (!strcmp(argv[i], "--")) { i++; while (i < argc) nargv[j++] = argv[i++]; } else if (!strcmp(argv[i], "--config-option")) { nargv[j++] = argv[i++]; if (i < argc) nargv[j++] = argv[i++]; } else if (!strncmp (argv[i], "--config-file=", strlen("--config-file="))) nargv[j++] = argv[i++]; else i++; } nargv[j] = NIL; execv(cmd, nargv); prayer_fatal(prayer, "execv(%s) failed: %s", cmd, strerror(errno)); /* NOTREACHED */ return (NIL); } /* ====================================================================== */ static BOOL prayer_main_write_pid(struct config *config) { char *name = pool_printf(NIL, "%s/prayer.pid", config->pid_dir); FILE *file; if ((file = fopen(name, "w")) == NIL) return (NIL); fprintf(file, "%lu\n", (unsigned long) getpid()); fclose(file); return (T); } /* ====================================================================== */ int main(int argc, char *argv[]) { BOOL want_prefork = T; BOOL want_foreground = NIL; BOOL want_session = T; char *ports = NIL; char *config_filename = PRAYER_CONFIG_FILE; struct config *config = config_create(); struct prayer *prayer; struct list_item *li; int i; extern char **environ; struct ssl_config ssl_config; /* Disable supplementary groups, look for (temporary) unprivileged group */ if (getuid() == 0) { struct group *group; setgroups(0, NIL); if ((group = getgrnam("other")) != NIL) setgid(group->gr_gid); else if ((group = getgrnam("nobody")) != NIL) setgid(group->gr_gid); } if (getenv("PRAYER_CONFIG_FILE")) config_filename = getenv("PRAYER_CONFIG_FILE"); initsetproctitle("prayer", argc, argv, environ); os_signal_init(); response_record_version(VERSION_PRAYER); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--help")) { fprintf(stderr, "Options:\n"); fprintf(stderr, (" --config-file: Define prayer config file\n")); fprintf(stderr, (" " "(Overrides compilation default and PRAYER_CONFIG_FILE)\n")); fprintf(stderr, (" --config-option: Override single configuration option\n")); fprintf(stderr, "\n"); fprintf(stderr, (" --foreground: " "Run single threaded server in foreground\n")); fprintf(stderr, (" --disable-prefork: Run as simple fork()/exec() daemon\n")); fprintf(stderr, (" --disable-session: Don't start up prayer-session server\n")); fprintf(stderr, (" --help: Show this list of options\n")); fprintf(stderr, (" --: " "End of prayer options: remaining options will be passed\n")); fprintf(stderr, (" to prayer-session server process\n")); exit(0); } else if (!strcmp(argv[i], "--foreground")) want_foreground = T; else if (!strcmp(argv[i], "--disable-prefork")) want_prefork = NIL; else if (!strcmp(argv[i], "--disable-session")) want_session = NIL; else if (!strncmp(argv[i], "--config-file=", strlen("--config-file="))) { config_filename = strdup(argv[i] + strlen("--config-file=")); } else if (!strcmp(argv[i], "--config-option")) { i++; /* Processes next argv */ } else if (!strncmp(argv[i], "--ports=", strlen("--ports="))) { ports = argv[i] + strlen("--ports="); } else if (!strcmp(argv[i], "--")) { continue; } else { fprintf(stderr, "Unknown option: %s\n", argv[i]); exit(1); } } config = config_create(); if (!config_parse_file(config, config_filename)) exit(1); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--config-option")) { if (++i < argc) { if (!config_parse_option(config, strdup(argv[i]))) exit(1); } else fprintf(stderr, "--config processes following option"); } } if (!config_check(config)) exit(1); if (!config_expand(config)) exit(1); /* Generate a clean copy of the configuration without all of the noise */ { struct config *config_clean = config_clone_parsed(config); config_free(config); config = config_clean; } /* Set up prayer frontend structure to bind everything together */ prayer = prayer_create(config); if (ports == NIL) { if (config->http_port_list == NIL) prayer_fatal(prayer, "No HTTP or HTTPS ports defined"); for (li = config->http_port_list->head; li; li = li->next) { struct config_http_port *chp = (struct config_http_port *) li; prayer_http_port_open(prayer, chp->port, chp->use_ssl, chp->interface); } } else if (!prayer_main_use_existing(prayer, ports)) prayer_fatal(prayer, "Invalid --ports argument"); if (list_length(prayer->http_port_list) == 0L) prayer_fatal(prayer, "No HTTP or HTTPS ports active"); /* Don't need root privs after ports bound, files open */ if (getuid() == 0) { if ((config->prayer_uid == 0) || (config->prayer_gid == 0)) log_fatal("Configured to run as root!"); if (config->prayer_gid) { setgid(config->prayer_gid); if (config->prayer_user && config->prayer_user[0]) initgroups(config->prayer_user, config->prayer_gid); } if (config->prayer_uid) setuid(config->prayer_uid); if (getuid() == 0) log_fatal("Failed to lose root priveledges"); /* Stop impossible loop */ /* Reexec after losing root privs to prevent core dump paranoia */ if (ports == NIL) { prayer_main_exec(prayer, argc, argv); /* Should be redundant */ prayer_fatal(prayer, "prayer_main_exec() failed"); } } if (getuid() == 0) log_fatal("Configured to run as root!"); config_mkdirs(config); log_misc_init(config, argv[0], "prayer"); prayer_log_open(prayer); if (config->limit_vm) os_limit_vm(config->limit_vm); /* Ports have bound successfully and we've lost root privilege */ /* Fork off a session server process now if we want one. */ if (want_session) { pid_t pid = fork(); if (pid < 0) prayer_fatal(prayer, "Couldn't start session server - fork() failed: %s", strerror(errno)); if (pid == 0) { /* Child process */ ; /* Shut down unneeded file descriptors */ prayer_http_port_close(prayer); /* Including stdin, stdout, stderr */ close(0); close(1); close(2); open("/dev/null", O_RDONLY); /* Reopen stdin */ open("/dev/null", O_WRONLY); /* Reopen stdout */ open("/dev/null", O_WRONLY); /* Reopen stderr */ prayer_main_start_session(prayer, argc, argv); } } if (config->tmp_dir) chdir(config->tmp_dir); /* Required for SSL stuff */ config_extract_ssl(config, &ssl_config); iostream_init(&ssl_config); if (config->prayer_background && !want_foreground) { pid_t pid = fork(); if (pid < 0) prayer_fatal(prayer, "Failed to background server - fork() failed: %s", strerror(errno)); if (pid > 0) exit(0); /* Parent process */ /* Child process */ /* Shut down stdin, stdout, stderr */ close(0); close(1); close(2); open("/dev/null", O_RDONLY); /* Reopen stdin */ open("/dev/null", O_WRONLY); /* Reopen stdout */ open("/dev/null", O_WRONLY); /* Reopen stderr */ } prayer_main_write_pid(config); if (want_prefork && !want_foreground) prayer_server_prefork(prayer); else prayer_server(prayer, want_foreground); /* NOTREACHED */ return (0); } ./prayer-1.3.5/servers/prayer-debug.cf0000644006513000651300000006434511774013127016201 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/servers/prayer-debug.cf,v 1.26 2012/07/01 09:20:23 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2008 # See the file NOTICE for conditions of use and distribution. # # Master configuration file (debug version) # # Typical configuration: # Read-only files stored under $prefix # Read-write (i.e: variable) files stored under $var_prefix # # Any line can be folded using "\" character at end of line: following # Linear White space is pruned. prefix = "../files" var_prefix = "../files" # User ID to run as if we start off as root #prayer_user = "prayer" # Group ID to run as if we start off as root #prayer_group = "prayer" # Run prayer as background process. # TRUE => will return as soon as valid configuration is found. prayer_background = FALSE # Create mode for new files file_perms = 0640 # Create mode for new directories directory_perms = 0750 # Check existing directories under ${var_prefix}? #check_directory_perms = TRUE ###################################################################### # Location of backend servers # Syntax for imapd server entries (applies to both lookups and default): # host - Default IMAP port on given target system # host:port - Defined port on given target system # host/ssl - Default IMAPS port on given target system # (only if SSL support compiled into c-client library) # host:port/ssl - Defined port for imap over SSL on given target system # # "host1, host2, host3" => interfaces for a multihomed system: Prayer picks # one interface at random to seed c-client or accountd interface code. # CDB lookup map overrides default imapd_server location imapd_user_map = "" # Default imapd server. imapd_server = "localhost" # Name of Prayer user preferences file on IMAP server prefs_folder_name = ".prayer" # "Accountd" is the auxillary account management daemon. At the moment its # only suitable for the central mail systems in Cambridge. # Syntax for accountd server entries (applies to both lookups and default): # host - Default ACCOUNTD port on given target system (145) # host:port - Defined port on given target system # host/ssl - Default ACCOUNT port on given target system using SSL. # (only if ACCOUNTD running with SSL support!) # host:port/ssl - Defined port for accountd over SSL on given target system # # "host1, host2, host3" => interfaces for a multihomed system: Prayer picks # one interface at random to seed c-client or accountd interface code. # CDB lookup map overrides default accountd_server location accountd_user_map = "" # Name of normal accountd server, used for most activities. accountd_server = localhost:8145 # Name of NIS master system for password and GECOS name changes #accountd_nis_server = localhost # Accountd connections time out after a short time. accountd_timeout = 2m # Talk to Cyrus timsieved using MANAGESIEVE protocol. Overrides accountd stuff # sieved_server = localhost:2000 # sieved_user_map = "/opt/dist/users/cyrus.cdb" # Default timsieved timeout is 10 minutes sieved_timeout = 9m # Cyrus limit defined by sieve_maxscriptsize option sieve_maxsize = 32k # Possible to define a separate accountd server for the NIS master machine # (for password and fullname updates) #accountd_nis_server = localhost # # Warn user if password and GECOS changes are not immediate # accountd_passwd_delay = 30m # accountd_fullname_delay = 24h ###################################################################### # Mail domain configuration # Following is used in as SMTP bounce address. Typically one of the entries # defined on the local_domain list. Defaults to "$default_domain". # #return_path_domain = "" # Define a list of local_domains. These are domains which can be used as # valid default_domains. Two possible formats: # # local_domain # local_domain # # First format just defines a local_domain which will appear on the list # visible to user preferences. Second format also defines a list a CDB map # file which defines valid entries in that domain: used for personal name # expansion and checking for valid addresses. Defaults to a single # entry which corresponds to "$default_domain". # #local_domain $prefix/local_domains/.cdb #local_domain $prefix/local_domains/.cdb # Filter configuration. # # A filter pattern which is equivalent to, or at least approximates the # list of local domains. Defaults to "$default_domain" #filter_domain_pattern = "" ###################################################################### # hostname_service is a DNS servicename for the entire service. Typically # only needed if you are running more than one Webmail gateway system. # (Example: webmail.hermes.cam.ac.uk is an alias for webmail[123].hermes...) #hostname_service = "" # Hostname is the canonical name for this particular system, used in # session and icon URLs which are generated by Prayer. This is derived # automatically using gethostname(2) if no value provided. However, there # are situations, especially involving SSL certificates where the default # hostname may not be appropriate. The special value "__UNDEFINED__" here # means the startup script or command line must provide a hostname using a # --config-option override or via the environment variable PRAYER_HOSTNAME. # This is just a safeguard for systems which use DNS round robining to # distribute load across a number of machines. #hostname = "__UNDEFINED__" # Define a single HTTP port to bind to: # # You can define an arbitary list of ports of both kinds by using a series # of separate "use_http_port" and "use_https_port" directives, with one # port on each line. Format: "interface:port" or "ipaddr:port" to bind to a # single interface, "port" to bind to all interfaces. # use_http_port 8080 # SSL is disabled in the default configuration file as you really need an # appropriate certificate. # # use_https_port 8081 # Prayer will put a warning on the login page for HTTP connections if both # HTTP and HTTPS sessions are available. This will provide a link to the # SSL version of the service, defaulting to port 443 or failing that the # first defined HTTPS port. ssl_default_port overrides the built in logic. # # Should be rarely required now that Prayer automatically derives an # appropriate port if none is provided here # # ssl_default_port = 443 # Make sure that the login request actually comes from the page in question referer_block_invalid = TRUE referer_log_invalid = TRUE # Dump core on fatal() error. fatal_dump_core = FALSE # Enable verbose logging log_debug = TRUE # Client must connect from consistent IP addresses. May be useful as # a security measure in LAN environments. Painful for dialup users # whose connections may drop out. fix_client_ipaddr = FALSE # GZIP compression enabled by default if: # 1) gzip compression enabled at compile time. # 2) use_gzip set in user prefs # 3) User agent known to support Content-Encoding: gzip # 4) User agent asks for Content-Encoding: gzip or x-gzip. # 5) IP address of client appears in "gzip_allow_nets" OR # IP address of client does not appear in "gzip_allow_nets" # # Following IP address lists allow us to tune this a bit more tightly. # allow list is scanned first, then deny list. # # Following is correct for Cambridge networks ONLY:: # #gzip_allow_nets = 131.111.99.0/24 #gzip_deny_nets = 127.0.0.1 : \ # 131.111.0.0/16 : 129.169.0.0/16 : \ # 128.232.0.0/16 : 193.60.80.0/20 # Log hostnames rather than IP addresses to session_log when logging in # from one of the following networks. A list of fast local networks which # we know will provide fast reverse lookup from IP address to name. # Following is correct for Cambridge networks ONLY:: # # log_name_nets = 127.0.0.1 : \ # 131.111.0.0/16 : 129.169.0.0/16 : \ # 128.232.0.0/16 : 193.60.80.0/20 # Limit on any single process to stop runaway process killing system. limit_vm = 150m # Limits on the number of messages allowed by a single login session # (may need to tune this with experience). recips_max_msg = 250 recips_max_session = 1000 sending_allow_dir = "${var_prefix}/sending/allow" sending_block_dir = "${var_prefix}/sending/block" ###################################################################### # Maximum sizes for components in HTTP request. Prayer should be able to # cope with arbitary size input, however the incoming request has to be # stored somewhere. Eventually you will run out of swap if someone tries # hard enough... # Maximum for initial line in HTTP request http_max_method_size = 32k # Maximum for headers associated to this request http_max_hdr_size = 64k # Maximum for HTTP payload. This is the one that is likely to be reached in # normal use. http_max_body_size = 100m # Minimum and maximum number of preforked "prayer" HTTP servers. http_min_servers = 8 http_max_servers = 256 # Maximum number of connections that each frontend server will process http_max_connections = 20 # Present HTTP cookies to browser as "username:port=value" rather than # "username=value" Allows simultaneous login sessions from a single client # browser. However can leave a trail of cookies behind. Probably don't # want this in the long term, its here for experimentation purposes only at # the moment. http_cookie_use_port = FALSE # Various timeouts for HTTP sessions. # Timeout for (dirty) spare server waiting for fresh HTTP connection http_timeout_idle = 10s # Timeout for HTTP connection which last served an icon URL http_timeout_icons = 5s # Timeout for HTTP connection which last served an session URL http_timeout_session = 15s # Temporary, while setting up templates. http_dump = TRUE # Icons URLs are valid for 7 days. (In contrast sessions URLs expire # immediately: Browsers really shouldn't be trying to cache this stuff, # especially when it is coming in over HTTPS). icon_expire_timeout = 7d # Locatation of SSL certificate file (only used if SSL ports defined). # Required if we are going to provide SSL services. ssl_cert_file = "$prefix/certs/prayer.pem" # Locatation of SSL private key file (only used if SSL ports defined). # Required if we are going to provide SSL services. ssl_privatekey_file = "$prefix/certs/prayer.pem" # Master server will regenerate shared RSA key at this interval: ssl_rsakey_lifespan = 15m # RSA key remains fresh in child process for this long after first actual use. ssl_rsakey_freshen = 15m # SSL session cache timeout. ssl_session_timeout = 24h # EGD socket, if system has no /dev/urandom #egd_socket = "/var/prngd/urandom" # List of SSL ciphers to use # Following requires OpenSSL library with TLS 1.2 support ssl_cipher_list = "ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!EXP" # Following should work with older SSL libraries # ssl_cipher_list = "ALL:!ADH:RC4+RSA:+HIGH:!MEDIUM:!LOW:!SSLv2:!EXP" # Server picks preferred cipher rather than client: equivalent to Apache # SSLHonorCipherOrder option. ssl_server_preference = T ###################################################################### # Session specific configuration # Session switches to idle mode after this much time: connections to IMAP # and accountd servers are shut down. session_idle_time = 10m # Session disconnects entirely after this much idle time. session_timeout = 30m # Session disconnects entirely after this much idle time on compose screen session_timeout_compose = 2h # Checkpoint "inbox", "other" and draft streams every 20 minutes stream_checkpoint = T stream_ping_interval = 20m # Shut down Postponed, Preferences and Transfer streams entirely # after 15 minutes idle time, but only if idle mode doesn't beat us to it. stream_misc_timeout = 15m # Stat log files every few minutes to see if target file has been # renamed or removed. 0s => stat() log file every time something is logged. log_ping_interval = 10m # Reopen database files every few minutes to cope with log cycling. db_ping_interval = 30m # Display specific configuration # Banners for login screen login_template = "login" login_banner = "Webmail Service (Debug version)" login_service_name = "Prayer" # Address are pruned to this many characters on the mailbox list screen list_addr_maxlen = 30 # Subjects are pruned to this many characters on the mailbox list screen list_subject_maxlen = 30 # Maximum number of folders in shortcut dialogue change_max_folders = 20 # Ispell languages that we want to support, with some descriptive text # for the preferences screen. use_ispell_language british "British English" use_ispell_language american "American English" # Max size of single attachment: 10 MBytes draft_att_single_max = 10M # Max size of all attachments: 10 MBytes draft_att_total_max = 10M # fix_from_address suppresses From address option from Preferences and # Roles screens. fix_from_address = FALSE # Defaults for Cyrus (actually Hermes derivative) spam_purge command. spam_purge_name = "spam_purge" spam_purge_prefix = "# Spam Purge Timeout:" spam_purge_timeout = 60 ###################################################################### # Location of sendmail binary or drop in replacement such as Exim. sendmail_path = /usr/lib/sendmail # Location of Aspell Binary (takes precedence over ispell_path) aspell_path = /usr/bin/aspell # Location of Ispell Binary (backwards compatibility only) #ispell_path = /usr/bin/ispell # Message of the day file motd_path = "$prefix/etc/motd.html" # HTML to insert into login page login_insert1_path = "$prefix/etc/ucsnews.html" # HTML to insert into login page #login_insert2_path = "$prefix/etc/ucsnews.html" # Login security: Prayer's front page defaults to a login form. # If the user does not connect via SSL then this can be changed # to a page without a form (in order to encourage secure logins) # or changed to a redirect to the secure login page. The insecure # login page remains accessible if these settings are enabled, so # it can be disabled for full security. # Encourage secure logins by omitting the login form from the front page. ssl_encouraged = FALSE # Redirect from the insecure front page to the secure one. ssl_redirect = FALSE # Disable the insecure login page ssl_required = FALSE # Following only interesting for Hermes. raven_enable = FALSE raven_key_path = "$prefix/raven_keys" # Location of icon files icon_dir = "$prefix/icons" # Location of static pages (HTML, CSS etc) static_dir = "$prefix/static" # Location of binary files bin_dir = "." # Various directories used by the running system # Logs stored in $log_dir log_dir = "$var_prefix/logs" # $lock_dir used for interlocking between prayer processes lock_dir = "$var_prefix/locks" # $socket_dir is location for unix domain sockets which connect frontend # to backend in proxy mode of operation. socket_dir = "$var_prefix/sockets" # Split socket directory into 64 subdirs keyed on first letter of sessionID # Code provides compatibility in both directions: can switch back and forward socket_split_dir = TRUE # Name of Unix domain socket (in $socket_dir) used for initial handshake # between prayer and prayer-session processes when a user logs in init_socket_name = init # $ssl_session_dir is location for SSL session cache ssl_session_dir = "$var_prefix/ssl_scache" # Location for temporary files e.g; attachments and folders in transist # during upload and download operation. Core files also end up here tmp_dir = "$var_prefix/tmp" # Location for PID files for prayer and prayer-session master processes. pid_dir = "$var_prefix/pid" # Temporary hack to remove "mail/" from favourites list (and anywhere # else where we find the strings embedded into .prayer files). strip_mail = T # Interface to Hermes finger database lookup_rpasswd = "/data/finger/rpasswd.cdb" lookup_rusername = "/data/finger/rusername.cdb" lookup_username = "/data/finger/username.cdb" lookup_fullname = "/data/finger/fullname.cdb" ldap_server = "ldap.lookup.cam.ac.uk" ldap_base_dn = "ou=people,o=University of Cambridge,dc=cam,dc=ac,dc=uk" ldap_timeout = 15s ###################################################################### # Template stuff template_path = "../../templates" template_set = "cam" template_use_compiled = FALSE template old "Traditional" template cam "Cambridge House Style" ###################################################################### # Theme stuff theme blue description "Web Safe Blue" theme blue fgcolor "#000000" # Black theme blue fgcolor_link "#0000ff" # Dark Blue theme blue bgcolor "#ccffff" # Light Blue theme blue bgcolor_banner "#66ffff" # Darkish Blue theme blue bgcolor_row1 "#ccffff" # Light Blue theme blue bgcolor_row2 "#99ffff" # Middle Blue theme blue bgcolor_status "#ffffcc" # Yellow theme blue bgcolor_status_none "#ccffcc" # Green theme blue fgcolor_quote1 "#800000" # Brick Red theme blue fgcolor_quote2 "#008000" # Green theme blue fgcolor_quote3 "#000080" # Blue theme blue fgcolor_quote4 "#ff0000" # Orange theme green description "Web Safe Green" theme green fgcolor "#000000" # Black theme green fgcolor_link "#0000ff" # Dark Blue theme green bgcolor "#ccffcc" # Light Green theme green bgcolor_banner "#99ff99" # Middle Green theme green bgcolor_row1 "#ccffcc" # Light Green theme green bgcolor_row2 "#99ff99" # Middle Green theme green bgcolor_status "#ffffcc" # Yellow theme green bgcolor_status_none "#ccffff" # Light Blue theme green fgcolor_quote1 "#800000" # Brick Red theme green fgcolor_quote2 "#008000" # Green theme green fgcolor_quote3 "#000080" # Blue theme green fgcolor_quote4 "#ff0000" # Orange theme yellow description "Web Safe Yellow" theme yellow fgcolor "#000000" # Black theme yellow fgcolor_link "#0000ff" # Dark Blue theme yellow bgcolor "#ffffcc" # Light Yellow theme yellow bgcolor_banner "#ffff66" # Middle Yellow theme yellow bgcolor_row1 "#ffffcc" # Light Yellow theme yellow bgcolor_row2 "#ffff66" # Middle Yellow theme yellow bgcolor_status "#ccffff" # Light Blue theme yellow bgcolor_status_none "#ccffcc" # Green theme yellow fgcolor_quote1 "#800000" # Brick Red theme yellow fgcolor_quote2 "#008000" # Green theme yellow fgcolor_quote3 "#000080" # Blue theme yellow fgcolor_quote4 "#ff0000" # Orange theme gray description "Shades of Gray" # NB: Not Web safe! theme gray fgcolor "#000000" # Black theme gray fgcolor_link "#0000ff" # Dark Blue theme gray bgcolor "#eeeeee" # Light gray theme gray bgcolor_banner "#cccccc" # Dark gray theme gray bgcolor_row1 "#eeeeee" # Light gray theme gray bgcolor_row2 "#dddddd" # Middle gray theme gray bgcolor_status "#ffffcc" # Yellow theme gray bgcolor_status_none "#ccffcc" # Green theme gray fgcolor_quote1 "#800000" # Brick Red theme gray fgcolor_quote2 "#008000" # Green theme gray fgcolor_quote3 "#000080" # Blue theme gray fgcolor_quote4 "#ff0000" # Orange theme high description "High Constrast" # Yuck! theme high fgcolor "#000000" # Black theme high fgcolor_link "#0000ff" # Dark Blue theme high bgcolor "#ffffff" # Very, very white theme high bgcolor_banner "#cccccc" # Dark gray theme high bgcolor_row1 "#ffffff" # Very, very white theme high bgcolor_row2 "#cccccc" # Dark gray theme high bgcolor_status "#ffffcc" # Yellow theme high bgcolor_status_none "#ccffcc" # Green theme high fgcolor_quote1 "#800000" # Brick Red theme high fgcolor_quote2 "#008000" # Green theme high fgcolor_quote3 "#000080" # Blue theme high fgcolor_quote4 "#ff0000" # Orange theme help description "Default Help Text theme" theme help fgcolor "#000000" # Black theme help fgcolor_link "#0000ff" # Dark Blue theme help bgcolor "#ffffcc" # Yellow theme help bgcolor_banner "#66ffff" # Darkish Blue theme help bgcolor_row1 "#ccffff" # Light Blue theme help bgcolor_row2 "#99ffff" # Middle Blue theme help bgcolor_status "#ccffff" # Light Blue theme help bgcolor_status_none "#ccffcc" # Green theme help fgcolor_quote1 "#800000" # Brick Red theme help fgcolor_quote2 "#008000" # Green theme help fgcolor_quote3 "#000080" # Blue theme help fgcolor_quote4 "#ff0000" # Orange theme_default_main = gray theme_default_help = help ###################################################################### # Default user preferences # Let users disable Raven logins if they really want to. allow_raven_login = TRUE # Confirmation dialogue when user logs out confirm_logout = TRUE # Confirmation dialogue when user hits expunge confirm_expunge = FALSE # Confirmation dialogue when user deletes mail folder or directory confirm_rm = TRUE # Expunge deleted messages from INBOX automatically on logout? expunge_on_exit = FALSE # Number of messages per screen on message list screen msgs_per_page = 10 # Max Number of messages per screen on message list screen msgs_per_page_max = 50 # Min Number of messages per screen on message list screen msgs_per_page_min = 4 # Number of addressbook entries per page on abook_list screen abook_per_page = 10 # Max Number of addressbook entries per page on abook_list screen abook_per_page_max = 50 # Min Number of addressbook entries per page on abook_list screen abook_per_page_min = 4 # Supress dotfiles from directory listing suppress_dotfiles = TRUE # Mail directory in user's account maildir = "" # Use IMAP NAMESPACE command to find personal_hierarchy and hiersep use_namespace = TRUE # If not supplied by NAMESPACE personal_hierarchy = "" # If not supplied by NAMESPACE hiersep = "/" # Dual use mailboxes dualuse = TRUE # Names of postponed_folder and sent_mail_folder, relative to maildir postponed_folder = "postponed-msgs" sent_mail_folder = "sent-mail" # Default domain for outgoing mail. Defaults to "$hostname". # default_domain = "" # Language for ispell. ispell_language = "british" # Only works with aspell spell_skip_quoted = TRUE # Size of small and large compose windows small_cols = 80 small_rows = 14 large_cols = 80 large_rows = 24 # Default Sort mode for mailbox list. One of: # ARRIVAL, DATE, FROM, TO, CC, SIZE, SUBJECT, REFERENCES, ORDEREDSUBJECT # # ARRIVAL is most efficient, and recommended # sort_mode = ARRIVAL # Favour reverse sort rather than normal sort order? sort_reverse = FALSE # Default Sort mode for addressbook list. One of: # ORDERED, ALIAS, NAME, COMMENT, ADDRESS abook_sort_mode = ORDERED # Favour reverse sort rather than normal sort order? abook_sort_reverse = FALSE # Wrap lines at this many characters line_wrap_len = 76 # Enabled advanced line wrap options? line_wrap_advanced = FALSE # Line wrap automaticaly on reply. line_wrap_on_reply = TRUE # Line wrap automaticaly on spell check. line_wrap_on_spell = TRUE # Line wrap automaticaly on send. line_wrap_on_send = TRUE # sent_mail item on compose screen by default use_sent_mail = TRUE # Use persistent mark for aggregate operations use_mark_persist = FALSE # Zoom automatically after sucessful search use_search_zoom = TRUE # Unmake messages after sucessful aggregate operation use_agg_unmark = TRUE # Use icons: may be overriden by value of User-Agent use_icons = TRUE # Enable welcome screen use_welcome = TRUE # Duplicate banner icons on certain screens. use_tail_banner = TRUE # Use HTTP cookie for Session-ID, if the browser supports cookies # If disabled, or user rejects cookie, then session-ID is stored in URL. use_cookie = TRUE # Use page substiution rather than HTTP redirects. Faster, but the URLs # that are generated are less predictable. Page substitution and browser # history mechanism don't coexist well at the moment (Prayer would need to # cache final page value for each substiution event). use_substitution = FALSE # Allow HTTP/1.1, if the browser supports it use_http_1_1 = TRUE # Allow HTTP/1.1 pipelining, if the browser supports it use_pipelining = TRUE # Allow persistent HTTP/1.1 and HTTP/1.0 persistent connections, # if the browser supports them use_persist = TRUE # Allow short URLs, if the browser supports them use_short = TRUE # Allow gzip compression, if the browser supports it use_gzip = TRUE # Show text/html bodyparts inline. Content is scrubbed to remove # dangerous tags: see documentation for more details. # # text/html will be displayed in preference to text/plain if this is set. html_inline = TRUE # Show remote images automatically. If this is not set, "Show unsafe images" # will appear on pages showing HTML mail. html_remote_images = FALSE # Same as above for text/* bodyparts which start "" (case-independant!) # Does anyone other than spammers actually use this? html_inline_auto = TRUE # Send message mime-type through to browser. If FALSE then mime-type # is replaced with "application/octet-stream" which should force # download to local disk, bypassing any automatic processing of bodyparts # by the User-Agent. Unclear at the moment whether we need to do this, # or whether this should be done selectively based on the User-Agent preserve_mimetype = TRUE ./prayer-1.3.5/servers/prayer.h0000644006513000651300000000453111071070744014741 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/prayer.h,v 1.4 2008/10/02 07:01:56 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Global state for Prayer frontend processes */ struct prayer_http_port { struct prayer_port *next; /* Linked list */ char *name; /* NIL */ unsigned long port; /* Port number */ int sockfd; /* Socket descriptor bound to this port */ BOOL use_ssl; /* T => connections to this port will use SSL */ }; struct prayer { struct pool *pool; /* Allocation pool */ struct config *config; /* Prayer configuration */ struct request *request; /* Current HTTP request to process */ struct log *accesslog; struct list *http_port_list; /* Port list */ int select_lock_fd; /* Prevents concurrent select() */ /* Details about current connection */ struct ipaddr *ipaddr; /* IP address of peer */ unsigned long port; /* Port of active request */ BOOL use_ssl; /* Current requests uses SSL */ BOOL is_session; /* _last_ request was for session URL */ struct template_vals *template_vals; /* Filled in for each new template */ }; struct prayer *prayer_create(struct config *config); void prayer_free(struct prayer *prayer); char *prayer_url_prefix(struct prayer *prayer, struct pool *tpool); void prayer_template_setup(struct prayer *prayer); BOOL prayer_log_open(struct prayer *prayer); BOOL prayer_log_ping(struct prayer *prayer); BOOL prayer_lock_open(struct prayer *prayer); BOOL prayer_http_port_open(struct prayer *prayer, unsigned long port, BOOL use_ssl, char *interface); BOOL prayer_http_port_close(struct prayer *prayer); BOOL prayer_http_port_alloc(struct prayer *prayer, unsigned long port, BOOL use_ssl, int sockfd); void prayer_accesslog(struct prayer *prayer, struct request *request); void prayer_connection_log(struct prayer *prayer, char *fmt, ...); void prayer_paniclog(struct prayer *prayer, char *fmt, ...); void prayer_fatal(struct prayer *prayer, char *fmt, ...); ./prayer-1.3.5/servers/prayer.c0000644006513000651300000002053111415113363014727 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/prayer.c,v 1.6 2010/07/07 15:02:11 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_shared.h" #include "prayer.h" #include "prayer_server.h" /* Support routines for "prayer" frontend HTTP server and proxy */ /* prayer_create() ****************************************************** * * Create a prayer structure, used to bind all other global state * config: Prayer configuration * * Returns: Ptr to prayer structure, using own pool. ***********************************************************************/ struct prayer *prayer_create(struct config *config) { struct pool *pool = pool_create(sizeof(struct prayer)); struct prayer *prayer = pool_alloc(pool, sizeof(struct prayer)); prayer->pool = pool; prayer->config = config; prayer->request = NIL; prayer->accesslog = log_create(config, NIL); prayer->http_port_list = list_create(pool, T); prayer->select_lock_fd = -1; /* Use session timeouts for initial exchange */ prayer->ipaddr = ipaddr_create(pool); prayer->port = 0L; prayer->use_ssl = NIL; prayer->is_session = T; prayer->template_vals = NIL; return (prayer); } /* prayer_free() ******************************************************** * * Free a prayer instance. Closes log fd if open as well * prayer: Prayer structure ***********************************************************************/ void prayer_free(struct prayer *prayer) { log_free(prayer->accesslog); pool_free(prayer->pool); } /* ====================================================================== */ /* prayer_url_prefix() ************************************************** * * Generate a URL prefix from prayer structure for current active port. * prayer: * tpool: Target pool * * Returns: URL prefix ***********************************************************************/ char *prayer_url_prefix(struct prayer *prayer, struct pool *tpool) { struct config *config = prayer->config; if (prayer->use_ssl) { if (prayer->port == 443) return (pool_printf(tpool, "https://%s", config->hostname)); return (pool_printf(tpool, "https://%s:%d", config->hostname, prayer->port)); } if (prayer->port == 80) return (pool_printf(tpool, "http://%s", config->hostname)); return (pool_printf(tpool, "http://%s:%d", config->hostname, prayer->port)); } /* prayer_template_setup() ********************************************* * * Initialise prayer->template_vals if we are going to template_expand() * prayer: * ***********************************************************************/ void prayer_template_setup(struct prayer *prayer) { struct request *request = prayer->request; struct config *config = prayer->config; prayer->template_vals = template_vals_create (request->pool, config->template_path, config->template_set, config->template_use_compiled, T, template_vals_urlstate_create(request->pool)); template_vals_string(prayer->template_vals, "$url_prefix", prayer_url_prefix(prayer, request->pool)); if (config->login_service_name) template_vals_string(prayer->template_vals, "g_service_name", config->login_service_name); } /* ====================================================================== */ /* prayer_log_open() **************************************************** * * Open log file (but only after setup procedure complete and running * as correct user and group!) * prayer: Prayer structure ***********************************************************************/ BOOL prayer_log_open(struct prayer * prayer) { return (log_open(prayer->accesslog, "access_log")); } /* prayer_log_ping() **************************************************** * * Reopen log file. * prayer: Prayer structure ***********************************************************************/ BOOL prayer_log_ping(struct prayer * prayer) { return (log_ping(prayer->accesslog)); } /* ====================================================================== */ /* prayer_http_port_open() ********************************************** * * Open HTTP port * prayer: Prayer structure * port: Port to bind * use_ssl: Flag that this port will be used for SSL connections when * active. * interface:Interface to bind to. * * Returns: T on success. NIL => couldn't bind to port ***********************************************************************/ BOOL prayer_http_port_open(struct prayer * prayer, unsigned long port, BOOL use_ssl, char *interface) { int *sockfds, i; struct prayer_http_port *fhp; if (!(sockfds = os_bind_inet_socket(port, interface))) return (NIL); /* Result is list of sockfds, terminated by negative number */ for (i=0; sockfds[i] >= 0; i++) { fhp = pool_alloc(prayer->pool, sizeof(struct prayer_http_port)); fhp->port = port; fhp->use_ssl = use_ssl; fhp->sockfd = sockfds[i]; list_push(prayer->http_port_list, (struct list_item *) fhp, NIL); } return (T); } /* ====================================================================== */ /* prayer_http_port_alloc() ********************************************* * * Add prayer_http_port to end of active list. Used by prayer to reproduce * the work above if it execs itself after ports are opened and setuid() * called in order to lose root process coredump paranoia. * prayer: Prayer structure * use_ssl: Indicate that this will be a SSL port * sockfd: Socket that is bound to this port ***********************************************************************/ BOOL prayer_http_port_alloc(struct prayer * prayer, unsigned long port, BOOL use_ssl, int sockfd) { struct prayer_http_port *fhp; fhp = pool_alloc(prayer->pool, sizeof(struct prayer_http_port)); fhp->port = port; fhp->use_ssl = use_ssl; fhp->sockfd = sockfd; list_push(prayer->http_port_list, (struct list_item *) fhp, NIL); return (T); } /* ====================================================================== */ /* prayer_http_port_close() ********************************************* * * Close all HTTP ports bound by this prayer structure. * prayer: Prayer structure ***********************************************************************/ BOOL prayer_http_port_close(struct prayer * prayer) { struct list_item *li; if (prayer->http_port_list) { for (li = prayer->http_port_list->head; li; li = li->next) { struct prayer_http_port *fhp = (struct prayer_http_port *) li; close(fhp->sockfd); } } return (T); } /* ====================================================================== */ /* Interface to logging subsystem that picks up on prayer state */ void prayer_accesslog(struct prayer *prayer, struct request *request) { unsigned long size; char *http_request = (request->log_entry) ? request->log_entry : request->request; if (request->gzip_buffer) size = buffer_size(request->gzip_buffer); else size = buffer_size(request->write_buffer); log_here(prayer->accesslog, "[%s] (%lu) %s -> %lu %lu %s", ipaddr_text(prayer->ipaddr), prayer->port, http_request, request->status, size, ((request->use_http_1_1) ? "1.1" : "1.0")); } /* Compatibility Interface to new fangled panic log system... */ void prayer_paniclog(struct prayer *prayer, char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = log_entry_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_panic_ap(prayer->config, NIL, len, fmt, ap); va_end(ap); } void prayer_fatal(struct prayer *prayer, char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = log_entry_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_panic_ap(prayer->config, NIL, len, fmt, ap); va_end(ap); /* Generate core dump */ abort(); } ./prayer-1.3.5/servers/session_unix.c0000644006513000651300000002234711413374146016170 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_unix.c,v 1.4 2010/07/02 14:32:06 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "server.h" /* Set of routines to manage incoming connections via proxy HTTP server * frontend */ /* session_unix_process_connection() ************************************ * * Process incoming connection from frontend server (HTTP single shot). * session: * sockfd: Socket descriptor for incoming connection. ************************************************************************/ static void session_unix_process_connection(struct session *session, int sockfd) { struct config *config = session->config; struct iostream *stream = iostream_create(NIL, sockfd, 0); struct request *request = request_create(config, stream, NIL); struct ipaddr remote; int byte0, byte1; /* Set a (Long) timeout as backstop in case frontend goes into loop */ iostream_set_timeout(stream, config->session_timeout); session->request = request; request->user_agent = user_agent_clone(request->pool, session->user_agent); if (session->config->http_dump) request_dump(request); if (session->telemetry) request_telemetry(request, session->telemetry_fd, session->telemetry_all); /* Proxy: request follows IP address */ if (!ipaddr_fetch_iostream(&remote, stream)) { struct buffer *b = request->write_buffer; html_common_start(config, b, "Protocol error"); bputs(b, "Protocol error: couldn't determine IP address of peer."); html_common_end(b); response_html(request, 404); ioputc('0', request->stream); response_send(request); log_misc ("Couldn't determine IP address of peer for running session %s", session->url_prefix_asession); iostream_close(stream); request_free(request); return; } if (config->fix_client_ipaddr && !ipaddr_compare(session->ipaddr, &remote)) { struct buffer *b = request->write_buffer; html_common_start(config, b, "Security Alert"); bputs(b, "Security alert: this session did not login "); bputs(b, "from this IP address. Please login properly" CRLF); html_common_end(b); response_html(request, 404); ioputc('0', request->stream); response_send(request); log_misc ("HTTP Request from invalid IP address %s to running session %s", ipaddr_text(&remote), session->url_prefix_asession); iostream_close(stream); request_free(request); return; } if (((byte0 = iogetc(stream)) == EOF) || ((byte1 = iogetc(stream)) == EOF)) { struct buffer *b = request->write_buffer; html_common_start(config, b, "Protocol error"); bputs(b, "Protocol error: couldnt determine process ID of peer"); html_common_end(b); response_html(request, 404); ioputc('0', request->stream); response_send(request); log_misc("Couldn't determine process ID of peer", session->url_prefix_asession); iostream_close(stream); request_free(request); return; } session->frontend_pid = (byte0 * 256) + byte1; if (request_parse(request)) session_exchange(session); /* Send single response to frontend */ else if (!request->iseof) response_error(request, request->status); if (request->persist) { ioputc('1', request->stream); } else { ioputc('0', request->stream); } response_send(request); session_accesslog(session, request); iostream_close(stream); request_free(request); session->request = NIL; } /* ====================================================================== */ /* session_unix_loop() ************************************************** * * Master loop for single login session using proxy server * session: * sockfd: Socket descriptor for Unix domain socket. * (the thing that we are going to accept() on). ************************************************************************/ static BOOL session_unix_loop(struct session *session, int sockfd) { struct config *config = session->config; int newsockfd; fd_set readfds; unsigned long timeout = 0; int rc; BOOL idle = NIL; char *last_cmd; int use_compose_timeout; /* Requests should queue on sockfd until we are ready to serve them */ for (;;) { last_cmd = memblock_string(session->last_cmd); use_compose_timeout = NIL; if ((config->session_timeout_compose > 0) && (!strcmp(last_cmd, "compose") || !strcmp(last_cmd, "sieve"))) use_compose_timeout = T; if (idle) { if (use_compose_timeout) timeout = (config->session_timeout_compose - config->session_idle_time); else if ((config->session_timeout > 0)) timeout = config->session_timeout - config->session_idle_time; } else { if (config->session_idle_time > 0) timeout = config->session_idle_time; else if (use_compose_timeout) timeout = config->session_timeout_compose; else timeout = config->session_timeout; } FD_ZERO(&readfds); FD_SET(sockfd, &readfds); if (timeout > 0) { struct timeval timeval; timeval.tv_sec = timeout; timeval.tv_usec = 0; do { rc = select(sockfd + 1, &readfds, NIL, NIL, &timeval); } while ((rc < 0) && (errno == EINTR)); } else { do { rc = select(sockfd + 1, &readfds, NIL, NIL, NIL); } while ((rc < 0) && (errno == EINTR)); } if ((rc < 0) && (errno != EINTR)) { session_paniclog(session, "[session_unix_loop()] select() failed, errno = %d", errno); return (NIL); } /* Reopen logs if required */ session_log_ping(session); log_misc_ping(); if (!FD_ISSET(sockfd, &readfds)) { if (!idle && (config->session_idle_time > 0)) { session_log(session, "[session_unix_loop] Session going to sleep"); session_streams_idle(session); idle = T; continue; } session_log(session, "[session_unix_loop] Session timed out"); break; } if (idle) { session_log(session, "[session_unix_loop] Idle session waking up"); idle = NIL; } if ((newsockfd = os_accept_unix(sockfd)) < 0) return (NIL); /* Following will always close newsockfd */ session_unix_process_connection(session, newsockfd); if (session->want_disconnect) /* Either client or servers wants out */ break; } return (T); } /* ====================================================================== */ /* session_unix() ******************************************************** * * Run session using unix domain socket for communication via proxy frontend * session: * stream: iostream connection to prayer frontend. Used to send * URL for sucessful login request. * * Returns: T if session successful. NIL => startup error. ************************************************************************/ BOOL session_unix(struct session * session, struct iostream * stream) { struct config *config = session->config; int sockfd; char *name; unsigned long pid = (unsigned long)getpid(); session->is_direct = NIL; /* Unix domain socket */ /* Need to set up, bind() and listen() on session stream before * we send any response to the frontend. Otherwise race condition * exists: frontend might try to connect to non-existant session... */ if (config->socket_split_dir) name = pool_printf(NIL, "%s/%c/%s:%lu:%s", config->socket_dir, session->sessionid[0], session->username, pid, session->sessionid); else name = pool_printf(NIL, "%s/%s:%lu:%s", config->socket_dir, session->username, pid, session->sessionid); if ((sockfd = os_bind_unix_socket(name)) < 0) { ioputs(stream, "NO Server failed to initialise" CRLF); ioflush(stream); iostream_close(stream); return (NIL); } /* Login suceeded: okay to tell frontend where to find us now! */ ioprintf(stream, "OK %s@init" CRLF, session->url_prefix_session); ioflush(stream); iostream_close(stream); setproctitle("Login session for %s", session->username); /* Start session loop: accept process connections */ session_unix_loop(session, sockfd); close(sockfd); /* Finished with socket file: remove */ unlink(name); free(name); return (T); } ./prayer-1.3.5/servers/prayer_server.c0000644006513000651300000007133111413375357016334 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/prayer_server.c,v 1.12 2010/07/02 14:42:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_shared.h" #include "prayer.h" #include "prayer_login.h" #include "prayer_server.h" static void prayer_compose_dump(struct prayer *prayer, struct request *request, char *user) { struct template_vals *tvals = prayer->template_vals; struct buffer *b = request->write_buffer; struct assoc *h = NIL; char *s; request_decode_form(request); h = request->form; template_vals_string(tvals, "user", user); if ((s=assoc_lookup(h, "hdr_To"))) template_vals_string(tvals, "$hdr_to", s); if ((s=assoc_lookup(h, "hdr_Cc"))) template_vals_string(tvals, "$hdr_cc", s); if ((s=assoc_lookup(h, "hdr_Bcc")) && s[0]) template_vals_string(tvals, "$hdr_bcc", s); if ((s=assoc_lookup(h, "hdr_Fcc")) && s[0]) template_vals_string(tvals, "$hdr_fcc", s); if ((s=assoc_lookup(h, "hdr_Reply_To")) && s[0]) template_vals_string(tvals, "$hdr_reply_to", s); if ((s=assoc_lookup(h, "hdr_Subject"))) template_vals_string(tvals, "$hdr_subject", s); if ((s=assoc_lookup(h, "body"))) template_vals_string(tvals, "body", s); template_expand("frontend_compose_timeout", tvals, b); } /* check_argv_valid_() *************************************************** * * Check that the username argument supplied in URL looks sane before * we try to build the path to a socket using it. Should be a short * but not empty string without any "/" or ".." sequences. * ************************************************************************/ static BOOL check_argv_valid(char *s) { if (!(s && s[0] && (strlen(s) < 32))) return(NIL); /* Check for ".." or "/" embedded into username */ while (*s) { if (s[0] == '/') return(NIL); if ((s[0] == '.') && (s[1] == '.')) return(NIL); s++; } return(T); } static void generate_connect_error_page(struct prayer *prayer) { struct request *request = prayer->request; struct buffer *b = request->write_buffer; struct template_vals *tvals = prayer->template_vals; char *username = ""; char *s; prayer_template_setup(prayer); tvals = prayer->template_vals; if (request->argc >= 1) { username = pool_strdup(request->pool, request->argv[1]); if ((s=strchr(username, ':'))) *s = '\0'; template_vals_string(tvals, "user", username); } if ((request->argc >= 5) && (!strcmp(request->argv[4], "compose")) && (request->method == POST)) { prayer_compose_dump(prayer, request, username); } else { template_expand("frontend_timeout", tvals, b); } response_html(request, 404); } /* prayer_process_session_request() ************************************** * * Process a session URL: connect to session server and proxy request * verbatim there ************************************************************************/ static BOOL prayer_process_session_request(struct prayer *prayer) { struct config *config = prayer->config; struct request *request = prayer->request; struct buffer *b = request->write_buffer; struct iostream *stream; int fd, c; BOOL persist; char *socketname; /* Blind proxy to backend server */ prayer->is_session = T; /* Check that the user hasn't foolishly removed the s from https */ if (!prayer->use_ssl && config->ssl_required) { response_error(request, 403); /* Forbidden */ response_send(request); prayer_accesslog(prayer, request); return (NIL); } /* argv: /session/username/session/... */ if (request->argc < 3) { response_error(request, 404); response_send(request); prayer_accesslog(prayer, request); return (NIL); } /* Decode username+pid argument */ string_url_decode(request->argv[1]); /* Check decoded string for sneakiness */ if (!check_argv_valid(request->argv[1])) { response_error(request, 404); response_send(request); prayer_accesslog(prayer, request); return (NIL); } /* Replace empty argv[2] with "CRSid=session" value if cookie exists */ if (request->argv[2][0] == '\0') { char *s = assoc_lookup(request->hdrs, "cookie"); char *t; char *u; /* Need cookie parsing library? */ while (s && *s && (t = strchr(s, '='))) { *t++ = '\0'; if ((u = strchr(t, ';'))) *u++ = '\0'; if (!strcmp(string_trim_whitespace(s), request->argv[1])) { request->argv[2] = string_trim_whitespace(t); break; } s = u; } } /* No session id, even after cookie lookup */ if (request->argv[2][0] == '\0') { generate_connect_error_page(prayer); /* Do we need to kill session cookie? Next login should kill anyway */ request->persist = NIL; response_send(request); prayer_accesslog(prayer, request); return (NIL); } /* Check decoded string for sneakiness */ if (!check_argv_valid(request->argv[2])) { response_error(request, 404); response_send(request); prayer_accesslog(prayer, request); return (NIL); } if (config->socket_split_dir) { socketname = pool_printf(request->pool, "%s/%c/%s:%s", config->socket_dir, request->argv[2][0], request->argv[1], request->argv[2]); fd = os_connect_unix_socket(socketname); /* Backwards compatibility */ if (fd < 0) { socketname = pool_printf(request->pool, "%s/%s:%s", config->socket_dir, request->argv[1], request->argv[2]); fd = os_connect_unix_socket(socketname); } } else { socketname = pool_printf(request->pool, "%s/%s:%s", config->socket_dir, request->argv[1], request->argv[2]); fd = os_connect_unix_socket(socketname); /* Forwards compatibility */ if (fd < 0) { socketname = pool_printf(request->pool, "%s/%c/%s:%s", config->socket_dir, request->argv[2][0], request->argv[1], request->argv[2]); fd = os_connect_unix_socket(socketname); } } if (fd < 0) { generate_connect_error_page(prayer); /* Do we need to kill session cookie? Next login should kill anyway */ request->persist = NIL; response_send(request); prayer_accesslog(prayer, request); return (NIL); } stream = iostream_create(request->pool, fd, 0); /* Set a (Long) timeout as backstop in case session goes into loop */ iostream_set_timeout(stream, config->session_timeout); /* Copy IP address through to the session server */ ipaddr_send_iostream(prayer->ipaddr, stream); /* Send Process ID to backend for logging purposes */ ioputc((getpid() / 256), stream); ioputc((getpid() % 256), stream); /* Copy buffer verbatim */ buffer_rewind(request->read_buffer); while ((c = bgetc(request->read_buffer)) != EOF) ioputc(c, stream); /* Flush data to backend */ ioflush(stream); /* Bail out if far end died */ if (stream->oerror) { iostream_close(stream); return (NIL); } /* Get persist status byte from backend */ if ((c = iogetc(stream)) == EOF) { iostream_close(stream); return (NIL); } /* First byte sent to proxy is '1' or '0' indicating Keep-Alive state */ persist = (c == '1'); /* Now fetch entire response from backend before we start to pass it * on. This way backend isn't stalled if prayer is passing data on * across slow link and user shuts us down */ while ((c = iogetc(stream)) != EOF) bputc(b, c); /* Finished with this connection to backup */ iostream_close(stream); /* Pass cached copy onto client */ buffer_rewind(b); while ((c = bgetc(b)) != EOF) ioputc(c, request->stream); return (persist); } /* ====================================================================== */ /* prayer_process_request_internal() ************************************** * * Process a single request to prayer frontend server * prayer: Global state * request: (Complete) HTTP request to process * offset: Offset into request argv array: allows us to skip over * metadata ************************************************************************/ static void prayer_process_request_internal(struct prayer *prayer, struct request *request) { struct config *config = prayer->config; int argc = request->argc; char **argv = &request->argv[0]; /* Icons, if configured */ if (config->icon_dir && (argc == 2) && !strcmp(argv[0], "icons")) { char *filename = pool_strcat3(request->pool, config->icon_dir, "/", argv[1]); if ((request->method == GET) || (request->method == HEAD)) { /* Send an icon */ response_file(request, request->method, filename, config->icon_expire_timeout, assoc_lookup(request->hdrs, "if-modified-since")); } else response_error(request, 501); /* Not implemented */ return; } /* Static files (CSS/JS), if configured */ if (config->static_dir && (argc == 2) && !strcmp(argv[0], "static")) { char *filename = pool_strcat3(request->pool, config->static_dir, "/", argv[1]); if ((request->method == GET) || (request->method == HEAD)) { response_file(request, request->method, filename, config->static_expire_timeout, assoc_lookup(request->hdrs, "if-modified-since")); } else response_error(request, 501); /* Not implemented */ return; } /* Cope with "/robots.txt" */ if ((argc == 1) && (!strcasecmp(argv[0], "robots.txt"))) { struct buffer *b = request->write_buffer; bputs(b, "User-agent: *" CRLF); bputs(b, "Disallow: /session" CRLF); bputs(b, "Disallow: /login" CRLF); bputs(b, "Disallow: /icons" CRLF); response_text(request, 200); return; } /* Cope with /login/.../xyz screen */ if ((argc == 2) && (!strcmp(argv[0], "login"))) { string_url_decode(request->argv[1]); prayer_login(prayer, request->argv[1]); return; } /* Deal with /raven request */ if ((argc == 1) && (!strcmp(argv[0], "raven"))) { prayer_login_raven(prayer); return; } /* Page not found for anything other than the login page */ if (argc > 0) { response_error(request, 404); return; } prayer_login_preamble(prayer); } /* ====================================================================== */ /* prayer_process_request() ********************************************** * * Process a single request to prayer frontend server. * prayer: Global state * request: (Complete) HTTP request to process ************************************************************************/ static BOOL prayer_process_request(struct prayer *prayer, struct request *request) { prayer->is_session = NIL; prayer_process_request_internal(prayer, request); response_send(request); prayer_accesslog(prayer, request); return (request->persist); } /* ====================================================================== */ /* prayer_process_connection() ******************************************* * * Process HTTP connection (which may consist of one or many separate * HTTP requests). * prayer: * sockfd: Socket descriptor for incoming connection ************************************************************************/ static BOOL prayer_process_connection(struct prayer *prayer, int sockfd) { struct config *config = prayer->config; struct iostream *stream; BOOL persist; unsigned long request_count; stream = iostream_create(prayer->pool, sockfd, 0); iostream_set_timeout(stream, config->http_timeout_icons); if (prayer->use_ssl && !iostream_ssl_start_server(stream)) { log_misc("Invalid https connection from %s on port %lu", ipaddr_text(prayer->ipaddr), prayer->port); iostream_close(stream); return (NIL); } log_misc("Incoming %s connection from %s on port %lu", (prayer->use_ssl) ? "https" : "http", ipaddr_text(prayer->ipaddr), prayer->port); prayer->is_session = T; /* Until we know better */ request_count = 0; do { struct request *request = request_create(config, stream, T); struct user_agent *user_agent = user_agent_create(request->pool); prayer->request = request; request->user_agent = user_agent; if (prayer->is_session) iostream_set_timeout(stream, config->http_timeout_session); else iostream_set_timeout(stream, config->http_timeout_icons); setproctitle("%s %s connection from %s on port %lu", (prayer->is_session) ? "Session" : "Icon", (prayer->use_ssl) ? "https" : "http", ipaddr_text(prayer->ipaddr), prayer->port); if (!request_parse(request)) { /* EOF or badly forwarded request */ if (!request->iseof) { response_error(request, request->status); response_send(request); log_misc("Invalid %s request: %s", (prayer->use_ssl) ? "https" : "http", request->request); } request_free(request); break; } /* Do something useful with HTTP/0.9 request */ if (request->major == 0) { response_0_9_error(request); response_send(request); log_misc("Invalid %s request (0.9 format): %s", (prayer->use_ssl) ? "https" : "http", request->request); break; } /* Got a valid request: process it */ request_count++; /* Set up browser specific options and workarounds, e.g: * Lynx and w3m don't need icons * Netscape 4 needs some delibarately broken markup to work properly. * Some old versions of Mac Mozilla have broken SSL implementations. */ user_agent_setup_browser(user_agent, assoc_lookup(request->hdrs, "user-agent")); request_parse_argv(request); if ((request->argc > 0) && !strcmp(request->argv[0], "session")) { persist = prayer_process_session_request(prayer); } else persist = prayer_process_request(prayer, request); if (persist && request->use_http_1_1 && user_agent->use_pipelining && iostream_have_input(request->stream)) log_misc("Pipelining on port %lu", prayer->port); else if (!ioflush(request->stream)) persist = NIL; /* Close connection if we failed to sent to UA */ request_free(request); /* Ping access and miscellaneous logs every few minutes */ prayer_log_ping(prayer); log_misc_ping(); } while (persist); iostream_close(stream); if (request_count != 1) log_misc("Closing %s connection, %lu valid requests processed", (prayer->use_ssl) ? "https" : "http", request_count); else log_misc("Closing %s connection, 1 valid request processed", (prayer->use_ssl) ? "https" : "http"); return (T); } /* ====================================================================== */ /* ====================================================================== */ /* prayer_server_single() ************************************************ * * Single server instance used simple fork server * prayer: Global state * foreground: T => Run in foreground: don't fork off child processes * sockfd: Socket descriptor (thing that we accept() on) * port: Port associated with this socket descriptor * use_ssl: Use SSL for connections to this port ************************************************************************/ static BOOL prayer_server_single(struct prayer *prayer, BOOL foreground, int sockfd, unsigned long port, BOOL use_ssl) { int newsockfd; int childpid; struct ssl_config ssl_config; config_extract_ssl(prayer->config, &ssl_config); prayer->port = port; prayer->use_ssl = use_ssl; prayer->is_session = T; /* Until we know better */ if ((newsockfd = os_accept_inet(sockfd, prayer->ipaddr)) < 0) return (NIL); /* May be transcient error: continue */ if (foreground) { /* prayer_process_connection() always closes newsockfd */ prayer_process_connection(prayer, newsockfd); return (T); } if ((childpid = fork()) < 0) { prayer_paniclog(prayer, "[prayer_server_single()] fork() failed: %s", strerror(errno)); /* May be transcient error: continue */ } if (childpid == 0) { /* Child process */ if (!os_signal_child_clear()) abort(); close(sockfd); /* Make sure that RSAkey isn't going to expire immediately */ iostream_freshen_rsakey(&ssl_config); /* prayer_process_connection() always closes newsockfd */ prayer_process_connection(prayer, newsockfd); exit(0); } /* Parent */ close(newsockfd); return (T); } /* ====================================================================== */ /* prayer_server() ******************************************************* * * Master server routine for simple fork()/exec() server. * prayer: Global configuration * foreground: Run in foreground rather than forking off children ************************************************************************/ BOOL prayer_server(struct prayer * prayer, BOOL foreground) { struct list_item *li; fd_set fds; int maxsockfd; struct ssl_config ssl_config; config_extract_ssl(prayer->config, &ssl_config); if (!os_signal_child_init(os_child_reaper)) return (NIL); log_misc("Frontend master server started okay"); setproctitle("Master server"); for (;;) { FD_ZERO(&fds); maxsockfd = 0; for (li = prayer->http_port_list->head; li; li = li->next) { struct prayer_http_port *fhp = (struct prayer_http_port *) li; FD_SET(fhp->sockfd, &fds); if (fhp->sockfd > maxsockfd) maxsockfd = fhp->sockfd; } while (select(maxsockfd + 1, &fds, NIL, NIL, NIL) < 0) { if (errno != EINTR) prayer_fatal(prayer, "prayer_server(): select() failed: %s", strerror(errno)); } for (li = prayer->http_port_list->head; li; li = li->next) { struct prayer_http_port *fhp = (struct prayer_http_port *) li; if (FD_ISSET(fhp->sockfd, &fds)) prayer_server_single(prayer, foreground, fhp->sockfd, fhp->port, fhp->use_ssl); } /* Replace (shared) RSA key every few minutes */ iostream_check_rsakey(&ssl_config); /* Ping access and miscellaneous logs every few minutes */ prayer_log_ping(prayer); log_misc_ping(); } return (T); } /* ====================================================================== */ /* ====================================================================== */ /* Prefork version */ /* prayer_slave_server() ************************************************* * * Single server instance used by prefork server. * prayer: Global state * mymutex: Mymutex for select/accept cycle * parentfd: Connection to parent process. Close to indicate that * this child process is now active. ************************************************************************/ static BOOL prayer_slave_server(struct prayer *prayer, struct mymutex *mymutex, int parentfd) { struct prayer_http_port *fhp; struct config *config = prayer->config; unsigned long max_connections = config->http_max_connections; struct list_item *li; fd_set fds; int maxsockfd; int newsockfd; int rc; unsigned long connect_count; unsigned long mymutex_timeout; struct ssl_config ssl_config; config_extract_ssl(config, &ssl_config); if (!os_signal_child_init(os_child_reaper)) return (NIL); if (!mymutex_slave_init(mymutex)) return(NIL); log_misc("Frontend slave server started okay"); for (connect_count = 0; ((max_connections == 0) || (connect_count < max_connections)); connect_count++) { FD_ZERO(&fds); maxsockfd = 0; for (li = prayer->http_port_list->head; li; li = li->next) { struct prayer_http_port *fhp = (struct prayer_http_port *) li; FD_SET(fhp->sockfd, &fds); if (fhp->sockfd > maxsockfd) maxsockfd = fhp->sockfd; } setproctitle("Spare slave server"); if ((connect_count > 0) && (config->http_timeout_idle > 0)) mymutex_timeout = config->http_timeout_idle; else mymutex_timeout = 0; if (!mymutex_on(mymutex, mymutex_timeout)) break; setproctitle("Active slave server"); if ((connect_count > 0) && (config->http_timeout_idle)) { struct timeval timeout; timeout.tv_sec = config->http_timeout_idle; timeout.tv_usec = 0; do { rc = select(maxsockfd + 1, &fds, NIL, NIL, &timeout); } while ((rc < 0) && (errno == EINTR)); } else { do { rc = select(maxsockfd + 1, &fds, NIL, NIL, NIL); } while ((rc < 0) && (errno == EINTR)); } /* This slave server is now busy, will die after timeout */ /* Tell parent to start up fresh spare slave server */ if (parentfd >= 0) { close(parentfd); parentfd = -1; } if (rc < 0) prayer_fatal(prayer, "prayer_server(): select() failed: %s", strerror(errno)); /* Shut down connection on timeout */ if (rc == 0) break; /* Ping access and miscellaneous logs every few minutes */ prayer_log_ping(prayer); log_misc_ping(); for (li = prayer->http_port_list->head; li; li = li->next) { fhp = (struct prayer_http_port *) li; if (FD_ISSET(fhp->sockfd, &fds)) break; } if (li == NIL) prayer_fatal(prayer, "prayer_server(): select() returned with no fds set"); fhp = (struct prayer_http_port *) li; prayer->port = fhp->port; prayer->use_ssl = fhp->use_ssl; prayer->is_session = T; /* Until we know better */ newsockfd = os_accept_inet(fhp->sockfd, prayer->ipaddr); if (!mymutex_off(mymutex)) prayer_fatal(prayer, "prayer_server(): failed to release lock: %s", strerror(errno)); if (newsockfd < 0) continue; /* May be transcient error: continue */ /* Make sure that RSAkey isn't going to expire immediately */ iostream_freshen_rsakey(&ssl_config); prayer_process_connection(prayer, newsockfd); close(newsockfd); } mymutex_slave_cleanup(mymutex); return (T); } /* ====================================================================== */ static unsigned long prayer_prefork_children = 0; static void prayer_prefork_child_reaper() { int status; pid_t child; do { child = waitpid(0, &status, WNOHANG); if ((child > 0) && (prayer_prefork_children > 0)) prayer_prefork_children--; } while (child > 0); } /* ====================================================================== */ /* prayer_prefork_server() *********************************************** * * Master routine for prefork server. * prayer: Global state. ************************************************************************/ BOOL prayer_server_prefork(struct prayer *prayer) { struct config *config = prayer->config; unsigned long i, j; unsigned long spare_servers = config->http_min_servers; pid_t childpid; int *child_fds = pool_alloc(NIL, spare_servers * sizeof(int)); struct mymutex *mymutex; struct ssl_config ssl_config; config_extract_ssl(config, &ssl_config); if (!(mymutex=mymutex_create(config->pool, config->lock_dir, "accept_lock"))) log_fatal("Failed to create accept mymutex"); /* Enable alarm handler */ if (!os_signal_child_init(prayer_prefork_child_reaper)) return (NIL); log_misc("Frontend master server started okay"); setproctitle("Master server"); for (i = 0; i < spare_servers; i++) { int sockfd[2]; if (!os_socketpair(sockfd)) prayer_fatal(prayer, "[prayer_server_prefork()] socketpair() failed: %s", strerror(errno)); if ((childpid = fork()) < 0) prayer_fatal(prayer, "[prayer_server_prefork()] initial fork() failed: %s", strerror(errno)); if (childpid == 0) { for (j = 0; j < i; j++) close(child_fds[j]); close(sockfd[0]); prayer_slave_server(prayer, mymutex, sockfd[1]); exit(0); } child_fds[i] = sockfd[0]; close(sockfd[1]); prayer_prefork_children++; } for (;;) { fd_set fds; int maxsockfd = 0; int sockfd[2]; unsigned long fork_attempts; FD_ZERO(&fds); for (i = 0; i < spare_servers; i++) { FD_SET(child_fds[i], &fds); if (child_fds[i] > maxsockfd) maxsockfd = child_fds[i]; } while (select(maxsockfd + 1, &fds, NIL, NIL, NIL) < 0) { if (errno != EINTR) prayer_fatal(prayer, "prayer_server_prefork(): select() failed: %s", strerror(errno)); } for (i = 0; i < spare_servers; i++) { if (FD_ISSET(child_fds[i], &fds)) { close(child_fds[i]); if (!os_socketpair(sockfd)) prayer_fatal(prayer, "[prayer_server_prefork()] socketpair() failed: %s", strerror(errno)); fork_attempts = 0; while ((childpid = fork()) < 0) { prayer_paniclog(prayer, "[prayer_server_prefork()] fork() failed: %s", strerror(errno)); /* fork() failure may be transient error: Retry a few times */ if (++fork_attempts < 10) { sleep(30); continue; } /* And then give up completely */ exit(1); } if (childpid == 0) { for (i = 0; i < spare_servers; i++) close(child_fds[i]); close(sockfd[0]); prayer_slave_server(prayer, mymutex, sockfd[1]); exit(0); } child_fds[i] = sockfd[0]; close(sockfd[1]); prayer_prefork_children++; } } if (config->http_max_servers > 0) { while (prayer_prefork_children > config->http_max_servers) sleep(1); /* Wait for SIGCHLD */ } /* Replace (shared) RSA key every few minutes */ iostream_check_rsakey(&ssl_config); /* Ping access and miscellaneous logs every few minutes */ prayer_log_ping(prayer); log_misc_ping(); } mymutex_free(mymutex); return (T); } ./prayer-1.3.5/servers/prayer_chroot.c0000644006513000651300000002417411063701635016320 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/prayer_chroot.c,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_shared.h" #include "prayer.h" #include "prayer_server.h" BOOL prayer_main_use_existing(struct prayer *prayer, char *ports) { char *use_ssl, *fd, *next; while (ports) { if ((next = strchr(ports, ','))) *next++ = '\0'; if (!(use_ssl = strchr(ports, ':'))) return (NIL); *use_ssl++ = '\0'; if (!(fd = strchr(use_ssl, ':'))) return (NIL); *fd++ = '\0'; if (((atoi(ports) == 0) || (atoi(fd) == 0))) return (NIL); if (!strcmp(use_ssl, "1")) prayer_http_port_alloc(prayer, atoi(ports), T, atoi(fd)); else prayer_http_port_alloc(prayer, atoi(ports), NIL, atoi(fd)); ports = next; } return (T); } BOOL prayer_main_exec(struct prayer * prayer, int argc, char *argv[]) { struct config *config = prayer->config; struct pool *p = pool_create(8192); struct buffer *b = buffer_create(p, 256); char *cmd; char **nargv = pool_alloc(p, (argc + 2) * sizeof(char *)); int i; struct list_item *li; bputs(b, "--ports="); for (li = prayer->http_port_list->head; li; li = li->next) { struct prayer_http_port *fhp = (struct prayer_http_port *) li; if (fhp->use_ssl) bprintf(b, "%lu:1:%lu,", fhp->port, fhp->sockfd); else bprintf(b, "%lu:0:%lu,", fhp->port, fhp->sockfd); } cmd = pool_printf(p, "%s/prayer", config->bin_dir); for (i = 0; i < argc; i++) nargv[i] = argv[i]; nargv[argc++] = buffer_fetch(b, 0, buffer_size(b) - 1, NIL); nargv[argc] = NIL; execv(cmd, nargv); prayer_fatal(prayer, "execv(%s) failed: %s", cmd, strerror(errno)); /* NOTREACHED */ return (NIL); } BOOL prayer_main_start_session(struct prayer * prayer, int argc, char *argv[]) { struct config *config = prayer->config; char *cmd = pool_printf(NIL, "%s/prayer-session", config->bin_dir); char **nargv = pool_alloc(NIL, (1 + argc) * sizeof(char *)); int i, j; nargv[0] = "prayer-session"; i = 1; j = 1; while (i < argc) { if (!strcmp(argv[i], "--")) { i++; while (i < argc) nargv[j++] = argv[i++]; } else if (!strcmp(argv[i], "--config-option")) { nargv[j++] = argv[i++]; if (i < argc) nargv[j++] = argv[i++]; } else if (!strncmp (argv[i], "--config-file=", strlen("--config-file="))) nargv[j++] = argv[i++]; else i++; } nargv[j] = NIL; execv(cmd, nargv); prayer_fatal(prayer, "execv(%s) failed: %s", cmd, strerror(errno)); /* NOTREACHED */ return (NIL); } /* ====================================================================== */ static BOOL prayer_main_write_pid(struct config *config) { char *name = pool_printf(NIL, "%s/prayer.pid", config->pid_dir); FILE *file; if ((file = fopen(name, "w")) == NIL) return (NIL); fprintf(file, "%lu\n", (unsigned long) getpid()); fclose(file); return (T); } /* ====================================================================== */ int main(int argc, char *argv[]) { BOOL want_prefork = T; BOOL want_foreground = NIL; BOOL want_session = T; char *ports = NIL; char *config_filename = PRAYER_CONFIG_FILE; struct config *config = config_create(); struct prayer *prayer; struct list_item *li; int i; extern char **environ; struct ssl_config ssl_config; /* Disable supplementary groups, look for (temporary) unprivileged group */ if (getuid() == 0) { struct group *group; setgroups(0, NIL); if ((group = getgrnam("other")) != NIL) setgid(group->gr_gid); else if ((group = getgrnam("nobody")) != NIL) setgid(group->gr_gid); } if (getenv("PRAYER_CONFIG_FILE")) config_filename = getenv("PRAYER_CONFIG_FILE"); initsetproctitle("prayer", argc, argv, environ); os_signal_init(); response_record_version(VERSION_PRAYER); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--help")) { fprintf(stderr, "Options:\n"); fprintf(stderr, (" --config-file: Define prayer config file\n")); fprintf(stderr, (" " "(Overrides compilation default and PRAYER_CONFIG_FILE)\n")); fprintf(stderr, (" --config-option: Override single configuration option\n")); fprintf(stderr, "\n"); fprintf(stderr, (" --foreground: " "Run single threaded server in foreground\n")); fprintf(stderr, (" --disable-prefork: Run as simple fork()/exec() daemon\n")); fprintf(stderr, (" --disable-session: Don't start up prayer-session server\n")); fprintf(stderr, (" --help: Show this list of options\n")); fprintf(stderr, (" --: " "End of prayer options: remaining options will be passed\n")); fprintf(stderr, (" to prayer-session server process\n")); exit(0); } else if (!strcmp(argv[i], "--foreground")) want_foreground = T; else if (!strcmp(argv[i], "--disable-prefork")) want_prefork = NIL; else if (!strcmp(argv[i], "--disable-session")) want_session = NIL; else if (!strncmp(argv[i], "--config-file=", strlen("--config-file="))) { config_filename = strdup(argv[i] + strlen("--config-file=")); } else if (!strcmp(argv[i], "--config-option")) { i++; /* Processes next argv */ } else if (!strncmp(argv[i], "--ports=", strlen("--ports="))) { ports = argv[i] + strlen("--ports="); } else if (!strcmp(argv[i], "--")) { continue; } else { fprintf(stderr, "Unknown option: %s\n", argv[i]); exit(1); } } config = config_create(); if (!config_parse_file(config, config_filename)) exit(1); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--config-option")) { if (++i < argc) { if (!config_parse_option(config, strdup(argv[i]))) exit(1); } else fprintf(stderr, "--config processes following option"); } } if (!config_check(config)) exit(1); if (!config_expand(config)) exit(1); /* Generate a clean copy of the configuration without all of the noise */ { struct config *config_clean = config_clone_parsed(config); config_free(config); config = config_clean; } /* Set up prayer frontend structure to bind everything together */ prayer = prayer_create(config); if (ports == NIL) { if (config->http_port_list == NIL) prayer_fatal(prayer, "No HTTP or HTTPS ports defined"); for (li = config->http_port_list->head; li; li = li->next) { struct config_http_port *chp = (struct config_http_port *) li; prayer_http_port_open(prayer, chp->port, chp->use_ssl, chp->interface); } } else if (!prayer_main_use_existing(prayer, ports)) prayer_fatal(prayer, "Invalid --ports argument"); if (list_length(prayer->http_port_list) == 0L) prayer_fatal(prayer, "No HTTP or HTTPS ports active"); if (config->prayer_background && !want_foreground) { pid_t pid = fork(); if (pid < 0) prayer_fatal(prayer, "Failed to background server - fork() failed: %s", strerror(errno)); if (pid > 0) exit(0); /* Parent process */ /* Child process */ /* Shut down stdin, stdout, stderr */ close(0); close(1); close(2); open("/dev/null", O_RDONLY); /* Reopen stdin */ open("/dev/null", O_WRONLY); /* Reopen stdout */ open("/dev/null", O_WRONLY); /* Reopen stderr */ } /* Don't need root privs after ports bound, files open */ if (getuid() == 0) { if ((config->prayer_uid == 0) || (config->prayer_gid == 0)) log_fatal("Configured to run as root!"); /* XXX Experiment XXX */ if (config->tmp_dir) chdir(config->tmp_dir); if (chroot("/chroot/prayer") < 0) { prayer_fatal(prayer, "Chroot %s failed: %s", config->var_prefix, strerror(errno)); } if (config->prayer_gid) { setgid(config->prayer_gid); if (config->prayer_user && config->prayer_user[0]) initgroups(config->prayer_user, config->prayer_gid); } if (config->prayer_uid) setuid(config->prayer_uid); if (getuid() == 0) { /* Stop impossible loop */ log_fatal("Failed to lose root privileges"); } os_prctl_set_dumpable(); } if (getuid() == 0) log_fatal("Configured to run as root!"); config_mkdirs(config); log_misc_init(config, argv[0], "prayer"); prayer_log_open(prayer); if (config->limit_vm) os_limit_vm(config->limit_vm); if (config->tmp_dir) chdir(config->tmp_dir); /* Required for SSL stuff */ config_extract_ssl(config, &ssl_config); iostream_init(&ssl_config); prayer_main_write_pid(config); if (want_prefork && !want_foreground) prayer_server_prefork(prayer); else prayer_server(prayer, want_foreground); /* NOTREACHED */ return (0); } ./prayer-1.3.5/servers/Makefile0000644006513000651300000000771211773606560014744 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/servers/Makefile,v 1.20 2012/06/30 14:30:08 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2008 # See the file NOTICE for conditions of use and distribution. ifeq ($(strip $(RPM_BUILD)), true) include ../Config-RPM else include ../Config endif BASECFLAGS += -I../lib -I../shared -I../session # Default list of things to build BIN = prayer prayer-session prayer-chroot # Enable on the fly compression ifeq ($(strip $(GZIP_ENABLE)), true) BASE_LIBS += $(Z_LIBS) endif # Enable LDAP ifeq ($(strip $(LDAP_ENABLE)), true) BASE_LIBS += $(LDAP_LIBS) endif # Enable Electric Fence ifeq ($(strip $(FENCE_ENABLE)), true) BASECFLAGS += $(FENCE_INCLUDE) BASE_LIBS += $(FENCE_LIBS) endif # Enable libtidy ifeq ($(strip $(TIDY_ENABLE)), true) BASECFLAGS += $(TIDY_INCLUDE) BASE_LIBS += $(TIDY_LIBS) endif ifeq ($(strip $(SSL_ENABLE)), true) ifeq ($(strip $(RAVEN_ENABLE)), true) RAVEN_ENABLE_DEFS = -DRAVEN_ENABLE endif SERVER_SSL_DEFS = -DSSL_ENABLE SERVER_SSL_INCLUDE = $(SSL_INCLUDE) SERVER_SSL_LIBS = $(SSL_LIBS) ifeq ($(strip $(SESSION_CACHE_ENABLE)), true) # Berkeley DB required for SSL session cache. SERVER_SSL_DEFS += -DSESSION_CACHE_ENABLE SERVER_SSL_LIBS += $(DB_LIBS) endif LIB=../lib/lib_withssl.a else LIB=../lib/lib_nossl.a endif ifeq ($(strip $(ACCOUNTD_ENABLE)), true) ifeq ($(strip $(ACCOUNTD_USE_BSD_PTY)), true) BASE_LIBS += -lutil endif endif PRAYER_LIBS = $(BASE_LIBS) $(SERVER_SSL_LIBS) SESSION_LIBS = $(CCLIENT_LIBS) $(BASE_LIBS) # Add SSL if c-client needs SSL ifeq ($(strip $(CCLIENT_SSL_ENABLE)), true) SESSION_LIBS += $(SSL_LIBS) endif # Add PAM if backend needs pam ifeq ($(strip $(CCLIENT_PAM_ENABLE)), true) SESSION_LIBS += $(PAM_LIBS) endif # Add Kerberos if backend needs Kerberos ifeq ($(strip $(CCLIENT_KERB_ENABLE)), true) SESSION_LIBS += $(KERB_LIBS) endif MYCFLAGS = $(BASECFLAGS) $(SERVER_SSL_INCLUDE) $(CCLIENT_INCLUDE) MYLDFLAGS = $(BASELDFLAGS) TEMPLATES= ../templates/index.o \ ../templates/old/templates.a \ ../templates/cam/templates.a \ TEMPLATES_FRONTEND= ../templates/index.o \ ../templates/old/templates_frontend.a \ ../templates/cam/templates_frontend.a PRAYER_OBJS= prayer.o prayer_login.o prayer_server.o portlist.o \ ../shared/shared.a $(LIB) $(TEMPLATES_FRONTEND) SESSION_OBJS= \ session_config.o session_exchange.o session_unix.o session_server.o \ session_main.o portlist.o ../cmd/cmd.a ../session/session.a \ ../shared/shared.a ../lib/lib_nossl.a SESSION_OBJS += $(TEMPLATES) ######################################################################### all: $(BIN) clean: -rm -f $(BIN) core *.o *.flc *~ \#*\# install: all $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_DIR) -d \ $(BROOT)$(BIN_DIR) $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_EXEC) \ prayer $(BROOT)$(BIN_DIR) $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_EXEC) \ prayer-chroot $(BROOT)$(BIN_DIR) $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_EXEC) \ prayer-session $(BROOT)$(BIN_DIR) prayer: $(PRAYER_OBJS) prayer_main.o $(CC) $(MYLDFLAGS) -o prayer prayer_main.o $(PRAYER_OBJS) $(PRAYER_LIBS) prayer-chroot: $(PRAYER_OBJS) prayer_chroot.o $(CC) $(MYLDFLAGS) -o prayer-chroot prayer_chroot.o $(PRAYER_OBJS) $(PRAYER_LIBS) prayer-session: $(SESSION_OBJS) $(CC) $(MYLDFLAGS) -o prayer-session \ $(SESSION_OBJS) $(SESSION_LIBS) prayer_login.o: prayer_login.c *.h Makefile $(CC) $(MYCFLAGS) -c $(RAVEN_ENABLE_DEFS) $< prayer_main.o: prayer_main.c *.h Makefile $(CC) $(MYCFLAGS) -c \ -DPRAYER_CONFIG_FILE=\"$(PRAYER_CONFIG_FILE)\" $< prayer_chroot.o: prayer_chroot.c *.h Makefile $(CC) $(MYCFLAGS) -c \ -DPRAYER_CONFIG_FILE=\"$(PRAYER_CONFIG_FILE)\" $< session_main.o: session_main.c *.h Makefile $(CC) $(MYCFLAGS) -c \ -DPRAYER_CONFIG_FILE=\"$(PRAYER_CONFIG_FILE)\" $< # Default build rule %.o: %.c *.h Makefile $(CC) $(MYCFLAGS) -c $< ./prayer-1.3.5/servers/portlist.c0000644006513000651300000001253311415053461015312 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/portlist.c,v 1.4 2010/07/07 10:30:09 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "server.h" /* portlist is a class which manages of lists of (HTTP) ports which are * used by session_inet(). Each port can have an associated file descriptor * if the port is active or allocated but idle. Can also have an associated * child process if port currently active. Experimental! */ /* portlist_create() **************************************************** * * Create a new portlist structure. * pool: Target pool * first_port: First port in range * count: Number of ports in range * * Returns: Ptr to new portlist structure. ***********************************************************************/ struct portlist *portlist_create(unsigned long first_port, unsigned long count) { struct portlist *pl = pool_alloc(NIL, sizeof(struct portlist)); pl->idle = list_create(NIL, T); pl->active = list_create(NIL, T); pl->next = first_port; pl->last = first_port + count - 1; return (pl); } /* portlist_free() ******************************************************* * * Free portlist ************************************************************************/ void portlist_free(struct portlist *pl) { list_free(pl->idle); list_free(pl->active); free(pl); } /* ====================================================================== */ /* portlist_free_port_bypid() ******************************************* * * Free a port based on process id of associated child process. (Actually * just moves the port from active to idle list). * pl: Portlist * pid: Process id, * * Returns: T if port was allocated, NIL otherwise ***********************************************************************/ BOOL portlist_free_port_bypid(struct portlist * pl, pid_t pid) { unsigned long offset; struct list_item *li; struct port *port = NIL; struct port *newport; if (pl == NIL) return (NIL); for (offset = 0, li = pl->active->head; li; offset++, li = li->next) { port = (struct port *) li; if (port->pid == pid) break; } if (li == NIL) return (NIL); /* Move from active to inactive list: Could make this more efficient! */ newport = pool_alloc(NIL, sizeof(struct port)); newport->inet_port = port->inet_port; newport->sockfd = port->sockfd; newport->pid = 0; list_unshift(pl->idle, (struct list_item *) newport, NIL); list_remove_byoffset(pl->active, offset); return (T); } /* portlist_free_port() ************************************************** * * Free a port based on port number (Actually just moves the port from * active to idle list). * pl: Portlist * pid: Process id, * * Returns: T if port was allocated, NIL otherwise ***********************************************************************/ BOOL portlist_free_port(struct portlist * pl, unsigned long inet_port) { unsigned long offset; struct list_item *li; struct port *port = NIL; struct port *newport; for (offset = 0, li = pl->active->head; li; offset++, li = li->next) { port = (struct port *) li; if (port->inet_port == inet_port) break; } if (li == NIL) return (NIL); /* Move from active to inactive list: Could make this more efficient! */ newport = pool_alloc(NIL, sizeof(struct port)); newport->inet_port = port->inet_port; newport->sockfd = port->sockfd; newport->pid = 0; list_unshift(pl->idle, (struct list_item *) newport, NIL); list_remove_byoffset(pl->active, offset); return (T); } /* ====================================================================== */ /* portlist_close_all() ************************************************** * * Close all ports in list. * pl: Portlist ***********************************************************************/ void portlist_close_all(struct portlist *pl) { struct list_item *li; for (li = pl->active->head; li; li = li->next) { struct port *port = (struct port *) li; int fd = port->sockfd; close(fd); } for (li = pl->idle->head; li; li = li->next) { struct port *port = (struct port *) li; int fd = port->sockfd; close(fd); } } /* ====================================================================== */ /* portlist_close_all_execpt() ****************************************** * * Close all ports in list, except the nominated one which is about to * be passed to child process * pl: Portlist * except: fd to be left open ***********************************************************************/ void portlist_close_all_except(struct portlist *pl, int except_fd) { struct list_item *li; for (li = pl->active->head; li; li = li->next) { struct port *port = (struct port *) li; int fd = port->sockfd; if (fd != except_fd) close(fd); } for (li = pl->idle->head; li; li = li->next) { struct port *port = (struct port *) li; int fd = port->sockfd; close(fd); } } ./prayer-1.3.5/servers/session_config.c0000644006513000651300000000500611063701635016441 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_config.c,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "server.h" /* Config methods applied to running session */ /* session_config_local_domain_open() *********************************** * * Open local_domain CDB maps. ************************************************************************/ BOOL session_config_local_domain_open(struct config *config) { struct list_item *li; if (config->local_domain_list == NIL) return (T); for (li = config->local_domain_list->head; li; li = li->next) { struct config_local_domain *cld = (struct config_local_domain *) li; if (cld->file) { if (cld->cdb_map) cdb_close(cld->cdb_map); if ((cld->cdb_map = cdb_open(cld->file)) == NIL) { log_panic("Couldn't open local_domains map file: %s\n", cld->file); return (NIL); } log_debug("Opened CDB map for local domain: %s", cld->name); } } config->local_domain_time = time(NIL); return (T); } /* session_config_local_domain_ping() *********************************** * * Reopen local_domain CDB maps at periodic intervals. ************************************************************************/ BOOL session_config_local_domain_ping(struct config * config) { struct list_item *li; time_t now = time(NIL); if (config->local_domain_list == NIL) return (T); if (config->db_ping_interval == 0) return (T); if ((config->local_domain_time + config->db_ping_interval) >= now) return (T); for (li = config->local_domain_list->head; li; li = li->next) { struct config_local_domain *cld = (struct config_local_domain *) li; if (cld->file) { if (cld->cdb_map) cdb_close(cld->cdb_map); if ((cld->cdb_map = cdb_open(cld->file)) == NIL) { log_panic("Couldn't open local_domains map file: %s\n", cld->file); return (NIL); } log_debug("Reopened CDB map for local domain: %s", cld->name); } } config->local_domain_time = now; return (T); } ./prayer-1.3.5/servers/session_server.h0000644006513000651300000000066311063701635016513 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_server.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ BOOL session_server(struct config *config, BOOL foreground); ./prayer-1.3.5/servers/session_main.c0000644006513000651300000001360411063701635016123 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_main.c,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "server.h" BOOL session_main_exec(struct config * config, int argc, char *argv[]) { struct pool *p = pool_create(8192); char *cmd; char **nargv = pool_alloc(p, (argc + 2) * sizeof(char *)); int i; cmd = pool_printf(p, "%s/prayer-session", config->bin_dir); for (i = 0; i < argc; i++) nargv[i] = argv[i]; nargv[argc++] = "--no-exec"; nargv[argc] = NIL; execv(cmd, nargv); log_fatal("execv(%s) failed: %s", cmd, strerror(errno)); /* NOTREACHED */ return (NIL); } /* ====================================================================== */ static BOOL session_main_write_pid(struct config *config) { char *name = pool_printf(NIL, "%s/prayer-session.pid", config->pid_dir); FILE *file; if ((file = fopen(name, "w")) == NIL) return (NIL); fprintf(file, "%lu\n", (unsigned long) getpid()); fclose(file); return (T); } /* ====================================================================== */ int main(int argc, char *argv[]) { BOOL want_foreground = NIL; BOOL no_exec = NIL; char *config_filename = PRAYER_CONFIG_FILE; struct config *config = config_create(); int i; extern char **environ; struct ssl_config ssl_config; /* mm_init() must be first thing that we do! */ mm_init(); /* Disable supplementary groups, look for temporary unprivileged group */ if (getuid() == 0) { struct group *group; setgroups(0, NIL); if ((group = getgrnam("other")) != NIL) setgid(group->gr_gid); else if ((group = getgrnam("nobody")) != NIL) setgid(group->gr_gid); } if (getenv("PRAYER_CONFIG_FILE")) config_filename = getenv("PRAYER_CONFIG_FILE"); initsetproctitle("prayer-session", argc, argv, environ); response_record_version(VERSION_PRAYER); os_signal_init(); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--help")) { fprintf(stderr, "Options:\n"); fprintf(stderr, (" --config-file: Define prayer config file\n")); fprintf(stderr, (" " "(Overrides compilation default and PRAYER_CONFIG_FILE)\n")); fprintf(stderr, (" --config-option: Override single configuration option\n")); fprintf(stderr, "\n"); fprintf(stderr, (" --debug: Enable debugging\n")); fprintf(stderr, (" --foreground: " "Run single threaded session server in foreground\n")); fprintf(stderr, (" --help: Show this list of options\n")); exit(0); } else if (!strcmp(argv[i], "--foreground")) want_foreground = T; else if (!strcmp(argv[i], "--no-exec")) no_exec = T; else if (!strncmp(argv[i], "--config-file=", strlen("--config-file="))) { config_filename = strdup(argv[i] + strlen("--config-file=")); } else if (!strcmp(argv[i], "--config-option")) { i++; /* Processes next argv */ } else { fprintf(stderr, "Unknown option: %s\n", argv[i]); exit(1); } } config = config_create(); if (!config_parse_file(config, config_filename)) exit(1); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--config-option")) { if (++i < argc) { if (!config_parse_option(config, strdup(argv[i]))) exit(1); } else fprintf(stderr, "--config processes following option"); } } if (!config_check(config)) exit(1); if (!config_expand(config)) exit(1); /* Generate a clean copy of the configuration without all of the noise */ { struct config *config_clean = config_clone_parsed(config); config_free(config); config = config_clean; } /* Shouldn't be relevant now that prayer-session started from prayer */ /* Don't need root privs after ports bound, files open */ if (getuid() == 0) { if ((config->prayer_uid == 0) || (config->prayer_gid == 0)) log_fatal("Configured to run as root!"); if (config->prayer_gid) { setgid(config->prayer_gid); if (config->prayer_user && config->prayer_user[0]) initgroups(config->prayer_user, config->prayer_gid); } if (config->prayer_uid) setuid(config->prayer_uid); if (getuid() == 0) log_fatal("Failed to lose root priveledges"); /* Stop impossible loop */ /* Reexec after losing root privs to prevent core dump paranoia */ if (no_exec == NIL) { session_main_exec(config, argc, argv); log_fatal("session_main_exec() failed"); /* Should be redundant */ } } if (getuid() == 0) log_fatal("Configured to run as root!"); config_mkdirs(config); log_misc_init(config, argv[0], "prayer_session"); if (config->limit_vm) os_limit_vm(config->limit_vm); config_extract_ssl(config, &ssl_config); iostream_init(&ssl_config); /* Required for SSL stuff */ cmd_dispatch_init(); /* Initialise cmd_dispatch table */ if (!session_config_local_domain_open(config)) exit(1); if (config->tmp_dir) chdir(config->tmp_dir); session_main_write_pid(config); session_server(config, want_foreground); return (0); } ./prayer-1.3.5/servers/.cvsignore0000644006513000651300000000020311063701635015257 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/servers/.cvsignore,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ prayer prayer-session prayer-chroot *.flc ./prayer-1.3.5/servers/server.h0000644006513000651300000000056311063701635014747 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/server.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ #include "prayer_session.h" #include "session_config.h" #include "session_streams.h" #include "session_exchange.h" #include "session_unix.h" #include "session_server.h" #include "portlist.h" void cmd_dispatch_init(void); BOOL cmd_dispatch(struct session *session, char *text); ./prayer-1.3.5/servers/session_exchange.c0000644006513000651300000001330011513073334016750 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_exchange.c,v 1.7 2011/01/11 15:27:24 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "server.h" /* session_exchange() *************************************************** * * Manage single HTTP exchange with user agent (can be initiated by * proxy frontend or direct connection to session server). ***********************************************************************/ BOOL session_exchange(struct session * session) { struct prefs *prefs = session->options->prefs; struct config *config = session->config; struct request *request = session->request; struct user_agent *user_agent = request->user_agent; char *sequence; struct template_vals *tvals; char *template_set = config->template_set; /* Do something useful with HTTP/0.9 */ if (request->major == 0) { response_0_9_error(request); return (NIL); } /* Check for valid host if one supplied */ if (request->url_host) { BOOL rc = NIL; if (!strcasecmp(request->url_host, "localhost")) rc = T; else if (config->hostname && !strcasecmp(request->url_host, config->hostname)) rc = T; else if (config->hostname_service && !strcasecmp(request->url_host, config->hostname_service)) rc = T; if (!rc) { response_error(request, 403); /* Forbidden */ return (NIL); } } request_parse_argv(request); request_parse_charset(request); if (session->use_gzip) { request->allow_gzip = T; request_parse_encoding(request); } else request->allow_gzip = NIL; /* argv: /session/username/session/sequence... */ if ((request->argc < 5) || (strcmp(request->argv[0], "session") != 0)) { response_error(request, 404); /* Not found */ return (NIL); } sequence = request->argv[3]; request->argv = &request->argv[4]; request->argc -= 4; session->sequence_okay = T; if (strcmp(sequence, "NOSEQ") != 0) { BOOL error = NIL; if (session->sequence != session_sequence(sequence)) session->sequence_okay = NIL; session_bump_sequence(session); session_update_sequence(session); if (user_agent->use_substitution) { /* Check that the sequence number is correct: * Browser back button doesn't work with page substituton enabled * Spell checker and browser buttons don't get on at all well * (flag forall methods would be sensible) */ if (!session->sequence_okay) error = T; } else { /* Browser back button works fine without page substition * apart from folder changes. */ if (session->sequence_last_change > session_sequence(sequence)) error = T; } if (error) { char *last_cmd = session_last_cmd(session); if (last_cmd && last_cmd[0]) { session_message(session, ("Browser history disabled as unsafe: " "use Webmail navigation icons and links")); session_redirect(session, request, last_cmd); return (T); } session_log(session, ("[session_exchange] " "Internal error: last command not recorded")); session_redirect(session, request, "restart"); return (T); } } else { /* Just in case NOSEQ URL generates a redirect */ session_update_sequence(session); } /* Only safe to call session_redirect() after this point */ /* Check IMAP streams before processing each session request * (reopens streams if required + ping every once in a while * Have to do this here rather than in parent routines so that we * have a HTTP connection back to client for restart page... * * Don't make this test if it would cause infinite loop of redirects */ if ((strcmp(request->argv[0], "restart") != 0) && (strcmp(request->argv[0], "exit") != 0)) { if (!session_streams_check(session)) { session_redirect(session, request, "restart"); return (T); } } /* Reopen local domains every once in a while */ session_config_local_domain_ping(session->config); session_log(session, "[session_exchange] %s", request->argv[0]); if (config->template_list && list_lookup_byname(config->template_list, prefs->template_set)) template_set = prefs->template_set; else template_set = config->template_set; /* Safe default */ /* Set up template_vars ready for dispatch */ session->template_vals = tvals = template_vals_create(request->pool, config->template_path, template_set, config->template_use_compiled, T, session_extract_urlstate(session)); template_vals_string(tvals, "g_cmd", request->argv[0]); /* Look for defined session method */ if (cmd_dispatch(session, request->argv[0])) return (request->persist); if ((request->method == GET) || (request->method == HEAD)) response_error(request, 404); /* Not found */ else response_error(request, 501); /* Not implemented */ return (NIL); } ./prayer-1.3.5/servers/session_streams.h0000644006513000651300000000144311063701635016660 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_streams.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ BOOL session_streams_idle(struct session *session); BOOL session_streams_check(struct session *session); BOOL session_streams_change(struct session *session, char *name); MAILSTREAM *session_streams_find(struct session *session, char *name); BOOL session_streams_ping(struct session *session, char *mailbox); BOOL session_streams_save_options(struct session *session); void session_streams_close(struct session *session); ./prayer-1.3.5/servers/prayer_login.h0000644006513000651300000000102311063701635016123 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/prayer_login.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ void prayer_login_raven(struct prayer *prayer); void prayer_login(struct prayer *prayer, char *username); void prayer_login_preamble(struct prayer *prayer); ./prayer-1.3.5/servers/session_server.c0000644006513000651300000003202711063701635016505 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/servers/session_server.c,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "server.h" /* ====================================================================== */ /* Structure containing information pertaining to a single login request */ struct session_server_request { struct pool *pool; /* Scratch pool for this request */ char *username; /* Username for this login request */ char *password; /* Password for this login request */ unsigned long port; /* Frontend port for this login request */ BOOL use_ssl; /* Using SSL on this port */ char *ua_options; /* User interface override options */ struct ipaddr *ipaddr; /* IP address for this request */ }; /* ====================================================================== */ /* session_server_request_create() ************************************** * * Create new session_server_request structure with its own pool. ************************************************************************/ static struct session_server_request *session_server_request_create(void) { struct pool *pool = pool_create((sizeof(struct session_server_request)) + 256); struct session_server_request *bsr = pool_alloc(pool, sizeof(struct session_server_request)); memset((void *) bsr, 0, sizeof(struct session_server_request)); bsr->pool = pool; bsr->ipaddr = ipaddr_create(pool); return (bsr); } /* session_server_request_free() ***************************************** * * Discard (pool of) sesssion_server_request ************************************************************************/ static void session_server_request_free(struct session_server_request *bsr) { pool_free(bsr->pool); } /* ====================================================================== */ /* session_server_parse_request() **************************************** * * Parse login request from prayer frontend process * bsr: session server request * stream: iostream connection to frontend server. * * Returns: T if valid login request. * NIL on protocol error or unexpected disconnect ************************************************************************/ static BOOL session_server_parse_request(struct session_server_request *bsr, struct iostream *stream) { struct buffer *b = buffer_create(bsr->pool, 0); int c; char *line; char *portstr, *sslstr; char *iptext; while (((c = iogetc(stream)) != EOF) && (c != '\015') && (c != '\012')) bputc(b, c); if (c == EOF) { log_panic("[session_server_parse_request()] Truncated input line"); return (NIL); } line = buffer_fetch(b, 0L, buffer_size(b), NIL); if (!((bsr->username = string_get_token(&line)) && (bsr->password = string_get_token(&line)) && (bsr->ua_options = string_get_token(&line)))) { log_panic("[session_server_parse_request()] Truncated input line"); return (NIL); } bsr->username = string_canon_decode(bsr->username); bsr->password = string_canon_decode(bsr->password); bsr->ua_options = string_canon_decode(bsr->ua_options); /* Some people insist on entering username as upper case... */ string_lcase(bsr->username); if (!((portstr = string_get_token(&line)) && (sslstr = string_get_token(&line)) && (iptext = string_get_token(&line)))) { log_panic("[session_server_parse_request()] Truncated input line"); return (NIL); } bsr->port = atoi(portstr); bsr->use_ssl = (atoi(sslstr) != 0) ? T : NIL; if (bsr->port == 0L) { log_panic(("[session_server_parse_request()] " "Invalid port number (%s) supplied"), portstr); return (NIL); } if (!ipaddr_parse(bsr->ipaddr, iptext)) { log_panic("[session_server_parse_request()] Invalid IP address"); return (NIL); } return (T); } /* ====================================================================== */ /* session_server_process_request() ************************************** * * Process login request in either foreground or (more normal background) * bsr: session_login_request * ssl_portlist: Portlist for SSL if direct connection mode * plain_portlist: Portlist for plaintext if direct connection mode * sockfd: Socket for master listener * (passed here only so that child process can close). * stream: iostream connection to prayer frontend * (Used to return consequence of login request) * foreground: Foreground login session (used for debugging) * * Returns: T if login request processed sucessfully * NIL on error. ************************************************************************/ static BOOL session_server_process_request(struct session_server_request *bsr, struct config *config, struct portlist *ssl_portlist, struct portlist *plain_portlist, int sockfd, struct iostream *stream, BOOL foreground) { struct session *session = NIL; struct port *port = NIL; pid_t childpid; struct user_agent *user_agent = user_agent_create(bsr->pool); /* Parse user agent options into temporary structure */ user_agent_parse(user_agent, pool_strdup(bsr->pool, bsr->ua_options)); if (foreground) { /* Set up a new, clean session */ if ((session = session_create(config)) == NIL) { log_panic("[session_server()] session_create() failed"); return (NIL); } if (!session_login(session, bsr->username, bsr->password, bsr->port, bsr->use_ssl, bsr->ua_options, bsr->ipaddr)) { session_log(session, "Attempted login failed: \"%s\"", ml_errmsg()); if (ml_have_error()) { ioprintf(stream, "NO %s" CRLF, ml_errmsg()); } else ioputs(stream, "NO Login Incorrect" CRLF); ioflush(stream); session_free(session); return (NIL); } session_unix(session, stream); session_free(session); return (T); } if ((childpid = fork()) < 0) { /* May be transcient error! */ session_paniclog(session, "[session_server()] fork() failed, %s", strerror(errno)); return (NIL); } if (port) port->pid = childpid; if (childpid != 0) return (T); /* Parent process */ /***** Child process *******/ /* Shut down file descriptors that the child neither wants or needs */ close(sockfd); if (config->direct_enable) { if (port) { portlist_close_all_except(ssl_portlist, port->sockfd); portlist_close_all_except(plain_portlist, port->sockfd); } else { portlist_close_all(ssl_portlist); portlist_close_all(plain_portlist); } } /* Clear out child reaper: interferes with waitpid */ if (!os_signal_child_clear()) return (NIL); /* Set up a new, clean session */ if ((session = session_create(config)) == NIL) log_fatal("[session_server()] session_create() failed"); if (!session_login(session, bsr->username, bsr->password, bsr->port, bsr->use_ssl, bsr->ua_options, bsr->ipaddr)) { session_log(session, "Attempted login failed: \"%s\"", ml_errmsg()); if (ml_have_error()) ioprintf(stream, "NO %s" CRLF, ml_errmsg()); else ioputs(stream, "NO Login Incorrect" CRLF); ioflush(stream); session_free(session); exit(0); /* NOTREACHED */ return (NIL); } session_unix(session, stream); session_free(session); exit(0); /* NOTREACHED */ return (NIL); } /* ====================================================================== */ /* session_server_ping() ************************************************* * * Ping various log files once in a while. * config: Prayer configuration ************************************************************************/ static void session_server_ping(struct config *config) { /* Reopen misc log file */ log_misc_ping(); /* Reopen local domain maps */ session_config_local_domain_ping(config); } /* ====================================================================== */ /* session_server() ****************************************************** * * Master session server routine * config: Prayer configuration * foreground: Run as foreground server (for debugging purposes) * * Returns: NIL on fatal error during startup. Otherwise never! ************************************************************************/ BOOL session_server(struct config *config, BOOL foreground) { struct portlist *ssl_portlist = NIL; struct portlist *plain_portlist = NIL; int sockfd, newsockfd; struct session_server_request *bsr; char *name; struct iostream *stream; int maxfd, rc; fd_set readfds; pid_t child; unsigned long timeout = 0L; if (config->direct_enable) { ssl_portlist = portlist_create(config->direct_ssl_first, config->direct_ssl_count); plain_portlist = portlist_create(config->direct_plain_first, config->direct_plain_count); } if (config->socket_dir == NIL) { /* Should be impossible! */ log_panic("[session_server()] socket_dir not defined"); return (NIL); } if (!os_signal_child_init(os_child_reaper)) return (NIL); name = pool_printf(NIL, "%s/%s", config->socket_dir, config->init_socket_name); if ((sockfd = os_bind_unix_socket(name)) < 0) return (NIL); log_misc("Backend master server started okay"); for (;;) { setproctitle("Master server"); do { do { if (((child = os_waitpid_nohang()) > 0) && !portlist_free_port_bypid(ssl_portlist, child)) portlist_free_port_bypid(plain_portlist, child); } while (child > 0); /* Requests should queue on sockfd until we are ready to serve them */ /* SIGCHLD breaks select() with EINTR, readfds recalculated */ FD_ZERO(&readfds); FD_SET(sockfd, &readfds); maxfd = sockfd; timeout = config->log_ping_interval; if (config->direct_enable && ((timeout == 0) || (config->ssl_rsakey_lifespan < timeout))) timeout = config->ssl_rsakey_lifespan; if (timeout > 0) { struct timeval timeval; timeval.tv_sec = timeout; timeval.tv_usec = 0; rc = select(maxfd + 1, &readfds, NIL, NIL, &timeval); } else { rc = select(maxfd + 1, &readfds, NIL, NIL, NIL); } } while ((rc < 0) && (errno == EINTR)); if (rc == 0) { /* Ping various log files and recalculate SSL RSA key once in a while */ session_server_ping(config); continue; } if (!FD_ISSET(sockfd, &readfds)) continue; /* Have new incoming connection */ if ((newsockfd = os_accept_unix(sockfd)) < 0) { log_panic("[session_server()] accept() failed, %s", strerror(errno)); continue; /* Might be transient failure */ } if ((stream = iostream_create(NIL, newsockfd, 0)) == NIL) { log_panic ("[session_server()] Couldn't bind iostream to socket"); continue; } iostream_set_timeout(stream, config->session_timeout); bsr = session_server_request_create(); if (!session_server_parse_request(bsr, stream)) { ioputs(stream, "BAD Invalid request from frontend" CRLF); log_panic ("[session_server_inet()] Invalid request from frontend "); } else { session_server_process_request(bsr, config, ssl_portlist, plain_portlist, sockfd, stream, foreground); } iostream_close(stream); session_server_request_free(bsr); /* Ping various log files and recalculate SSL RSA key once in a while */ session_server_ping(config); } } ./prayer-1.3.5/shared/0000755006513000651300000000000011775262602013047 5ustar dpc22dpc22./prayer-1.3.5/shared/gzip.h0000644006513000651300000000062611063701636014170 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/gzip.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ struct buffer *gzip(struct buffer *input); ./prayer-1.3.5/shared/config.h0000644006513000651300000003473411773606560014503 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/config.h,v 1.10 2012/06/30 14:30:08 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Prayer Configuration */ #define CONFIG_CWD_MAXLEN (4096) struct config_local_domain { /* Local domain */ struct list_item *next; /* Linked list */ char *name; /* Name of domain */ char *file; /* CDB file assocaited with domain */ void *cdb_map; /* Open CDB map associated with domain */ }; struct config_http_port { /* HTTP or HTTPS port */ struct list_item *next; /* Linked list */ char *name; /* Name of port (unused: list placeholder) */ unsigned long port; /* Intenet domain port number */ char *interface; /* Interface name or IP (NIL => all) */ BOOL use_ssl; /* T => Connections here will use SSL */ }; struct config_language { /* Ispell languages */ struct list_item *next; /* Linked list */ char *name; /* Ispell name of language e.g: british */ char *desc; /* Text description for preferences page */ }; struct config_template { struct config_template *next; /* Linked list */ char *name; /* Short name of this theme */ char *description; /* Description for prefs screen */ }; struct config_theme { struct config_theme *next; /* Linked list */ char *name; /* Short name of this theme */ char *description; /* Description for prefs screen */ char *fgcolor; /* Default foreground colour */ char *fgcolor_link; /* Default link foreground colour */ char *bgcolor; /* Default background colour */ char *bgcolor_banner; /* Background for cmd banners */ char *bgcolor_row1; /* Background for even rows */ char *bgcolor_row2; /* Background for odd rows */ char *bgcolor_status; /* Background for status lines */ char *bgcolor_status_none; /* Background for empty status */ char *fgcolor_quote1; /* 1st level of quoting */ char *fgcolor_quote2; /* 2nd level of quoting */ char *fgcolor_quote3; /* 3rd level of quoting */ char *fgcolor_quote4; /* 4th level of quoting */ }; #define config_theme_check_bgcolor(theme, color) \ (color && color[0] && (strcmp(theme->bgcolor, color) != 0)) struct config { struct pool *pool; /* Private pool for config */ /* Assorted paths */ char *prefix; /* (Optional) read-only prefix */ char *var_prefix; /* (Optional) read-write prefix */ BOOL raven_enable; /* Enable raven login */ char *raven_key_path; /* Path to raven keys */ char *login_insert1_path; /* Chunks of HTML to insert into login screen */ char *login_insert2_path; /* Chunks of HTML to insert into login screen */ char *login_template; /* Template to use on login screen */ char *motd_path; /* Message of the day filename */ char *welcome_path; /* Welcome message */ char *icon_dir; /* Icon directory */ char *static_dir; /* Dir with Static entites: HTML,CSS */ unsigned long static_expire_timeout; /* Expires:for static files (secs) */ char *socket_dir; /* Socket Directory */ BOOL socket_split_dir; /* Split sockets across directories */ char *ssl_cipher_list; /* List of ciphers */ BOOL ssl_server_preference; /* Server selects preferred cipher */ char *ssl_session_dir; /* SSL session directory */ char *lock_dir; /* Lock Directory */ char *log_dir; /* Log directory */ char *tmp_dir; /* Directory for temporary files */ char *pid_dir; /* Directory for PID files */ char *bin_dir; /* Location of binaries */ char *init_socket_name; /* Name of socket within socketdir */ unsigned long file_perms; /* For new read-write files */ unsigned long directory_perms; /* For new read-write directoies */ BOOL check_directory_perms; /* T => check read-write */ /* file and directory permissions */ BOOL log_debug; /* T => Enable debug logging */ BOOL fatal_dump_core; /* fatal() should dump core? */ char *template_path; /* Where to find raw template files */ char *template_set; /* (Default?) template set to use */ BOOL template_use_compiled; /* Use compiled templates */ /* Frontend server configuration */ char *prayer_user; /* User that prayer will run as */ uid_t prayer_uid; /* Equivalent UID after lookup */ char *prayer_group; /* Group that prayer will run as */ gid_t prayer_gid; /* Equivalent GID after lookup */ BOOL prayer_background; /* Master prayer should fork and exit */ char *hostname_canonical; /* Overrides gethostbyname */ char *hostname; /* Overrides gethostbyname */ char *hostname_service; /* Login screen, overrides hostname */ BOOL referer_block_invalid;/* Block logins from unknown referers */ BOOL referer_log_invalid; /* Log invalid referrer headers */ BOOL fix_client_ipaddr; /* Client must login from single addr */ char *gzip_allow_nets; /* Enable gzip from this list */ char *gzip_deny_nets; /* Disable gzip from this list */ char *log_name_nets; /* Reverse lookup, log name for nets */ /* Emergency backstops */ unsigned long limit_vm; /* Limit on single prayer or prayer-session */ unsigned long recips_max_msg; unsigned long recips_max_session; char *sending_allow_dir; /* Override block_sending */ char *sending_block_dir; /* Disable sending on account */ /* HTTP configuration */ BOOL http_cookie_use_port; /* Use username:port in cookie */ unsigned long http_timeout_idle; /* In seconds */ unsigned long http_timeout_icons; /* In seconds */ unsigned long http_timeout_session; /* In seconds */ unsigned long http_min_servers; /* Minimum spare frontend servers */ unsigned long http_max_servers; /* Maximum spare frontend servers */ unsigned long http_max_connections; /* Maximum connections to f'end server */ unsigned long http_max_method_size; /* In bytes */ unsigned long http_max_hdr_size; /* In bytes */ unsigned long http_max_body_size; /* In bytes */ BOOL http_dump; /* Temporary */ struct list *http_port_list; /* List of HTTP and HTTPS ports */ char *ssl_cert_file; /* SSL Certificate file */ char *ssl_privatekey_file; /* SSL Privatekey file */ char *ssl_dh_file; /* SSL DH file */ unsigned long ssl_session_timeout; /* Timeout for SSL sessions */ unsigned long ssl_rsakey_lifespan; /* Master server regenerates RSA key */ unsigned long ssl_rsakey_freshen; /* Keys last this long after 1st use */ unsigned long ssl_default_port; /* Default HTTPS port, if any */ BOOL ssl_encouraged; /* Warn before login if not SSL */ BOOL ssl_redirect; /* Redirect non-SSL sessions to SSL */ BOOL ssl_required; /* Disable insecure login */ char *egd_socket; /* Path for EGD socket */ /* Direct access configuration */ unsigned long direct_enable; /* Enable direct access to session */ unsigned long direct_ssl_first; /* Direst SSL Ports start here */ unsigned long direct_ssl_count; /* Direct SSL Ports available */ unsigned long direct_plain_first; /* Direst Plain Ports start here */ unsigned long direct_plain_count; /* Direct plain Ports available */ /* Various timeouts */ unsigned long session_idle_time; /* Session moves into idle mode */ unsigned long session_timeout_compose; /* Backend session timeout (compose) */ unsigned long session_timeout; /* Backend session timeout (secs) */ unsigned long icon_expire_timeout; /* Expires: hdr for icons (secs) */ unsigned long session_key_len; /* Length of session key */ unsigned long stream_checkpoint; /* Checkpoint or ping live streams */ unsigned long stream_ping_interval; /* C'point/Ping interval live streams */ unsigned long stream_misc_timeout; /* Timeouts for misc streams */ unsigned long log_ping_interval; /* Ping log files at this interval */ unsigned long db_ping_interval; /* Ping db files at this interval */ /* Global defaults affecting look and feel (use to prime user prefs?) */ char *login_banner; /* Login banner */ char *login_service_name; /* Login service name */ unsigned long list_addr_maxlen; /* cmd_list: Max size of address */ unsigned long list_subject_maxlen; /* cmd_list: Max size of subject */ struct list *local_domain_list; /* List of local domains w/lookups */ unsigned long local_domain_time; /* Time CDB files last reopened */ struct list *ispell_language_list; /* List of languages for ispell */ char *filter_domain_pattern; /* Filter pattern for local domains */ unsigned long change_max_folders; /* Max folders on change dialogue */ unsigned long draft_att_single_max; /* Limit on single attachment */ unsigned long draft_att_total_max; /* Limit on all attachments */ /* Location of Backend IMAP server */ char *imapd_user_map; /* CDB map: username -> server[:port] */ char *imapd_server; /* Default server[:port] */ char *prefs_folder_name; /* Name of preferences file on server */ char *accountd_user_map; /* CDB map: username -> server[:port] */ char *accountd_server; /* Accountd server */ char *accountd_nis_server; /* Accountd NIS server */ unsigned long accountd_timeout; /* Accountd Timeout */ unsigned long accountd_passwd_delay; /* Delay for passwd updates */ unsigned long accountd_fullname_delay; /* Delay for fullname updates */ unsigned long vacation_default_days; /* Default :days option for sieve */ char *sieved_user_map; /* CDB map: username -> server[:port] */ char *sieved_server; /* Sieved server */ unsigned long sieve_maxsize; /* Cyrus default is 32K */ unsigned long sieved_timeout; /* Sieved Timeout */ char *sendmail_path; /* Path to sendmail */ char *aspell_path; /* Path to aspell (Takes priority) */ char *ispell_path; /* Path to ispell */ char *return_path_domain; /* Return path domain */ BOOL fix_from_address; /* Stop user changing from address */ unsigned long spam_purge_timeout; /* Default value used by IMAP server */ char *spam_purge_name; /* Name of sieve folder used for spam purge */ char *spam_purge_prefix; /* Prefix to use in spam purge file */ BOOL strip_mail; /* Strip mail/ from favourites, maybe others */ char *lookup_fullname; /* Map from userid to GeCOS fullname */ char *lookup_rpasswd; /* Finger database, GeCOS reverse lookup */ char *lookup_rusername; /* Finger database, Jackdaw reverse lookup */ char *lookup_username; /* Finger database, forward lookup */ char *ldap_server; /* LDAP server to use */ char *ldap_base_dn; /* LDAP base DN */ unsigned long ldap_timeout; /* in seconds */ struct list *template_list; /* List of defined templates */ /* Theme stuff */ struct list *theme_list; /* List of defined themes */ char *theme_default_main; /* Name of default main theme */ char *theme_default_help; /* Name of default help theme */ struct config_theme *theme_main; /* Default theme for main text */ struct config_theme *theme_help; /* Default theme for help text */ /* User preference defaults : see prefs.h for details */ BOOL allow_raven_login; BOOL confirm_expunge; BOOL expunge_on_exit; BOOL confirm_logout; BOOL confirm_rm; unsigned long msgs_per_page; unsigned long msgs_per_page_min; unsigned long msgs_per_page_max; unsigned long abook_per_page; unsigned long abook_per_page_min; unsigned long abook_per_page_max; BOOL suppress_dotfiles; char *maildir; BOOL use_namespace; char *personal_hierarchy; char *hiersep; BOOL dualuse; char *postponed_folder; char *sent_mail_folder; char *default_domain; char *ispell_language; BOOL spell_skip_quoted; /* aspell only */ unsigned long small_cols; unsigned long small_rows; unsigned long large_cols; unsigned long large_rows; char *sort_mode; BOOL sort_reverse; char *abook_sort_mode; BOOL abook_sort_reverse; unsigned long line_wrap_len; BOOL line_wrap_advanced; BOOL line_wrap_on_reply; BOOL line_wrap_on_spell; BOOL line_wrap_on_send; BOOL use_sent_mail; BOOL use_search_zoom; BOOL use_mark_persist; BOOL use_agg_unmark; BOOL use_icons; BOOL use_welcome; BOOL use_unread; BOOL use_tail_banner; BOOL use_cookie; BOOL use_substitution; BOOL use_http_1_1; BOOL use_pipelining; BOOL use_persist; BOOL use_short; BOOL use_gzip; BOOL html_inline; BOOL html_inline_auto; BOOL html_remote_images; BOOL preserve_mimetype; }; #define CONFIG_PREFERRED_POOL_SIZE (2048) #define CONFIG_PREFERRED_TEMP_POOL_SIZE (8192) struct config *config_create(void); void config_free(struct config *config); struct config *config_clone_parsed(struct config *src); BOOL config_parse_file(struct config *config, char *filename); BOOL config_parse_option(struct config *config, char *option); BOOL config_expand(struct config *config); BOOL config_check(struct config *config); BOOL config_mkdirs(struct config *config); BOOL config_local_domain_open(struct config *config); void config_extract_ssl(struct config *config, struct ssl_config *ssl_config); ./prayer-1.3.5/shared/common.h0000644006513000651300000000136711774022551014513 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/common.h,v 1.16 2012/07/01 10:24:41 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Useful constants used by several different files */ /* Prayer Version numbers for frontend and backend code */ #define VERSION_PRAYER "1.3.5" /* Common character sequences */ #define CR "\015" #define LF "\012" #define CRLF "\015\012" /* Sort mode shared by prefs and msgmap */ typedef enum { ARRIVAL, DATE, FROM, SUBJECT, TO, CC, SIZE, REFERENCES, ORDEREDSUBJECT } SORTMODE; ./prayer-1.3.5/shared/log.c0000644006513000651300000004365611063701636014005 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/log.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "shared.h" /* Program name */ static char *log_progname = NIL; #define LOG_TMP_SIZE (255) /* Space on stack rather than heap */ #define LOG_PREFIX_SIZE (50) /* Max length of prefix without username */ /* log_create() *********************************************************** * * Create new log struct * config: Prayer configuration * pool: Pool to expand filename into * * Returns: New log structure ************************************************************************/ struct log *log_create(struct config *config, struct pool *pool) { struct log *log; log = pool_alloc(pool, sizeof(struct log)); log->config = config; log->pool = pool; log->name = NIL; log->fd = -1; log->inode = 0; log->last_ping = 0; log->peer_pid = 0; return (log); } /* log_free() ************************************************************ * * Free log structure (unless allocated against pool) * log: Structure to free ************************************************************************/ void log_free(struct log *log) { if (log->fd >= 0) close(log->fd); if (log->pool) return; if (log->name) free(log->name); free(log); } /* log_open() ************************************************************ * * Open log file * log: Structure which will contain all info related to log file * name: Name of log file to open. * * Returns: T if log opened successfully. ************************************************************************/ BOOL log_open(struct log *log, char *name) { struct pool *pool = log->pool; struct config *config = log->config; int open_flags; int open_perms; struct stat sbuf; if (!(name && name[0])) { log_panic("log_open() called with empty file name"); return (NIL); } if (config && config->log_dir && config->log_dir[0] && name && (name[0] != '/')) log->name = pool_strcat3(pool, config->log_dir, "/", name); else log->name = pool_strdup(pool, name); /* Calculate arguments for open() */ if (getuid() != 0) open_flags = O_APPEND | O_WRONLY | O_CREAT; /* Non-root can create files */ else open_flags = O_APPEND | O_WRONLY; /* Don't create files as root */ open_perms = ((config && config->file_perms) ? config->file_perms : 0644); /* Try to open or create file */ if ((log->fd = open(log->name, open_flags, open_perms)) < 0) { log_panic("Couldn't open log file: \"%s\": %s", log->name, strerror(errno)); return (NIL); } /* Record file inode and last ping times */ if (fstat(log->fd, &sbuf) < 0) { log_panic("Couldn't fstat() log file: \"%s\": %s", log->name, strerror(errno)); return (NIL); } log->inode = sbuf.st_ino; log->last_ping = time(NIL); return (T); } /* log_open() ************************************************************ * * Open log file * log: Structure which will contain all info related to log file * * Returns: T if log pinged okay. ************************************************************************/ BOOL log_ping(struct log * log) { struct config *config = log->config; int open_flags; int open_perms; struct stat sbuf; time_t now = time(NIL); /* No log structure allocated. Shouldn't happen! */ if (log == NIL) return (NIL); /* Log file already open and pinged recently? */ if ((log->fd >= 0) && (config->log_ping_interval > 0) && (log->last_ping + config->log_ping_interval) >= now) return (T); /* Ping log file: has the inode changed? */ if ((stat(log->name, &sbuf) >= 0) && (sbuf.st_ino == log->inode)) return (T); /* Calculate arguments for open(2) */ if (getuid() != 0) open_flags = O_APPEND | O_WRONLY | O_CREAT; /* Non-root can create files */ else open_flags = O_APPEND | O_WRONLY; /* Don't create files as root */ open_perms = ((config && config->file_perms) ? config->file_perms : 0644); /* Reopen log file */ close(log->fd); if ((log->fd = open(log->name, O_APPEND | O_WRONLY | O_CREAT, open_perms)) < 0) { log_panic("Couldn't open log file: \"%s\": %s", log->name, strerror(errno)); return (NIL); } /* Record inode and ping time */ log->inode = sbuf.st_ino; log->last_ping = now; return (T); } /* ====================================================================== */ /* ====================================================================== */ /* Routines for logging messages to log files, syslog and sterr */ /* log_entry_size() ****************************************************** * * Calculate size of log entry item. Doesn't include timestamps and other * (fixed length) padding that that the log function may want to add * fmt: Format string * ap: va_list ************************************************************************/ unsigned long log_entry_size(char *fmt, va_list ap) { return (pool_vprintf_size(fmt, ap)); } /* ====================================================================== */ /* log_timestamp() ******************************************************* * * Generate suitable (fixed length!) prefix for log line. * log: * buffer: Target buffer * username: Username to log. NIL => username unknown or no significant ************************************************************************/ static void log_timestamp(struct log *log, char *buffer, char *username) { time_t now; struct tm *tm; static char *date_month[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; time(&now); tm = localtime(&now); sprintf(buffer, "%s %c%c %c%c:%c%c:%c%c ", date_month[tm->tm_mon], '0' + ((tm->tm_mday / 10) % 10), '0' + ((tm->tm_mday) % 10), '0' + ((tm->tm_hour / 10) % 10), '0' + ((tm->tm_hour) % 10), '0' + ((tm->tm_min / 10) % 10), '0' + ((tm->tm_min) % 10), '0' + ((tm->tm_sec / 10) % 10), '0' + ((tm->tm_sec) % 10)); buffer = buffer + strlen(buffer); if (log && log->peer_pid) sprintf(buffer, "[%lu:%lu] ", (unsigned long) log->peer_pid, (unsigned long) getpid()); else sprintf(buffer, "[%lu] ", (unsigned long) getpid()); buffer = buffer + strlen(buffer); if (username && username[0]) sprintf(buffer, "(%s) ", username); } /* log_terminate() ******************************************************* * * Terminate a log entry: make sure that it finishs with a '\n' * buffer: Working buffer * len: Current length of data in buffer ************************************************************************/ static unsigned long log_terminate(char *buffer, unsigned long len) { /* Make sure that string terminates with '\n' */ if ((len > 2) && (buffer[len - 2] == '\015') && (buffer[len - 1] == '\012')) { buffer[len - 2] = '\n'; /* CRLF -> LF */ buffer[len - 1] = '\0'; return (len - 1); } if ((len > 1) && ((buffer[len - 1] != '\015') && (buffer[len - 1] != '\012'))) { /* Add a "\n" to the end of the string */ buffer[len] = '\n'; buffer[len + 1] = '\0'; return (len + 1); } buffer[len - 1] = '\n'; /* CR or LF -> LF */ return (len); } /* log_out_of_memory() *************************************************** * * Out of memory while trying to report error. Send something to * syslog and paniclog so we have some idea what is going on. ************************************************************************/ static void log_out_of_memory(void) { if (log_progname) fprintf(stderr, "%s PANICLOG:\n", log_progname); else fprintf(stderr, "Prayer PANICLOG:\n"); fprintf(stderr, " [log_panic] Out of memory\n"); if (log_progname) openlog(log_progname, LOG_PID | LOG_CONS, LOG_MAIL); else openlog("prayer", LOG_PID | LOG_CONS, LOG_MAIL); syslog(LOG_ERR, "[log_panic] Out of memory"); closelog(); } /* ====================================================================== */ /* log_panic_ap() ******************************************************** * * Log string to panic log. If panic file cannot be opened then the message * is sent to syslog and stderr. * config: Configuration. * username: Username to put in log file. (NIL => none) * len: Length of (variable part of) log entry * fmt: Format string * ap: va_list ************************************************************************/ void log_panic_ap(struct config *config, char *username, unsigned long len, char *fmt, va_list ap) { char *buffer, *error; int fd; int timelen, maxlen; char *name; char *progname = (log_progname) ? log_progname : "prayer"; /* Only try ro write to file if config->log_dir defined and expanded */ if (config && config->log_dir && config->log_dir[0] && (config->log_dir[0] != '$')) name = pool_strcat3(NIL, config->log_dir, "/", "paniclog"); else name = NIL; /* Username string can be arbitrarily long */ maxlen = len + LOG_PREFIX_SIZE; if (username) maxlen += strlen(username) + 3; /* "(%s) " */ /* Alloc temporary buffer with space for Date + Expanded String + \n */ /* Important that _something_ reported to user */ if ((buffer = malloc(maxlen)) == NIL) { log_out_of_memory(); return; } log_timestamp(NIL, buffer, username); error = buffer + (timelen = strlen(buffer)); pool_vprintf(error, fmt, ap); len = log_terminate(error, len); if (name) { int open_flags; int open_perms; open_perms = ((config && config->file_perms) ? config->file_perms : 0644); if (getuid() != 0) open_flags = O_CREAT | O_APPEND | O_WRONLY; else open_flags = O_APPEND | O_WRONLY; if ((fd = open(name, open_flags, open_perms)) >= 0) { write(fd, buffer, timelen + len); close(fd); /* Copy error to stderr (noop after stderr redirected to /dev/null) */ fprintf(stderr, "%s: %s", progname, buffer); free(buffer); return; } } /* Failed to write to named file: write to stderr and syslog */ fprintf(stderr, "%s PANICLOG:\n", progname); fprintf(stderr, " Failed to open panic log file: \"paniclog\"\n"); fprintf(stderr, " Error was: %s", buffer); openlog(progname, LOG_PID | LOG_CONS, LOG_MAIL); if (name) syslog(LOG_ERR, "Failed to write log entry to \"%s\": %s", name, error); else syslog(LOG_ERR, "Failed to write log entry: %s", error); closelog(); free(buffer); } /* ====================================================================== */ /* log_ap() *************************************************************** * * Log string to open file descriptor * fd: Target file descriptor * pool: Scratch pool (NIL => malloc and free own memory) * username: Username to put in log file. * len: Length of (variable part of) log entry * fmt: Format string * ap: va_list ************************************************************************/ BOOL log_ap(struct log *log, struct pool *pool, char *username, unsigned long len, char *fmt, va_list ap) { char *output, *tmp; unsigned long timelen, maxlen; char log_tmp[LOG_TMP_SIZE + 1]; if (!log_ping(log)) return (NIL); /* Log file isn't open */ if (log->fd < 0) return (NIL); /* Username string can be arbitrarily long */ maxlen = len + LOG_PREFIX_SIZE; if (username) maxlen += strlen(username) + 3; /* "(%s) " */ /* Alloc temporary buffer with space for Date + Expanded String + \n */ if (pool) output = pool_alloc(pool, maxlen); else if ((maxlen) < LOG_TMP_SIZE) { output = log_tmp; } else if ((output = malloc(maxlen)) == NIL) { log_out_of_memory(); return (NIL); } /* Write timestamp, then log entry into the buffer */ log_timestamp(log, output, username); tmp = output + (timelen = strlen(output)); pool_vprintf(tmp, fmt, ap); len = log_terminate(tmp, len); /* Then punt the log entry to the file as a single (O_APPEND) write */ write(log->fd, output, timelen + len); if ((pool == NIL) && (output != log_tmp)) free(output); return (T); } /* log_here() ************************************************************* * * Log message to open log file * fd: File descriptor * fmt: Format string, followed by arguments. * * Returns: T on sucess ************************************************************************/ BOOL log_here(struct log * log, char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = pool_vprintf_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_ap(log, NIL, NIL, len, fmt, ap); va_end(ap); return (T); } /* log_record_peer_pid() ************************************************* * * Record process ID of peer (used by session access log only) * log: * pid: ************************************************************************/ void log_record_peer_pid(struct log *log, pid_t pid) { log->peer_pid = pid; } /* ====================================================================== */ /* ====================================================================== */ /* Support for process wide miscellaneous, debug and panic logs which * Don't require us to pass around global state handles. Seemed like a * good idea at the time, however this doesn't fit sit terribly well * with the rest of the prayer design. The routines are used mostly * by iostream classes and other. May want to come back and quietly * review this situation later */ /* A little bit of global state */ static struct log *log_misc_ptr = NIL; /* log_init() ************************************************************ * * Initialise the log subsystem: sets up the global state above. * config: Prayer configuration * progname: Program name * misc_log_name: Name for miscellaneous log entries (typically function * of progname) * * Returns: T => everything okay ************************************************************************/ BOOL log_misc_init(struct config *config, char *progname, char *log_name) { char *s; if ((s = strrchr(progname, '/'))) log_progname = strdup(s + 1); else log_progname = strdup(progname); log_misc_ptr = log_create(config, NIL); return (log_open(log_misc_ptr, log_name)); } /* log_misc_ping() ******************************************************* * * Reopen misc log file if required * ************************************************************************/ BOOL log_misc_ping() { return (log_ping(log_misc_ptr)); } /* ====================================================================== */ /* log_misc() ************************************************************* * * Log message to miscellaneous log if it is open * fmt: Format string, followed by arguments. ************************************************************************/ void log_misc(char *fmt, ...) { unsigned long len; va_list ap; if ((log_misc_ptr == NIL) || (log_misc_ptr->fd < 0)) return; va_start(ap, fmt); len = pool_vprintf_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_ap(log_misc_ptr, NIL, NIL, len, fmt, ap); va_end(ap); } /* log_debug() *********************************************************** * * Log message to miscellaneous log if it is open and debugging set * fmt: Format string, followed by arguments. ************************************************************************/ void log_debug(char *fmt, ...) { struct config *config = NIL; unsigned long len; va_list ap; if ((log_misc_ptr == NIL) || (log_misc_ptr->fd < 0)) return; if (log_misc_ptr->config) config = log_misc_ptr->config; if (config->log_debug == NIL) return; va_start(ap, fmt); len = pool_vprintf_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_ap(log_misc_ptr, NIL, NIL, len, fmt, ap); va_end(ap); } /* log_panic() *********************************************************** * * Log message to panic log * fmt: Format string, followed by arguments. ************************************************************************/ void log_panic(char *fmt, ...) { struct config *config = NIL; unsigned long len; va_list ap; if (log_misc_ptr && log_misc_ptr->config) config = log_misc_ptr->config; va_start(ap, fmt); len = pool_vprintf_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_panic_ap(config, NIL, len, fmt, ap); va_end(ap); } /* log_fatal() *********************************************************** * * Log message to panic log and exit. * fmt: Format string, followed by arguments. ************************************************************************/ void log_fatal(char *fmt, ...) { struct config *config = NIL; unsigned long len; va_list ap; va_start(ap, fmt); len = pool_vprintf_size(fmt, ap); va_end(ap); if (log_misc_ptr && log_misc_ptr->config) config = log_misc_ptr->config; va_start(ap, fmt); log_panic_ap(config, NIL, len, fmt, ap); va_end(ap); if (config && config->fatal_dump_core && (getuid() != 0)) abort(); exit(1); } ./prayer-1.3.5/shared/user_agent.h0000644006513000651300000000436211063701636015354 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/user_agent.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Preferences and overrides involving interaction with the user agent */ struct user_agent { struct pool *pool; /* Allocation pool */ char *agent; /* "User-Agent:" string from browser */ BOOL manual; /* Manual intervention by user */ BOOL use_override; /* Override defaults */ BOOL use_debug; /* Enable debug */ BOOL use_telemetry; /* Enable telemetry */ BOOL use_telemetry_all; /* Enable full telemetry */ BOOL use_telemetry_frontend; /* Enable telemetry:frontend servers */ BOOL use_icons; /* Enable icons */ BOOL use_cookie; /* Enable HTTP Cookie */ BOOL use_substitution; /* Enable Page substitution */ BOOL use_direct; /* Enable direct connection mode */ BOOL use_persist; /* Enable persistent HTTP connections */ BOOL use_http_1_1; /* Enable HTTP/1.1 */ BOOL use_pipelining; /* Enable HTTP/1.1 Pipelining */ BOOL use_short; /* Enable short URLS */ BOOL use_gzip; /* Enable gzip or x-gzip encoding */ }; struct user_agent *user_agent_create(struct pool *pool); void user_agent_free(struct user_agent *user_agent); struct user_agent *user_agent_clone(struct pool *pool, struct user_agent *src); void user_agent_copy(struct user_agent *dest, struct user_agent *src); void user_agent_generate_form(struct buffer *b, struct user_agent *ua); void user_agent_process_form(struct user_agent *ua, struct assoc *h); BOOL user_agent_process_argv(struct user_agent *ua, char *string, struct pool *p); char *user_agent_options(struct user_agent *ua); void user_agent_parse(struct user_agent *ua, char *string); void user_agent_setup_browser(struct user_agent *user_agent, char *browser); ./prayer-1.3.5/shared/response.c0000644006513000651300000010045711300506502015040 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/response.c,v 1.8 2009/11/17 11:47:14 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "shared.h" /* Routines for generating bits of HTTP response */ /* ====================================================================== */ static char *response_version = "Uninitialized"; /* response_record_version() *********************************************** * * Record version number: * **************************************************************************/ void response_record_version(char *version) { response_version = pool_strdup(NIL, version); } /* ====================================================================== */ /* response_status_text() ************************************************ * * Convert HTTP status code into human readable text ************************************************************************/ static char *response_status_text(unsigned long code) { static struct _HTTPReasons { unsigned long status; char *reason; } *reason, reasons[] = { { 100, "Continue"} , { 101, "Switching Protocols"} , { 200, "OK"} , { 201, "Created"} , { 202, "Accepted"} , { 203, "Non-Authoritative Information"} , { 204, "No Content"} , { 205, "Reset Content"} , { 206, "Partial Content"} , { 300, "Multiple Choices"} , { 301, "Moved Permanently"} , { 302, "Moved Temporarily"} , { 303, "See Other"} , { 304, "Not Modified"} , { 305, "Use Proxy"} , { 400, "Bad Request"} , { 401, "Unauthorized"} , { 402, "Payment Required"} , { 403, "Forbidden"} , { 404, "Not Found"} , { 405, "Method Not Allowed"} , { 406, "Not Acceptable"} , { 407, "Proxy Authentication Required"} , { 408, "Request Timeout"} , { 409, "Conflict"} , { 410, "Gone"} , { 411, "Length Required"} , { 412, "Precondition Failed"} , { 413, "Request Entity Too Large"} , { 414, "Request-URI Too Long"} , { 415, "Unsupported Media Type"} , { 500, "Internal Server Error"} , { 501, "Not Implemented"} , { 502, "Bad Gateway"} , { 503, "Service Unavailable"} , { 504, "Gateway Timeout"} , { 505, "HTTP Version Not Supported"} , { 000, NULL} }; reason = reasons; while (reason->status <= code) if (reason->status == code) return (reason->reason); else reason++; return "No Reason"; } /* ====================================================================== */ /* response_decode_date() ************************************************ * * Convert HTTP date string into time_t for time comparisons ************************************************************************/ static time_t response_decode_date(char *s) { int n = 0; struct tm tmvalue, *tm = &tmvalue; static char *date_month[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* Ignore spaces, day name and spaces */ while ((*s == ' ') || (*s == '\t')) s++; while ((*s != ' ') && (*s != '\t')) s++; while ((*s == ' ') || (*s == '\t')) s++; /* Scanf should be safe as only used to decode numbers, not strings here */ /* try to recognize the date format */ if ((sscanf(s, "%*s %d %d:%d:%d %d%*s", &tm->tm_mday, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, &tm->tm_year) != 5) && (sscanf(s, "%d %n%*s %d %d:%d:%d GMT%*s", &tm->tm_mday, &n, &tm->tm_year, &tm->tm_hour, &tm->tm_min, &tm->tm_sec) != 5) && (sscanf(s, "%d-%n%*[A-Za-z]-%d %d:%d:%d GMT%*s", &tm->tm_mday, &n, &tm->tm_year, &tm->tm_hour, &tm->tm_min, &tm->tm_sec) != 5)) return NIL; /* s points now to the month string */ s += n; for (n = 0; n < 12; n++) { char *p = date_month[n]; if (tolower(*p++) == tolower(*s)) if (*p++ == tolower(s[1])) if (*p == tolower(s[2])) break; }; if (n == 12) return (NIL); tm->tm_mon = n; /* finish the work */ if (tm->tm_year > 1900) tm->tm_year -= 1900; else if (tm->tm_year < 70) tm->tm_year += 100; tm->tm_isdst = 0; return (mktime(tm)); } /* ====================================================================== */ /* response_date_string() ************************************************ * * Print HTTP format date to output buffer ************************************************************************/ void response_date_string(struct buffer *b, time_t time) { static char *date_day[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char *date_month[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; struct tm *tm = gmtime(&time); bprintf(b, "%s, %c%c %s %lu %c%c:%c%c:%c%c GMT", date_day[tm->tm_wday], '0' + ((tm->tm_mday / 10) % 10), '0' + ((tm->tm_mday) % 10), date_month[tm->tm_mon], (unsigned long) tm->tm_year + 1900, '0' + ((tm->tm_hour / 10) % 10), '0' + ((tm->tm_hour) % 10), '0' + ((tm->tm_min / 10) % 10), '0' + ((tm->tm_min) % 10), '0' + ((tm->tm_sec / 10) % 10), '0' + ((tm->tm_sec) % 10)); } /* ====================================================================== */ /* response_header_prime() *********************************************** * * Prime response_hdrs component of request structure. Two calls for single * requests implies a logic fault in the main program, typically two * separate calls to response_html because cmd_something routine failed to * return correctly after page was generated. * request: Complete HTTP request * * Returns: (Empty) buffer that response headers will be written into ************************************************************************/ static struct buffer *response_header_prime(struct request *request) { if (request->response_hdrs) log_fatal("Request \"%s\" generated two responses: shutting down", request->request); request->response_hdrs = buffer_create(request->pool, RESPONSE_HDR_BLOCK_SIZE); return (request->response_hdrs); } /* response_header_start() *********************************************** * * Set up HTTP response based on request and user-agent configuration * and defaults. A few extra headers will be added for each type of * response. * request: Complete HTTP requests that we are responding to * (includes user-agent structure for this request) * status: HTTP response code to this request * ************************************************************************/ static void response_header_start(struct request *request, unsigned long status) { struct user_agent *ua = request->user_agent; char *s; time_t now = time(NIL); struct buffer *b = request->response_hdrs; /* Work out if this connection or its proxy is going to remain alive * after this r */ if (request->iseof) request->persist = NIL; else if (request->error) request->persist = NIL; else if (ua->use_persist == NIL) request->persist = NIL; else if (ua->use_http_1_1 && (request->major == 1) && (request->minor == 1)) { /* HTTP 1.1 defaults to Persistent connections */ if ((s = assoc_lookup(request->hdrs, "connection")) && !strcasecmp(s, "close")) request->persist = NIL; request->use_http_1_1 = T; } else { /* HTTP 1.0 defaults to connection close */ if (!((s = assoc_lookup(request->hdrs, "connection")) && (!strcasecmp(s, "Keep-Alive")))) request->persist = NIL; request->use_http_1_1 = NIL; } request->status = status; if (request->use_http_1_1) { /* HTTP 1.1 response */ bprintf(b, "HTTP/1.1 %lu %s" CRLF, status, response_status_text(status)); bputs(b, "Date: "); response_date_string(b, now); bputs(b, "" CRLF); bprintf(b, "Server: Prayer/%s" CRLF, response_version); bputs(b, "MIME-Version: 1.0" CRLF); bputs(b, "Allow: GET, HEAD, POST" CRLF); if (request->persist) bputs(b, "Connection: Keep-Alive" CRLF); else bputs(b, "Connection: close" CRLF); return; } /* HTTP 1.0 response */ bprintf(b, "HTTP/1.0 %lu %s" CRLF, status, response_status_text(status)); bputs(b, "Date: "); response_date_string(b, time(NIL)); bputs(b, "" CRLF); bprintf(b, "Server: Prayer/%s" CRLF, response_version); bputs(b, "MIME-Version: 1.0" CRLF); bputs(b, "Allow: GET, HEAD, POST" CRLF); /* Send Keep-Alive if HTTP 1.0 only if client requested Keep-Alive */ if (request->persist) bputs(b, "Connection: Keep-Alive" CRLF); } /* response_header_end() *********************************************** * * Finish off response_hdrs block. Doesn't actually do anything more * than add a CRLF separator line to the header block. Could eliminate * this routine by doing this in response_send * request: Complete HTTP requests that we are responding to * ************************************************************************/ static void response_header_end(struct request *request) { struct buffer *b = request->response_hdrs; bputs(b, "" CRLF); } /* ====================================================================== */ /* response_error() ****************************************************** * * Set up a (HTML) error response based on the given status code * request: Complete HTTP requests that we are responding to * status: Error code * ************************************************************************/ void response_error(struct request *request, unsigned long status) { struct config *config = request->config; struct buffer *b; char *errmsg = response_status_text(request->status = status); char *title = pool_printf(request->pool, "%lu %s", status, errmsg); if (buffer_size(request->write_buffer) > 0) request->write_buffer = buffer_create(request->pool, PREFERRED_BUFFER_BLOCK_SIZE); b = request->write_buffer; /* Generate a nice clean body for the error */ html_common_start(config, b, title); bprintf(b, "

%s

" CRLF, errmsg); if (request->url && request->url[0]) { if (status == 404) { bputs(b, "The requested URL \""); html_common_quote_string(b, request->url); bputs(b, "\" was not found on this server." CRLF); } else { bputs(b, "Error status from URL: \""); html_common_quote_string(b, request->url); bputs(b, "\"." CRLF); } } else { bprintf(b, "Error status %d (%s) from HTTP request:" CRLF, status, errmsg); if (request->request) { bputs(b, "
" CRLF); html_common_quote_string(b, request->request); bputs(b, "
" CRLF); } } html_common_end(b); /* Now generate the headers */ b = response_header_prime(request); request->error = T; response_header_start(request, status); if (request->use_http_1_1) bputs(b, ("Cache-control: no-cache, no-store, must-revalidate, " "post-check=0, pre-check=0" CRLF)); bputs(b, "Pragma: no-cache" CRLF); bputs(b, "Expires: "); response_date_string(b, time(NIL)); bputs(b, "" CRLF); bprintf(b, "Content-Type: text/html; charset=UTF-8" CRLF); bprintf(b, "Content-Length: %lu" CRLF, buffer_size(request->write_buffer)); response_header_end(request); } /* ====================================================================== */ /* response_html() ******************************************************* * * Set up HTTP headers for a HTML response. * request: Complete HTTP request * status: Status code * ************************************************************************/ void response_html(struct request *request, unsigned long status) { struct buffer *b = response_header_prime(request); unsigned long size = buffer_size(request->write_buffer); #ifdef GZIP_ENABLE if (request->allow_gzip && request->user_agent->use_gzip) { if (request->use_gzip || request->use_x_gzip) { request->gzip_buffer = gzip(request->write_buffer); size = buffer_size(request->gzip_buffer); } } #endif /* Generate simple header block for HTML */ response_header_start(request, status); bputs(b, "Content-Type: text/html; charset=UTF-8" CRLF); if (request->use_http_1_1) bputs(b, ("Cache-control: no-cache, no-store, must-revalidate, " "post-check=0, pre-check=0" CRLF)); else bputs(b, "Pragma: no-cache" CRLF); bputs(b, "Expires: "); response_date_string(b, time(NIL)); bputs(b, "" CRLF); bprintf(b, "Content-Length: %lu" CRLF, size); #ifdef GZIP_ENABLE if (request->gzip_buffer) { if (request->use_gzip) bputs(b, "Content-Encoding: gzip" CRLF); else if (request->use_x_gzip) bputs(b, "Content-Encoding: x-gzip" CRLF); } #endif response_header_end(request); } /* response_text() ******************************************************* * * Set up HTTP headers for a text/plain response. * request: Complete HTTP request * status: Status code * ************************************************************************/ void response_text(struct request *request, unsigned long status) { struct buffer *b = response_header_prime(request); unsigned long size = buffer_size(request->write_buffer); #ifdef GZIP_ENABLE if (request->allow_gzip && request->user_agent->use_gzip) { if (request->use_gzip || request->use_x_gzip) { request->gzip_buffer = gzip(request->write_buffer); size = buffer_size(request->gzip_buffer); } } #endif /* Generate simple header block for simple text */ response_header_start(request, status); bputs(b, "Content-Type: text/plain; charset=utf-8"CRLF); if (request->use_http_1_1) bputs(b, ("Cache-control: no-cache, no-store, must-revalidate, " "post-check=0, pre-check=0" CRLF)); else bputs(b, "Cache-control: no-cache" CRLF); bputs(b, "Expires: "); response_date_string(b, time(NIL)); bputs(b, "" CRLF); bprintf(b, "Content-Length: %lu" CRLF, size); #ifdef GZIP_ENABLE if (request->gzip_buffer) { if (request->use_gzip) bputs(b, "Content-Encoding: gzip" CRLF); else if (request->use_x_gzip) bputs(b, "Content-Encoding: x-gzip" CRLF); } #endif response_header_end(request); } /* response_raw() ******************************************************** * * Set up HTTP headers for a raw (binary) response. * request: Complete HTTP request * name: Name of attachment (most user-agents ignore this?) * type: Typically "application/octet-stream". Conceivable that other * values have some use. * status: Status code * * Notes: Content-Disposition defined by RFC 2183 * MSIE has numerous bugs related to file downloads. * ************************************************************************/ void response_raw(struct request *request, char *name, char *type, unsigned long status) { struct buffer *b = response_header_prime(request); unsigned long size = buffer_size(request->write_buffer); char *ua; #ifdef GZIP_ENABLE if (request->allow_gzip && request->user_agent->use_gzip) { if ((ua = assoc_lookup(request->hdrs, "user-agent")) && strstr(ua, "Opera")) { /* No gzip for Opera attachment downloads: Opera is broken */ } else if (request->use_gzip || request->use_x_gzip) { request->gzip_buffer = gzip(request->write_buffer); size = buffer_size(request->gzip_buffer); } } #endif if (name) { char *s; /* Isolate last component of name */ if ((s = strrchr(name, '/'))) name = s + 1; else if ((s = strrchr(name, '\\'))) name = s + 1; /* Replace " characters from name to prevent quoting problems */ /* Tab characters cause problems for MSIE */ name = pool_strdup(request->pool, name); for (s = name; *s; s++) { if (*s == '"') *s = '_'; if (*s == '\t') *s = '_'; } } else name = "unknown"; if ((ua = assoc_lookup(request->hdrs, "user-agent")) && !strncasecmp(ua, "Mozilla/4.0 (compatible; MSIE ", strlen("Mozilla/4.0 (compatible; MSIE ")) && !strstr(ua, "Opera")) { /* Handle MSIE as special case: very broken! */ /* NB: Opera may claim to be MSIE, but it really isn't! */ /* Switch off HTTP/1.1 and KeepAlive for this request */ request->user_agent->use_http_1_1 = NIL; request->user_agent->use_persist = NIL; /* Generate simple header block for simple text */ response_header_start(request, status); bputs(b, "Content-Transfer-Encoding: binary" CRLF); /* Stolen from IMP */ bprintf(b, "Content-Type: application/x-msdownload" CRLF); bprintf(b, "Content-Disposition: attachment; filename=\"%s\"" CRLF, string_url_encode(request->pool, name)); /* MSIE can't cope with download links which expire immediately? */ bputs(b, "Expires: "); response_date_string(b, time(NIL) + (10 * 60)); /* 10 mins */ bputs(b, "" CRLF); } else { /* Everything else seems to cope just fine with following code */ response_header_start(request, status); bputs(b, "Content-Transfer-Encoding: binary" CRLF); /* Stolen from Squirelmail */ bprintf(b, "Content-Type: %s; name=\"%s\"" CRLF, type, name); bprintf(b, "Content-Disposition: attachment; filename=\"%s\"" CRLF, name); if (request->use_http_1_1) bputs(b, ("Cache-control: no-cache, no-store, must-revalidate, " "post-check=0, pre-check=0" CRLF)); else bputs(b, "Pragma: no-cache" CRLF); bputs(b, "Expires: "); response_date_string(b, time(NIL)); bputs(b, "" CRLF); } bprintf(b, "Content-Length: %lu" CRLF, size); #ifdef GZIP_ENABLE if (request->gzip_buffer) { if (request->use_gzip) bputs(b, "Content-Encoding: gzip" CRLF); else if (request->use_x_gzip) bputs(b, "Content-Encoding: x-gzip" CRLF); } #endif response_header_end(request); } /* ====================================================================== */ /* response_file() ******************************************************* * * Set up HTTP headers for a raw (binary) response of known type. * request: Complete HTTP request * method: Method (can get from request!) * filename: File to send * timeout: Timeout for this file (typically deefined by config). * if_modified_since: HTTP header if exists. * * Returns: T => response buffers set up successfully * NIL => no such file. Up to client routine to send error page ************************************************************************/ BOOL response_file(struct request *request, HTTP_METHOD method, char *filename, unsigned long timeout, char *if_modified_since) { struct buffer *b; struct stat sbuf; char *e = strrchr(filename, '.'); FILE *file; int c; char *s; s = filename; /* Check file rather than directory */ if ((stat(s, &sbuf) != 0) || (S_ISDIR(sbuf.st_mode))) { response_error(request, 404); return (NIL); } if (if_modified_since && (method == GET)) { if (response_decode_date(if_modified_since) > sbuf.st_mtime) { /* Not modified */ response_header_prime(request); response_header_start(request, 304); response_header_end(request); return (T); } } if ((file = fopen(s, "r")) == NIL) { request->error = T; response_error(request, 404); return (NIL); } b = response_header_prime(request); response_header_start(request, 200); /* Success */ if (e) { if (!strcasecmp(e, ".html") || !strcasecmp(e, ".htm")) bputs(b, "Content-Type: text/html; charset=utf-8" CRLF); else if (!strcasecmp(e, ".gif")) bputs(b, "Content-Type: image/gif" CRLF); else if (!strcasecmp(e, ".jpg")) bputs(b, "Content-Type: image/jpeg" CRLF); else if (!strcasecmp(e, ".png")) bputs(b, "Content-Type: image/png" CRLF); else if (!strcasecmp(e, ".ico")) bputs(b, "Content-Type: image/png" CRLF); else if (!strcasecmp(e, ".css")) bputs(b, "Content-Type: text/css" CRLF); else if (!strcasecmp(e, ".js")) bputs(b, "Content-Type: text/javascript" CRLF); else bputs(b, "Content-Type: text/plain" CRLF); } else bputs(b, "Content-Type: text/plain" CRLF); bprintf(b, "Content-Length: %lu" CRLF, sbuf.st_size); /* Following stolen from Apache: * * Make an ETag header out of various pieces of information. We use * the last-modified date and, if we have a real file, the * length and inode number - note that this doesn't have to match * the content-length (i.e. includes), it just has to be unique * for the file. * * If the request was made within a second of the last-modified date, * we send a weak tag instead of a strong one, since it could * be modified again later in the second, and the validation * would be incorrect. */ bprintf(b, "ETag: \"%lx-%lx-%lx\"" CRLF, (unsigned long) sbuf.st_ino, (unsigned long) sbuf.st_size, (unsigned long) sbuf.st_mtime); bputs(b, "Expires: "); response_date_string(b, (time(NIL) + timeout)); bputs(b, "" CRLF); bputs(b, "Last-Modified: "); response_date_string(b, sbuf.st_mtime); bputs(b, "" CRLF); response_header_end(request); /* Now punt data to the write buffer */ b = request->write_buffer; if (method != HEAD) { while ((c = fgetc(file)) != EOF) bputc(b, c); } fclose(file); return (T); } /* ====================================================================== */ /* response_0.9_error() ************************************************** * * Set up a (HTML) error page for unqualified requests * request: Complete HTTP request ************************************************************************/ void response_0_9_error(struct request *request) { struct config *config = request->config; struct buffer *b; if (buffer_size(request->write_buffer) > 0) { buffer_free(request->write_buffer); request->write_buffer = buffer_create(request->pool, PREFERRED_BUFFER_BLOCK_SIZE); } b = request->write_buffer; html_common_start(config, b, "Unsupported Browser"); bprintf(b, "This application needs a HTTP/1.0 or better" CRLF); bprintf(b, "browser which supports POST" CRLF); html_common_end(b); response_html(request, 501); /* Not implemented */ } /* ====================================================================== */ /* response_redirect() ************************************************** * * Set up HTTP headers for a HTTP temporary redirect (302 response) * request: Complete HTTP request * location: Target for redirection ************************************************************************/ void response_redirect(struct request *request, char *location) { struct buffer *b = response_header_prime(request); /* Temporary redirection */ response_header_start(request, 302); bprintf(b, "Location: %s" CRLF, location); bputs(b, "Content-Length: 0" CRLF); response_header_end(request); /* Clear out any body data which we might have accumulated */ if (buffer_size(request->write_buffer) > 0) request->write_buffer = buffer_create(request->pool, PREFERRED_BUFFER_BLOCK_SIZE); } /* response_cookie_redirect() ******************************************** * * Set up HTTP headers for a HTTP temporary redirect (302 response) * which also sets up a Cookie. * request: Complete HTTP request * location: Target for redirection * cookie_key: Cookie Key * cookie_value: Cookie Value * path: Restrict Cookie to this path * domain: Restrict Cookie to this domain * secure: Mark Cookie as SSL-only ************************************************************************/ void response_cookie_redirect(struct request *request, char *location, char *cookie_key, char *cookie_value, char *path, char *domain, BOOL secure) { struct buffer *b = response_header_prime(request); /* Generate simple header block */ /* Temporary redirection */ response_header_start(request, 302); bprintf(b, "Location: %s" CRLF, location); bputs(b, "Content-Length: 0" CRLF); #if 1 /* XXX Experiment: do "sesion cookies" work reliably? */ bprintf(b, "Set-Cookie: %s=%s; path=%s; domain=%s", cookie_key, cookie_value, path, domain); if (secure) bputs(b, "; secure"); bputs(b, "" CRLF); #else bprintf(b, "Set-Cookie: %s=%s; path=%s; domain=%s", cookie_key, cookie_value, path, domain); if (secure) bputs(b, "; secure"); bputs(b, "; expires="); response_date_string(b, time(NIL) + (24 * 60 * 60)); bputs(b, "" CRLF); #endif response_header_end(request); /* Clear out any body data which we might have accumulated */ if (buffer_size(request->write_buffer) > 0) request->write_buffer = buffer_create(request->pool, PREFERRED_BUFFER_BLOCK_SIZE); } /* response_clear_cookie_redirect() ************************************** * * Set up HTTP headers for a HTTP temporary redirect (302 response) * which also clears a Cookie. * request: Complete HTTP request * location: Target for redirection * cookie_key: Cookie Key * cookie_value: Cookie Value * path: Restrict Cookie to this path * domain: Restrict Cookie to this domain * secure: Mark Cookie as SSL-only ************************************************************************/ void response_clear_cookie_redirect(struct request *request, char *location, char *cookie_key, char *cookie_value, char *path, char *domain, BOOL secure) { struct buffer *b = response_header_prime(request); /* Generate simple header block */ /* Temporary redirection */ response_header_start(request, 302); bprintf(b, "Location: %s" CRLF, location); bputs(b, "Content-Length: 0" CRLF); bprintf(b, "Set-Cookie: %s=%s; path=%s; domain=%s", cookie_key, cookie_value, path, domain); if (secure) bputs(b, "; secure"); bputs(b, "; Max-Age=0; expires="); response_date_string(b, time(NIL)); bputs(b, "" CRLF); response_header_end(request); /* Clear out any body data which we might have accumulated */ if (buffer_size(request->write_buffer) > 0) request->write_buffer = buffer_create(request->pool, PREFERRED_BUFFER_BLOCK_SIZE); } /* ====================================================================== */ /* response_telemetry_all() ********************************************** * * Record full request and response in telemetry file for debugging. * which also clears a Cookie. * request: Complete HTTP request ************************************************************************/ static void response_telemetry_all(struct request *request) { BOOL body = (request->method != HEAD); unsigned long count; unsigned long request_size; unsigned long size; char *block; char *s; struct buffer *b; int c; request_size = buffer_size(request->read_buffer); if (body) size = (request_size + buffer_size(request->response_hdrs) + buffer_size(request->write_buffer)); else size = request_size + buffer_size(request->response_hdrs); block = pool_alloc(request->pool, size + 1); s = block; b = request->read_buffer; buffer_rewind(b); count = 0; while (((c = bgetc(b)) != EOF) && (count < request_size)) { *s++ = c; count++; } b = request->response_hdrs; buffer_rewind(b); while ((c = bgetc(b)) != EOF) *s++ = c; if (body) { b = request->write_buffer; buffer_rewind(b); while ((c = bgetc(b)) != EOF) *s++ = c; } *s = '\0'; write(request->telemetry_fd, block, size); } /* response_telemetry() *************************************************** * * Record request and response hdrs in telemetry file for debugging. * request: Complete HTTP request ************************************************************************/ static void response_telemetry(struct request *request) { unsigned long count; unsigned long request_size; unsigned long size; char *block; char *s; struct buffer *b; int c; request_size = request->method_size + request->hdrs_size + 1; size = request_size + buffer_size(request->response_hdrs); block = pool_alloc(request->pool, size + 1); s = block; b = request->read_buffer; buffer_rewind(b); count = 0; while (((c = bgetc(b)) != EOF) && (count < request_size)) { *s++ = c; count++; } b = request->response_hdrs; buffer_rewind(b); while ((c = bgetc(b)) != EOF) *s++ = c; *s = '\0'; write(request->telemetry_fd, block, size); } /* ====================================================================== */ /* XXX Temporary */ static void response_dump(struct request *request) { struct buffer *b = request->write_buffer; FILE *file; int c; if ((file=fopen("last-response.html", "w")) == NULL) return; buffer_rewind(b); while ((c = bgetc(b)) != EOF) fputc(c, file); fclose(file); } /* ====================================================================== */ /* response_send() ******************************************************* * * Actually send a complete HTTP response after header and body setup * request: Complete HTTP request, including links to response structure * and iostream that connects up to client. ************************************************************************/ void response_send(struct request *request) { struct iostream *stream = request->stream; struct buffer *b; BOOL body = (request->method != HEAD); int c; if (!request->response_hdrs) log_fatal("Request \"%s\" generated no response", request->request); /* writev possible here? Only on plaintext connections! */ b = request->response_hdrs; buffer_rewind(b); while ((c = bgetc(b)) != EOF) ioputc(c, stream); if (body) { if (request->gzip_buffer) b = request->gzip_buffer; else b = request->write_buffer; buffer_rewind(b); while ((c = bgetc(b)) != EOF) ioputc(c, stream); } if (request->dump) response_dump(request); if (request->telemetry_all) response_telemetry_all(request); else if (request->telemetry) response_telemetry(request); } ./prayer-1.3.5/shared/response.h0000644006513000651300000000312211063701636015047 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/response.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Chunk size for response header block. Typical hdr << 1024 bytes */ #define RESPONSE_HDR_BLOCK_SIZE (1024) void response_record_version(char *version); struct request *response_create(struct pool *p, struct iostream *stream); void response_add_header(struct request *r, char *hdr); void response_discard_headers(struct request *r); void response_error(struct request *r, unsigned long status); void response_html(struct request *r, unsigned long status); void response_text(struct request *r, unsigned long status); void response_raw(struct request *r, char *name, char *type, unsigned long status); BOOL response_file(struct request *request, HTTP_METHOD method, char *filename, unsigned long timeout, char *if_modified_since); void response_redirect(struct request *request, char *location); void response_cookie_redirect(struct request *request, char *location, char *cookie_key, char *cookie_value, char *path, char *domain, BOOL secure); void response_clear_cookie_redirect(struct request *request, char *location, char *cookie_key, char *cookie_value, char *path, char *domain, BOOL secure); void response_0_9_error(struct request *request); void response_send(struct request *request); ./prayer-1.3.5/shared/request.h0000644006513000651300000001327111063701636014707 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/request.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Methods to process HTTP header */ typedef enum { UNKNOWN, OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT } HTTP_METHOD; typedef enum { REQUEST_METHOD, REQUEST_HDRS, REQUEST_BODY_SIMPLE, REQUEST_BODY_CHUNKED, REQUEST_COMPLETE } REQUEST_STATE; typedef enum { CHUNK_HDR, CHUNK_BODY, CHUNK_TRAILER, CHUNK_COMPLETE } CHUNK_STATE; struct request { /* Common fields */ struct pool *pool; /* Allocate memory from this pool */ struct config *config; /* Global configuration */ struct iostream *stream; /* Bidirection pipe with client */ /* Input buffer */ struct buffer *read_buffer; /* Incoming request */ struct buffer *chunked; /* Decoded version of chunked encoding */ REQUEST_STATE state; /* State of current request */ unsigned long method_size; /* Offset to hdrs in read_buffer */ unsigned long hdrs_offset; /* Offset to hdrs in read_buffer */ unsigned long hdrs_size; /* Size of hdrs in read_buffer */ unsigned long hdrs_crlfs; /* Size of hdrs in read_buffer */ unsigned long body_offset; /* Offset to body in read_buffer */ unsigned long body_current; /* Current number of bytes fetched */ unsigned long body_size; /* Size of body in read_buffer */ CHUNK_STATE chunk_state; /* State of current chunk */ unsigned long chunk_hdr_offset; /* Offset for current chunk hdr */ unsigned long chunk_hdr_current; /* Offset for current chunk hdr */ unsigned long chunk_hdr_size; /* Size of current chunk header */ unsigned long chunk_body_offset; /* Offset for current chunk hdr */ unsigned long chunk_body_current; /* Offset for current chunk hdr */ unsigned long chunk_body_size; /* Size of current chunk header */ unsigned long chunk_trlr_offset; /* Offset to trailers, if used */ unsigned long chunk_trlr_size; /* Size of trailer, if used */ unsigned long chunk_trlr_crlfs; /* CRLFs in trailer, if used */ BOOL frontend; /* Frontend server */ BOOL preserve; /* Preserve headers for proxy or telemetry */ BOOL iseof; /* Reached EOF */ BOOL error; /* Request generated error */ /* Decoded request */ char *request; /* Copy of request line */ unsigned long major; /* Major HTTP revision */ unsigned long minor; /* Minor HTTP revision */ char *url; /* Copy of original request URL */ char *url_host; /* Host component in request URL */ char *url_port; /* Port component in request URL */ char *url_path; /* Path component in request URL */ int argc; /* Number of components in path */ char **argv; /* Individual components in path */ char *get_suffix; /* String following '?' in GET request */ char *log_entry; /* Replaces HTTP request in logs */ /* Processed request */ HTTP_METHOD method; /* HTTP method */ struct assoc *hdrs; /* Headers used in this request */ struct assoc *form; /* Hash key->value for GET or POST request */ /* Response information */ unsigned long status; /* Status of this request */ BOOL dump; /* XXX For templates */ BOOL telemetry; /* Send headers in telemetry */ BOOL telemetry_all; /* Send everything in telemetry */ int telemetry_fd; /* File descriptor for telemetry */ struct buffer *response_hdrs; /* Pending response */ struct buffer *write_buffer; /* Body of Pending response */ struct buffer *gzip_buffer; /* Compressed response */ struct user_agent *user_agent; /* Link to user-agent info */ BOOL use_http_1_1; /* Using HTTP 1.1 in response */ BOOL persist; /* Keep connection open after request */ BOOL use_utf8; /* Use UTF-8 in output */ BOOL allow_gzip; /* Allow gzip encoding */ BOOL use_gzip; /* Use gzip in output */ BOOL use_x_gzip; /* Use x-gzip in output */ }; #define REQUEST_PREFERRED_BLOCK_SIZE (8192) struct request *request_create(struct config *config, struct iostream *stream, BOOL isproxy); void request_free(struct request *request); void request_dump(struct request *request); void request_telemetry(struct request *request, int fd, BOOL all); void request_forge_redirect(struct request *request, char *url); BOOL request_parse(struct request *request); BOOL request_complete(struct request *request); BOOL request_decode_post_multipart(struct request *request, struct assoc *hdrs, char **start, char **end); void request_decode_form(struct request *request); void request_parse_argv(struct request *request); void request_parse_charset(struct request *request); void request_parse_encoding(struct request *request); int request_test_referer(struct request *request, char *hostname); ./prayer-1.3.5/shared/shared.h0000644006513000651300000000203011063701636014454 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/shared.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include "lib.h" #include "common.h" #include "config.h" #include "user_agent.h" #include "request.h" #include "response.h" #include "gzip.h" #include "html_common.h" #include "setproctitle.h" #include "mymutex.h" #include "log.h" ./prayer-1.3.5/shared/config.c0000644006513000651300000026110311773606560014466 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/config.c,v 1.12 2012/06/30 14:30:08 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "shared.h" /* Class to manage Prayer configuration */ /* ====================================================================== */ /* Code to compute canonical hostname, stolen from PINE */ /*---------------------------------------------------------------------- Get the current host and domain names Args: hostname -- buffer to return the hostname in hsize -- size of buffer above domainname -- buffer to return domain name in dsize -- size of buffer above Result: The system host and domain names are returned. If the full host name is akbar.cac.washington.edu then the domainname is cac.washington.edu. On Internet connected hosts this look up uses /etc/hosts and DNS to figure all this out. On other less well connected machines some other file may be read. If there is no notion of a domain name the domain name may be left blank. On a PC where there really isn't a host name this should return blank strings. The .pinerc will take care of configuring the domain names. That is, this should only return the native system's idea of what the names are if the system has such a concept. ----*/ #define MAX_ADDRESS (511) static void getdomainnames(char *hostname, int hsize, char *domainname, int dsize) { char *dn, hname[MAX_ADDRESS+1]; struct hostent *he; char **alias; char *maybe = NULL; gethostname(hname, MAX_ADDRESS); he = gethostbyname(hname); hostname[0] = '\0'; if(he == NULL){ strncpy(hostname, hname, hsize-1); hostname[hsize-1] = '\0'; } else{ /* * If no dot in hostname it may be the case that there * is an alias which is really the fully-qualified * hostname. This could happen if the administrator has * (incorrectly) put the unqualified name first in the * hosts file, for example. The problem with looking for * an alias with a dot is that now we're guessing, since * the aliases aren't supposed to be the official hostname. * We'll compromise and only use an alias if the primary * name has no dot and exactly one of the aliases has a * dot. */ strncpy(hostname, he->h_name, hsize-1); hostname[hsize-1] = '\0'; if (strchr(hostname, '.') == NULL) { /* no dot in hostname */ for(alias = he->h_aliases; *alias; alias++){ if(strchr(*alias, '.') != NULL){ /* found one */ if(maybe){ /* oops, this is the second one */ maybe = NULL; break; } else maybe = *alias; } } if(maybe){ strncpy(hostname, maybe, hsize-1); hostname[hsize-1] = '\0'; } } } hostname[hsize-1] = '\0'; if((dn = strchr(hostname, '.')) != NULL) strncpy(domainname, dn+1, dsize-1); else strncpy(domainname, hostname, dsize-1); domainname[dsize-1] = '\0'; } /* ====================================================================== */ struct config_theme *config_theme_create(struct pool *pool) { struct config_theme *theme = pool_alloc(pool, sizeof(struct config_theme)); memset(theme, 0, sizeof(struct config_theme)); theme->name = NIL; /* Theme Name */ theme->description = NIL; /* Theme description */ theme->fgcolor = NIL; /* Default foreground colour */ theme->fgcolor = NIL; /* Default link colour */ theme->bgcolor = NIL; /* Default background colour */ theme->bgcolor_banner = NIL; /* Background for cmd banners */ theme->bgcolor_row1 = NIL; /* Background for even rows */ theme->bgcolor_row2 = NIL; /* Background for odd rows */ theme->bgcolor_status = NIL; /* Background for status lines */ theme->bgcolor_status_none = NIL; /* Background empty status lines */ theme->fgcolor_quote1 = NIL; /* 1st level of quoting */ theme->fgcolor_quote2 = NIL; /* 2nd level of quoting */ theme->fgcolor_quote3 = NIL; /* 3rd level of quoting */ theme->fgcolor_quote4 = NIL; /* 4th level of quoting */ return (theme); } /* ====================================================================== */ /* config_create() ********************************************************* * * Create a new config structure using own pool **************************************************************************/ struct config *config_create(void) { struct pool *pool = pool_create(CONFIG_PREFERRED_POOL_SIZE); struct config *config = pool_alloc(pool, sizeof(struct config)); memset(config, 0, sizeof(struct config)); config->pool = pool; config->prefix = NIL; config->var_prefix = NIL; config->raven_enable = NIL; config->raven_key_path = ""; config->login_insert1_path = NIL; config->login_insert2_path = NIL; config->login_template = "login"; config->motd_path = NIL; config->welcome_path = NIL; config->icon_dir = NIL; config->static_dir = NIL; config->static_expire_timeout = (7 * 24 * 60 * 60); /* 7 days */ config->socket_dir = NIL; config->socket_split_dir = NIL; config->ssl_cipher_list = NIL; config->ssl_server_preference = NIL; config->ssl_session_dir = NIL; config->lock_dir = NIL; config->log_dir = NIL; config->tmp_dir = NIL; config->pid_dir = NIL; config->bin_dir = NIL; config->init_socket_name = NIL; config->file_perms = 0640; config->directory_perms = 0750; config->check_directory_perms = NIL; config->log_debug = NIL; config->fatal_dump_core = NIL; config->template_path = "../templates"; config->template_set = "old"; config->template_use_compiled = T; config->template_list = NIL; config->prayer_user = NIL; config->prayer_uid = 0; config->prayer_group = NIL; config->prayer_gid = 0; config->prayer_background = T; config->hostname = NIL; config->hostname_service = NIL; config->hostname_canonical = NIL; config->referer_log_invalid = T; config->referer_block_invalid = NIL; config->fix_client_ipaddr = NIL; config->gzip_allow_nets = NIL; config->gzip_deny_nets = NIL; config->log_name_nets = NIL; config->limit_vm = 0; config->recips_max_msg = 0; config->recips_max_session = 0; config->sending_allow_dir = NIL; config->sending_block_dir = NIL; config->http_cookie_use_port = NIL; config->http_max_method_size = 0; config->http_max_hdr_size = 0; config->http_max_body_size = 0; config->http_port_list = NIL; config->http_timeout_idle = 30; config->http_timeout_icons = 10; config->http_timeout_session = 60; config->http_min_servers = 4; config->http_max_servers = 64; config->http_max_connections = 0; config->http_dump = NIL; config->ssl_cert_file = NIL; config->ssl_privatekey_file = NIL; config->ssl_dh_file = NIL; config->ssl_rsakey_lifespan = 15 * 60; config->ssl_rsakey_freshen = 15 * 60; config->ssl_session_timeout = 0; /* Disable session cache */ config->ssl_default_port = 0; config->ssl_encouraged = NIL; config->ssl_redirect = NIL; config->ssl_required = NIL; config->egd_socket = NIL; config->direct_enable = NIL; config->direct_ssl_first = 0; config->direct_ssl_count = 0; config->direct_plain_first = 0; config->direct_plain_count = 0; config->session_idle_time = 0; /* Disable idle mode */ config->session_timeout = (4 * 60 * 60); /* 4 hours */ config->session_timeout_compose = 0; /* Same as main timeout */ config->icon_expire_timeout = (7 * 24 * 60 * 60); /* 7 days */ config->session_key_len = 18; config->stream_checkpoint = T; config->stream_misc_timeout = 0; config->stream_ping_interval = (5 * 60); /* 5 mins */ config->log_ping_interval = (5 * 60); /* 5 mins */ config->db_ping_interval = (30 * 60); /* 30 mins */ config->login_banner = NIL; config->login_service_name = NIL; config->list_addr_maxlen = 30; config->list_subject_maxlen = 30; config->local_domain_list = NIL; config->local_domain_time = 0; config->filter_domain_pattern = NIL; config->change_max_folders = 20; config->draft_att_single_max = 0; config->draft_att_total_max = 0; config->imapd_user_map = NIL; config->imapd_server = NIL; config->prefs_folder_name = NIL; config->accountd_user_map = NIL; config->accountd_server = NIL; config->accountd_nis_server = NIL; config->accountd_passwd_delay = 0; config->accountd_fullname_delay = 0; config->vacation_default_days = 31; config->accountd_timeout = NIL; config->sieve_maxsize = 0; config->sieved_user_map = NIL; config->sieved_server = NIL; config->sieved_timeout = (9*60); /* Seconds */ config->sendmail_path = "/usr/lib/sendmail"; config->aspell_path = NIL; config->ispell_path = NIL; config->return_path_domain = NIL; config->fix_from_address = NIL; config->spam_purge_timeout = 60; config->spam_purge_name = "spam_purge"; config->spam_purge_prefix = "# Spam Purge Timeout:"; config->strip_mail = NIL; config->lookup_fullname = NIL; config->lookup_rpasswd = NIL; config->lookup_rusername = NIL; config->lookup_username = NIL; config->ldap_server = NIL; config->ldap_base_dn = NIL; config->ldap_timeout = 0; config->theme_list = NIL; config->theme_default_main = NIL; config->theme_default_help = NIL; config->theme_main = NIL; config->theme_help = NIL; config->allow_raven_login = T; config->confirm_expunge = NIL; config->confirm_logout = T; config->confirm_rm = T; config->expunge_on_exit = NIL; config->msgs_per_page = 12; config->msgs_per_page_max = 50; config->msgs_per_page_min = 4; config->abook_per_page = 12; config->abook_per_page_max = 50; config->abook_per_page_min = 4; config->suppress_dotfiles = T; config->use_namespace = T; config->maildir = ""; config->personal_hierarchy = ""; config->hiersep = "/"; config->dualuse = NIL; config->postponed_folder = "postponed-msgs"; config->sent_mail_folder = "sent-mail"; config->default_domain = NIL; config->ispell_language = "british"; config->spell_skip_quoted = T; config->small_cols = 80; config->small_rows = 18; config->large_cols = 80; config->large_rows = 32; config->sort_mode = "ARRIVAL"; config->sort_reverse = NIL; config->abook_sort_mode = "ORDERED"; config->abook_sort_reverse = NIL; config->line_wrap_len = 76; config->line_wrap_advanced = NIL; config->line_wrap_on_reply = T; config->line_wrap_on_spell = T; config->line_wrap_on_send = T; config->use_sent_mail = T; config->use_search_zoom = T; config->use_agg_unmark = T; config->use_icons = T; config->use_welcome = T; config->use_unread = T; config->use_tail_banner = T; config->use_mark_persist = NIL; config->use_cookie = T; config->use_substitution = T; config->use_http_1_1 = T; config->use_pipelining = T; config->use_persist = T; config->use_short = T; config->use_gzip = T; config->html_inline = T; config->html_inline_auto = T; config->html_remote_images = NIL; config->preserve_mimetype = T; return (config); } /* config_free() ********************************************************* * * Free config structure ************************************************************************/ void config_free(struct config *config) { pool_free(config->pool); } /* ====================================================================== */ /* config_paniclog() ******************************************************* * * Special interation of paniclog() to print errrors consistently when * frontend or session starting up with introducing dependancies on code * which is specific to the frontend or session processes. **************************************************************************/ static void config_paniclog(struct config *config, char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = log_entry_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_panic_ap(config, NIL, len, fmt, ap); va_end(ap); } /* ====================================================================== */ /* conf used only to calculate offsets into live config structure */ static struct config conf; #define OFFSET(x) ((char*)(&conf.x) - (char *)&conf) /* Config options. Searched by binary chop => must be sorted correctly * However config_init() checks that order is correct, bails out otherwise */ static struct { char *name; enum { config_bool, config_number, config_time, config_string, config_path, config_list, config_perm, config_unknown } type; int offset; } config_options[] = { { "abook_per_page", config_number, OFFSET(abook_per_page)} , { "abook_per_page_max", config_number, OFFSET(abook_per_page_max)} , { "abook_per_page_min", config_number, OFFSET(abook_per_page_min)} , { "abook_sort_mode", config_string, OFFSET(abook_sort_mode)} , { "abook_sort_reverse", config_bool, OFFSET(abook_sort_reverse)} , { "accountd_fullname_delay", config_time, OFFSET(accountd_fullname_delay)} , { "accountd_nis_server", config_string, OFFSET(accountd_nis_server)} , { "accountd_passwd_delay", config_time, OFFSET(accountd_passwd_delay)} , { "accountd_server", config_string, OFFSET(accountd_server)} , { "accountd_timeout", config_time, OFFSET(accountd_timeout)} , { "accountd_user_map", config_path, OFFSET(accountd_user_map)} , { "allow_raven_login", config_bool, OFFSET(allow_raven_login)} , { "aspell_path", config_path, OFFSET(aspell_path)} , { "bin_dir", config_path, OFFSET(bin_dir)} , { "change_max_folders", config_number, OFFSET(change_max_folders)} , { "check_directory_perms", config_bool, OFFSET(check_directory_perms)} , { "confirm_expunge", config_bool, OFFSET(confirm_expunge)} , { "confirm_logout", config_bool, OFFSET(confirm_logout)} , { "confirm_rm", config_bool, OFFSET(confirm_rm)} , { "db_ping_interval", config_time, OFFSET(db_ping_interval)} , { "default_domain", config_string, OFFSET(default_domain)} , { "direct_enable", config_bool, OFFSET(direct_enable)} , { "direct_plain_count", config_number, OFFSET(direct_plain_count)} , { "direct_plain_first", config_number, OFFSET(direct_plain_first)} , { "direct_ssl_count", config_number, OFFSET(direct_ssl_count)} , { "direct_ssl_first", config_number, OFFSET(direct_ssl_first)} , { "directory_perms", config_perm, OFFSET(directory_perms)} , { "draft_att_single_max", config_number, OFFSET(draft_att_single_max)} , { "draft_att_total_max", config_number, OFFSET(draft_att_total_max)} , { "dualuse", config_bool, OFFSET(dualuse)} , { "egd_socket", config_path, OFFSET(egd_socket)} , { "expunge_on_exit", config_bool, OFFSET(expunge_on_exit)} , { "fatal_dump_core", config_bool, OFFSET(fatal_dump_core)} , { "file_perms", config_perm, OFFSET(file_perms)} , { "filter_domain_pattern", config_string, OFFSET(filter_domain_pattern)} , { "fix_client_ipaddr", config_bool, OFFSET(fix_client_ipaddr)} , { "fix_from_address", config_bool, OFFSET(fix_from_address)} , { "gzip_allow_nets", config_string, OFFSET(gzip_allow_nets)} , { "gzip_deny_nets", config_string, OFFSET(gzip_deny_nets)} , { "hiersep", config_string, OFFSET(hiersep)} , { "hostname", config_string, OFFSET(hostname)} , { "hostname_canonical", config_string, OFFSET(hostname_canonical)} , { "hostname_service", config_string, OFFSET(hostname_service)} , { "html_inline", config_bool, OFFSET(html_inline)} , { "html_inline_auto", config_bool, OFFSET(html_inline_auto)} , { "html_remote_images", config_bool, OFFSET(html_remote_images)} , { "http_cookie_use_port", config_bool, OFFSET(http_cookie_use_port)} , { "http_dump", config_bool, OFFSET(http_dump)} , { "http_max_body_size", config_number, OFFSET(http_max_body_size)} , { "http_max_connections", config_number, OFFSET(http_max_connections)} , { "http_max_hdr_size", config_number, OFFSET(http_max_hdr_size)} , { "http_max_method_size", config_number, OFFSET(http_max_method_size)} , { "http_max_servers", config_number, OFFSET(http_max_servers)} , { "http_min_servers", config_number, OFFSET(http_min_servers)} , { "http_timeout_icons", config_time, OFFSET(http_timeout_icons)} , { "http_timeout_idle", config_time, OFFSET(http_timeout_idle)} , { "http_timeout_session", config_time, OFFSET(http_timeout_session)} , { "icon_dir", config_path, OFFSET(icon_dir)} , { "icon_expire_timeout", config_time, OFFSET(icon_expire_timeout)} , { "imapd_server", config_string, OFFSET(imapd_server)} , { "imapd_user_map", config_path, OFFSET(imapd_user_map)} , { "init_socket_name", config_string, OFFSET(init_socket_name)} , { "ispell_language", config_string, OFFSET(ispell_language)} , { "ispell_path", config_path, OFFSET(ispell_path)} , { "large_cols", config_number, OFFSET(large_cols)} , { "large_rows", config_number, OFFSET(large_rows)} , { "ldap_base_dn", config_string, OFFSET(ldap_base_dn)} , { "ldap_server", config_string, OFFSET(ldap_server)} , { "ldap_timeout", config_time , OFFSET(ldap_timeout)} , { "limit_vm", config_number, OFFSET(limit_vm)} , { "line_wrap_advanced", config_bool, OFFSET(line_wrap_advanced)} , { "line_wrap_len", config_number, OFFSET(line_wrap_len)} , { "line_wrap_on_reply", config_bool, OFFSET(line_wrap_on_reply)} , { "line_wrap_on_send", config_bool, OFFSET(line_wrap_on_send)} , { "line_wrap_on_spell", config_bool, OFFSET(line_wrap_on_spell)} , { "list_addr_maxlen", config_number, OFFSET(list_addr_maxlen)} , { "list_subject_maxlen", config_number, OFFSET(list_subject_maxlen)} , { "local_domain_list", config_list, OFFSET(local_domain_list)} , { "lock_dir", config_path, OFFSET(lock_dir)} , { "log_debug", config_bool, OFFSET(log_debug)} , { "log_dir", config_path, OFFSET(log_dir)} , { "log_name_nets", config_string, OFFSET(log_name_nets)} , { "log_ping_interval", config_time, OFFSET(log_ping_interval)} , { "login_banner", config_string, OFFSET(login_banner)} , { "login_insert1_path", config_path, OFFSET(login_insert1_path)} , { "login_insert2_path", config_path, OFFSET(login_insert2_path)} , { "login_service_name", config_string, OFFSET(login_service_name)} , { "login_template", config_string, OFFSET(login_template)} , { "lookup_fullname", config_path, OFFSET(lookup_fullname)} , { "lookup_rpasswd", config_path, OFFSET(lookup_rpasswd)} , { "lookup_rusername", config_path, OFFSET(lookup_rusername)} , { "lookup_username", config_path, OFFSET(lookup_username)} , { "maildir", config_string, OFFSET(maildir)} , { "motd_path", config_path, OFFSET(motd_path)} , { "msgs_per_page", config_number, OFFSET(msgs_per_page)} , { "msgs_per_page_max", config_number, OFFSET(msgs_per_page_max)} , { "msgs_per_page_min", config_number, OFFSET(msgs_per_page_min)} , { "personal_hierarchy", config_string, OFFSET(personal_hierarchy)} , { "pid_dir", config_path, OFFSET(pid_dir)} , { "postponed_folder", config_string, OFFSET(postponed_folder)} , { "prayer_background", config_bool, OFFSET(prayer_background)} , { "prayer_gid", config_number, OFFSET(prayer_gid)} , { "prayer_group", config_string, OFFSET(prayer_group)} , { "prayer_uid", config_number, OFFSET(prayer_uid)} , { "prayer_user", config_string, OFFSET(prayer_user)} , { "prefix", config_string, OFFSET(prefix)} , { "prefs_folder_name", config_string, OFFSET(prefs_folder_name)} , { "preserve_mimetype", config_bool, OFFSET(preserve_mimetype)} , { "raven_enable", config_bool, OFFSET(raven_enable)} , { "raven_key_path", config_path, OFFSET(raven_key_path)} , { "recips_max_msg", config_number, OFFSET(recips_max_msg)} , { "recips_max_session", config_number, OFFSET(recips_max_session)} , { "referer_block_invalid", config_bool, OFFSET(referer_block_invalid)} , { "referer_log_invalid", config_bool, OFFSET(referer_log_invalid)} , { "return_path_domain", config_string, OFFSET(return_path_domain)} , { "sending_allow_dir", config_path, OFFSET(sending_allow_dir)} , { "sending_block_dir", config_path, OFFSET(sending_block_dir)} , { "sendmail_path", config_path, OFFSET(sendmail_path)} , { "sent_mail_folder", config_string, OFFSET(sent_mail_folder)} , { "session_idle_time", config_time, OFFSET(session_idle_time)} , { "session_key_len", config_number, OFFSET(session_key_len)} , { "session_timeout", config_time, OFFSET(session_timeout)} , { "session_timeout_compose", config_time, OFFSET(session_timeout_compose)} , { "sieve_maxsize", config_number, OFFSET(sieve_maxsize)} , { "sieved_server", config_string, OFFSET(sieved_server)} , { "sieved_timeout", config_time, OFFSET(sieved_timeout)} , { "sieved_user_map", config_path, OFFSET(sieved_user_map)} , { "small_cols", config_number, OFFSET(small_cols)} , { "small_rows", config_number, OFFSET(small_rows)} , { "socket_dir", config_path, OFFSET(socket_dir)} , { "socket_split_dir", config_bool, OFFSET(socket_split_dir)} , { "sort_mode", config_string, OFFSET(sort_mode)} , { "sort_reverse", config_bool, OFFSET(sort_reverse)} , { "spam_purge_name", config_string, OFFSET(spam_purge_name)} , { "spam_purge_prefix", config_string, OFFSET(spam_purge_prefix)} , { "spam_purge_timeout", config_number, OFFSET(spam_purge_timeout)} , { "spell_skip_quoted", config_bool, OFFSET(spell_skip_quoted)} , { "ssl_cert_file", config_path, OFFSET(ssl_cert_file)} , { "ssl_cipher_list", config_string, OFFSET(ssl_cipher_list)} , { "ssl_default_port", config_number, OFFSET(ssl_default_port)} , { "ssl_dh_file", config_path, OFFSET(ssl_dh_file)} , { "ssl_encouraged", config_bool, OFFSET(ssl_encouraged)} , { "ssl_privatekey_file", config_path, OFFSET(ssl_privatekey_file)} , { "ssl_redirect", config_bool, OFFSET(ssl_redirect)} , { "ssl_required", config_bool, OFFSET(ssl_required)} , { "ssl_rsakey_freshen", config_time, OFFSET(ssl_rsakey_freshen)} , { "ssl_rsakey_lifespan", config_time, OFFSET(ssl_rsakey_lifespan)} , { "ssl_server_preference", config_bool, OFFSET(ssl_server_preference)} , { "ssl_session_dir", config_path, OFFSET(ssl_session_dir)} , { "ssl_session_timeout", config_time, OFFSET(ssl_session_timeout)} , { "static_dir", config_path, OFFSET(static_dir)} , { "static_expire_timeout", config_time, OFFSET(static_expire_timeout)} , { "stream_checkpoint", config_bool, OFFSET(stream_checkpoint)} , { "stream_misc_timeout", config_time, OFFSET(stream_misc_timeout)} , { "stream_ping_interval", config_time, OFFSET(stream_ping_interval)} , { "strip_mail", config_bool, OFFSET(strip_mail)} , { "suppress_dotfiles", config_bool, OFFSET(suppress_dotfiles)} , { "template_path", config_string, OFFSET(template_path)} , { "template_set", config_string, OFFSET(template_set)} , { "template_use_compiled", config_bool, OFFSET(template_use_compiled)} , { "theme_default_help", config_string, OFFSET(theme_default_help)} , { "theme_default_main", config_string, OFFSET(theme_default_main)} , { "tmp_dir", config_path, OFFSET(tmp_dir)} , { "use_agg_unmark", config_bool, OFFSET(use_agg_unmark)} , { "use_cookie", config_bool, OFFSET(use_cookie)} , { "use_gzip", config_bool, OFFSET(use_gzip)} , { "use_http_1_1", config_bool, OFFSET(use_http_1_1)} , { "use_icons", config_bool, OFFSET(use_icons)} , { "use_mark_persist", config_bool, OFFSET(use_mark_persist)} , { "use_namespace", config_bool, OFFSET(use_namespace)} , { "use_persist", config_bool, OFFSET(use_persist)} , { "use_pipelining", config_bool, OFFSET(use_pipelining)} , { "use_search_zoom", config_bool, OFFSET(use_search_zoom)} , { "use_sent_mail", config_bool, OFFSET(use_sent_mail)} , { "use_short", config_bool, OFFSET(use_short)} , { "use_substitution", config_bool, OFFSET(use_substitution)} , { "use_tail_banner", config_bool, OFFSET(use_tail_banner)} , { "use_unread", config_bool, OFFSET(use_unread)} , { "use_welcome", config_bool, OFFSET(use_welcome)} , { "vacation_default_days", config_number, OFFSET(vacation_default_days)} , { "var_prefix", config_string, OFFSET(var_prefix)} , { "welcome_path", config_path, OFFSET(welcome_path)} , { NIL, config_unknown, NIL} }; static unsigned long options_size = 0L; /* ====================================================================== */ /* config_init() ********************************************************* * * Initialise config engine. Counts number of options in the "options" * array, and makes sure that they are properly sorted for binary chop * searches. ************************************************************************/ static BOOL config_init(void) { unsigned long offset; offset = 0; while (config_options[offset].name) { if (config_options[offset + 1].name) { if (strcmp(config_options[offset].name, config_options[offset + 1].name) > 0) { config_paniclog(NIL, "config.c: options array sorted incorrectly at %s", config_options[offset].name); return (NIL); } } offset++; } options_size = offset; return (T); } /* ====================================================================== */ /* config_find_key() ***************************************************** * * Find offset to "options" structure which corresponds to key * key: Key to lookup * * Returns: Array offset, (-1) on error. ************************************************************************/ static int config_find_option(char *key) { int first = 0; int last = options_size; int middle = 0; int rc; /* Binary chop */ while (first < last) { middle = (first + last) / 2; rc = strcmp(config_options[middle].name, key); if (rc == 0) return (middle); else if (rc < 0) first = middle + 1; else last = middle; } /* Check whether last interaction of loop found match */ if (!strcmp(config_options[middle].name, key)) return (middle); return (-1); /* Not found */ } /* ====================================================================== */ /* Various static support functions for config_clone */ static char *maybe_pool_strdup(struct pool *pool, char *s) { return ((s) ? pool_strdup(pool, s) : NIL); } static void config_clone_bool(BOOL * dst, BOOL * src) { *dst = *src; } static void config_clone_number(unsigned long *dst, unsigned long *src) { *dst = *src; } static void config_clone_string(struct pool *pool, char **dst, char **src) { *dst = maybe_pool_strdup(pool, *src); } static void config_clone_http_port(struct config *config, struct config_http_port *src) { struct config_http_port *dst = pool_alloc(config->pool, sizeof(struct config_http_port)); dst->next = NIL; if (src->interface) dst->interface = pool_strdup(config->pool, src->interface); else dst->interface = NIL; dst->port = src->port; dst->use_ssl = src->use_ssl; list_push(config->http_port_list, (struct list_item *) dst, src->name); } static void config_clone_local_domain(struct config *config, struct config_local_domain *src) { struct config_local_domain *dst = pool_alloc(config->pool, sizeof(struct config_local_domain)); dst->next = NIL; dst->file = maybe_pool_strdup(config->pool, src->file); dst->cdb_map = src->cdb_map; list_push(config->local_domain_list, (struct list_item *) dst, src->name); } static void config_clone_language(struct config *config, struct config_language *src) { struct config_language *dst = pool_alloc(config->pool, sizeof(struct config_language)); dst->next = NIL; dst->desc = maybe_pool_strdup(config->pool, src->desc); list_push(config->ispell_language_list, (struct list_item *) dst, src->name); } static void config_clone_template(struct config *config, struct config_template *src) { struct pool *pool = config->pool; struct config_template *dst = pool_alloc(pool, sizeof(struct config_template)); dst->description = maybe_pool_strdup(pool, src->description); list_push(config->template_list, (struct list_item *) dst, src->name); } static void config_clone_theme(struct config *config, struct config_theme *src) { struct pool *pool = config->pool; struct config_theme *dst = pool_alloc(pool, sizeof(struct config_theme)); dst->description = maybe_pool_strdup(pool, src->description); dst->fgcolor = maybe_pool_strdup(pool, src->fgcolor); dst->fgcolor_link = maybe_pool_strdup(pool, src->fgcolor_link); dst->bgcolor = maybe_pool_strdup(pool, src->bgcolor); dst->bgcolor_banner = maybe_pool_strdup(pool, src->bgcolor_banner); dst->bgcolor_row1 = maybe_pool_strdup(pool, src->bgcolor_row2); dst->bgcolor_row2 = maybe_pool_strdup(pool, src->bgcolor_row1); dst->bgcolor_status = maybe_pool_strdup(pool, src->bgcolor_status); dst->bgcolor_status_none = maybe_pool_strdup(pool, src->bgcolor_status_none); dst->fgcolor_quote1 = maybe_pool_strdup(pool, src->fgcolor_quote1); dst->fgcolor_quote2 = maybe_pool_strdup(pool, src->fgcolor_quote2); dst->fgcolor_quote3 = maybe_pool_strdup(pool, src->fgcolor_quote3); dst->fgcolor_quote4 = maybe_pool_strdup(pool, src->fgcolor_quote4); list_push(config->theme_list, (struct list_item *) dst, src->name); } /* ====================================================================== */ /* config_clone_parsed() *************************************************** * * Take an existing config and clone it into a fresh pool. Used after * all setup, parsing and expansion has occured to give us a clean * config structure without any baggage. **************************************************************************/ struct config *config_clone_parsed(struct config *src) { struct pool *pool = pool_create(CONFIG_PREFERRED_POOL_SIZE); struct config *config = pool_alloc(pool, sizeof(struct config)); unsigned long offset; struct list_item *li; memset(config, 0, sizeof(struct config)); config->pool = pool; offset = 0; while (config_options[offset].name) { void *s = ((char *) src) + config_options[offset].offset; void *d = ((char *) config) + config_options[offset].offset; switch (config_options[offset].type) { case config_bool: config_clone_bool((BOOL *) d, (BOOL *) s); break; case config_number: case config_time: case config_perm: config_clone_number((unsigned long *) d, (unsigned long *) s); break; case config_string: case config_path: config_clone_string(pool, (char **) d, (char **) s); break; default: /* Ignore config_list and config_unknown entries! */ break; } offset++; } config->http_port_list = NIL; config->local_domain_list = NIL; config->ispell_language_list = NIL; config->template_list = NIL; config->theme_list = NIL; /* Clone HTTP Port List */ if (src->http_port_list) { config->http_port_list = list_create(config->pool, T); for (li = src->http_port_list->head; li; li = li->next) config_clone_http_port(config, (struct config_http_port *) li); } /* Clone domain list */ if (src->local_domain_list) { config->local_domain_list = list_create(config->pool, T); for (li = src->local_domain_list->head; li; li = li->next) config_clone_local_domain(config, (struct config_local_domain *) li); } else config->local_domain_list = NIL; /* Clone ispell language list */ if (src->ispell_language_list) { config->ispell_language_list = list_create(config->pool, T); for (li = src->ispell_language_list->head; li; li = li->next) config_clone_language(config, (struct config_language *) li); } else config->ispell_language_list = NIL; /* Clone templates */ if (src->template_list) { config->template_list = list_create(config->pool, T); for (li = src->template_list->head; li; li = li->next) config_clone_template(config, (struct config_template *) li); } /* Clone themes */ config->theme_main = NIL; config->theme_help = NIL; if (src->theme_list) { config->theme_list = list_create(config->pool, T); for (li = src->theme_list->head; li; li = li->next) config_clone_theme(config, (struct config_theme *) li); /* Should be valid if we've got this far... */ if (config->theme_default_main) config->theme_main = (struct config_theme *) list_lookup_byname(config->theme_list, config->theme_default_main); /* Should be valid if we've got this far... */ if (config->theme_default_help) config->theme_help = (struct config_theme *) list_lookup_byname(config->theme_list, config->theme_default_help); } else config->theme_list = NIL; /* Make sure that theme_main points somewhere */ if (config->theme_main == NIL) config->theme_main = config_theme_create(config->pool); /* Make sure that theme_help points somewhere */ if (config->theme_help == NIL) config->theme_help = config_theme_create(config->pool); return (config); } /* ====================================================================== */ /* Various static utility routines for parsing elements of config file */ static BOOL config_parse_rest(char **textp) { char *text = *textp; char *s; if (!(text && text[0])) return (NIL); text = string_trim_whitespace(text); if (*text == '"') { text++; for (s = text; *s; s++) { if (*s == '"') { *s++ = '\0'; while (string_isspace(*s)) s++; if (*s && (*s != '#')) return (NIL); *textp = text; return (T); } } return (NIL); } for (s = text; *s; s++) { if (*s == '#') { *s = '\0'; break; } } *textp = text; return (T); } static BOOL config_parse_bool(BOOL * result, char *s) { if (!config_parse_rest(&s)) return (NIL); if (!strcasecmp(s, "TRUE") || !strcasecmp(s, "T") || !strcmp(s, "1")) { *result = T; return (T); } if (!strcasecmp(s, "FALSE") || !strcasecmp(s, "NIL") || !strcmp(s, "0")) { *result = NIL; return (T); } return (NIL); } static BOOL config_parse_number(unsigned long *result, char *text) { char *s; unsigned long multiple = 1; if (!config_parse_rest(&text)) return (NIL); for (s = text; s[1]; s++) if (!Uisdigit(*s)) return (NIL); if (Uisdigit(*s)) multiple = 1; else { switch (Utoupper(*s)) { case 'K': multiple = 1024; break; case 'M': multiple = (1024 * 1024); break; default: return (NIL); } *s++ = '\0'; if (*s) return (NIL); } *result = (multiple * atoi(text)); return (T); } static BOOL config_parse_perm(unsigned long *result, char *s) { if (!config_parse_rest(&s)) return (NIL); if (s[0] != '0') return (NIL); if ((s[1] < '0') || (s[1] > '7')) return (NIL); if ((s[2] < '0') || (s[2] > '7')) return (NIL); if ((s[3] < '0') || (s[3] > '7')) return (NIL); if (s[4]) return (NIL); *result = (((s[1] - '0') * (8 * 8)) + ((s[2] - '0') * (8)) + (s[3] - '0')); return (T); } static BOOL config_parse_time(unsigned long *result, char *text) { char *s; unsigned long multiple; if (!config_parse_rest(&text)) return (NIL); for (s = text; s[1]; s++) if (!Uisdigit(*s)) return (NIL); if (Uisdigit(*s)) multiple = 1; else { switch (Utoupper(*s)) { case 'S': multiple = 1; break; case 'M': multiple = 60; break; case 'H': multiple = 60 * 60; break; case 'D': multiple = 24 * 60 * 60; break; default: return (NIL); } *s++ = '\0'; if (*s) return (NIL); } *result = (multiple * atoi(text)); return (T); } static BOOL config_parse_string(char **result, char *text, struct pool *pool) { if (!config_parse_rest(&text)) return (NIL); text = string_trim_whitespace(text); *result = pool_strdup(pool, string_trim_whitespace(text)); return (T); } static BOOL config_parse_list(struct list **listp, char *text, struct pool *pool) { char *next; if (!config_parse_rest(&text)) return (NIL); *listp = list_create(pool, T); while ((next = strchr(text, ':'))) { *next++ = '\0'; text = string_trim_whitespace(text); if (text && text[0]) list_push(*listp, NIL, text); text = next; } if (text && text[0]) text = string_trim_whitespace(text); if (text && text[0]) list_push(*listp, NIL, text); return (T); } /* ====================================================================== */ /* config_parse_single() ************************************************* * * Parse a single (key, value) pair extracted from configuration file * or passed as command line option. * config: * key: Text for key * value: Text for value * lineno: Line number in configuration file (for error messages) * 0 if this option passed in on the command line. ************************************************************************/ static BOOL config_parse_single(struct config *config, char *key, char *value, unsigned long lineno) { struct pool *pool = config->pool; int i; char *ptr; if ((i = config_find_option(key)) < 0) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Unknown option %s"), lineno, key); else config_paniclog(config, "Unknown option %s", key); return (NIL); } ptr = ((char *) config) + config_options[i].offset; switch (config_options[i].type) { case config_bool: if (!config_parse_bool((BOOL *) ptr, value)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes boolean argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes boolean argument", key); return (NIL); } break; case config_number: if (!config_parse_number((unsigned long *) ptr, value)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes a numeric argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes a numeric argument", key); return (NIL); } break; case config_perm: if (!config_parse_perm((unsigned long *) ptr, value)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes a permission argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes a permission argument", key); return (NIL); } break; case config_time: if (!config_parse_time((unsigned long *) ptr, value)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes a time argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes a time argument", key); return (NIL); } break; case config_string: case config_path: if (!config_parse_string((char **) ptr, value, pool)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes string argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes string argument", key); return (NIL); } break; case config_list: if (!config_parse_list((struct list **) ptr, value, pool)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes a time argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes a list argument", key); return (NIL); } break; default: return (NIL); } return (T); } /* ====================================================================== */ /* config_skip_whitespace() ********************************************** * * Skip over whitespace in string (clone of string_skip_whitespace?) * sp: Ptr to string. Updated to reflect location of next token * * Returns: Location of the next token. ************************************************************************/ static char *config_skip_whitespace(char **sp) { char *s = *sp; if (!s) return (NIL); /* Skip leading whitespace */ while ((*s == ' ') || (*s == '\t')) s++; *sp = s; return ((*s) ? s : NIL); } /* config_get_key() ******************************************************* * * Get key token from config line (token terminated by whitespace or '=' * character). * sp: Ptr to string. Updated to reflect location of next token * * Returns: Location of the next token. *************************************************************************/ static char *config_get_key(char **sp) { char *s = *sp, *result; if (!s) return (NIL); while ((*s == ' ') || (*s == '\t')) s++; /* Record position of this token */ result = s; /* Find next whitespace character, '=', or end of string */ while ((*s) && (*s != ' ') && (*s != '\t') && (*s != '=')) s++; /* Tie off the string unless \0 already reached, or '=' separator */ if (*s && (*s != '=')) { *s++ = '\0'; while ((*s == ' ') || (*s == '\t')) s++; } if (*s != '=') return (NIL); *s++ = '\0'; while ((*s == ' ') || (*s == '\t')) s++; /* Record position of first non-whitespace character for next caller */ *sp = s; return (result); } /* config_check_keyword() ************************************************ * * Check whether string at (*sp) matches given keyword, * sp: Ptr to string. Updated to reflect location of next token * * Returns: T if substring match suceeded. ************************************************************************/ static BOOL config_check_keyword(char **sp, char *keyword) { char *s = *sp; unsigned long len = strlen(keyword); if (strncmp(s, keyword, len) != 0) return (NIL); s += len; /* Keyword must be followed by whitespace */ if ((*s != ' ') && (*s != '\t')) return (NIL); while ((*s == ' ') || (*s == '\t')) s++; /* Record position of first non-whitespace character for next caller */ *sp = s; return (T); } /* ====================================================================== */ /* config_parse_local_domain() ******************************************* * * Parse a "local_domain" line * config: * lineno: * option: local_domain option to parse ************************************************************************/ static BOOL config_parse_local_domain(struct config *config, unsigned long lineno, char *option) { struct pool *pool = config->pool; struct list **listp = &config->local_domain_list; struct config_local_domain *ld; char *domain; char *file; if ((domain = string_get_token(&option)) == NIL) { if (lineno > 0) { config_paniclog(config, ("Line %lu of config file badly formatted:" " \"local_domain %s %s\""), lineno, domain, option); } else { config_paniclog(config, "Option badly formatted: \"local_domain %s %s\"", domain, option); } return (NIL); } file = string_get_token(&option); domain = string_trim_whitespace(domain); if (file) file = string_trim_whitespace(file); ld = pool_alloc(pool, sizeof(struct config_local_domain)); ld->file = (file) ? pool_strdup(pool, file) : NIL; ld->cdb_map = NIL; if (*listp == NIL) *listp = list_create(pool, T); list_push(*listp, (struct list_item *) ld, domain); return (T); } /* config_parse_ispell_language() **************************************** * * Parse an "ispell_language" line * config: * lineno: * option: local_domain option to parse ************************************************************************/ static BOOL config_parse_ispell_language(struct config *config, unsigned long lineno, char *option) { struct pool *pool = config->pool; struct list **listp = &config->ispell_language_list; struct config_language *lang; char *name; char *desc; if ((name = string_get_token(&option)) == NIL) { if (lineno > 0) config_paniclog(config, "Empty \"use_ispell_language\" clause at line %lu", lineno); else config_paniclog(config, "Empty \"use_ispell_language\" clause"); return (NIL); } if (!config_parse_string(&desc, option, pool)) { if (lineno > 0) config_paniclog(config, "Invalid \"use_ispell_language\" clause at line %lu", lineno); else config_paniclog(config, "Invalid \"use_ispell_language\" clause"); return (NIL); } lang = pool_alloc(pool, sizeof(struct config_language)); lang->name = pool_strdup(pool, name); lang->desc = desc; if (*listp == NIL) *listp = list_create(pool, T); list_push(*listp, (struct list_item *) lang, name); return (T); } /* config_parse_template() *********************************************** * * Parse a "template" line * config: * lineno: * option: templaye option to parse ************************************************************************/ static BOOL config_parse_template(struct config *config, unsigned long lineno, char *option) { struct pool *pool = config->pool; struct list **listp = &config->template_list; struct config_template *template; char *name; char *desc; if ((name = string_get_token(&option)) == NIL) { if (lineno > 0) config_paniclog(config, "Empty \"template\" clause at line %lu", lineno); else config_paniclog(config, "Empty \"template\" clause"); return (NIL); } if (!config_parse_string(&desc, option, pool)) { if (lineno > 0) config_paniclog(config, "Invalid \"template\" clause at line %lu", lineno); else config_paniclog(config, "Invalid \"template\" clause"); return (NIL); } template = pool_alloc(pool, sizeof(struct config_template)); template->name = pool_strdup(pool, name); template->description = desc; if (*listp == NIL) *listp = list_create(pool, T); list_push(*listp, (struct list_item *) template, name); return (T); } /* config_parse_theme() ************************************************** * * Parse an "theme" line * config: * lineno: * option: theme option to parse ************************************************************************/ static BOOL config_parse_theme(struct config *config, unsigned long lineno, char *option) { struct pool *pool = config->pool; struct config_theme *theme; char *name; char *key; char *value; if ((name = string_get_token(&option)) == NIL) { if (lineno > 0) config_paniclog(config, "Empty theme clause at line %lu", lineno); else config_paniclog(config, "Empty theme clause"); return (NIL); } if ((key = string_get_token(&option)) == NIL) { if (lineno > 0) config_paniclog(config, "Incomplete theme clause at line %lu", lineno); else config_paniclog(config, "Incomplete theme clause"); return (NIL); } if (!config_parse_string(&value, option, pool)) { if (lineno > 0) config_paniclog(config, "Invalid theme clause at line %lu", lineno); else config_paniclog(config, "Invalid theme clause"); return (NIL); } /* Create new theme list if needed */ if (config->theme_list == NIL) config->theme_list = list_create(pool, T); /* Create new theme if required */ if ((theme = (struct config_theme *) list_lookup_byname(config->theme_list, name)) == NIL) { theme = config_theme_create(pool); list_push(config->theme_list, (struct list_item *) theme, name); } if (!strcmp(key, "description")) theme->description = pool_strdup(pool, value); else if (!strcmp(key, "fgcolor")) theme->fgcolor = pool_strdup(pool, value); else if (!strcmp(key, "fgcolor_link")) theme->fgcolor_link = pool_strdup(pool, value); else if (!strcmp(key, "fgcolor_quote1")) theme->fgcolor_quote1 = pool_strdup(pool, value); else if (!strcmp(key, "fgcolor_quote2")) theme->fgcolor_quote2 = pool_strdup(pool, value); else if (!strcmp(key, "fgcolor_quote3")) theme->fgcolor_quote3 = pool_strdup(pool, value); else if (!strcmp(key, "fgcolor_quote4")) theme->fgcolor_quote4 = pool_strdup(pool, value); else if (!strcmp(key, "bgcolor")) theme->bgcolor = pool_strdup(pool, value); else if (!strcmp(key, "bgcolor_banner")) theme->bgcolor_banner = pool_strdup(pool, value); else if (!strcmp(key, "bgcolor_row1")) theme->bgcolor_row1 = pool_strdup(pool, value); else if (!strcmp(key, "bgcolor_row2")) theme->bgcolor_row2 = pool_strdup(pool, value); else if (!strcmp(key, "bgcolor_status")) theme->bgcolor_status = pool_strdup(pool, value); else if (!strcmp(key, "bgcolor_status_none")) theme->bgcolor_status_none = pool_strdup(pool, value); else { if (lineno > 0) config_paniclog(config, "Unknown theme key \"%s\" at line %lu of config file", key, lineno); else config_paniclog(config, "Unknown theme key \"%s\"", key); return (NIL); } return (T); } /* config_parse_http_port() *********************************************** * * Parse a "http_port" line * config: * lineno: * use_ssl: This is a HTTPS port * option: local_domain option to parse ************************************************************************/ static BOOL config_parse_http_port(struct config *config, BOOL use_ssl, unsigned long lineno, char *orig_option) { struct pool *pool = config->pool; struct list **listp = &config->http_port_list; char *s; char *option = pool_strdup(pool, orig_option); char *interface; unsigned long port; BOOL error; struct config_http_port *chp; interface = NIL; port = 0; error = NIL; if (!config_parse_rest(&option)) error = T; else if ((s = (strrchr(option, ':')))) { *s++ = '\0'; if (!config_parse_number(&port, s)) error = T; interface = pool_strdup(pool, option); } else if (!config_parse_number(&port, option)) error = T; if (error) { if (lineno > 0) { config_paniclog(config, ("Line %lu of config file badly formatted:" " \"use_http%s_port %lu %s\""), lineno, ((use_ssl) ? "s" : ""), port, orig_option); } else { config_paniclog(config, "Option badly formatted: \"use_http%s_port %lu %s\"", ((use_ssl) ? "s" : ""), port, orig_option); } return (NIL); } chp = pool_alloc(pool, sizeof(struct config_http_port)); chp->interface = interface; chp->port = port; chp->use_ssl = use_ssl; if (*listp == NIL) *listp = list_create(pool, T); list_push(*listp, (struct list_item *) chp, NIL); return (T); } /* ====================================================================== */ /* config_parse_option() ************************************************* * * Parse a single option passed in from the command line * config: * option: "key=value" or " " to parse * * Returns: T if option parsed successfully * NIL otherwise (message will be sent to paniclog). ************************************************************************/ BOOL config_parse_option(struct config * config, char *option) { char *key, *value; option = string_trim_whitespace(option); if (option[0] == '\0') return (T); if (config_check_keyword(&option, "local_domain")) return (config_parse_local_domain(config, 0L, option)); if (config_check_keyword(&option, "use_ispell_language")) return (config_parse_ispell_language(config, 0L, option)); if (config_check_keyword(&option, "template")) return (config_parse_template(config, 0L, option)); if (config_check_keyword(&option, "theme")) return (config_parse_theme(config, 0L, option)); if (config_check_keyword(&option, "use_http_port")) return (config_parse_http_port(config, NIL, 0L, option)); if (config_check_keyword(&option, "use_https_port")) return (config_parse_http_port(config, T, 0L, option)); if ((key = config_get_key(&option)) == NIL) { config_paniclog(config, "Option badly formatted: \"%s\"", option); return (NIL); } if ((value = config_skip_whitespace(&option)) == NIL) { config_paniclog(config, "Option badly formatted: \"%s %s\"", key, option); return (NIL); } return (config_parse_single(config, key, value, 0L)); } /* ====================================================================== */ /* config_get_line() **************************************************** * * Get a linear whitespace line (e.g: folded RFC822 or HTTP header line) * sp: Ptr to current string location * (updated to point to following line) * squeeze: Remove superfluous spaces from result. * * Returns: Ptr to this line ***********************************************************************/ static char *config_get_line(char **sp, BOOL squeeze) { char *s, *result; s = *sp; if (!(s && s[0])) return (NIL); /* CR, LF or CRLF before data proper starts? */ if ((s[0] == '\015') || (s[0] == '\012')) { result = s; if ((s[0] == '\015') && (s[1] == '\012')) { /* CRLF */ *s = '\0'; s += 2; } else *s++ = '\0'; /* CR or LF */ *sp = s; return (result); } result = s; /* Record position of non-LWS */ while (*s) { if ((*s == '\015') || (*s == '\012')) { /* CR, LF or CRLF */ char *t = s; s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; if ((*s != ' ') && (*s != '\t')) { *t = '\0'; break; } } else s++; } *sp = s; /* Set up for next caller */ return (result); } /* config_count_line() *************************************************** * * Count number of lines in string ************************************************************************/ static unsigned long config_count_line(char *s) { unsigned long lines = 1; while (*s) { if ((*s == '\015') || (*s == '\012')) { s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; lines++; } else s++; } return (lines); } /* config_compress_line() ************************************************ * * Remove continuation sequences from LWS line ************************************************************************/ static BOOL config_compress_line(char *s) { char *t = s; while (*s) { /* Check for correctly folded line */ if ((s[0] == '\\') && ((s[1] == '\015') || (s[1] == '\012'))) { s += ((s[1] == '\015') && (s[2] == '\012')) ? 3 : 2; while (string_isspace(*s)) s++; continue; } /* Check for unexpected line break */ if ((s[0] == '\015') || (s[0] == '\012')) return (NIL); if (s > t) *t++ = *s++; else t++, s++; } *t = '\0'; return (T); } /* ====================================================================== */ /* config_parse_file() *************************************************** * * Parse configuration file * config: * filename: Name of configuration file (main() routine will pass * compile time default or user specified version). * * Returns: T if option parsed successfully * NIL otherwise (message will be sent to paniclog). ************************************************************************/ BOOL config_parse_file(struct config * config, char *filename) { struct pool *tpool = pool_create(CONFIG_PREFERRED_TEMP_POOL_SIZE); struct buffer *b = buffer_create(tpool, CONFIG_PREFERRED_TEMP_POOL_SIZE); char *text; char *line, *key, *value; unsigned long next_lineno = 1; unsigned long cur_lineno = 1; BOOL okay; FILE *file; int c; /* Read configuration file into buffer, realloc as char array */ if ((file = fopen(filename, "r")) == NULL) { config_paniclog(config, "Couldn't open configuration file: \"%s\"", filename); return (NIL); } while ((c = getc(file)) != EOF) bputc(b, c); fclose(file); text = buffer_fetch(b, 0, buffer_size(b), NIL); /* Prep options array if we need to */ if ((options_size == 0L) && !config_init()) { pool_free(tpool); return (NIL); } okay = T; while ((line = config_get_line(&text, NIL))) { cur_lineno = next_lineno; next_lineno += config_count_line(line); if (!config_compress_line(line)) { config_paniclog(config, "Invalid folded line starting at line %d: \"%s\"", cur_lineno, line); okay = NIL; continue; } if (line[0] == '#') continue; line = string_trim_whitespace(line); if (line[0] == '\0') continue; if (config_check_keyword(&line, "local_domain")) { if (!config_parse_local_domain(config, cur_lineno, line)) okay = NIL; continue; } if (config_check_keyword(&line, "use_ispell_language")) { if (!config_parse_ispell_language(config, cur_lineno, line)) okay = NIL; continue; } if (config_check_keyword(&line, "template")) { if (!config_parse_template(config, cur_lineno, line)) okay = NIL; continue; } if (config_check_keyword(&line, "theme")) { if (!config_parse_theme(config, cur_lineno, line)) okay = NIL; continue; } if (config_check_keyword(&line, "use_http_port")) { if (!config_parse_http_port(config, NIL, cur_lineno, line)) okay = NIL; continue; } if (config_check_keyword(&line, "use_https_port")) { if (!config_parse_http_port(config, T, cur_lineno, line)) okay = NIL; continue; } if ((key = config_get_key(&line)) == NIL) { config_paniclog(config, "Line %lu of config file badly formatted: \"%s\"", cur_lineno, line); okay = NIL; continue; } if ((value = config_skip_whitespace(&line)) == NIL) { config_paniclog(config, "Line %lu of config file badly formatted: \"%s %s\"", cur_lineno, key, line); okay = NIL; continue; } if (!config_parse_single(config, key, value, cur_lineno)) okay = NIL; } pool_free(tpool); return (okay); } /* ====================================================================== */ /* Couple of support macros to help test the integrity of the configuration * that we have just parsed */ #define TEST_STRING(x, y) \ { \ if (!(x && x[0])) { \ config_paniclog(config, "config: "y" not defined"); \ return(NIL); \ } \ } #define TEST_NUMBER(x, y) \ { \ if (x == 0) { \ config_paniclog(config, "config: "y" not defined"); \ return(NIL); \ } \ } #define HOSTNAME_TMP_BUFFER_SIZE (8192) /* ====================================================================== */ /* config_locate_port() ************************************************** * * Lookup HTTP port in config structure * list: ************************************************************************/ static struct config_http_port *config_locate_port(struct config *config, unsigned long port) { struct list *list = config->http_port_list; struct list_item *li; for (li = list->head; li; li = li->next) { struct config_http_port *chp = (struct config_http_port *) li; if (chp->port == port) return (chp); } return (NIL); } /* config_find_port() **************************************************** * * Pick a default HTTP or HTTPS port * config: * want_ssl: T => want a SSL port (443 preferred) * NIL => want a plaintext port (80 preferred) * * Returns: Port structure, NIL if none appropriate. ************************************************************************/ static struct config_http_port *config_find_port(struct config *config, BOOL want_ssl) { struct list *list = config->http_port_list; struct list_item *li; /* Assign canonical port if it is available */ for (li = list->head; li; li = li->next) { struct config_http_port *chp = (struct config_http_port *) li; if (want_ssl) { if ((chp->port == 443) && (chp->use_ssl == T)) return (chp); } else { if ((chp->port == 80) && (chp->use_ssl == NIL)) return (chp); } } /* Otherwise scan for first available port of the correct type */ for (li = list->head; li; li = li->next) { struct config_http_port *chp = (struct config_http_port *) li; if (want_ssl) { if (chp->use_ssl == T) return (chp); } else { if (chp->use_ssl == NIL) return (chp); } } return (NIL); } /* ====================================================================== */ /* Static support routines for config_check */ static BOOL config_check_sort_mode(char *mode) { if (mode == NIL) return (NIL); switch (Utoupper(mode[0])) { case 'A': if (!strcasecmp(mode, "ARRIVAL")) return (T); break; case 'C': if (!strcasecmp(mode, "CC")) return (T); break; case 'D': if (!strcasecmp(mode, "DATE")) return (T); break; case 'F': if (!strcasecmp(mode, "FROM")) return (T); break; case 'S': if (!strcasecmp(mode, "SUBJECT")) return (T); else if (!strcasecmp(mode, "SIZE")) return (T); break; case 'T': if (!strcasecmp(mode, "TO")) return (T); break; } return (NIL); } /* ====================================================================== */ /* config_check() ********************************************************* * * Check that a parsed configuration is sane and self-consistent. * config: * * Returns: T if config okay, NIL otherwise *************************************************************************/ BOOL config_check(struct config * config) { BOOL use_ssl = NIL; struct list_item *li; struct config_http_port *chp; char hostname[MAX_ADDRESS+1], domainname[MAX_ADDRESS+1]; TEST_STRING(config->icon_dir, "icon_dir"); TEST_STRING(config->socket_dir, "socket_dir"); TEST_STRING(config->init_socket_name, "init_socket_name"); TEST_STRING(config->ssl_session_dir, "ssl_session_dir"); #ifndef MUTEX_SEMAPHORE TEST_STRING(config->lock_dir, "lock_dir"); #endif TEST_STRING(config->log_dir, "log_dir"); TEST_STRING(config->tmp_dir, "tmp_dir"); TEST_STRING(config->pid_dir, "pid_dir"); TEST_STRING(config->bin_dir, "bin_dir"); if (config->prayer_user && config->prayer_uid) { config_paniclog(config, "config: prayer_user and prayer_uid both defined"); return (NIL); } if (config->prayer_group && config->prayer_gid) { config_paniclog(config, "config: prayer_group and prayer_gid both defined"); return (NIL); } /* Calculate hostnames */ getdomainnames(hostname, sizeof(hostname)-1, domainname, sizeof(domainname)-1); if (!(config->hostname_canonical && config->hostname_canonical[0])) config->hostname_canonical = pool_strdup(config->pool, hostname); /* Set hostname from environment variable? */ if (getenv("PRAYER_HOSTNAME")) config->hostname = pool_strdup(config->pool, getenv("PRAYER_HOSTNAME")); if (config->hostname && config->hostname[0]) { /* Check for __UNDEFINED__ special case */ if (!strcasecmp(config->hostname, "__UNDEFINED__")) { config_paniclog(config, ("config: hostname undefined. Should have been " "set up using --config-option \"hostname=value\"?")); return (NIL); } } else config->hostname = pool_strdup(config->pool, hostname); TEST_NUMBER(config->http_timeout_idle, "http_timeout_idle"); TEST_NUMBER(config->http_timeout_icons, "http_timeout_icons"); TEST_NUMBER(config->http_timeout_session, "http_timeout_session"); TEST_NUMBER(config->http_max_method_size, "http_max_method_size"); TEST_NUMBER(config->http_max_hdr_size, "http_max_hdr_size"); TEST_NUMBER(config->http_max_body_size, "http_max_body_size"); if (!(config->http_port_list && config->http_port_list->head)) { config_paniclog(config, "config: No HTTP or HTTPS ports defined"); return (NIL); } /* Check ssl_default_port, derive automatically if not defined */ if (config->ssl_default_port) { chp = config_locate_port(config, config->ssl_default_port); if (chp == NIL) { config_paniclog(config, "config: ssl_default_port defines unused port: %lu", config->ssl_default_port); return (NIL); } if (chp->use_ssl == NIL) { config_paniclog(config, "config: ssl_default_port defines plaintext port: %lu", config->ssl_default_port); return (NIL); } } else if ((chp = config_find_port(config, T))) config->ssl_default_port = chp->port; for (li = config->http_port_list->head; li; li = li->next) { struct config_http_port *chp = (struct config_http_port *) li; if (chp->use_ssl) { use_ssl = T; break; } } if (use_ssl) { TEST_STRING(config->ssl_cert_file, "ssl_cert_file"); TEST_STRING(config->ssl_privatekey_file, "ssl_privatekey_file"); TEST_NUMBER(config->ssl_rsakey_lifespan, "ssl_rsakey_lifespan"); } if (config->direct_enable) { if (((config->direct_ssl_first == 0) || (config->direct_ssl_count == 0)) && ((config->direct_plain_first == 0) || (config->direct_plain_count == 0))) { config_paniclog(config, ("config: direct_enable set, " "but no direct access ports have been set up")); return (NIL); } /* Check for overlap */ if (config->direct_ssl_first && config->direct_ssl_count && config->direct_ssl_first && config->direct_ssl_count) { unsigned long start1 = config->direct_ssl_first; unsigned long len1 = config->direct_ssl_count; unsigned long start2 = config->direct_plain_first; unsigned long len2 = config->direct_plain_count; if ((len1 > 0) && (len2 > 0)) { if (((start1 + len1) > start2) && (start1 + len1) <= (start2 + len2)) { config_paniclog(config, ("config: DIRECT mode SSL and " "plaintext ports overlap")); return (NIL); } if (((start2 + len2) > start1) && (start2 + len2) <= (start1 + len1)) { config_paniclog(config, ("config: DIRECT mode SSL and " "plaintext ports overlap")); return (NIL); } } } } TEST_NUMBER(config->session_timeout, "session_timeout"); if (config->session_idle_time >= config->session_timeout) { config_paniclog(config, "config: session_idle_time > session_timeout_compose"); return (NIL); } if (config->session_timeout_compose > 0) { if (config->session_idle_time >= config->session_timeout_compose) { config_paniclog(config, "config: session_idle_time > session_timeout_compose"); return (NIL); } } TEST_NUMBER(config->icon_expire_timeout, "icon_expire_timeout"); TEST_NUMBER(config->static_expire_timeout, "static_expire_timeout"); TEST_NUMBER(config->session_key_len, "session_key_len"); TEST_NUMBER(config->list_addr_maxlen, "list_addr_maxlen"); TEST_NUMBER(config->list_subject_maxlen, "list_subject_maxlen"); TEST_STRING(config->prefs_folder_name, "prefs_folder_name"); TEST_STRING(config->sendmail_path, "sendmail_path"); /* Default user preferences */ TEST_STRING(config->sort_mode, "sort_mode"); TEST_STRING(config->postponed_folder, "postponed_folder"); TEST_STRING(config->sent_mail_folder, "sent_mail_folder"); TEST_STRING(config->ispell_language, "ispell_language"); TEST_NUMBER(config->small_rows, "small_rows"); TEST_NUMBER(config->small_cols, "small_cols"); TEST_NUMBER(config->large_rows, "large_rows"); TEST_NUMBER(config->large_cols, "large_cols"); if (!config_check_sort_mode(config->sort_mode)) { config_paniclog(config, "config: sort_mode \"%s\" is invalid", config->sort_mode); return (NIL); } return (T); } /* ====================================================================== */ /* Static utility routine for config_expand() */ static BOOL config_macro_expand(struct config *config, char *name, char **valuep) { struct pool *pool = config->pool; char *value; if (*valuep == NIL) return (NIL); value = *valuep; if (!strncmp(value, "$prefix", strlen("$prefix"))) { if (config->prefix == NIL) { config_paniclog(config, "$prefix referenced by \"%s\" but not defined", name); return (NIL); } *valuep = pool_strcat(pool, config->prefix, value + strlen("$prefix")); return (T); } if (!strncmp(value, "${prefix}", strlen("${prefix}"))) { if (config->prefix == NIL) { config_paniclog(config, "$prefix referenced by \"%s\" but not defined", name); return (NIL); } *valuep = pool_strcat(pool, config->prefix, value + strlen("${prefix}")); return (T); } if (!strncmp(value, "$var_prefix", strlen("$var_prefix"))) { if (config->var_prefix == NIL) { config_paniclog(config, "$var_prefix referenced by \"%s\" but not defined", name); return (NIL); } *valuep = pool_strcat(pool, config->var_prefix, value + strlen("$var_prefix")); return (T); } if (!strncmp(value, "${var_prefix}", strlen("${var_prefix}"))) { if (config->var_prefix == NIL) { config_paniclog(config, "$var_prefix referenced by \"%s\" but not defined", name); return (NIL); } *valuep = pool_strcat(pool, config->var_prefix, value + strlen("${var_prefix}")); return (T); } return (T); } /* ====================================================================== */ /* config_expand() ******************************************************** * * Expand macros from configuration file. * Handles: $prefix and $var_prefix. UID and GID lookups for prayer_user * and prayer_group. * config: * * Returns: T if config expansion okay, NIL otherwise *************************************************************************/ BOOL config_expand(struct config * config) { unsigned long offset; BOOL okay = T; struct passwd *pwd; struct group *group; char cwd[CONFIG_CWD_MAXLEN]; if (getcwd(cwd, CONFIG_CWD_MAXLEN) == NIL) { config_paniclog(config, "config_expand(): getcwd() failed"); return (NIL); } for (offset = 0L; offset < options_size; offset++) { char *ptr = ((char *) config) + config_options[offset].offset; char **valuep = (char **) ptr; if (config_options[offset].type != config_path) continue; if (*valuep == NIL) continue; if (*valuep[0] == '\0') continue; if (!config_macro_expand (config, config_options[offset].name, valuep)) okay = NIL; if (*valuep && (*valuep[0] != '/')) *valuep = pool_strcat3(config->pool, cwd, "/", *valuep); } if (config->prayer_user) { if ((pwd = getpwnam(config->prayer_user))) { config->prayer_uid = pwd->pw_uid; } else { config_paniclog(config, "prayer_user: User \"%s\" not defined", config->prayer_group); okay = NIL; } } if (config->prayer_group) { if ((group = getgrnam(config->prayer_group))) { config->prayer_gid = group->gr_gid; } else { config_paniclog(config, "prayer_group: Group \"%s\" not defined", config->prayer_group); okay = NIL; } } if ((config->prayer_uid != 0L) && (config->prayer_uid != 0L)) { if (config->directory_perms == 0L) config->directory_perms = 0750; if (config->file_perms == 0L) config->file_perms = 0640; } else { if (config->directory_perms == 0L) config->directory_perms = 0755; if (config->file_perms == 0L) config->file_perms = 0644; } if (config->check_directory_perms) { if ((config->prayer_uid == 0) || (config->prayer_gid == 0)) { config_paniclog(config, ("check_directory_perms set," " but user and group not supplied")); return (NIL); } } /* Fill in default_domain, return_path_domain and local_domains from * hostname if nothing else supplied */ if (config->default_domain == NIL) config->default_domain = pool_strdup(config->pool, config->hostname); if (config->return_path_domain == NIL) config->return_path_domain = pool_strdup(config->pool, config->default_domain); if (config->filter_domain_pattern == NIL) config->filter_domain_pattern = pool_strdup(config->pool, config->default_domain); if (config->local_domain_list) { struct list_item *li; for (li = config->local_domain_list->head; li; li = li->next) { struct config_local_domain *cld = (struct config_local_domain *) li; if (cld->file) { if (!config_macro_expand (config, "local_domain", &cld->file)) okay = NIL; } } } else { struct config_local_domain *ld; ld = pool_alloc(config->pool, sizeof(struct config_local_domain)); ld->file = NIL; ld->cdb_map = NIL; config->local_domain_list = list_create(config->pool, T); list_push(config->local_domain_list, (struct list_item *) ld, config->default_domain); } if (config->theme_default_main) { if (!(config->theme_main = (struct config_theme *) list_lookup_byname(config->theme_list, config->theme_default_main))) { config_paniclog(config, "theme_default_main set to undefined theme"); return (NIL); } } else config->theme_main = config_theme_create(config->pool); if (config->theme_default_help) { if (!(config->theme_help = (struct config_theme *) list_lookup_byname(config->theme_list, config->theme_default_help))) { config_paniclog(config, "theme_default_help set to undefined theme"); return (NIL); } } else config->theme_help = config_theme_create(config->pool); return (okay); } /* ====================================================================== */ /* Static utility routine to check directory permissions. */ static BOOL config_check_perms(struct config *config, char *dir, struct stat *sbufp) { BOOL okay = T; if (config->prayer_uid != sbufp->st_uid) okay = NIL; else if (config->prayer_gid != sbufp->st_gid) okay = NIL; else if (sbufp->st_mode & S_IXOTH) okay = NIL; if (!okay) { if (config->prayer_user && config->prayer_group) log_fatal(("\"%s\" directory must be owned by user \"%s\"," " group \"%s\" and not accessible by othe0rs"), dir, config->prayer_user, config->prayer_group); else log_fatal(("\"%s\" directory must be owned by uid \"%lu\" and" " gid \"%lu\" and not accessible by others"), dir, config->prayer_user, config->prayer_group); } return (okay); } /* Static utility routine to create working directory */ static BOOL config_mkdir(struct config *config, struct pool *tpool, char *prefix, char *dir) { char *partname, *s; struct stat sbuf; mode_t mkdir_perms = ((config->directory_perms) ? (config->directory_perms) : 0755); BOOL check_intermediate = NIL; if (!(dir && dir[0])) { log_fatal("[config_mkdir()] Empty directory name supplied"); /* NOTREACHED */ return (-1); } if (prefix && prefix[0] && !strncmp(dir, prefix, strlen(prefix))) { /* Scan pathname from end of prefix */ partname = pool_strdup(tpool, dir); s = partname + strlen(prefix); check_intermediate = T; if (*s == '/') s++; } else { /* Start scanning from start of path */ partname = pool_strdup(tpool, dir); s = partname + 1; check_intermediate = NIL; } /* Find first component of path which doesn't exist */ while ((s = strchr(s, '/'))) { *s = '\0'; if (stat(partname, &sbuf) < 0) break; if (check_intermediate && config->check_directory_perms) { if (!config_check_perms(config, partname, &sbuf)) return (NIL); } else if (sbuf.st_mode & S_IWOTH) { log_fatal(("Problem with directory \"%s\", parent directory \"%s\"" " is world writable!"), dir, partname); /* NOTREACHED */ return (-1); } *s++ = '/'; } if (s != NIL) { if (errno != ENOENT) { log_fatal("Couldn't access directory: \"%s\": %s", partname, strerror(errno)); /* NOTREACHED */ return (-1); } /* Try and create each directory in turn */ while (1) { if (mkdir(partname, mkdir_perms) < 0) { log_fatal("Couldn't create directory: \"%s\" - \"%s\": %s", dir, partname, strerror(errno)); /* NOTREACHED */ return (-1); } *s++ = '/'; if (!(s = strchr(s, '/'))) break; *s = '\0'; } } /* Does last component in path already exist? */ if (stat(dir, &sbuf) == 0) { if (config->check_directory_perms) { if (!config_check_perms(config, dir, &sbuf)) return (NIL); } return (T); } if (errno != ENOENT) { log_fatal("Couldn't access directory: \"%s\": %s", dir, strerror(errno)); /* NOTREACHED */ return (-1); } /* Try to make last component in path */ if (mkdir(dir, mkdir_perms) < 0) { log_fatal("Couldn't create directory: \"%s\": %s", dir, strerror(errno)); /* NOTREACHED */ return (NIL); } return (T); } /* ====================================================================== */ /* config_mkdirs() ******************************************************** * * Create working directories (typically under ${var_prefix} if they * don't already exist. Check permissions on intermediate directories * under ${var_prefix} if so configured. *************************************************************************/ BOOL config_mkdirs(struct config * config) { struct pool *tpool = pool_create(1024); char *var_prefix; struct stat sbuf; if (config->check_directory_perms && config->var_prefix) { if (stat(config->var_prefix, &sbuf) < 0) { log_fatal("Directory \"%s\" cannot be accessed: %s", config->var_prefix, strerror(errno)); /* NOT REACHED */ return (NIL); } #if 0 /* XXX DPC 10/04/2005: Temporary */ if (!config_check_perms(config, config->var_prefix, &sbuf)) return (NIL); #endif } var_prefix = (config->var_prefix) ? config->var_prefix : ""; if (config->log_dir && config->log_dir[0]) config_mkdir(config, tpool, var_prefix, config->log_dir); if (config->lock_dir && config->lock_dir[0]) config_mkdir(config, tpool, var_prefix, config->lock_dir); if (config->socket_dir && config->socket_dir[0]) config_mkdir(config, tpool, var_prefix, config->socket_dir); if (config->socket_split_dir) { char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; while (*v) config_mkdir(config, tpool, var_prefix, pool_printf(tpool, "%s/%c", config->socket_dir, *v++)); } if (config->ssl_session_dir && config->ssl_session_dir[0]) config_mkdir(config, tpool, var_prefix, config->ssl_session_dir); if (config->tmp_dir && config->tmp_dir[0]) config_mkdir(config, tpool, var_prefix, config->tmp_dir); if (config->pid_dir && config->pid_dir[0]) config_mkdir(config, tpool, var_prefix, config->pid_dir); if (config->sending_allow_dir && config->sending_allow_dir[0]) config_mkdir(config, tpool, var_prefix, config->sending_allow_dir); if (config->sending_block_dir && config->sending_block_dir[0]) config_mkdir(config, tpool, var_prefix, config->sending_block_dir); pool_free(tpool); return (T); } void config_extract_ssl(struct config *src, struct ssl_config *dst) { dst->ssl_cipher_list = src->ssl_cipher_list; dst->ssl_server_preference = src->ssl_server_preference; dst->ssl_session_dir = src->ssl_session_dir; dst->ssl_cert_file = src->ssl_cert_file; dst->ssl_privatekey_file = src->ssl_privatekey_file; dst->ssl_dh_file = src->ssl_dh_file; dst->ssl_session_timeout = src->ssl_session_timeout; dst->ssl_rsakey_lifespan = src->ssl_rsakey_lifespan; dst->ssl_rsakey_freshen = src->ssl_rsakey_freshen; dst->ssl_default_port = src->ssl_default_port; dst->egd_socket = src->egd_socket; dst->log_debug = src->log_debug; } ./prayer-1.3.5/shared/user_agent.c0000644006513000651300000005044111260150251015334 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/user_agent.c,v 1.5 2009/09/28 15:05:13 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "shared.h" /* Class for recording attributes and behaviour of different user agents, * in order to determine suitable behaviour and set of optimisations */ /* user_agent_create() ************************************************** * * Creates a fresh user agent structure. ***********************************************************************/ struct user_agent *user_agent_create(struct pool *pool) { struct user_agent *result; result = (struct user_agent *) pool_alloc(pool, sizeof(struct user_agent)); /* Defaults */ result->pool = pool; result->manual = NIL; result->agent = NIL; result->use_override = NIL; result->use_debug = NIL; result->use_telemetry = NIL; result->use_telemetry_all = NIL; result->use_telemetry_frontend = NIL; result->use_icons = T; result->use_cookie = T; result->use_substitution = NIL; result->use_direct = T; result->use_pipelining = T; result->use_http_1_1 = T; result->use_pipelining = T; result->use_persist = T; result->use_short = T; result->use_gzip = T; return (result); } /* user_agent_free() **************************************************** * * Free user agent structure ***********************************************************************/ void user_agent_free(struct user_agent *user_agent) { if (user_agent->pool == NIL) free(user_agent); } /* ====================================================================== */ /* user_agent_clear() *************************************************** * * Clear out user agent structure. ***********************************************************************/ static void user_agent_clear(struct user_agent *ua) { /* Defaults */ ua->manual = NIL; ua->use_override = NIL; ua->use_debug = NIL; ua->use_telemetry = NIL; ua->use_telemetry_all = NIL; ua->use_telemetry_frontend = NIL; ua->use_icons = NIL; ua->use_cookie = NIL; ua->use_substitution = NIL; ua->use_direct = NIL; ua->use_pipelining = NIL; ua->use_pipelining = NIL; ua->use_http_1_1 = NIL; ua->use_persist = NIL; ua->use_short = NIL; ua->use_gzip = NIL; } /* ====================================================================== */ /* user_agent_clone() *************************************************** * * Copy a user agent structure * dest: Destination * src: Source ***********************************************************************/ struct user_agent *user_agent_clone(struct pool *pool, struct user_agent *src) { struct user_agent *result; result = (struct user_agent *) pool_alloc(pool, sizeof(struct user_agent)); memcpy((void *) result, (void *) src, sizeof(struct user_agent)); return (result); } /* user_agent_copy() **************************************************** * * Copy a user agent structure * dest: Destination * src: Source ***********************************************************************/ void user_agent_copy(struct user_agent *dest, struct user_agent *src) { memcpy((void *) dest, (void *) src, sizeof(struct user_agent)); } /* ====================================================================== */ /* user_agent_set_option() ********************************************** * * Set or clear user-agent flag from text string. * ua: * option: Option name * enable: T => enable. NIL => disable. ***********************************************************************/ static void user_agent_set_option(struct user_agent *ua, char *option, BOOL enable) { switch (option[0]) { case 'c': if (!strcmp(option, "cookie")) ua->use_cookie = enable; break; case 'd': if (!strcmp(option, "debug")) ua->use_debug = enable; else if (!strcmp(option, "direct")) ua->use_direct = enable; break; case 'g': if (!strcmp(option, "gzip")) ua->use_gzip = enable; case 'h': if (!strcmp(option, "http_1.1")) ua->use_http_1_1 = enable; else if (!strcmp(option, "http_1_1")) ua->use_http_1_1 = enable; break; case 'i': if (!strcmp(option, "icons")) ua->use_icons = enable; break; case 'm': if (!strcmp(option, "manual")) ua->manual = enable; break; case 'o': if (!strcmp(option, "override")) ua->use_override = enable; break; case 'p': if (!strcmp(option, "pipelining")) ua->use_pipelining = enable; else if (!strcmp(option, "persist")) ua->use_persist = enable; break; case 's': if (!strcmp(option, "substitution")) ua->use_substitution = enable; else if (!strcmp(option, "short")) ua->use_short = enable; break; case 't': if (!strcmp(option, "telemetry")) ua->use_telemetry = enable; else if (!strcmp(option, "telemetry_all")) ua->use_telemetry_all = enable; else if (!strcmp(option, "telemetry-all")) ua->use_telemetry_all = enable; else if (!strcmp(option, "telemetry_frontend")) ua->use_telemetry_frontend = enable; else if (!strcmp(option, "telemetry-frontend")) ua->use_telemetry_frontend = enable; break; } } static void user_agent_failsafe(struct user_agent *ua) { ua->manual = T; ua->use_substitution = NIL; ua->use_direct = NIL; ua->use_http_1_1 = NIL; ua->use_pipelining = NIL; ua->use_persist = NIL; ua->use_short = NIL; ua->use_gzip = NIL; } /* ====================================================================== */ /* Static utility routine for generating part of extended login screen */ static void html_form_table_checkbox(struct buffer *b, char *desc, char *name, BOOL enabled) { bprintf(b, "", name, (enabled) ? "checked" : ""); bprintf(b, " %s" CRLF, desc); } /* user_agent_generate_form() ******************************************* * * Generate diagnostic form for login screen. * b: Target Buffer for HTML. * ua: User agent. ***********************************************************************/ void user_agent_generate_form(struct buffer *b, struct user_agent *ua) { bputs(b, "" CRLF); bputs(b, "
User-Agent:"); if (ua->agent) html_common_quote_string(b, ua->agent); else bputs(b, "Unknown" CRLF); bputs(b, "
" CRLF); bputs(b, "" CRLF); html_form_table_checkbox(b, "Enable icons", "use_icons", ua->use_icons); html_form_table_checkbox(b, "Enable short URLS", "use_short", ua->use_short); bputs(b, "" CRLF); bputs(b, "" CRLF); html_form_table_checkbox(b, "Enable HTTP Cookie", "use_cookie", ua->use_cookie); html_form_table_checkbox(b, "Enable Page substitition", "use_substitution", ua->use_substitution); bputs(b, "" CRLF); bputs(b, "" CRLF); html_form_table_checkbox(b, "Enable persistent HTTP connections", "use_persist", ua->use_persist); bputs(b, "" CRLF); bputs(b, "" CRLF); html_form_table_checkbox(b, "Enable HTTP/1.1", "use_http_1_1", ua->use_http_1_1); html_form_table_checkbox(b, "Enable HTTP/1.1 Pipelining", "use_pipelining", ua->use_pipelining); bputs(b, "" CRLF); bputs(b, "" CRLF); html_form_table_checkbox(b, "Enable gzip compression", "use_gzip", ua->use_gzip); bputs(b, "" CRLF); bputs(b, "" CRLF); html_form_table_checkbox(b, "Use direct connection", "use_direct", ua->use_direct); html_form_table_checkbox(b, "Override User Preferences", "use_override", ua->use_override); bputs(b, "" CRLF); bputs(b, "
" CRLF); } /* user_agent_process_form() ******************************************** * * Process user-agent status form if active * ua: User agent. * h: Associative array containing parsed form from login screen. ***********************************************************************/ void user_agent_process_form(struct user_agent *ua, struct assoc *h) { ua->manual = T; ua->use_icons = assoc_lookup(h, "use_icons") ? T : NIL; ua->use_cookie = assoc_lookup(h, "use_cookie") ? T : NIL; ua->use_pipelining = assoc_lookup(h, "use_pipelining") ? T : NIL; ua->use_http_1_1 = assoc_lookup(h, "use_http_1_1") ? T : NIL; ua->use_persist = assoc_lookup(h, "use_persist") ? T : NIL; ua->use_short = assoc_lookup(h, "use_short") ? T : NIL; ua->use_substitution = assoc_lookup(h, "use_substitution") ? T : NIL; ua->use_direct = assoc_lookup(h, "use_direct") ? T : NIL; ua->use_override = assoc_lookup(h, "use_override") ? T : NIL; ua->use_gzip = assoc_lookup(h, "use_gzip") ? T : NIL; } /* ====================================================================== */ /* user_agent_setup_browser() ******************************************* * * Set up user agent configuration, based on "User-Agent: " header * ua: User agent. * browser: String identifying browser, e.g: "mozilla/4". ***********************************************************************/ void user_agent_setup_browser(struct user_agent *ua, char *browser) { if (!(browser && browser[0])) return; ua->agent = pool_strdup(ua->pool, browser); ua->manual = NIL; /* Mozilla */ if (!strncasecmp(browser, "Mozilla/5", strlen("Mozilla/5"))) { /* Grr. Daft User-agent strings: * * Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) * AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9 */ if (strstr(browser, " AppleWebKit/") || strstr(browser, " Safari/")) { ua->use_icons = T; ua->use_cookie = T; ua->use_http_1_1 = T; ua->use_pipelining = NIL; /* Problems with persistent connections after file upload */ ua->use_persist = NIL; ua->use_gzip = T; return; } ua->use_icons = T; ua->use_cookie = T; ua->use_http_1_1 = T; ua->use_pipelining = T; ua->use_persist = T; ua->use_gzip = T; return; } /* Need better parsing library for compatible nonsense */ if (!strncasecmp(browser, "Mozilla/4.0 (compatible; MSIE ", strlen("Mozilla/4.0 (compatible; MSIE "))) { char *s; if ((s = strchr(browser, ')')) && !strcmp(s + 1, " Opera ")) { /* Opera */ ua->use_icons = T; ua->use_cookie = T; ua->use_http_1_1 = NIL; /* Possible problems with HTTP/1.1? */ ua->use_pipelining = NIL; ua->use_persist = NIL; /* Opera has problems with KeepAlive stuff */ ua->use_gzip = T; } else { /* MSIE */ ua->use_icons = T; ua->use_cookie = T; ua->use_http_1_1 = T; /* Possible problems with HTTP/1.1? */ ua->use_pipelining = T; ua->use_persist = T; ua->use_gzip = NIL; } return; } /* Cookie support broken in StarOffice */ if (!strncasecmp(browser, "Mozilla/3.0 (compatible; StarOffice ", strlen("Mozilla/3.0 (compatible; StarOffice "))) { ua->use_icons = T; ua->use_cookie = NIL; ua->use_http_1_1 = NIL; ua->use_pipelining = NIL; ua->use_persist = T; ua->use_gzip = T; return; } /* SSL support in Mac + Windows Netscape 4 is broken: can't handle * use_persist Checks: 4.08 okay. 4.5 and 4.7 definitely broken. * Solution: mask out use_persist for versions > 4.08. Unix Netscape 4 * appears to be completely different: supports HTTP/1.1 for a start! */ if (!strncasecmp(browser, "Mozilla/4.", strlen("Mozilla/4.")) && (browser[strlen("Mozilla/4.")] != '0')) { char *s = strchr(browser, '('); if (s && !strncasecmp(s + 1, "Macintosh", strlen("Macintosh"))) { ua->use_icons = T; ua->use_cookie = T; ua->use_http_1_1 = NIL; ua->use_pipelining = NIL; ua->use_persist = NIL; ua->use_gzip = T; return; } else if (s && !strncasecmp(s + 1, "Win", strlen("Win"))) { ua->use_icons = T; ua->use_cookie = T; ua->use_http_1_1 = T; ua->use_pipelining = T; ua->use_persist = NIL; ua->use_gzip = T; return; } } /* Generic Netscape settings */ if (!strncasecmp(browser, "Mozilla/", strlen("Mozilla/"))) { ua->use_icons = T; ua->use_cookie = T; ua->use_http_1_1 = T; ua->use_pipelining = T; ua->use_gzip = T; return; } /* Fake Netscape */ if (!strncasecmp(browser, "Netscape/", strlen("Netscape/"))) { ua->use_icons = T; ua->use_cookie = T; ua->use_http_1_1 = T; ua->use_pipelining = T; ua->use_gzip = T; return; } /* Lynx */ if (!strncasecmp(browser, "Lynx/", strlen("Lynx/"))) { ua->use_icons = NIL; ua->use_cookie = NIL; ua->use_pipelining = NIL; ua->use_gzip = T; return; } /* W3M */ if (!strncasecmp(browser, "w3m/", strlen("w3m/"))) { ua->use_icons = NIL; ua->use_cookie = NIL; ua->use_pipelining = NIL; ua->use_gzip = T; return; } } /* ====================================================================== */ /* user_agent_process_browser() ***************************************** * * Set up user agent configuration based on user supplied override * ua: User agent. * s: String identifying browser, e.g: "netscape". ***********************************************************************/ static void user_agent_process_browser(struct user_agent *ua, char *s) { if (!strcmp(s, "mozilla")) user_agent_setup_browser(ua, "Mozilla/5.x (simulation)"); else if (!strcmp(s, "netscape")) user_agent_setup_browser(ua, "Netscape/4.x (simulation)"); else if (!strcmp(s, "ie")) user_agent_setup_browser(ua, "IE/Unknown (simulation)"); else if (!strcmp(s, "lynx")) user_agent_setup_browser(ua, "Lynx/Unknown (simulation)"); else if (!strcmp(s, "w3m")) user_agent_setup_browser(ua, "w3m/Unknown (simulation)"); else user_agent_setup_browser(ua, "Unknown/Unknown (simulation)"); } /* user_agent_process_argv() ******************************************** * * Process user agent options from argv array string. See URL_OPTIONS * for full details. * enable=option,option,option * disable=option,option,option * opts=option,option,option * user-agent= * debug * override * manual * telemetry * telemetry_all * telemetry-all * telemetry_frontend * telemetry-frontend * * Args: * ua: User agent * string: String identifying browser, e.g: "netscape". * pool: Target pool ***********************************************************************/ BOOL user_agent_process_argv(struct user_agent *ua, char *string, struct pool *pool) { /* Allow empty arguments */ if (!strcmp(string, "")) return (T); if (!strncasecmp(string, "disable=", strlen("disable="))) { char *s = pool_strdup(pool, string + strlen("disable=")); char *t; ua->manual = T; while (s) { if ((t = strchr(s, ','))) *t++ = '\0'; user_agent_set_option(ua, s, NIL); s = t; } return (T); } if (!strncasecmp(string, "enable=", strlen("enable="))) { char *s = pool_strdup(pool, string + strlen("enable=")); char *t; ua->manual = T; while (s) { if ((t = strchr(s, ','))) *t++ = '\0'; user_agent_set_option(ua, s, T); s = t; } return (T); } if (!strncasecmp(string, "opts=", strlen("opts="))) { char *s = pool_strdup(pool, string + strlen("opts=")); char *t; user_agent_clear(ua); ua->manual = T; while (s) { if ((t = strchr(s, ','))) *t++ = '\0'; user_agent_set_option(ua, s, T); s = t; } return (T); } if (!strncasecmp(string, "user-agent=", strlen("user-agent="))) user_agent_process_browser(ua, string + strlen("user-agent=")); else if (!strncasecmp(string, "browser=", strlen("browser="))) user_agent_process_browser(ua, string + strlen("user-agent=")); else if (!strcmp(string, "failsafe")) user_agent_failsafe(ua); else if (!strcmp(string, "debug")) ua->use_debug = T; else if (!strcmp(string, "text")) ua->use_icons = NIL; else if (!strcmp(string, "lores")) ua->use_icons = NIL; else if (!strcmp(string, "override")) ua->use_override = T; else if (!strcmp(string, "manual")) ua->manual = T; else if (!strcmp(string, "telemetry")) ua->use_telemetry = T; else if (!strcmp(string, "telemetry_all")) ua->use_telemetry_all = T; else if (!strcmp(string, "telemetry-all")) ua->use_telemetry_all = T; else if (!strcmp(string, "telemetry_frontend")) ua->use_telemetry_frontend = T; else if (!strcmp(string, "telemetry-frontend")) ua->use_telemetry_frontend = T; else return (NIL); ua->manual = T; return (T); } /* ====================================================================== */ /* user_agent_parse() *************************************************** * * Build a user agent from list of options * ua: User agent * string: String containing list of comma separated options. ***********************************************************************/ void user_agent_parse(struct user_agent *ua, char *string) { char *s = string; char *t; user_agent_clear(ua); while (s) { if ((t = strchr(s, ','))) *t++ = '\0'; user_agent_set_option(ua, s, T); s = t; } } /* ====================================================================== */ /* user_agent_options() ************************************************* * * Convery user agent options into printable representation. * ua: User agent * * Returns: String containing list of options eg: "cookie" ***********************************************************************/ char *user_agent_options(struct user_agent *ua) { struct buffer *b = buffer_create(ua->pool, 256); if (ua->use_debug) bputs(b, "debug,"); if (ua->manual) bputs(b, "manual,"); if (ua->use_override) bputs(b, "override,"); if (ua->use_telemetry) bputs(b, "telemetry,"); if (ua->use_telemetry_all) bputs(b, "telemetry_all,"); if (ua->use_telemetry_frontend) bputs(b, "telemetry_frontend,"); if (ua->use_icons) bputs(b, "icons,"); if (ua->use_cookie) bputs(b, "cookie,"); if (ua->use_pipelining) bputs(b, "pipelining,"); if (ua->use_http_1_1) bputs(b, "http_1_1,"); if (ua->use_persist) bputs(b, "persist,"); if (ua->use_substitution) bputs(b, "substitution,"); if (ua->use_short) bputs(b, "short,"); if (ua->use_direct) bputs(b, "direct,"); if (ua->use_gzip) bputs(b, "gzip,"); if (buffer_size(b) > 0) return (buffer_fetch(b, 0, buffer_size(b) - 1, NIL)); else return (pool_strdup(ua->pool, "")); } ./prayer-1.3.5/shared/log.h0000644006513000651300000000267711063701636014010 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/log.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ struct log { struct pool *pool; struct config *config; char *name; int fd; ino_t inode; time_t last_ping; pid_t peer_pid; }; struct log *log_create(struct config *config, struct pool *pool); void log_free(struct log *log); BOOL log_open(struct log *log, char *name); BOOL log_ping(struct log *log); /* ====================================================================== */ unsigned long log_entry_size(char *fmt, va_list ap); void log_panic_ap(struct config *config, char *username, unsigned long len, char *fmt, va_list ap); BOOL log_ap(struct log *log, struct pool *pool, char *username, unsigned long len, char *fmt, va_list ap); BOOL log_here(struct log *log, char *fmt, ...); void log_record_peer_pid(struct log *log, pid_t pid); /* ====================================================================== */ BOOL log_misc_init(struct config *config, char *progname, char *misc_log_name); BOOL log_misc_ping(); void log_misc(char *fmt, ...); void log_debug(char *fmt, ...); void log_panic(char *fmt, ...); void log_fatal(char *fmt, ...); ./prayer-1.3.5/shared/gzip.c0000644006513000651300000001360511063701636014164 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/gzip.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Code stolen from zlib: gzio.c and gzutil.c */ #include "shared.h" #ifndef GZIP_ENABLE struct buffer *gzip(struct buffer *input) { log_fatal("gzip() called without gzip support enabled"); return (NIL); } #else #include #define DEF_MEM_LEVEL 8 #define Z_BUFSIZE 16384 #define OS_CODE 0x03 /* assume Unix */ #define ALLOC(size) malloc(size) #define TRYFREE(p) {if (p) free(p);} #define F_OPEN(name, mode) fopen((name), (mode)) static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */ typedef struct gz_stream { z_stream stream; int z_err; /* error code for last stream operation */ int z_eof; /* set if end of input file */ Byte *inbuf; /* input buffer */ Byte *outbuf; /* output buffer */ uLong crc; /* crc32 of uncompressed data */ char *msg; /* error message */ int transparent; /* 1 if input file is not a .gz file */ struct buffer *output; } gz_stream; /* ====================================================================== */ /* Utility functions */ static void putLong(struct buffer *b, uLong x) { int n; for (n = 0; n < 4; n++) { bputc(b, (int) (x & 0xff)); x >>= 8; } } static void bwrite(struct buffer *b, unsigned char *x, unsigned long len) { while (len > 0) { bputc(b, *x++); len--; } } static int do_flush(gzFile file, int flush) { uInt len; int done = 0; gz_stream *s = (gz_stream *) file; s->stream.avail_in = 0; /* should be zero already anyway */ for (;;) { len = Z_BUFSIZE - s->stream.avail_out; if (len != 0) { bwrite(s->output, s->outbuf, len); s->stream.next_out = s->outbuf; s->stream.avail_out = Z_BUFSIZE; } if (done) break; s->z_err = deflate(&(s->stream), flush); /* Ignore the second of two consecutive flushes: */ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; /* deflate has finished flushing only when it hasn't used up * all the available space in the output buffer: */ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; } return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; } static int destroy(gz_stream * s) { int err = Z_OK; if (!s) return Z_STREAM_ERROR; TRYFREE(s->msg); if (s->stream.state != NULL) err = deflateEnd(&(s->stream)); if (s->z_err < 0) err = s->z_err; TRYFREE(s->inbuf); TRYFREE(s->outbuf); TRYFREE(s); return (err); } /* ====================================================================== */ static gzFile my_gzopen(struct buffer *output) { int err; int level = Z_DEFAULT_COMPRESSION; /* compression level */ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ gz_stream *s; s = (gz_stream *) ALLOC(sizeof(gz_stream)); if (!s) return Z_NULL; s->stream.zalloc = (alloc_func) 0; s->stream.zfree = (free_func) 0; s->stream.opaque = (voidpf) 0; s->stream.next_in = s->inbuf = Z_NULL; s->stream.next_out = s->outbuf = Z_NULL; s->stream.avail_in = s->stream.avail_out = 0; s->z_err = Z_OK; s->z_eof = 0; s->crc = crc32(0L, Z_NULL, 0); s->msg = NULL; s->transparent = 0; s->output = output; err = deflateInit2(&(s->stream), level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); /* windowBits is passed < 0 to suppress zlib header */ s->stream.next_out = s->outbuf = (Byte *) ALLOC(Z_BUFSIZE); if (err != Z_OK || s->outbuf == Z_NULL) return destroy(s), (gzFile) Z_NULL; s->stream.avail_out = Z_BUFSIZE; errno = 0; /* Write a very simple .gz header: */ bprintf(s->output, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], Z_DEFLATED, 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /*xflags */ , OS_CODE); return (gzFile) s; } static int my_gzwrite(gzFile file, const voidp buf, unsigned len) { gz_stream *s = (gz_stream *) file; s->stream.next_in = (Bytef *) buf; s->stream.avail_in = len; while (s->stream.avail_in != 0) { if (s->stream.avail_out == 0) { s->stream.next_out = s->outbuf; bwrite(s->output, s->outbuf, Z_BUFSIZE); s->stream.avail_out = Z_BUFSIZE; } s->z_err = deflate(&(s->stream), Z_NO_FLUSH); if (s->z_err != Z_OK) break; } s->crc = crc32(s->crc, (const Bytef *) buf, len); return (int) (len - s->stream.avail_in); } static int my_gzclose(gzFile file) { int err; gz_stream *s = (gz_stream *) file; if (s == NULL) return Z_STREAM_ERROR; err = do_flush(file, Z_FINISH); if (err != Z_OK) return destroy((gz_stream *) file); putLong(s->output, s->crc); putLong(s->output, s->stream.total_in); return destroy((gz_stream *) file); } /* ====================================================================== */ struct buffer *gzip(struct buffer *input) { struct pool *pool = input->pool; struct buffer *output = buffer_create(pool, 0); gz_stream *stream = my_gzopen(output); unsigned char *src; unsigned long srcl; buffer_rewind(input); while (buffer_fetch_block(input, &src, &srcl)) my_gzwrite(stream, src, srcl); my_gzclose(stream); return (output); } #endif ./prayer-1.3.5/shared/Makefile0000644006513000651300000000243711160500433014476 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/shared/Makefile,v 1.5 2009/03/19 17:30:03 dpc22 Exp $ # # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2008 # See the file NOTICE for conditions of use and distribution. ifeq ($(strip $(RPM_BUILD)), true) include ../Config-RPM else include ../Config endif # Enable on the fly compression ifeq ($(strip $(GZIP_ENABLE)), true) GZIP_DEF = -DGZIP_ENABLE BASECFLAGS += $(Z_INCLUDE) endif # Enable SYSV mutex ifeq ($(strip $(MUTEX_SEMAPHORE)), true) MUTEX_DEF = -DMUTEX_SEMAPHORE endif # Enable Electric Fence ifeq ($(strip $(FENCE_ENABLE)), true) BASECFLAGS += $(FENCE_INCLUDE) endif BASECFLAGS += -I../lib MYCFLAGS = $(BASECFLAGS) SHARED_OBJS = \ config.o gzip.o html_common.o log.o \ request.o response.o user_agent.o all: $(SHARED_OBJS) rm -f shared.a ar r shared.a $(SHARED_OBJS) # response.o: need to add GZIP_ENABLE response.o: response.c *.h Makefile $(CC) $(MYCFLAGS) $(GZIP_DEF) -c $< # gzip.o: need to add GZIP_ENABLE gzip.o: gzip.c *.h Makefile $(CC) $(MYCFLAGS) $(GZIP_DEF) -c $< # config.o: need to add MUTEX_DEF config.o: config.c *.h Makefile $(CC) $(MYCFLAGS) $(MUTEX_DEF) -c $< # Default build rule %.o: %.c *.h Makefile $(CC) $(MYCFLAGS) -c $< clean: -rm -f shared.a $(SHARED_OBJS) *.flc *~ \#*\# ./prayer-1.3.5/shared/request.c0000644006513000651300000014262111063701636014704 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/request.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Various routines and data structures for parsing HTTP request on * input iostream. Should be able to cope with partial requests if * underlying iostream is running in a non-blocking mode: in this * case just call request_parse again when data is available. Eventually * a complete request will be flagged. */ #include "shared.h" /* request_create() ***************************************************** * * Create a new request structure with own pool (hijacked by lots of * subsiduary routines!) and some default values filled in. * config: Global configuration * stream: iostream from this request * frontend: Frontend server => probably need to proxy request. * Don't trample on buffers when parsing * * Returns: New request structure ***********************************************************************/ struct request *request_create(struct config *config, struct iostream *stream, BOOL frontend) { struct pool *p = pool_create(REQUEST_PREFERRED_BLOCK_SIZE); struct request *request = pool_alloc(p, sizeof(struct request)); /* Make sure cleared out */ memset(request, 0, sizeof(struct request)); /* Common fields */ request->pool = p; request->config = config; request->stream = stream; /* Input buffer */ request->read_buffer = buffer_create(p, PREFERRED_BUFFER_BLOCK_SIZE); request->chunked = NIL; request->state = REQUEST_METHOD; request->method_size = 0; request->hdrs_offset = 0; request->hdrs_size = 0; request->hdrs_crlfs = 1; request->body_offset = 0; request->body_current = 0; request->body_size = 0; request->chunk_state = CHUNK_HDR; request->chunk_hdr_offset = 0; request->chunk_hdr_current = 0; request->chunk_hdr_size = 0; request->chunk_body_offset = 0; request->chunk_body_current = 0; request->chunk_body_size = 0; request->chunk_trlr_offset = 0; request->chunk_trlr_size = 0; request->chunk_trlr_crlfs = 0; /* Following on from method line */ request->frontend = frontend; request->preserve = frontend; /* Frontend server _may_ be proxy */ request->iseof = NIL; request->error = NIL; /* Decoded request */ request->request = NIL; request->major = 0; request->minor = 0; request->url = NIL; request->url_host = NIL; request->url_port = NIL; request->url_path = NIL; request->argc = NIL; request->argv = NIL; request->get_suffix = NIL; request->log_entry = NIL; /* Processed request */ request->method = UNKNOWN; request->hdrs = assoc_create(p, 16, T); request->form = NIL; /* Response information */ request->status = 501; /* Not implemented */ request->dump = NIL; request->telemetry = NIL; request->telemetry_all = NIL; request->telemetry_fd = -1; request->response_hdrs = NIL; request->write_buffer = buffer_create(p, PREFERRED_BUFFER_BLOCK_SIZE); request->gzip_buffer = NIL; request->user_agent = NIL; /* Following indicate final state of response */ request->use_http_1_1 = NIL; /* Until we know better */ request->persist = T; /* Until we know better */ request->use_utf8 = NIL; request->allow_gzip = NIL; request->use_gzip = NIL; request->use_x_gzip = NIL; return (request); } /* request_free() ******************************************************* * * Free (pool associated with) request. * request: ***********************************************************************/ void request_free(struct request *request) { pool_free(request->pool); } /* ====================================================================== */ /* request_telemetry() ************************************************** * * Set up HTTP telemetry log for debugging purposes. * request: * fd: Output file descriptor for telemetry * all: T => Record headers and body * NIL => Record body only ***********************************************************************/ void request_telemetry(struct request *request, int fd, BOOL all) { request->telemetry = T; request->telemetry_all = all; request->telemetry_fd = fd; request->preserve = T; /* Make sure that request not trampled on */ } void request_dump(struct request *request) { request->dump = T; } /* ====================================================================== */ /* request_forge_redirect() ********************************************* * * Forge a HTTP redirect request: used by session_redirect for * transparent page substiution. * request: * url: Target URL ***********************************************************************/ void request_forge_redirect(struct request *request, char *url) { request->method = GET; request->url = url; request->url_path = url; request->form = NIL; /* Allocate a clean new write buffer if we need one */ if (buffer_size(request->write_buffer) > 0) request->write_buffer = buffer_create(request->pool, PREFERRED_BUFFER_BLOCK_SIZE); request_parse_argv(request); } /* ====================================================================== */ /* Some crude routines for decoding URL and body of post requests. The * following URL: "http://hoohoo.ncsa.uiuc.edu/cgi/overview.html" is old * but gives a lot of useful information about forms and CGI. * * Basic idea is that a form can send data to a Web server using either: * GET: data is appended to URL after ? * POST: data in request body. Length is defined by Content-Length header * * Data format is identical in both cases: * * key=value&key2=value&key3=value3 * * With any special characters (non-ACSII, "/" and "&") encoded in hex as * %XY. * */ /* request_parse_url() ************************************************** * * Parse request->url into component parts. * request: ***********************************************************************/ static BOOL request_parse_url(struct request *request) { struct pool *p = request->pool; char *s, *t = request->url; char c; if (!t) return (NIL); if (*t == '/') { /* Absolute path, no host provided */ request->url_host = "localhost"; request->url_port = NIL; request->url_path = s = pool_strdup(p, request->url); return (T); } if (!strncasecmp(t, "https://", strlen("https://"))) t += strlen("http://"); if (!strncasecmp(t, "http://", strlen("http://"))) t += strlen("http://"); else { /* Absolute path, no host provided */ request->url_host = "localhost"; request->url_port = NIL; request->url_path = s = pool_strdup(p, request->url); return (T); } /* Record start of hostname, look for end of hostname */ s = t; while ((c = *t) && (c != '/') && (c != ':')) t++; if (*t) *t++ = '\0'; request->url_host = pool_strdup(p, s); /* Record optional port component */ if (c == ':') { s = t; while ((c = *t) && (c != '/')) t++; if (*t) *t++ = '\0'; request->url_port = pool_strdup(p, s); } else request->url_port = NIL; /* Pathname, default to "/" */ if (c != '\0') request->url_path = s = pool_strdup(p, t); else request->url_path = pool_strdup(p, "/"); return (T); } /* ====================================================================== */ /* request_parse_method() *********************************************** * * Parse HTTP method line (e.g: "GET / HTTP/1.0" * request: * config: Configuration (defines maximum size of method) * * Returns: T => method parsed successfully * NIL => Error (temporary end of stream if request->iseos set) ***********************************************************************/ static BOOL request_parse_method(struct request *request) { struct config *config = request->config; struct iostream *stream = request->stream; struct buffer *b = request->read_buffer; int c; char *token; char *method; unsigned long count = request->method_size; unsigned long maxsize = config->http_max_method_size; /* Skip over leading whitespace */ while (((c = iogetc(stream)) == '\015') || (c == '\012')); /* Fetch and record characters until end of line */ while (c != EOF) { bputc(b, c); if ((maxsize > 0) && (++count >= maxsize)) { request->status = 413; /* Request Entity too large */ return (NIL); } if (c == '\012') break; c = iogetc(stream); } request->method_size = buffer_size(b); if (c == EOF) { /* Record permanent end of file */ request->iseof = T; return (NIL); } /* Method line is now complete: record and then parse */ if (request->method_size > 0) { method = buffer_fetch(b, 0, request->method_size - 1, request->preserve); request->request = pool_strdup(b->pool, method); if (request->method_size >= 2) { /* Chomp trailing CR so they don't appear in log files */ if (request->request[request->method_size - 2] == '\015') request->request[request->method_size - 2] = '\0'; } } else request->request = method = pool_strdup(b->pool, ""); if ((token = string_get_token(&method)) == NIL) { /* Bad request */ request->status = 400; return NIL; } /* Methods listed in RFC 2616. NB: Case dependant */ if (!strcmp(token, "OPTIONS")) request->method = OPTIONS; else if (!strcmp(token, "GET")) request->method = GET; else if (!strcmp(token, "HEAD")) request->method = HEAD; else if (!strcmp(token, "POST")) request->method = POST; else if (!strcmp(token, "PUT")) request->method = PUT; else if (!strcmp(token, "DELETE")) request->method = DELETE; else if (!strcmp(token, "TRACE")) request->method = TRACE; else if (!strcmp(token, "CONNECT")) request->method = CONNECT; else { request->method = UNKNOWN; /* Bad request */ request->status = 400; return NIL; } if ((request->method != HEAD) && (request->method != GET) && (request->method != POST)) { request->status = 405; /* Method not allowed */ return NIL; } if ((request->url = string_get_token(&method)) == NIL) { /* Bad request */ request->status = 400; return NIL; } if ((request_parse_url(request)) == NIL) return NIL; /* Default to HTTP 0.9 */ request->major = 0; request->minor = 9; token = string_get_token(&method); if (token) { int major, minor; if (strncasecmp(token, "HTTP/", strlen("HTTP/")) || (sscanf(token + strlen("HTTP/"), "%d.%d", &major, &minor) != 2)) { /* Bad request */ request->status = 400; return NIL; } request->major = major; request->minor = minor; if (string_get_token(&method)) { /* Bad request: garbage at end of the line */ request->status = 400; return NIL; } } if ((request->major == 1) && (request->minor == 1)) request->use_http_1_1 = T; return (T); } /* ====================================================================== */ /* request_process_headers() ******************************************** * * Convert (complete set of) HTTP headers into associative array. * request: * data: List of headers * * Returns: T => Headers parsed okay * NIL => Invalid data in headers ***********************************************************************/ static BOOL request_process_headers(struct request *request, char *data) { char *header, *key, *oldvalue, *value, *s; while ((header = string_get_lws_line(&data, T))) { /* Fetch one (possibly folded) header line at a time */ if (header[0] == '\0') continue; if (!((key = string_get_token(&header)) && ((value = string_next_token(&header))))) { /* Bad request */ request->status = 400; return (NIL); } /* Convert string to lower case */ for (s = key; *s; s++) *s = tolower(*s); if ((s == key) || (s[-1] != ':')) { /* Bad request */ request->status = 400; return (NIL); } s[-1] = '\0'; if ((oldvalue = assoc_lookup(request->hdrs, key))) { s = pool_alloc(request->hdrs->pool, strlen(value) + strlen(oldvalue) + 3); strcpy(s, oldvalue); /* Should be able to improve this */ strcat(s, ", "); strcat(s, value); value = s; } /* Generate assoc entry. Don't need to copy key and value */ assoc_update(request->hdrs, key, value, NIL); } return (T); } /* ====================================================================== */ /* request_parse_headers_init() ***************************************** * * Set up request parsing engine to read in and parse HTTP headers * request: ***********************************************************************/ static BOOL request_parse_headers_init(struct request *request) { struct buffer *b = request->read_buffer; /* Only session URLs and telemetry need proxy */ if (request->preserve && (request->telemetry == NIL) && (strncmp(request->url_path, "/session", strlen("/session")) != 0)) request->preserve = NIL; request->state = REQUEST_HDRS; request->hdrs_offset = buffer_size(b); request->hdrs_size = 0; request->hdrs_crlfs = 1; /* Following on from method line */ return (T); } /* request_parse_headers() ********************************************** * * Read in and parse HTTP headers from iostream. * request: * config: Prayer Configuration (used for size limits). * * Returns: T => Entire HTTP header section was read sucessfully. * NIL => Error parsing headers. ***********************************************************************/ static BOOL request_parse_headers(struct request *request) { struct config *config = request->config; struct iostream *stream = request->stream; struct buffer *b = request->read_buffer; unsigned long crlf_count = request->hdrs_crlfs; char *data; int c = EOF; unsigned long count = request->hdrs_size; unsigned long maxsize = config->http_max_hdr_size; /* Record hdrs location first time into loop */ if (request->hdrs_offset == 0) request->hdrs_offset = buffer_size(b); /* Read in data until end of header block located (CRLFCRLF or just LFLF) */ while ((crlf_count < 2) && ((c = iogetc(stream)) != EOF)) { bputc(b, c); if ((maxsize > 0) && (++count >= maxsize)) { request->status = 413; /* Request Entity too large */ return (NIL); } if (c == '\012') crlf_count++; else if (c != '\015') crlf_count = 0; } request->hdrs_size = count; request->hdrs_crlfs = crlf_count; /* Hdrs now complete */ /* Extract copy of entire header block from buffer */ data = buffer_fetch(b, request->hdrs_offset, request->hdrs_size, request->preserve); request_process_headers(request, data); return (T); } /* ====================================================================== */ /* request_parse_body_init() ******************************************** * * Set up HTTP parser for payload (chunked or normal) * request: * config: Prayer Configuration (used for size limits). * * Returns: T => Setup successful * NIL => Error (typically context-length too large). ***********************************************************************/ static BOOL request_parse_body_init(struct request *request) { struct config *config = request->config; struct iostream *stream = request->stream; struct buffer *b = request->read_buffer; char *value; unsigned long len; if ((value = assoc_lookup(request->hdrs, "content-length"))) { if (((len = atoi(value)) > config->http_max_body_size)) { /* Eat the body */ if (len < (5*config->http_max_body_size)) { while ((len > 0) && (iogetc(stream) != EOF)) len--; } request->status = 413; /* Request Entity too large */ return (NIL); } request->state = REQUEST_BODY_SIMPLE; request->body_offset = buffer_size(b); request->body_current = 0L; request->body_size = atoi(value); return (T); } if ((value = assoc_lookup(request->hdrs, "transfer-encoding")) && (strcasecmp(value, "identity") != 0)) { if (strcasecmp(value, "chunked") != 0) { /* We only support "chunked" and "identity" at the moment */ request->status = 501; /* Not implemented */ return (NIL); } request->state = REQUEST_BODY_CHUNKED; request->chunk_state = CHUNK_HDR; request->body_offset = buffer_size(b); request->body_current = 0; request->body_size = 0; /* Decode chunked buffer body as we proceed */ request->chunked = buffer_create(request->pool, PREFERRED_BUFFER_BLOCK_SIZE); request->chunk_hdr_offset = buffer_size(b); request->chunk_hdr_size = 0; request->chunk_body_offset = buffer_size(b); request->chunk_body_size = 0; return (T); } if (request->method == POST) { request->status = 411; /* POST method needs body */ return (NIL); } /* Request has no body */ request->state = REQUEST_COMPLETE; return (T); } /* request_parse_body_simple() ****************************************** * Read in and parse simple HTTP payload from iostream. * request: * * Returns: T => Entire HTTP header section was read sucessfully. * NIL => Reached end of file without full request ***********************************************************************/ static BOOL request_parse_body_simple(struct request *request) { struct iostream *stream = request->stream; struct buffer *b = request->read_buffer; unsigned long current = request->body_current; unsigned long size = request->body_size; int c = EOF; /* Record body location and size */ if (request->body_offset == 0) request->body_offset = buffer_size(b); while ((current < size) && ((c = iogetc(stream)) != EOF)) { bputc(b, c); current++; } request->body_current = current; if (current < size) { request->status = 400; /* Insufficient data */ return (NIL); } return (T); } /* ====================================================================== */ /* HTTP/1.1 Chunked encoding structure: * Chunked-Body = *chunk * last-chunk * trailer * CRLF * * chunk = chunk-size [ chunk-extension ] CRLF * chunk-data CRLF * chunk-size = 1*HEX * last-chunk = 1*("0") [ chunk-extension ] CRLF * * chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) * chunk-ext-name = token * chunk-ext-val = token | quoted-string * chunk-data = chunk-size(OCTET) * trailer = *(entity-header CRLF) * * Chunked encoding is ghastly, however the spec says we have to support * it for HTTP requests as well as responses. Doesn't mean that I can find * _anything_ with uses chunked encoding for requests. */ /* request_parse_chunk_hdr_init() *************************************** * * Set up HTTP parser for chunk header * request: Current (partly parsed) HTTP request ***********************************************************************/ static BOOL request_parse_chunk_hdr_init(struct request *request) { struct buffer *b = request->read_buffer; /* This chunk now complete: ready for next chunk... */ request->chunk_state = CHUNK_HDR; /* Shared code here! */ request->chunk_hdr_offset = buffer_size(b); request->chunk_hdr_size = 0; request->chunk_body_offset = 0; request->chunk_body_current = 0; request->chunk_body_size = 0; return (T); } /* request_parse_chunk_hdr() ******************************************** * Read in and parse simple HTTP chunk header payload from iostream. * request: Current (partly parsed) HTTP request * * Returns: T => Entire HTTP header section was read sucessfully. * NIL => End of file ***********************************************************************/ static BOOL request_parse_chunk_hdr(struct request *request) { struct config *config = request->config; struct iostream *stream = request->stream; struct buffer *b = request->read_buffer; int c; unsigned long count = buffer_size(b) - request->body_offset; unsigned long maxsize = config->http_max_body_size; /* Skip over leading whitespace */ while (((c = iogetc(stream)) == '\015') || (c == '\012')); while (c != EOF) { if ((maxsize > 0) && (++count >= maxsize)) { request->status = 413; /* Request Entity too large */ return (NIL); } bputc(b, c); if (c == '\012') break; c = iogetc(stream); } if (c == EOF) { request->iseof = T; return (NIL); } /* Chunk header is now complete */ return (T); } /* request_process_chunk_hdr() ****************************************** * * Set up HTTP parser using chunk header for chunk payload * request: * * Returns: T => Setup successful * NIL => Error (invalid chunk header) ***********************************************************************/ static BOOL request_process_chunk_hdr(struct request *request) { struct config *config = request->config; struct buffer *b = request->read_buffer; char *chunk_header; unsigned long count = buffer_size(b) - request->body_offset; unsigned long maxsize = config->http_max_body_size; /* Fetch linear block */ request->chunk_hdr_size = buffer_size(b) - request->chunk_hdr_offset; chunk_header = buffer_fetch(b, request->chunk_hdr_offset, request->chunk_hdr_size, request->preserve); /* Derive location and size of following chunk */ /* Hexidecimal number at start of chunk header line determines chunk size */ request->chunk_body_offset = buffer_size(b); request->chunk_body_current = 0; request->chunk_body_size = strtoul(chunk_header, &chunk_header, 16); if ((maxsize > 0) && (count + request->chunk_body_size) > maxsize) { request->status = 413; /* Request Entity too large */ return (NIL); } /* Sanity check remainder of the chunk header */ while (string_isspace(*chunk_header)) chunk_header++; if (chunk_header[0] && (chunk_header[0] != '\015') && (chunk_header[0] != '\012')) { if (chunk_header[0] != ';') { request->status = 400; /* Invalid request */ return (NIL); } } return (T); } /* request_parse_chunk_body() ******************************************* * Read in HTTP chunk body from iostream. * request: * * Returns: T => Entire HTTP header section was read sucessfully. * NIL => End of file ***********************************************************************/ static BOOL request_parse_chunk_body(struct request *request) { struct config *config = request->config; struct iostream *stream = request->stream; struct buffer *b = request->read_buffer; struct buffer *b2 = request->chunked; unsigned long current = request->chunk_body_current; unsigned long size = request->chunk_body_size; unsigned long count = buffer_size(b) - request->body_offset; unsigned long maxsize = config->http_max_body_size; int c = EOF; /* Record body location first time into loop: should be redundant */ if (request->chunk_body_offset == 0) request->chunk_body_offset = buffer_size(b); while ((current < size) && ((c = iogetc(stream)) != EOF)) { /* Strictly speaking redundant, but this way at least consistent */ if ((maxsize > 0) && (++count >= maxsize)) { request->status = 413; /* Request Entity too large */ return (NIL); } bputc(b, c); /* Vanilla version */ bputc(b2, c); /* Decoded version */ current++; } request->body_current = current; if (current < size) { request->status = 400; /* Insufficient data */ return (NIL); } return (T); } /* ====================================================================== */ /* Routines for processing trailer block in chunked incoding */ /* request_parse_chunk_trlr_init() ************************************** * * Set up HTTP parser for chunk trailer. Even more sillyness! * request: Current (partly parsed) HTTP request ***********************************************************************/ static BOOL request_parse_chunk_trlr_init(struct request *request) { struct buffer *b = request->read_buffer; request->chunk_state = CHUNK_TRAILER; request->chunk_trlr_offset = buffer_size(b); request->chunk_trlr_size = 0; request->chunk_trlr_crlfs = 1; /* Following on from method line */ return (T); } /* request_parse_chunk_trlr() ******************************************* * Read in and parse simple HTTP chunk trailer payload from iostream. * request: Current (partly parsed) HTTP request * * Returns: T => Entire HTTP header section was read sucessfully. * NIL => End of file ***********************************************************************/ static BOOL request_parse_chunk_trlr(struct request *request) { struct config *config = request->config; struct iostream *stream = request->stream; struct buffer *b = request->read_buffer; unsigned long crlf_count = request->chunk_trlr_crlfs; char *data; int c = NIL; unsigned long count = buffer_size(b) - request->body_offset; unsigned long maxsize = config->http_max_body_size; /* Record trlr location first time into loop: should be redundant */ if (request->chunk_trlr_offset == 0) request->chunk_trlr_offset = buffer_size(b); /* Read in data until end of trailer block located (CRLFCRLF or just LFLF) */ while ((crlf_count < 2) && ((c = iogetc(stream)) != EOF)) { if ((maxsize > 0) && (++count >= maxsize)) { request->status = 413; /* Request Entity too large */ return (NIL); } bputc(b, c); request->chunk_trlr_size++; if (c == '\012') crlf_count++; else if (c != '\015') crlf_count = 0; } request->chunk_trlr_crlfs = crlf_count; /* Trailer now complete */ /* Extract copy of entire header block from buffer */ data = buffer_fetch(b, request->chunk_trlr_offset, request->chunk_trlr_size, request->preserve); request_process_headers(request, data); /* Just for completeness sake: not actually used at all */ request->body_size = buffer_size(b) - request->body_offset; return (T); } /* ====================================================================== */ /* request_parse_body_chunked() ***************************************** * * Read in and parse HTTP chunk format including multiple headers and * trailers. I hope! This appears to match my understanding of the HTTP/1.1 * specification, but I can't find anything silly enought to use chunks in * HTTP requests. * * request: Current (partly parsed) HTTP request * * Returns: T => Entire HTTP chunk body section read sucessfully. * NIL => End of file * ***********************************************************************/ static BOOL request_parse_body_chunked(struct request *request) { while (request->chunk_state != CHUNK_COMPLETE) { switch (request->chunk_state) { case CHUNK_HDR: if (!request_parse_chunk_hdr(request)) return (NIL); if (!request_process_chunk_hdr(request)) return (NIL); if (request->chunk_body_size == 0) /* Final chunk */ request_parse_chunk_trlr_init(request); else request->chunk_state = CHUNK_BODY; break; case CHUNK_BODY: if (!request_parse_chunk_body(request)) return (NIL); request_parse_chunk_hdr_init(request); break; case CHUNK_TRAILER: if (!request_parse_chunk_trlr(request)) return (NIL); request->chunk_state = CHUNK_COMPLETE; break; case CHUNK_COMPLETE: break; } } return (T); } /* ====================================================================== */ /* request_parse() ***************************************************** * * Read in and parse entire HTTP request. Decodes silly chunk encodings. * request: Current HTTP request (may be partly read in and parsed!) * config: Prayer Configuration (used for size limits). * * Returns: T => Entire HTTP chunk body section read sucessfully. * NIL => End of file ***********************************************************************/ BOOL request_parse(struct request * request) { while (request->state != REQUEST_COMPLETE) { switch (request->state) { case REQUEST_METHOD: if (!request_parse_method(request)) return (NIL); if (request->major == 0) { request->state = REQUEST_COMPLETE; break; } request_parse_headers_init(request); break; case REQUEST_HDRS: if (!request_parse_headers(request)) return (NIL); if (!request_parse_body_init(request)) return (NIL); break; case REQUEST_BODY_SIMPLE: if (!request_parse_body_simple(request)) return (NIL); request->state = REQUEST_COMPLETE; break; case REQUEST_BODY_CHUNKED: if (!request_parse_body_chunked(request)) return (NIL); request->state = REQUEST_COMPLETE; break; case REQUEST_COMPLETE: break; } } request->state = REQUEST_COMPLETE; return (T); } /* ====================================================================== */ /* request_complete() *************************************************** * * Test whether HTTP request has been read in completely * * Returns: T => Request complete * NIL => Otherwise ***********************************************************************/ BOOL request_complete(struct request * request) { return ((request->state == REQUEST_COMPLETE)); } /* ====================================================================== */ /* request_parse_form_multipart() *************************************** * * Decode a file upload request (static support routine) * request: Complete HTTP request * boundary0: Boundary line to look form * data0: Pointer to data to be decoded * len: Length of data to be decoded * start0: Returns ptr to start of attachment witin data0 * end0: REturns ptr end of attachment within data0 ***********************************************************************/ static void request_parse_form_multipart(char *boundary0, char *data0, unsigned long len, char **start0, char **end0) { unsigned char *boundary = (unsigned char *) boundary0; unsigned char *data = (unsigned char *) data0; unsigned char **start = (unsigned char **) start0; unsigned char **end = (unsigned char **) end0; unsigned char *s; unsigned long blen = strlen((char *) boundary); *start = *end = s = data; /* Find first boundary line */ while (len >= (blen + 2)) { if ((s[0] == '-') && (s[1] == '-') && !strncmp((char *) &s[2], (char *) boundary, blen) && ((s[blen + 2] == '\012') || (s[blen + 2] == '\015'))) { if ((len >= (blen + 3)) && (s[blen + 2] == '\015') && (s[blen + 3] == '\012')) { s += blen + 4; len -= blen + 4; } else { s += blen + 3; len -= blen + 3; } *start = s; break; } s++; len--; } /* Find second boundary line */ while (len > (blen + 4)) { if ((s[0] == '-') && (s[1] == '-') && !strncmp((char *) &s[2], (char *) boundary, blen) && (s[blen + 2] == '-') && (s[blen + 3] == '-') && ((s[blen + 4] == '\012') || (s[blen + 4] == '\015'))) break; s++; len--; } /* Remove trailing CRLF, CR or LF */ if ((s >= (*start) + 2) && (s[-2] == '\015') && (s[-1] == '\012')) s -= 2; else if ((s >= (*start) + 1) && ((s[-1] == '\015') || (s[-1] == '\012'))) s--; *end = s; } /* ====================================================================== */ /* request_parse_form_multipart_hdrs() ********************************** * * Decode MIME headers from file upload request * hdrs: Associative array that should contain decoded headers * datap: Data to be decoded. Returns ptr to first line after hdrs * * Returns: T => sucessful. NIL => error decoding headers. ***********************************************************************/ static BOOL request_parse_form_multipart_hdrs(struct assoc *hdrs, char **datap) { char *s, *header, *key, *value, *oldvalue; if (!datap) return (NIL); while ((header = string_get_lws_line((char **) datap, T))) { /* Reached end of the block yet? */ if (header[0] == '\0') break; if (!hdrs) continue; if (!((key = string_get_token(&header)) && ((value = string_next_token(&header))))) { continue; } /* Convert string to lower case */ for (s = key; *s; s++) *s = tolower(*s); if ((s == key) || (s[-1] != ':')) { continue; } s[-1] = '\0'; if ((oldvalue = assoc_lookup(hdrs, key))) { s = pool_alloc(hdrs->pool, strlen(value) + strlen(oldvalue) + 3); strcpy(s, oldvalue); /* Should be able to improve this */ strcat(s, ", "); strcat(s, value); value = s; } /* Generate assoc entry. Don't need to copy key and value */ assoc_update(hdrs, key, value, NIL); } return (T); } /* ======================================================================*/ /* request_parse_form_multipart() *************************************** * * Decode RFC 1867 file upload request into MIME headers and body * request: Entire HTTP request to decode * hdrs: Target assoc array for MIME headers * startp: Returns ptr to start of upload body * endp: Returns ptr to end of upload body * * Returns: T => sucessful. NIL => error decoding headers. ***********************************************************************/ BOOL request_decode_post_multipart(struct request * request, struct assoc * hdrs, char **startp, char **endp) { char *ps, *ct, *s, *boundary; if (!((ct = assoc_lookup(request->hdrs, "content-type")) && ((s = string_get_token(&ct))) && !strcasecmp(s, "multipart/form-data;") && ((s = string_next_token(&ct))) && !strncasecmp(s, "boundary=", strlen("boundary=")) && (boundary = (s + strlen("boundary="))))) return (NIL); if (request->chunked) { /* Chunked message body has already been decoded */ unsigned long size = buffer_size(request->chunked); if (size == 0) return (NIL); /* Fetch linear copy of buffer */ ps = buffer_fetch(request->chunked, 0, size, request->preserve); } else { /* Get data from normal message buffer */ if (request->body_size == 0) return (NIL); /* Fetch linear copy of buffer */ ps = buffer_fetch(request->read_buffer, request->body_offset, request->body_size, request->preserve); } request_parse_form_multipart(boundary, ps, request->body_size, startp, endp); request_parse_form_multipart_hdrs(hdrs, startp); return (T); } /* ====================================================================== */ /* request_parse_form_string() ****************************************** * * Convert HTTP form entry (from GET or POST request) into associative * array. * pool: Target pool * post: String to parse * * Returns: Assocative array ***********************************************************************/ static struct assoc *request_parse_form_string(struct pool *pool, char *post) { struct assoc *h = assoc_create(pool, 16, T); char *key = post; char *value; char *s; /* Skip over any leading noise */ while (*post && (string_isspace(*post) || string_iseol(*post))) post++; /* XXX 09/04/2006 * * Following isn't quite correct in fact of invalid input "a&b=c". * End up with h{"a&b"} = "c" rather than h{"a"} = "", h{"b"} = "c". * * Doesn't appear to be doing any harm (really just GIGO), but we * should come back and fix this when we have time to test properly */ while (*post) { key = string_url_decode_component(&post, '='); if (*key) { /* Discard image map submit nonsense */ if ((s = strchr(key, '.'))) *s = '\0'; value = string_url_decode_component(&post, '&'); /* Only if we found '=' */ assoc_update(h, key, value, NIL); /* Replace, not update */ } } return (h); } /* ====================================================================== */ /* request_decode_get() ************************************************* * * Decode a GET form * request: Complete HTTP request * ***********************************************************************/ static void request_decode_get(struct request *request) { if (!request->get_suffix) return; request->form = request_parse_form_string(request->pool, request->get_suffix); } /* ====================================================================== */ /* Covert single section of multipart/formdata into key value pair */ static BOOL request_parse_formdata_single(struct pool *pool, struct assoc *result, char *data) { struct assoc *hdrs = assoc_create(pool, 16, T); char *s, *key, *encoding, *type, *charset; unsigned long decode_len = 0; if (!request_parse_form_multipart_hdrs(hdrs, &data)) return(NIL); if (!(encoding = assoc_lookup(hdrs, "content-transfer-encoding"))) encoding = ""; s = assoc_lookup(hdrs, "content-disposition"); if (!(s && !strncasecmp(s, "form-data", strlen("form-data")))) return(NIL); s += strlen("form-data"); s = string_ustr(s, "name="); if (!s) return(NIL); s += strlen("name="); if (!(key = string_get_value(&s))) return(NIL); /* Discard image map submit nonsense */ if ((s = strchr(key, '.'))) *s = '\0'; /* Strip off BASE64/QPRINT encoding. */ if (!strcasecmp(encoding, "BASE64")) { data = (char *) string_base64_decode((unsigned char *)data, strlen(data), &decode_len); } else if (!strcasecmp(encoding, "QUOTED-PRINTABLE")) { data = (char *) string_qprint_decode((unsigned char *)data, strlen(data), &decode_len); } if (!data) return(NIL); /* Convert to UTF-8 if not */ if (!(type = assoc_lookup(hdrs, "content-type"))) type = ""; charset = NIL; if ((s = string_ustr(type, "charset="))) { s += strlen("charset="); charset = string_get_value(&s); } if (charset && (strcasecmp(charset, "UTF-8") != 0)) { if (decode_len == 0) decode_len = strlen(data); data = utf8_from_string(pool, charset, data, decode_len); } assoc_update(result, key, data, NIL); return(T); } /* Split multipart/form-data into sections and parse one at a time */ static struct assoc * request_parse_formdata(struct pool *pool, char *boundary, char *data, unsigned long len) { struct assoc *h = assoc_create(pool, 16, T); unsigned long blen = strlen(boundary); char *start; char *end; char *s = data; BOOL last_part = NIL; /* Find and then skip the first boundary line */ while (*s) { if ((s[0] == '-') && (s[1] == '-') && !strncmp((char *) &s[2], (char *) boundary, blen) && ((s[blen + 2] == '\012') || (s[blen + 2] == '\015'))) { s += blen + 2; s += (s[0] == '\015' && s[1] == '\012') ? 2 : 1; break; } string_next_line(&s); } start = s; while (*s && !last_part) { /* Find next boundary line */ while (*s) { if ((s[0] == '-') && (s[1] == '-') && !strncmp((char *) &s[2], (char *) boundary, blen) && strchr("\015\012-", *s)) { break; } string_next_line(&s); } /* Record end of the preceding block. Remove trailing CRLF, CR or LF */ if ((s >= (start+2)) && (s[-2] == '\015') && (s[-1] == '\012')) end = s - 2; else if ((s >= (start+1)) && ((s[-1] == '\015') || (s[-1] == '\012'))) end = s - 1; else end = s; /* Process start ... end block */ *end = '\0'; request_parse_formdata_single(pool, h, start); /* Skip the boundary line. -- at the end indicates last block */ s += blen + 2; if (s[0] == '-' && s[1] == '-') { last_part = T; s += 2; } s += (s[0] == '\015' && s[1] == '\012') ? 2 : 1; start = s; } return(h); } /* request_decode_post() ************************************************ * * Decode a POST form * request: Complete HTTP request * ***********************************************************************/ static void request_decode_post(struct request *request) { char *ps, *ct, *s, *boundary = NIL; BOOL formdata = NIL; if (((ct = assoc_lookup(request->hdrs, "content-type")) && ((s = string_get_token(&ct))) && !strcasecmp(s, "multipart/form-data;") && ((s = string_next_token(&ct))) && !strncasecmp(s, "boundary=", strlen("boundary=")) && (boundary = (s + strlen("boundary="))))) formdata = T; if (request->chunked) { /* Chunked message body has already been decoded */ unsigned long size = buffer_size(request->chunked); if (size == 0) return; /* Fetch linear copy of buffer */ ps = buffer_fetch(request->chunked, 0, size, request->preserve); } else { /* Get data from normal message buffer */ if (request->body_size == 0) return; /* Fetch linear copy of buffer */ ps = buffer_fetch(request->read_buffer, request->body_offset, request->body_size, request->preserve); } /* NB: ps will get trashed by form parsing */ if (formdata) { request->form = request_parse_formdata(request->pool, boundary, ps, request->body_size); } else{ request->form = request_parse_form_string(request->pool, ps); } } /* ====================================================================== */ /* request_decode_form() ************************************************ * * Decode any kind of form * request: Complete HTTP request * ***********************************************************************/ void request_decode_form(struct request *request) { if (request->method == POST) request_decode_post(request); else request_decode_get(request); } /* ====================================================================== */ /* request_parse_argv() ************************************************* * * Break request->url_path into its component parts. * request: Entire HTTP request to decode * ***********************************************************************/ void request_parse_argv(struct request *request) { char *s; char *t; int i; /* Copy that we can trash */ s = pool_strdup(request->pool, request->url_path); if ((*s == '\0') || !strcmp(s, "/")) { /* Empty URL is special case */ request->argc = 0; request->argv = pool_alloc(request->pool, sizeof(char *)); request->argv[0] = NIL; return; } /* Skip leading '/' if present */ if (*s == '/') s++; /* First count the number of '/' characters in the url-path */ for (request->argc = 1, t = s; *t; t++) { if (*t == '?') break; if ((*t == '/') || (*t == '@')) request->argc++; } request->argv = pool_alloc(request->pool, (1 + request->argc) * sizeof(char *)); /* We know where the first argv elt starts */ request->argv[0] = s; i = 0; t = s; while (*t) { if ((*t == '/') || (*t == '@')) { *t++ = '\0'; /* Tie off previous string */ request->argv[++i] = t; /* Found start of next argv elt */ continue; } if (*t == '?') { *t++ = '\0'; /* Tie off previous string */ request->get_suffix = t; /* Record get location */ break; } t++; } request->argv[request->argc] = NIL; /* Tie off the array */ } /* ======================================================================*/ /* request_parse_charset() ********************************************** * * Parse "Accept-Charset:" header: decide whether to send UTF-8. * request: Decoded HTTP request * ***********************************************************************/ void request_parse_charset(struct request *request) { char *s, *t, *u; if (!(s = assoc_lookup(request->hdrs, "accept-charset"))) return; s = pool_strdup(request->pool, s); /* Need scratch version */ while (s) { t = strchr(s, ','); if (t) *t++ = '\0'; if ((u = strchr(s, ';'))) *u = '\0'; s = string_trim_whitespace(s); if (!strcasecmp(s, "utf-8")) { request->use_utf8 = T; break; } s = t; } } /* ======================================================================*/ /* request_parse_encoding() ********************************************** * * Parse "Accept-Content-Encoding:" header: determine whether client * accepts gzip or x-gzip. * ***********************************************************************/ void request_parse_encoding(struct request *request) { char *s, *t, *u; if (!(s = assoc_lookup(request->hdrs, "accept-encoding"))) return; s = pool_strdup(request->pool, s); /* Need scratch version */ request->allow_gzip = T; request->use_gzip = NIL; request->use_x_gzip = NIL; while (s) { t = strchr(s, ','); if (t) *t++ = '\0'; if ((u = strchr(s, ';'))) *u = '\0'; s = string_trim_whitespace(s); if (!strcasecmp(s, "gzip")) { request->use_gzip = T; break; } if (!strcasecmp(s, "x-gzip")) { request->use_x_gzip = T; break; } s = t; } } /* ======================================================================*/ /* request_test_referer() *********************************************** * * Check that "Referer:" header contains given hostname if it exists. * ***********************************************************************/ int request_test_referer(struct request *request, char *hostname) { char *ref = assoc_lookup(request->hdrs, "referer"); int len; if (!(ref && ref[0] && hostname && hostname[0])) return(T); while (Uisspace(*ref)) ref++; if (!strncasecmp(ref, "https://", 8)) ref += 8; else if (!strncasecmp(ref, "http://", 7)) ref += 7; len = strlen(hostname); if ((len > 0) && !strncasecmp(ref, hostname, len) && (ref[len] == '/' || ref[len] == '\\' || ref[len] == ':' || ref[len] == '\0')) return(T); return(NIL); } ./prayer-1.3.5/shared/html_common.c0000644006513000651300000000632111063701636015524 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/html_common.c,v 1.4 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "shared.h" /* Set of routines for generating chunks of HTML markup. */ /* html_common_start() *************************************************** * * HTML header ************************************************************************/ void html_common_start(struct config *config, struct buffer *b, char *title) { struct config_theme *theme = config->theme_main; bputs(b, (""CRLF)); bputs(b, (""CRLF)); bputs(b, ""CRLF); bprintf(b, "Webmail service: %s" CRLF, title); bputs(b, "" CRLF); bputs(b, ("" CRLF)); bprintf(b, (""CRLF), theme->name); bputs(b, "" CRLF); bputs(b, ""CRLF); } /* html_common_end() ***************************************************** * * End of HTML body ************************************************************************/ void html_common_end(struct buffer *b) { bprintf(b, "" CRLF); } /* ====================================================================== */ /* html_common_quote_char() ********************************************* * * Print character replacing significant HTML characters with eqivalent * escape sequences. * translation stuff. * b: Buffer * c: Character to print ***********************************************************************/ static void html_common_quote_char(struct buffer *b, unsigned char c) { if (c > 127) { bprintf(b, "&#%lu;", (unsigned long) c); } else switch (c) { case ' ': bputs(b, " "); break; case '"': bputs(b, """); break; case '&': bputs(b, "&"); break; case '<': bputs(b, "<"); break; case '>': bputs(b, ">"); break; default: bputc(b, c); } } /* html_common_quote() *************************************************** * * Print string replacing significant HTML characters with eqivalent * escape sequences. * translation stuff. * b: Buffer * t: String to print ***********************************************************************/ void html_common_quote_string(struct buffer *b, char *t) { unsigned char *s = (unsigned char *) t; unsigned char c; if (!s) bputs(b, "(nil)"); else while ((c = *s++)) html_common_quote_char(b, c); } ./prayer-1.3.5/shared/html_common.h0000644006513000651300000000107311063701636015530 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/shared/html_common.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ void html_common_start(struct config *config, struct buffer *b, char *title); void html_common_end(struct buffer *b); void html_common_quote_string(struct buffer *b, char *t); ./prayer-1.3.5/utils/0000755006513000651300000000000011775262603012742 5ustar dpc22dpc22./prayer-1.3.5/utils/ssl_prune_main.c0000644006513000651300000001020011063701650016103 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/utils/ssl_prune_main.c,v 1.3 2008/09/16 10:00:08 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" int main(int argc, char *argv[]) { char *ports = NIL; char *config_filename = PRAYER_CONFIG_FILE; struct config *config = config_create(); int i; extern char **environ; struct ssl_config ssl_config; /* Disable supplementary groups, look for (temporary) unprivileged group */ if (getuid() == 0) { struct group *group; setgroups(0, NIL); if ((group = getgrnam("other")) != NIL) setgid(group->gr_gid); else if ((group = getgrnam("nobody")) != NIL) setgid(group->gr_gid); } if (getenv("PRAYER_CONFIG_FILE")) config_filename = getenv("PRAYER_CONFIG_FILE"); initsetproctitle("prayer", argc, argv, environ); os_signal_init(); response_record_version(VERSION_PRAYER); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--help")) { fprintf(stderr, "Options:\n"); fprintf(stderr, (" --config-file: Define prayer config file\n")); fprintf(stderr, (" " "(Overrides compilation default and PRAYER_CONFIG_FILE)\n")); fprintf(stderr, (" --config-option: Override single configuration option\n")); fprintf(stderr, "\n"); fprintf(stderr, (" --help: Show this list of options\n")); fprintf(stderr, (" --: " "End of prayer options: remaining options will be passed\n")); fprintf(stderr, (" to prayer-session server process\n")); exit(0); } else if (!strncmp(argv[i], "--config-file=", strlen("--config-file="))) { config_filename = strdup(argv[i] + strlen("--config-file=")); } else if (!strcmp(argv[i], "--config-option")) { i++; /* Processes next argv */ } else if (!strncmp(argv[i], "--ports=", strlen("--ports="))) { ports = argv[i] + strlen("--ports="); } else if (!strcmp(argv[i], "--")) { continue; } else { fprintf(stderr, "Unknown option: %s\n", argv[i]); exit(1); } } config = config_create(); if (!config_parse_file(config, config_filename)) exit(1); /* prayer-ssl-prune doesn't care about hostname */ if (config->hostname && !strcmp(config->hostname, "__UNDEFINED__")) config->hostname = "undefined"; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--config-option")) { if (++i < argc) { if (!config_parse_option(config, strdup(argv[i]))) exit(1); } else fprintf(stderr, "--config processes following option"); } } if (!config_check(config)) exit(1); if (!config_expand(config)) exit(1); /* Generate a clean copy of the configuration without all of the noise */ { struct config *config_clean = config_clone_parsed(config); config_free(config); config = config_clean; } /* Don't need root privs any more */ if (getuid() == 0) { if ((config->prayer_uid == 0) || (config->prayer_uid == 0)) log_fatal("Configured to run as root!"); if (config->prayer_gid) setgid(config->prayer_gid); if (config->prayer_uid) setuid(config->prayer_uid); } if (getuid() == 0) log_fatal("Configured to run as root!"); config_mkdirs(config); log_misc_init(config, argv[0], "prayer"); config_extract_ssl(config, &ssl_config); ssl_prune_sessions(&ssl_config); /* NOTREACHED */ return (0); } ./prayer-1.3.5/utils/prayer-cyclog.SRC0000644006513000651300000000276311063701650016071 0ustar dpc22dpc22#! /bin/sh # $Cambridge: hermes/src/prayer/utils/prayer-cyclog.SRC,v 1.3 2008/09/16 10:00:08 dpc22 Exp $ suffix=gz # Following is correct for Linux. compress="/bin/gzip" chown="/bin/chown" chgrp="/bin/chgrp" mv="/bin/mv" rm="/bin/rm" cycle_log () { dir=$1 user=$2 group=$3 log=$4 keep=$5 file=$dir/$log if [ $keep -lt 10 ]; then keept=0$keep; else keept=$keep; fi; if [ -f $file.$keept ]; then $rm $file.$keept; fi; if [ -f $file.$keept.$suffix ]; then $rm $file.$keept.$suffix; fi; while [ $keep -gt 1 ]; do old=`expr $keep - 1` if [ $old -lt 10 ]; then oldt=0$old; else oldt=$old; fi; if [ -f $file.$oldt ]; then $mv $file.$oldt $file.$keept $compress $file.$keept $chown $user $file.$keept.$suffix $chgrp $group $file.$keept.$suffix elif [ -f $file.$oldt.$suffix ]; then $mv $file.$oldt.$suffix $file.$keept.$suffix $chown $user $file.$keept.$suffix $chgrp $group $file.$keept.$suffix fi keep=$old keept=$oldt done if [ -f $file ]; then $mv $file $file.01 $chown $user $file.01 $chgrp $group $file.01 fi } cycle_log "__VAR_PREFIX__/logs" "prayer" "prayer" "access_log" 28 cycle_log "__VAR_PREFIX__/logs" "prayer" "prayer" "session_log" 28 cycle_log "__VAR_PREFIX__/logs" "prayer" "prayer" "prayer" 28 cycle_log "__VAR_PREFIX__/logs" "prayer" "prayer" "prayer_session" 28 ./prayer-1.3.5/utils/prayer-sem-prune.c0000644006513000651300000000253611063701650016315 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/utils/prayer-sem-prune.c,v 1.3 2008/09/16 10:00:08 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2004 */ /* See the file NOTICE for conditions of use and distribution. */ #include "shared.h" #ifdef MUTEX_SEMAPHORE #include #include #ifndef __USE_GNU #define __USE_GNU /* Evil hack to get prototype for semtimedop */ #include #undef __USE_GNU #endif union semun { int val; struct semid_ds *buf; ushort *array; }; static int isinteger(char *s) { if ((s == NULL) || (*s == '\0')) return(0); while (*s) { if (!isdigit(*s)) return(0); s++; } return(1); } int main(int argc, char *argv[]) { union semun ick; int sem_id; int i; if (argc < 2) { fprintf(stderr, "Arg: semaphore id (see ipcs -s)\n"); exit(1); } for (i = 1 ; i < argc ; i++) { if (!isinteger(argv[i])) continue; sem_id = atoi(argv[i]); printf("Removing %d\n", sem_id); ick.val = 0; semctl(sem_id, 0, IPC_RMID, ick); } exit(0); } #else int main(int argc, char *argv[]) { exit(0); } #endif ./prayer-1.3.5/utils/Makefile0000644006513000651300000000547111160500433014371 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/utils/Makefile,v 1.9 2009/03/19 17:30:03 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2008 # See the file NOTICE for conditions of use and distribution. ifeq ($(strip $(RPM_BUILD)), true) include ../Config-RPM else include ../Config endif BASECFLAGS += -I../lib -I../shared -I../session # Default list of things to build BIN = prayer-ssl-prune prayer-cyclog prayer-sem-prune # Enable SYSV mutex ifeq ($(strip $(MUTEX_SEMAPHORE)), true) MUTEX_DEF = -DMUTEX_SEMAPHORE endif # Enable Electric Fence ifeq ($(strip $(FENCE_ENABLE)), true) BASECFLAGS += $(FENCE_INCLUDE) BASE_LIBS += $(FENCE_LIBS) endif # Enable on the fly compression ifeq ($(strip $(GZIP_ENABLE)), true) BASE_LIBS += $(Z_LIBS) endif # Add PAM if backend needs pam ifeq ($(strip $(CCLIENT_PAM_ENABLE)), true) BASECFLAGS += $(PAM_INCLUDE) endif # Add Kerberos if backend needs Kerberos ifeq ($(strip $(CCLIENT_KERB_ENABLE)), true) BASECFLAGS += $(KERB_INCLUDE) endif ifeq ($(strip $(ACCOUNTD_ENABLE)), true) ifeq ($(strip $(ACCOUNTD_USE_BSD_PTY)), true) BASE_LIBS += -lutil endif endif MYCFLAGS = $(BASECFLAGS) $(SSL_INCLUDE) $(CCLIENT_INCLUDE) MYLDFLAGS = $(BASELDFLAGS) PRUNE_OBJS = ssl_prune_main.o ../shared/shared.a PRUNE_LIBS = $(BASE_LIBS) ifeq ($(strip $(SSL_ENABLE)), true) PRUNE_OBJS += ../lib/lib_withssl.a PRUNE_LIBS += $(SSL_LIBS) ifeq ($(strip $(SESSION_CACHE_ENABLE)), true) # Berkeley DB required for SSL session cache. PRUNE_LIBS += $(DB_LIBS) endif else PRUNE_OBJS += ../lib/lib_nossl.a endif ######################################################################### all: $(BIN) clean: -rm -f $(BIN) core *.o *.flc *~ \#*\# install: all $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_DIR) -d \ $(BROOT)$(BIN_DIR) $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_EXEC) \ prayer-ssl-prune $(BROOT)$(BIN_DIR) $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_EXEC) \ prayer-sem-prune $(BROOT)$(BIN_DIR) $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_EXEC) \ prayer-db-prune $(BROOT)$(BIN_DIR) $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_EXEC) \ prayer-cyclog $(BROOT)$(BIN_DIR) prayer-ssl-prune: $(PRUNE_OBJS) $(CC) $(MYLDFLAGS) -o prayer-ssl-prune $(PRUNE_OBJS) $(PRUNE_LIBS) prayer-cyclog: prayer-cyclog.SRC perl -pe "s&__PREFIX__&${PREFIX}&; s&__VAR_PREFIX__&${VAR_PREFIX}&; s&__BIN_DIR__&${BIN_DIR}&;" < prayer-cyclog.SRC > prayer-cyclog ssl_prune_main.o: ssl_prune_main.c Makefile $(CC) $(MYCFLAGS) -c \ -DPRAYER_CONFIG_FILE=\"$(PRAYER_CONFIG_FILE)\" $< prayer-sem-prune: prayer-sem-prune.o $(CC) $(MYLDFLAGS) -o prayer-sem-prune prayer-sem-prune.o prayer-sem-prune.o: prayer-sem-prune.c $(CC) $(MYCFLAGS) $(MUTEX_DEF) -c $< # Default build rule %.o: %.c Makefile $(CC) $(MYCFLAGS) -c $< ./prayer-1.3.5/utils/prayer-db-prune0000644006513000651300000000072111063701650015667 0ustar dpc22dpc22#!/bin/sh -e # # $Cambridge: hermes/src/prayer/utils/prayer-db-prune,v 1.3 2008/09/16 10:00:08 dpc22 Exp $ # # Script to clear out obsolete Berkeley DB tranaction log files from the # Prayer SSL session cache. Based on work and research by Mike Brudenell # DB_BIN=/opt/db4/bin SSL_CACHE=/var/spool/prayer/ssl_scache PATH=${DB_BIN}:$PATH cd ${SSL_CACHE} db_checkpoint -h ${SSL_CACHE} -1 for i in `db_archive -h ${SSL_CACHE} -a` do rm $i done ./prayer-1.3.5/utils/ucsnews.pl0000755006513000651300000000350711063701650014764 0ustar dpc22dpc22#!/usr/bin/perl -w # # $Cambridge: hermes/src/prayer/utils/ucsnews.pl,v 1.2 2008/09/16 10:00:08 dpc22 Exp $ # # Small utility for dumping start of UCS news feed as suitable HTML use strict; use XML::RSS; use HTML::Entities; use LWP::Simple; # Declare variables my $content; my $url = "http://ucsnews.csx.cam.ac.uk/xml/rss20/feed.xml"; my $total = 6; # create new instance of XML::RSS my $rss = new XML::RSS; $content = get($url); die "Could not retrieve $url" unless $content; # parse the RSS content $rss->parse($content); print <
[rss feed] University Computing Service news
HTML # print the channel items my $count = 0; foreach my $item (@{$rss->{'items'}}) { next unless defined($item->{'title'}); next unless defined($item->{'link'}); next unless defined($item->{'pubDate'}); my $pubdate = $item->{'pubDate'}; # "Wed, 03 Sep 2008 15:55:00 +0100" -> "03 Sep 2008" $pubdate = $1 if ($pubdate =~ /^\w\w\w, (\d\d \w\w\w \d\d\d\d) \d\d:\d\d:\d\d \+0\d00$/); my $link = $item->{'link'}; my $title_html = HTML::Entities::encode($item->{'title'}); my $date_html = HTML::Entities::encode($pubdate); print <<"HTML";

${date_html}

${title_html}

HTML last if ((++$count) >= $total); } print < See also all Computing Service news
HTML ./prayer-1.3.5/utils/.cvsignore0000644006513000651300000000021311063701650014724 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/utils/.cvsignore,v 1.3 2008/09/16 10:00:08 dpc22 Exp $ # prayer-cyclog prayer-sem-prune prayer-ssl-prune y ./prayer-1.3.5/session/0000755006513000651300000000000011775262602013264 5ustar dpc22dpc22./prayer-1.3.5/session/favourite.h0000644006513000651300000000236711063701636015444 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/favourite.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* List of favourite mail folders */ struct favourite_list { struct list *list; /* List of favourits */ char *preferred; /* Name of preferred favourite */ }; struct favourite_list *favourite_list_create(void); void favourite_list_free(struct favourite_list *fl); void favourite_preferred(struct favourite_list *fl, char *preferred); BOOL favourite_add(struct favourite_list *fl, char *name); BOOL favourite_delete(struct favourite_list *fl, char *name); BOOL favourite_rename(struct favourite_list *fl, char *oldname, char *newname); void favourite_parse_line(struct favourite_list *fl, char *line, struct session *session); void favourite_print_options(struct favourite_list *fl, struct buffer *b); void favourite_template_vals(struct favourite_list *fl, struct template_vals *tvals, char *array); ./prayer-1.3.5/session/checksum.c0000644006513000651300000000571611063701636015236 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/checksum.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Little snippet of code to calculate file checksum and compare with * current value. Rather strange little checksum routine: just happens * to be compatible with what we are using at the moment... */ #include "prayer_session.h" /* checksum_hash_line() ************************************************** * * Convert single line of input into checksum value * line: Line to checksum * maxlen: Maximum length to checksum * [shouldn't be an ************************************************************************/ static int checksum_hash_line(char *line) { unsigned int total = 0; unsigned int i; char *p; for (i = 0, p = line; *p != '\0' && *p != '\n'; p++, i++) { total += (((unsigned int) *p) * (i + 1)); } return (total % 65536); } /* checksum_test() ******************************************************** * * Calculate checksum value for a string. * string: String to checksum * pool: Scratch pool * existing: Existing checksum * current: Calculated checksum * * Returns: T => Found existing checksum line *************************************************************************/ BOOL checksum_test(char *string, struct pool *pool) { char *checkstring = CHECKSUM_PREFIX; unsigned long checklen = strlen(checkstring); unsigned long file_checksum = 0; unsigned long checksum = 0; int rc = NIL; char *line, *p; string = pool_strdup(pool, string); while ((line=string_get_line(&string))) { if (line[0] != '#') { checksum += checksum_hash_line(line); checksum %= (1024 * 1024); /* Cap values to < 10^6 */ continue; } if (strncmp(line, checkstring, checklen) != 0) continue; p = line + strlen(checkstring); while (*p != '\0' && !Uisdigit(*p)) p++; file_checksum = atoi(p); rc = T; } return((rc && (checksum == file_checksum)) ? T : NIL); } /* checksum_calculate() **************************************************** * * Input: * string: string to checksum * pool: scratch pool * * Returns: * Checksum value. *************************************************************************/ unsigned long checksum_calculate(char *string, struct pool *pool) { char *line; unsigned long checksum = 0; string = pool_strdup(pool, string); while ((line=string_get_line(&string))) { if (line[0] == '#') continue; checksum += checksum_hash_line(line); checksum %= (1024 * 1024); /* Cap values to < 10^6 */ } return (checksum); } ./prayer-1.3.5/session/html_secure.c0000644006513000651300000004620511413152053015734 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/html_secure.c,v 1.11 2010/07/01 17:45:15 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* text/HTML model implemented by sqwebmail. * * Browser Security - HTML * * SqWebMail has the ability to display HTML E-mail, which leads to * several complicated situations regarding embedded Javascript or Java * applets that try to grab the mailboxid of the recipient (amongst other * things). SqWebMail attempts to remove all forms of scripting from HTML * E-mail as follows: * * The following HTML tags are removed: , , * , , , , , , * , , , , , , , * , , , , , , . * * The following HTML attributes are stripped from every tag: * ONLOAD=, ONMOUSEOVER=, and all ON*= attributes; TARGET=, CODE=, * CODETYPE=, and LANGUAGE= are removed; TARGET=_blank is added to * all tags. * * The HREF and SRC attributes are stripped, unless the URL starts * with one of the following: http:, https:, ftp:, gopher:, wais:, or * telnet, and cid:. * * The HREF and SRC attribute values are prefixed with a URL that * will resolve to SqWebMail, and with an additional TARGET="_blank" * attribute. A request to that resulting URL will result in a blank * page with a 0-second refresh to the original URL. This method * strips mailbox IDs from Referer: tags sent to external web site. * If the HREF attribute starts with a cid:, it is replaced by an * http: reference to SqWebMail that will return the specified MIME * part. * * IMG tags are removed and replaced with an A tag, in order to keep * the HTTP client from automatically loading any images from * external web sites, upon opening a given message. */ /* Additional notes for Prayer implementation * o We allow IMG tags, but the SRC argument is a /redirect to prevent * "Referrer:" attacks * * o No attempt to interpret multibyte characters sequences which some * browsers may recognise as alternatives for '<' etc in some character * sets. We rely on the fact that Prayer should always do 8 bit -> 7 bit * plus entity convertion when generating HTML pages, and will always * set a Charset. * * o Like IMP we replace tags with . This way the browser * should quitely ignore the noise inside a tag that we want to kill. */ #define MATCH(string, tag) ((strcasecmp(string, tag)) ? NIL : T) #define NMATCH(string, tag) ((strncasecmp(string, tag, strlen(tag))) ? NIL : T) /* ====================================================================== */ /* Static support routines */ static BOOL html_isspace(char c) { return ((c == ' ') || (c == '\t') || (c == '\015') || (c == '\012')); } static char *html_get_token(char **sp) { char *s = *sp, *result; if (!(s && *s)) return (NIL); while (html_isspace(*s)) s++; /* Do we need to strip out comments at token level? */ /* Record position of this token */ result = s; /* Find next whitespace character or end of string */ while ((*s) && !html_isspace(*s) && (*s != '"') && (*s != '\'')) s++; if (*s == '"') { s++; while ((*s) && (*s != '"')) s++; if (*s == '"') s++; } else if (*s == '\'') { s++; while ((*s) && (*s != '\'')) s++; if (*s == '\'') s++; } /* Tie off the string unless \0 already reached */ if (*s) { *s++ = '\0'; while (html_isspace(*s)) s++; } /* Record position of first non-whitespace character for next caller */ *sp = s; if (result[0] == '\0') return (NIL); return (result); } /* Foul piece of code to strip out the following character entities from * the HTML text: < > & " &#; and &#X; * * Can update in place as result will always be smaller than source */ static void my_strip_entities(char *src) { char *dst = src; if (!strchr(src, '&')) return; while (*src) { if (*src != '&') { *dst++ = *src++; /* Optimise the comment case */ continue; } if (!strncasecmp(src, "<", 4)) { src += 4; *dst++ = '<'; continue; } if (!strncasecmp(src, ">", 4)) { src += 4; *dst++ = '>'; continue; } if (!strncasecmp(src, "&", 5)) { src += 5; *dst++ = '&'; continue; } if (!strncasecmp(src, """, 6)) { src += 6; *dst++ = '"'; continue; } if (src[1] == '#') { char *t = src+2; unsigned long value; if (((*t == 'x') || (*t == 'X')) && Uisxdigit(t[1])) { t += 2; while (Uisxdigit(*t)) /* Decode &#X; */ t++; if (*t == ';') { value = strtoul(src+3, NIL, 16); if ((value > 0) && (value < 256)) { *dst++ = (char)value; src = t+1; continue; } } } else if (Uisdigit(*t)) { while (Uisdigit(*t)) /* Decode &#; */ t++; if (*t == ';') { value = strtoul(src+2, NIL, 10); if ((value > 0) && (value < 256)) { *dst++ = (char)value; src = t+1; continue; } } } } *dst++ = *src++; /* Failed to decode entity: just pass it through */ } *dst = '\0'; } /* ====================================================================== */ /* html_secure_old() ***************************************************** * * Generate "secure" version of HTML input, with dangerous tags stripped. * b: Output buffer * input: Input string. ************************************************************************/ static void html_secure_old(struct session *session, struct buffer *b, BOOL show_images, char *input) { struct options *options = session->options; struct prefs *prefs = options->prefs; char *s = input; char *tag, *token; char c; BOOL endtag, strip_tag; while (1) { /* Copy verbatim until we find a tag (Removes unmatched '>' chars: * apparently some browsers try to fix broken HTML by inferring missing * '<' characters. Yuck! */ while ((c = *s++) && (c != '<')) { if (c != '>') bputc(b, c); } if (c == '\0') break; /* Strip comments entirely to avoid problems with tags within comments */ if (!strncmp(s, "!--", strlen("!--"))) { s += strlen("!--"); while ((c = *s)) { if ((c == '-') && !strncmp(s, "-->", strlen("-->"))) { s += strlen("-->"); break; } s++; } continue; } /* Isolate tag */ tag = s; while ((c = *s) && (c != '>')) s++; if (c == '\0') break; *s++ = '\0'; if (!(token = html_get_token(&tag))) { /* Empty tag: Malformed HTML? */ continue; } if (*token == '/') { endtag = T; token++; } else endtag = NIL; strip_tag = NIL; switch (Utoupper(*token)) { case 'A': if (MATCH(token, "APP")) strip_tag = T; else if (MATCH(token, "APPLET")) strip_tag = T; break; case 'B': if (MATCH(token, "BASE")) strip_tag = T; else if (MATCH(token, "BODY")) strip_tag = T; break; case 'F': if (MATCH(token, "FRAME")) strip_tag = T; else if (MATCH(token, "FORM")) strip_tag = T; break; case 'I': if (MATCH(token, "IFRAME")) strip_tag = T; else if (MATCH(token, "IMG") && !show_images) strip_tag = T; break; case 'H': if (MATCH(token, "HTML")) strip_tag = T; else if (MATCH(token, "HEAD")) strip_tag = T; break; case 'M': if (MATCH(token, "META")) strip_tag = T; break; case 'O': if (MATCH(token, "OBJECT")) strip_tag = T; break; case 'T': if (MATCH(token, "TITLE")) strip_tag = T; break; case 'S': if (MATCH(token, "SCRIPT")) strip_tag = T; else if (MATCH(token, "SERVER")) strip_tag = T; else if (MATCH(token, "STYLE")) strip_tag = T; break; } if (strip_tag) { if (endtag) bputs(b, ""); else bputs(b, ""); continue; } /* Tag has been accepted */ if (endtag) { bputs(b, "html_remote_images) continue; break; case 'C': if (NMATCH(token, "CODE=")) continue; if (NMATCH(token, "CODEPAGE=")) continue; break; case 'H': if (NMATCH(token, "HREF=")) { char *t = token + strlen("HREF="); while (html_isspace(*t)) t++; /* Remove quotes */ if ((*t == '"') && t[1] && (t[strlen(t) - 1] == '"')) { t++; t[strlen(t) - 1] = '\0'; } else if ((*t == '\'') && t[1] && (t[strlen(t) - 1] == '\'')) { t++; t[strlen(t) - 1] = '\0'; } /* Indirect links for HTTP and HTTPS to remove "Referrer:" */ my_strip_entities(t); if (NMATCH(t, "http://") || NMATCH(t, "https://")) { bprintf(b, " target=\"_blank\" href=\"%s\"", t); continue; } else if (((NMATCH(t, "ftp:")) || (NMATCH(t, "gopher:")) || (NMATCH(t, "wais:")) || (NMATCH(t, "telnet:")) || (NMATCH(t, "cid:")))) { bprintf(b, " target=\"_blank\" href=\"%s\"", t); continue; } else if (NMATCH(t, "#")) { bprintf(b, " href=\"%s\"", t); continue; } else continue; /* Remove this HREF tag */ } break; case 'L': if (NMATCH(token, "LANGUAGE=")) continue; break; case 'O': if (NMATCH(token, "ONLOAD=")) continue; if (NMATCH(token, "ONMOUSEOVER=")) continue; if (NMATCH(token, "ON")) { char *t = token + 2; while (Uisalpha(*t)) t++; if (*t == '=') continue; } break; case 'S': if (NMATCH(token, "SRC=")) { char *t = token + strlen("SRC="); while (html_isspace(*t)) t++; /* Remove quotes */ if ((*t == '"') && t[1] && (t[strlen(t) - 1] == '"')) { t++; t[strlen(t) - 1] = '\0'; } else if ((*t == '\'') && t[1] && (t[strlen(t) - 1] == '\'')) { t++; t[strlen(t) - 1] = '\0'; } /* Indirect links for HTTP and HTTPS to remove "Referrer:" */ my_strip_entities(t); if (NMATCH(t, "http://") || NMATCH(t, "https://")) { bprintf(b, " TARGET=\"_blank\" SRC=\"%s\"", t); continue; } else if (((NMATCH(t, "ftp:")) || (NMATCH(t, "gopher:")) || (NMATCH(t, "wais:")) || (NMATCH(t, "telnet:")) || (NMATCH(t, "cid:")))) { bprintf(b, " TARGET=\"_blank\" SRC=\"%s\"", t); continue; } else continue; /* Remove this SRC tag */ } break; case 'T': /* Remove target attributes */ if (NMATCH(token, "TARGET=")) continue; break; } /* Default action: Accept this attribute */ bputc(b, ' '); bputs(b, token); } /* Close this tag */ bputc(b, '>'); } } /* ====================================================================== */ /* html_secure() ********************************************************* * * Generate "secure" version of HTML input, with dangerous tags stripped. * b: Output buffer * input: Input string. ************************************************************************/ void html_secure(struct session *session, struct buffer *b, BOOL show_images, char *input) { if (html_secure_tidy(session, b, show_images, input)) return; /* Fall back to original sanitizer if html_secure_tidy fails or disabled */ html_secure_old(session, b, show_images, input); } /* ====================================================================== */ /* html_secure_strip_all() *********************************************** * * Remove all HTML tags from source document, to generate something * suitable for reply. Really need to work harder at parsing HTML: * take a look at just what PINE does. * b: Output buffer * input: Input string. ************************************************************************/ /* Strip _all_ HTML tags from document */ void html_secure_strip_all(struct buffer *b, char *input) { char *s = input; char c; BOOL not_empty; while (1) { not_empty = NIL; /* Copy verbatim until we find a tag */ while ((c = *s++) && (c != '<')) { if ((c == '\015') && (*s == '\012')) { s++; /* CRLF */ bputs(b, "" CRLF); not_empty = NIL; } else if ((c == '\015') || (c == '\012')) { /* CR or LF */ bputs(b, "" CRLF); not_empty = NIL; } else if ((c == ' ') || (c == '\t')) { bputc(b, c); } else if ((c == '&')) { /* Do what if we fail to match? */ switch (Utoupper(*s)) { case '#': if (Uisdigit(s[1]) && Uisdigit(s[2]) && Uisdigit(s[3]) && (s[4] == ';')) { bputc(b, (char) ((((int) (s[1] - '0')) * 100) + (((int) (s[2] - '0')) * 10) + (((int) (s[3] - '0'))))); s += 4; continue; } break; case 'A': if (NMATCH(s, "AMP;")) { bputc(b, '&'); s += strlen("AMP;"); continue; } break; case 'G': if (NMATCH(s, "GT;")) { bputc(b, '>'); s += strlen("GT;"); continue; } break; case 'L': if (NMATCH(s, "LT;")) { bputc(b, '<'); s += strlen("LT;"); continue; } break; case 'N': if (NMATCH(s, "NBSP;")) { bputc(b, ' '); s += strlen("NBSP;"); continue; } break; case 'P': if (NMATCH(s, "POUND;")) { bputc(b, '&'); s += strlen("POUND;"); continue; } break; case 'Q': if (NMATCH(s, "QUOT;")) { bputc(b, '"'); s += strlen("QUOT;"); continue; } break; } /* Unrecognised '&' escape code. What is best action? */ bputc(b, '&'); } else { not_empty = T; bputc(b, c); } } if (c == '\0') break; /* Strip out comments completely */ if (!strncmp(s, "!--", strlen("!--"))) { s += strlen("!--"); while ((c = *s)) { if ((c == '-') && !strncmp(s, "-->", strlen("-->"))) { s += strlen("-->"); break; } s++; } continue; } /* Find other end of this tag */ while ((c = *s) && (c != '>')) s++; if (c == '\0') break; s++; if ((s[0] == '\015') && (s[1] == '\012')) { s += 2; /* CRLF */ if (not_empty) bputs(b, "" CRLF); } else if ((s[0] == '\015') || (s[0] == '\012')) { s++; /* CR or LF */ if (not_empty) bputs(b, "" CRLF); } } } ./prayer-1.3.5/session/speller.c0000644006513000651300000003100311063701636015066 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/speller.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Class which provides support routines to the spelling checker */ /* speller_create() ***************************************************** * * Create a speller structure. ***********************************************************************/ struct speller *speller_create(struct pool *p) { struct speller *speller = pool_alloc(p, sizeof(struct speller)); speller->pool = p; speller->stream = NIL; speller->pid = 0; speller->line = NIL; speller->offset = 0; speller->ignore = NIL; return (speller); } /* speller_free() ******************************************************* * * Free speller structure ***********************************************************************/ void speller_free(struct speller *speller) { struct speller_ignore_list *current, *next; if (speller->pool) return; for (current = speller->ignore; current; current = next) { next = current->next; free(current->word); free(current); } speller->ignore = NIL; free(speller); } /* ====================================================================== */ /* speller_start() ****************************************************** * * Start up engine for spell check run. * speller: * session: * text: Input text to be spell checked * language: Ispell language e.g: "british", "american" * spell_skip_quoted: Use --mode=email in ispell. * * Returns: T if spell check engine started okay. NIL on error. ***********************************************************************/ BOOL speller_start(struct speller *speller, struct session *session, char *text, char *language, BOOL spell_skip_quoted) { pid_t childpid; int sockfd[2]; int c; struct config *config = session->config; speller->language = pool_strdup(speller->pool, language); if (!((config->aspell_path && config->aspell_path[0]) || (config->ispell_path && config->ispell_path[0]))) { session_paniclog(session, "[speller_start()] No speller defined"); return (NIL); } if (!os_socketpair(sockfd)) { session_paniclog(session, "[speller_start()] socketpair()"); return (NIL); } if ((childpid = fork()) < 0) { session_paniclog(session, "[speller_start()] fork() failed"); return (NIL); } if (childpid == 0) { close(sockfd[0]); dup2(sockfd[1], 0); dup2(sockfd[1], 1); dup2(sockfd[1], 2); close(sockfd[1]); if (config->aspell_path) { if (spell_skip_quoted) { execl(config->aspell_path, "aspell", "-a", "--mode=email", "--encoding=utf-8", "-d", speller->language, NULL); } else { execl(config->aspell_path, "aspell", "-a", "-d", speller->language, NULL); } } else { execl(config->ispell_path, "ispell", "-a", "-d", speller->language, NULL); } session_fatal(session, "[speller_start()] Failed to execl() ispell"); } /* Parent */ close(sockfd[1]); /* Create iostream with small block size and timeout */ speller->stream = iostream_create(speller->pool, sockfd[0], 256); iostream_set_timeout(speller->stream, 30); /* Discard banner line */ while (((c = iogetc(speller->stream)) != EOF) && (c != '\n')); if (c == EOF) { session_paniclog(session, "[speller_start()] Failed to read banner line"); return (NIL); } speller->ignore = NIL; speller->pid = childpid; speller->line = text; speller->offset = 0; speller->cursize = 0; speller->output = buffer_create(NIL, 4096); /* Small output buffer */ speller->from_speller = buffer_create(NIL, 4096); /* Small input buffer */ speller->no_changes = 0; speller->last_line = 0; /* Offsets for last line of output */ speller->last_line1 = 0; return (T); } /* speller_stop() ******************************************************* * * Shut down current spell check session. ***********************************************************************/ void speller_stop(struct speller *speller) { struct speller_ignore_list *current, *next; int status = 0; int rc = 0; if (speller->pid) { if (speller->output) buffer_free(speller->output); if (speller->from_speller) buffer_free(speller->from_speller); if (speller->stream) iostream_close(speller->stream); do { rc = waitpid(speller->pid, &status, 0); } while ((rc < 0) && (errno == EINTR)); if ((rc >= 0) && WIFEXITED(status) && (WEXITSTATUS(status) != 0)) log_misc("Non-zero return code from spell checker"); if (!speller->pool) { for (current = speller->ignore; current; current = next) { next = current->next; free(current->word); free(current); } } speller->ignore = NIL; } speller->output = NIL; speller->from_speller = NIL; speller->pid = 0; speller->stream = NIL; } /* speller_active() ****************************************************** * * Check whether spell check running running. ************************************************************************/ BOOL speller_active(struct speller *speller) { if (speller->output && speller->from_speller && speller->stream) return (T); return (NIL); } /* ====================================================================== */ /* speller_feedline() *************************************************** * * Feed next line of input into the speller checker. Munges first character * to avoid confusing ispell. ***********************************************************************/ void speller_feedline(struct speller *speller) { char *s = speller->line; char c; /* Stop ispell from trying to interpret first character of output */ ioputc('^', speller->stream); while ((c = *s++) && (c != '\015') && (c != '\012')) ioputc(c, speller->stream); ioputc('\n', speller->stream); /* Flush line to ispell */ ioflush(speller->stream); } /* speller_getline() ***************************************************** * * Get line of output from the spell check engine. ************************************************************************/ char *speller_getline(struct speller *speller, struct pool *pool) { struct buffer *b = speller->from_speller; unsigned long start = buffer_size(b); int c; while ((c = iogetc(speller->stream)) != EOF) { if (c == '\n') break; bputc(b, c); } return ((char *) buffer_fetch(b, start, buffer_size(b) - start, NIL)); } /* ====================================================================== */ /* speller_copy_line_from_offset() ************************************* * * Copy remainder of current input line from draft into speller checker. ***********************************************************************/ BOOL speller_copy_from_offset(struct speller *speller) { char *s = speller->line; int c; utf8_find_offset(&s, speller->offset); /* Copy remainder of line to output buffer */ while ((c = *s) && (c != '\015') && (c != '\012')) { bputc(speller->output, c); s++; } if (*s) { if ((s[0] == '\015') && (s[1] == '\012')) s += 2; else s += 1; bputs(speller->output, "" CRLF); } if (speller->last_line > 0) { speller->last_line1 = speller->last_line; speller->last_line = buffer_size(speller->output); } else speller->last_line = buffer_size(speller->output); speller->line = s; speller->offset = 0; return ((s[0]) ? T : NIL); } /* speller_copy_to_offset() ********************************************* * * Copy input line from draft into output buffer up to given offset * speller: * offset: Copy up to here ***********************************************************************/ void speller_copy_to_offset(struct speller *speller, unsigned long offset) { char *s = speller->line; unsigned long i; utf8_find_offset(&s, speller->offset); for (i = speller->offset; i < offset; i++) utf8_print_char(speller->output, &s); speller->offset = offset; } /* ====================================================================== */ /* speller_copy_remainder() ********************************************* * * Copy remainder of current input line to output buffer ***********************************************************************/ void speller_copy_remainder(struct speller *speller) { char *s = speller->line; char c; utf8_find_offset(&s, speller->offset); while ((c = *s++)) bputc(speller->output, c); } /* speller_copy_string() ************************************************ * * Copy given string into output buffer ***********************************************************************/ void speller_copy_string(struct speller *speller, char *s) { char c; while ((c = *s++)) bputc(speller->output, c); } /* ====================================================================== */ /* speller_copy_output() ************************************************ * * Copy given string into output buffer ***********************************************************************/ char *speller_output(struct speller *speller) { return (buffer_fetch(speller->output, 0, buffer_size(speller->output), NIL)); } /* ====================================================================== */ /* speller_print_lastline() ********************************************* * * Print last last from output buffer * speller: * b: Target buffer ***********************************************************************/ void speller_print_lastline(struct speller *speller, struct buffer *b) { int c; buffer_seek_offset(speller->output, speller->last_line1); while ((c = bgetc(speller->output)) != EOF) html_quote_char(b, c); } /* ====================================================================== */ /* speller_record_cursize() ********************************************* * * Record current size ***********************************************************************/ void speller_record_cursize(struct speller *speller, unsigned long size) { speller->cursize = size; } /* speller_fetch_cursize() ********************************************** * * Fetch current size ***********************************************************************/ unsigned long speller_fetch_cursize(struct speller *speller) { return (speller->cursize); } /* ====================================================================== */ /* speller_skip_input() ************************************************* * * Skip input ***********************************************************************/ void speller_skip_input(struct speller *speller, unsigned long size) { speller->offset += size; } /* ====================================================================== */ /* speller_add_ignore_list() ******************************************** * * Add word to (temporary) ignore list ***********************************************************************/ void speller_add_ignore_list(struct speller *speller, char *word) { struct speller_ignore_list *new = pool_alloc(speller->pool, sizeof(struct speller_ignore_list)); /* Add word to front of list */ new->word = pool_strdup(speller->pool, word); new->next = speller->ignore; speller->ignore = new; } /* speller_check_ignore_list() ****************************************** * * Check word against current temporary ignore list. ***********************************************************************/ BOOL speller_check_ignore_list(struct speller *speller, char *word) { struct speller_ignore_list *current = speller->ignore; while (current) { if (!strcasecmp(current->word, word)) return (T); current = current->next; } return (NIL); } ./prayer-1.3.5/session/speller.h0000644006513000651300000000470211063701636015101 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/speller.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ struct speller_ignore_list { /* Temporary Ignore list */ struct speller_ignore_list *next; /* Linked list */ char *word; /* Word */ }; struct speller { struct pool *pool; /* Allocation Pool */ struct iostream *stream; /* Connection to ispell */ struct speller_ignore_list *ignore; /* List of errors to ignore */ char *language; /* Current ispeller language */ pid_t pid; /* PID of ispell child process */ char *line; /* Current input line */ unsigned long offset; /* Offset into input line */ unsigned long cursize; /* Size of current word */ struct buffer *output; /* Output buffer */ unsigned long last_line; /* Output Offset to last line */ unsigned long last_line1; /* Output Offset to last-1 line */ struct buffer *from_speller; /* Output from ispell */ unsigned long no_changes; /* Running count of changes */ }; struct speller *speller_create(struct pool *p); void speller_free(struct speller *speller); BOOL speller_start(struct speller *speller, struct session *session, char *text, char *language, BOOL spell_skip_quoted); void speller_stop(struct speller *speller); BOOL speller_active(struct speller *speller); void speller_feedline(struct speller *speller); char *speller_getline(struct speller *speller, struct pool *pool); BOOL speller_copy_from_offset(struct speller *speller); void speller_copy_to_offset(struct speller *speller, unsigned long offset); void speller_copy_remainder(struct speller *speller); void speller_copy_string(struct speller *speller, char *s); char *speller_output(struct speller *speller); void speller_print_lastline(struct speller *speller, struct buffer *b); void speller_record_cursize(struct speller *speller, unsigned long size); unsigned long speller_fetch_cursize(struct speller *speller); void speller_skip_input(struct speller *speller, unsigned long size); void speller_add_ignore_list(struct speller *speller, char *word); BOOL speller_check_ignore_list(struct speller *speller, char *word); ./prayer-1.3.5/session/utf8_calc.h0000644006513000651300000000023411063701636015277 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/utf8_calc.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ unsigned long utf8_calc_width(char *t, unsigned long bytes); ./prayer-1.3.5/session/account_sieve.h0000644006513000651300000000113611063701636016260 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/account_sieve.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ BOOL account_sieve_mail_check(struct account *account, struct pool *pool); BOOL account_sieve_mail_update(struct account *account, struct pool *pool); BOOL account_sieve_vacation_update(struct account *account, struct pool *pool); ./prayer-1.3.5/session/session.h0000644006513000651300000002415711102315173015113 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/session.h,v 1.7 2008/10/30 11:28:59 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* IMAP protocol allows sessions to disconnection after 30 mins idle time */ #define SESSION_DEFAULT_IMAP_TIMEOUT (29*60) struct session { /* General session stuff */ struct pool *pool; /* Allocate from this pool */ struct config *config; /* Generate configuration */ BOOL debug; /* Debugging */ BOOL want_disconnect; /* Disconnect after this request */ char *cwd; /* Current working directory */ char *dir_filter; /* Filter for directory listing */ char *username; /* Name of logged in user */ char *password; /* Password for logged in user */ char *newpassword; /* New Password logged in user */ struct memblock *last_cmd; /* Last command that was run */ struct memblock *last_help; /* Last help item */ struct account *account; /* Connection to accountd server */ struct sieve *sieve; /* Connection to sieve server */ BOOL use_sieve; /* Use sieve rather than accountd if set */ /* Location of servers */ char *imapd_server; /* Location of imap server */ char *accountd_server; /* Location of accountd server */ char *accountd_nis_server; /* Location of accountd NIS server */ char *sieved_server; /* Location of sieve server */ /* Some rather nasty session state */ char *rename_foldername; /* Name of folder to be renamed */ BOOL aggregate; /* Aggregate operation */ BOOL reply_all; /* Reply to all */ struct filter *half_filter; /* Half build filter item */ char *upload_name; /* Name for folder upload */ char *upload_file; /* Temp file for folder upload */ char *abook_compose_name; /* Name and email address for */ char *abook_compose_email; /* Abook compose option */ BOOL help_enabled; /* Help text enabled */ BOOL help_toolbar; /* Show help for toolbar as well */ unsigned long recips_count_session; /* Running total for this session */ BOOL sending_allow; /* Whitelist to override: */ BOOL sending_block; /* Shut down compromised accounts */ struct log *accesslog; /* Access log */ struct log *sessionlog; /* Session log */ BOOL http_dump; /* Temporary, remove */ int telemetry_fd; /* File descriptor for telemetry */ BOOL telemetry; /* Enable HTTP telemetry */ BOOL telemetry_all; /* Enable full HTTP telemetry */ unsigned long sequence; /* Session sequence number */ unsigned long sequence_last_change; /* Last folder change happened */ BOOL sequence_okay; /* NIL: Browser history in action */ /* HTTP Connection stuff, including request/response */ struct request *request; /* _Current_ request */ struct ipaddr *ipaddr; /* IP address for client */ pid_t frontend_pid; /* Process ID for logging */ BOOL use_ssl; /* Use SSL for frontend port */ unsigned long frontend_port; /* Frontend port for this session */ unsigned long session_port; /* Backend sessionport, if used */ BOOL is_direct; /* Direct connection */ char *url_prefix; /* Prefix for normal urls */ char *url_prefix_icons; /* Prefix for icon urls */ char *url_prefix_asession; /* Base Prefix for session urls */ char *url_prefix_bsession; /* Base Prefix for session urls */ char *url_prefix_short; /* Prefix for shortsession urls */ char *url_prefix_session; /* Prefix for session urls */ char *sessionid; /* SessionID for this user */ /* User interface stuff */ BOOL use_cookie; /* Session using cookie */ BOOL use_short; /* Use short URLS */ BOOL use_gzip; /* Use gzip compression */ char *abook_parent_cmd; /* Parent cmd for address book */ char *compose_parent_cmd; /* Parent cmd for compose */ char *take_parent_cmd; /* Parent cmd for abook_take */ char *copy_parent_cmd; /* Parent cmd for copy */ BOOL compose_large; /* Large compose window */ BOOL full_hdrs; /* Display full headers */ struct config_theme *theme_main; /* Main theme */ struct config_theme *theme_help; /* Help theme */ struct template_vals *template_vals; /* Filled in for each new template */ /* Folder stuff */ char *personal_hierarchy; /* From IMAP server NAMESPACE */ char *hiersep; /* From IMAP server NAMESPACE */ char *foldername; /* Current folder name */ char *other_foldername; /* Name of "other" folder */ char *draft_foldername; /* Name of "draft" folder */ MAILSTREAM *stream; /* MAILSTREAM for current folder */ MAILSTREAM *inbox_stream; /* MAILSTREAM for inbox */ MAILSTREAM *other_stream; /* MAILSTREAM for otherfolder */ MAILSTREAM *draft_stream; /* MAILSTREAM for drafts */ MAILSTREAM *prefs_stream; /* MAILSTREAM for preferences */ MAILSTREAM *xfer_stream; /* MAILSTREAM for transfers */ time_t inbox_last_ping_time; /* Time of last ping */ time_t other_last_ping_time; /* Time of last ping */ time_t draft_last_ping_time; /* Time of last ping */ time_t prefs_last_ping_time; /* Time of last ping */ time_t xfer_last_ping_time; /* Time of last ping */ unsigned long current; /* Current message */ unsigned long last_displayed; /* Last message to be displayed */ struct msgmap *zm; /* Zoom map */ struct memblock *message; /* Status message to display */ BOOL message_isalert; /* T => was an error message */ struct options *options; /* Miscellaneous user options */ struct lookup *lookup; /* Interface to lookup system */ struct folderlist *folderlist; /* Folderlist (replaces dircache)*/ struct speller *speller; /* Interface to spell checker */ struct draft *draft; /* Draft message */ struct draft *draft0; /* Previous draft message */ struct user_agent *ua_initial; /* Initial user agent prefs */ struct user_agent *user_agent; /* Modified user agent prefs */ }; BOOL session_log_open(struct session *session); BOOL session_log_ping(struct session *session); struct session *session_create(struct config *config); void session_update_sequence(struct session *session); void session_bump_sequence(struct session *session); struct template_vals_urlstate * session_extract_urlstate(struct session *session); void session_seed_template(struct session *session, struct template_vals *tvals); void session_setup_urls(struct session *session); char *session_mailbox_prefs(struct session *session, struct pool *pool); char *session_mailbox(struct session *session, struct pool *pool, char *folder); char *session_dir(struct session *session, struct pool *pool, char *dir); BOOL session_login(struct session *session, char *username, char *password, unsigned long port, BOOL use_ssl, char *ua_options, struct ipaddr *ipaddr); void session_setup_child(struct session *session); void session_close_logs(struct session *session); void session_close_streams(struct session *session); void session_free(struct session *session); /* void *prefs needed to break cicular dependancy */ void session_use_prefs(struct session *session, void *prefs, BOOL initial); unsigned long session_sequence(char *seqno); void session_make_redirect(struct session *session, struct request *request, char *location); void session_make_cookie_redirect(struct session *session, struct request *request, char *location); void session_make_clear_cookie_redirect(struct session *session, struct request *request, char *location); void session_make_session_redirect(struct session *session, struct request *request, char *cmd); void session_make_session_cookie_redirect(struct session *session, struct request *request, char *cmd); void session_make_session_clear_cookie_redirect(struct session *session, struct request *request, char *cmd); void session_redirect(struct session *session, struct request *request, char *url); void session_record_cmd(struct session *session, char *cmd); void session_message(struct session *session, char *fmt, ...); void session_message_clear(struct session *session); void session_alert(struct session *session, char *fmt, ...); void session_init_last_cmd(struct session *session, unsigned long maxlen); void session_record_last_cmd(struct session *session, char *last_cmd); char *session_last_cmd(struct session *session); void session_accesslog(struct session *session, struct request *request); void session_log(struct session *session, char *fmt, ...); void session_paniclog(struct session *session, char *fmt, ...); void session_fatal(struct session *session, char *fmt, ...); ./prayer-1.3.5/session/stream.c0000644006513000651300000000563111063701636014723 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/stream.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Helper functions for c-client stream object */ /* Mostly working around ideas that c-client seems to use text strings * rather than flag bits to mark messages. May just be limits in my * understanding of c-client, but I can't find a better interface to work * with at the moment */ /* ====================================================================== */ /* stream_check_uid() *************************************************** * * Check that msgno and msguid match. * session: * stream: * msgno: Message Number which should contain this UID (bext first guess) * msguid: Message UID that we are looking for * * Returns: Msgno of message containing this UID (typically msgno unless * an external expunge event has just taken place). ***********************************************************************/ unsigned long stream_check_uid(struct session *session, MAILSTREAM * stream, unsigned long msgno, unsigned long msguid) { if ((msgno == 0) || (msguid == 0)) { session_message(session, "Reference to illegal Message UID 0"); session_log(session, "[stream_check_uid] Reference to illegal Message UID 0"); return (0); } /* Could just do reverse lookup (msguid -> msgno). This way is a bit * more efficient as don't have to scan the entire index looking for a * particular UID most of the time */ if ((msgno > stream->nmsgs) || (ml_uid(session, stream, msgno) != msguid)) { /* Messages have moved: external expunge event */ if (((msgno = ml_msgno(session, stream, msguid)) == 0) || (msgno > stream->nmsgs)) { /* Couldn't find this UID in folder */ session_message(session, "Message UID %lu has been expunged", msguid); return (0); } } return (msgno); } /* stream_find_unread() ************************************************** * * Find first unread message in stream. ************************************************************************/ unsigned long stream_find_unread(struct session *session, MAILSTREAM * stream) { unsigned long msgno; char seq[64]; if (stream->nmsgs == 0) return (0); sprintf(seq, "1:%lu", stream->nmsgs); ml_fetch_fast(session, stream, seq, 0); /* Record last unread message from inbox */ for (msgno = 1; msgno <= stream->nmsgs; msgno++) { if (!mail_elt(stream, msgno)->seen) return (msgno); } return (0); } ./prayer-1.3.5/session/rfc1522.h0000644006513000651300000000106111063701636014512 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/rfc1522.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ unsigned char *rfc1522_decode(unsigned char *d, size_t len, char *s, char **charset); char *rfc1522_encode(char *d, size_t len, unsigned char *s, char *charset); ./prayer-1.3.5/session/addr.h0000644006513000651300000000144511063701636014346 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/addr.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Some utility routines for processing address objects */ char *addr_text(struct pool *pool, ADDRESS * addr); char *addr_text_exclude(struct session *session, struct pool *pool, ADDRESS * addr, ADDRESS * exclude); ADDRESS * addr_parse_destructive(char *text, char *default_domain); ADDRESS * addr_parse(struct pool *pool, char *text, char *default_domain); BOOL addr_check_valid(struct pool *pool, char *text); ./prayer-1.3.5/session/session_streams.c0000644006513000651300000007151311063701636016653 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/session_streams.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* session stream manipulation stuff amalgamated here. This is a bit of a * mess simply because struct session defines half a dozen independant * streams, and session idle mode, stream checking and folder change * affect a number of different streams. * * Putting it all here in one place to encourage rationalisation/cleanup at * some future point. However this probably isn't a high priority as the * mess is more or less invisible to the main body of the code which only * cares about session->stream. Thought: define abstraction, have ptrs from * struct session into abstraction so that all changes within this * abstraction transparent to other code */ #include "prayer_session.h" /* session_streams_idle() ************************************************ * * Shut down transient resources if session is idle ************************************************************************/ BOOL session_streams_idle(struct session *session) { unsigned long marked = msgmap_marked_count(session->zm); /* Will be reassigned when we wake up */ session->stream = NIL; if (session->inbox_stream) { if ((session->stream == session->inbox_stream) && (marked > 0)) /* Garbage collect inbox stream */ mail_gc(session->inbox_stream, GC_ENV | GC_TEXTS); else { /* Shut down inbox stream */ ml_close(session, session->inbox_stream); session->inbox_stream = NIL; } } if (session->other_stream) { if ((session->stream == session->other_stream) && (marked > 0)) { /* Garbage collect other stream */ mail_gc(session->other_stream, GC_ENV | GC_TEXTS); } else { /* Shut down other stream */ ml_close(session, session->other_stream); session->other_stream = NIL; } } if (session->draft_stream) { if ((session->stream == session->draft_stream) && (marked > 0)) { /* Garbage collect draft stream */ mail_gc(session->draft_stream, GC_ENV | GC_TEXTS); } else { /* Shut down other stream */ ml_close(session, session->draft_stream); session->draft_stream = NIL; } } /* Shut down preferences stream */ if (session->prefs_stream) { ml_close(session, session->prefs_stream); session->prefs_stream = NIL; } /* Shut down transfer stream */ if (session->xfer_stream) { ml_close(session, session->xfer_stream); session->xfer_stream = NIL; } /* Shut down account connections as well */ account_close(session->account); sieve_close(session->sieve); return (T); } /* ====================================================================== */ /* Some static utility routines for session_streams_check() */ static BOOL session_reopen_inbox_stream(struct session *session) { struct request *request = session->request; struct pool *pool = request->pool; session->inbox_stream = ml_open(session, NIL, session_mailbox(session, pool, "inbox"), 0); if (session->inbox_stream == NIL) { session_log(session, "[session_reopen_inbox_stream] Failed to reopen inbox"); return (NIL); } if (!strcasecmp(session->foldername, "inbox")) { session->stream = session->inbox_stream; msgmap_associate(session->zm, session, session->inbox_stream); } session_log(session, "[session_reopen_inbox_stream] Reopened inbox"); session->inbox_last_ping_time = time(NIL); return (T); } static BOOL session_reopen_other_stream(struct session *session) { struct request *request = session->request; struct pool *pool = request->pool; session->other_stream = ml_open(session, NIL, session_mailbox(session, pool, session->other_foldername), 0); if (session->other_stream == NIL) { session_log(session, "[session_reopen_other_stream] Failed to reopen %s", session->other_foldername); return (NIL); } if (!strcmp(session->foldername, session->other_foldername)) { session->stream = session->other_stream; msgmap_associate(session->zm, session, session->other_stream); } session_log(session, "[session_reopen_other_stream] Reopened %s", session->other_foldername); session->other_last_ping_time = time(NIL); return (T); } static BOOL session_reopen_draft_stream(struct session *session) { struct request *request = session->request; struct pool *pool = request->pool; session->draft_stream = ml_open(session, NIL, session_mailbox(session, pool, session->draft_foldername), 0); if (session->draft_stream == NIL) { session_log(session, "[session_reopen_draft_stream] Failed to reopen %s", session->draft_foldername); return (NIL); } if (!strcmp(session->foldername, session->draft_foldername)) { session->stream = session->draft_stream; msgmap_associate(session->zm, session, session->draft_stream); } session_log(session, "[session_reopen_draft_stream] Reopened %s", session->draft_foldername); session->draft_last_ping_time = time(NIL); return (T); } /* ====================================================================== */ static unsigned long *session_marked_list(struct pool *pool, MAILSTREAM * stream) { unsigned long count = 0; unsigned long msgno; unsigned long *result; for (msgno = 1; msgno <= stream->nmsgs; msgno++) { MESSAGECACHE *elt = mail_elt(stream, msgno); if (elt->spare) count++; } result = pool_alloc(pool, (count + 1) * sizeof(unsigned long)); count = 0; for (msgno = 1; msgno <= stream->nmsgs; msgno++) { MESSAGECACHE *elt = mail_elt(stream, msgno); if (elt->spare) result[count++] = mail_uid(stream, msgno); } result[count] = 0; return (result); } unsigned long session_apply_marked_list(MAILSTREAM * stream, unsigned long *list) { unsigned long count = 0; unsigned long msgno; for (msgno = 1; msgno <= stream->nmsgs; msgno++) { unsigned long uid = mail_uid(stream, msgno); if (uid == *list) { mail_elt(stream, msgno)->spare = T; count++; list++; } else if (uid > (*list)) { list++; if (*list == 0L) break; } } return (count); } /* ====================================================================== */ static BOOL session_check_inbox_stream(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; time_t now = time(NIL); BOOL use_check = config->stream_checkpoint; BOOL current = (session->stream == session->inbox_stream); unsigned long *marklist = NIL; if (use_check) { if (ml_check(session, session->inbox_stream)) { session_log(session, "[session_check_inbox_stream] Checkpoint inbox"); session->inbox_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } else { if (ml_ping(session, session->inbox_stream)) { session_log(session, "[session_check_inbox_stream] Pinged inbox"); session->inbox_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } /* Need to reopen inbox. First record current marked messages */ if (current) marklist = session_marked_list(pool, session->inbox_stream); ml_close(session, session->inbox_stream); session->inbox_stream = ml_open(session, NIL, session_mailbox(session, pool, "INBOX"), 0); if (session->inbox_stream == NIL) { session_log(session, "[session_check_inbox_stream] Failed to reopen inbox"); return (NIL); } if (current) { session->stream = session->inbox_stream; if (marklist) msgmap_marked_set(session->zm, session_apply_marked_list(session->stream, marklist)); msgmap_associate(session->zm, session, session->inbox_stream); } if (msgmap_marked_count(session->zm) > 0) session_log(session, ("[session_check_inbox_stream] " "Reopened inbox with %lu marked msgs"), msgmap_marked_count(session->zm)); else session_log(session, "[session_check_inbox_stream] Reopened inbox"); return (T); } static BOOL session_check_other_stream(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; time_t now = time(NIL); BOOL use_check = config->stream_checkpoint; BOOL current = (session->stream == session->other_stream); unsigned long *marklist = NIL; if (use_check) { if (ml_check(session, session->other_stream)) { session_log(session, "[session_check_other_stream] Checkpoint %s", session->other_foldername); session->other_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } else { if (ml_ping(session, session->other_stream)) { session_log(session, "[session_check_other_stream] Pinged %s", session->other_foldername); session->other_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } /* Need to reopen other stream. First record current marked messages */ if (current) marklist = session_marked_list(pool, session->other_stream); ml_close(session, session->other_stream); session->other_stream = ml_open(session, NIL, session_mailbox(session, pool, session->other_foldername), 0); if (session->other_stream == NIL) { session_log(session, "[session_check_other_stream] Failed to reopen %s", session->other_foldername); return (NIL); } if (current) { session->stream = session->other_stream; if (marklist) msgmap_marked_set(session->zm, session_apply_marked_list(session->stream, marklist)); msgmap_associate(session->zm, session, session->other_stream); } if (msgmap_marked_count(session->zm) > 0) session_log(session, ("[session_check_other_stream] " "Reopened %s with %lu marked msgs"), session->other_foldername, msgmap_marked_count(session->zm)); else session_log(session, "[session_check_other_stream] Reopened %s", session->other_foldername); session->other_last_ping_time = now; return (T); } static BOOL session_check_draft_stream(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; time_t now = time(NIL); BOOL use_check = config->stream_checkpoint; BOOL current = (session->stream == session->draft_stream); unsigned long *marklist = NIL; if (use_check) { if (ml_check(session, session->draft_stream)) { session_log(session, "[session_check_draft_stream] Checkpoint %s", session->draft_foldername); session->draft_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } else { if (ml_ping(session, session->draft_stream)) { session_log(session, "[session_check_draft_stream] Pinged %s", session->draft_foldername); session->draft_last_ping_time = now; if (current) msgmap_check(session->zm); return (T); } } /* Need to reopen other stream. First record current marked messages */ if (current) marklist = session_marked_list(pool, session->draft_stream); ml_close(session, session->draft_stream); session->draft_stream = ml_open(session, NIL, session_mailbox(session, pool, session->draft_foldername), 0); if (session->draft_stream == NIL) { session_log(session, "[session_check_draft_stream] Failed to reopen %s", session->draft_foldername); return (NIL); } if (current) { session->stream = session->draft_stream; if (marklist) msgmap_marked_set(session->zm, session_apply_marked_list(session->stream, marklist)); msgmap_associate(session->zm, session, session->draft_stream); } if (msgmap_marked_count(session->zm) > 0) session_log(session, ("[session_check_draft_stream] " "Reopened %s with %lu marked msgs"), session->draft_foldername, msgmap_marked_count(session->zm)); else session_log(session, "[session_check_draft_stream] Reopened %s", session->draft_foldername); session->draft_last_ping_time = now; return (T); } /* ====================================================================== */ /* session_streams_check() *********************************************** * * Check to see if MAILSTREAM connections to IMAP server have timed out * Quietly reconnect connections which have timed out ************************************************************************/ BOOL session_streams_check(struct session * session) { struct config *config = session->config; time_t now = time(NIL); time_t interval; interval = (time_t) config->stream_ping_interval; /* IMAP server may time out after 30 minutes */ if ((interval == 0) || (interval > SESSION_DEFAULT_IMAP_TIMEOUT)) interval = SESSION_DEFAULT_IMAP_TIMEOUT; /* Check or reopen inbox stream if needed */ if (session->inbox_stream == NIL) { if (!session_reopen_inbox_stream(session)) return (NIL); } else if ((session->inbox_last_ping_time + interval) < now) { if (!session_check_inbox_stream(session)) return (NIL); } /* Check or reopen other stream if needed */ if (session->other_stream) { if (((session->other_last_ping_time + interval) < now) && !session_check_other_stream(session)) return (NIL); } else if (session->foldername && session->other_foldername && !strcmp(session->foldername, session->other_foldername) && !session_reopen_other_stream(session)) return (NIL); /* Check or reopen draft stream if needed */ if (session->draft_stream) { if (((session->draft_last_ping_time + interval) < now) && !session_check_draft_stream(session)) return (NIL); } else if (session->foldername && session->draft_foldername && !strcmp(session->foldername, session->draft_foldername) && !session_reopen_draft_stream(session)) return (NIL); interval = config->stream_misc_timeout; /* IMAP server may time out after 30 minutes */ if ((interval == 0) || (interval > SESSION_DEFAULT_IMAP_TIMEOUT)) interval = SESSION_DEFAULT_IMAP_TIMEOUT; /* Shut down preferences stream if it has been idle */ if (session->prefs_stream && ((session->prefs_last_ping_time + interval) < now)) { ml_close(session, session->prefs_stream); session->prefs_stream = NIL; } /* Shut down transfer stream if it has been idle */ if (session->xfer_stream && ((session->xfer_last_ping_time + interval) < now)) { ml_close(session, session->xfer_stream); session->xfer_stream = NIL; } /* Shut down account connections if they have been idle */ account_timeout_close(session->account); sieve_timeout_close(session->sieve, session); return (T); } /* ====================================================================== */ /* session_streams_change() ********************************************** * * Change to named folder, updating session stream stuff as required ************************************************************************/ BOOL session_streams_change(struct session * session, char *name) { struct request *request = session->request; struct msgmap *zm = session->zm; MAILSTREAM *stream; if (!strcasecmp(name, "inbox")) { /* Switch back to inbox stream */ string_strdup(&session->foldername, "INBOX"); session->stream = session->inbox_stream; } else if (session->other_stream && session->other_foldername && !strcmp(name, session->other_foldername)) { /* Switch to other stream */ string_strdup(&session->foldername, session->other_foldername); session->stream = session->other_stream; } else if (!strcmp(name, session->draft_foldername)) { /* Switch to draft stream, opening if required */ if (!session->draft_stream) { if (!(stream = ml_open(session, NIL, session_mailbox(session, request->pool, session-> draft_foldername), 0))) return (NIL); session->draft_stream = session->stream = stream; session->draft_last_ping_time = time(NIL); } else session->stream = stream = session->draft_stream; string_strdup(&session->foldername, session->draft_foldername); } else { /* Open fresh other_stream */ /* Just in case ml_open() fails */ stream = session->other_stream; session->other_stream = NIL; /* Open stream, reusing existing other stream if possible */ if (!(stream = ml_open(session, stream, session_mailbox(session, request->pool, name), 0))) return (NIL); string_strdup(&session->other_foldername, name); string_strdup(&session->foldername, name); session->other_stream = session->stream = stream; session->other_last_ping_time = time(NIL); } stream = session->stream; msgmap_associate(zm, session, stream); msgmap_update(zm); if (zm->nmsgs > 0) { if (zm->sort_reverse) session->current = msgmap_value(zm, 1); else session->current = msgmap_value(zm, zm->nmsgs); } else session->current = 0; session->last_displayed = session->current; /* Record current session sequence number: intercept browser back button */ session->sequence_last_change = session->sequence; return (T); } /* ====================================================================== */ /* session_streams_find() ************************************************ * * Work out if we have open connection to nominated mail folder already. ************************************************************************/ MAILSTREAM *session_streams_find(struct session * session, char *name) { if (!strcasecmp(name, "INBOX")) return (session->inbox_stream); if (session->other_foldername && !strcmp(name, session->other_foldername)) return (session->other_stream); if (session->draft_foldername && !strcmp(name, session->draft_foldername)) return (session->draft_stream); return (NIL); } /* ====================================================================== */ /* session_streams_ping() ************************************************ * * Ping stream associated with mailbox name if active ************************************************************************/ BOOL session_streams_ping(struct session * session, char *mailbox) { if (!strcasecmp(mailbox, "inbox") && session->inbox_stream) { if (!ml_ping(session, session->inbox_stream)) return (NIL); session->inbox_last_ping_time = time(NIL); if (session->stream == session->inbox_stream) msgmap_check(session->zm); return (T); } if (session->other_foldername && session->other_stream && !strcmp(mailbox, session->other_foldername)) { if (!ml_ping(session, session->other_stream)) return (NIL); session->other_last_ping_time = time(NIL); if (session->stream == session->other_stream) msgmap_check(session->zm); return (T); } if (!strcmp(mailbox, session->draft_foldername) && session->draft_stream) { if (!ml_ping(session, session->draft_stream)) return (NIL); session->draft_last_ping_time = time(NIL); if (session->stream == session->draft_stream) msgmap_check(session->zm); return (T); } return (T); } /* ====================================================================== */ /* session_save_options_to_stream() ************************************** * * Utility routine to help save user preferences. * session: Global state * stream Connection to preferences folder ************************************************************************/ static BOOL session_save_options_to_stream(struct session *session, MAILSTREAM * stream) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; struct options *options = session->options; unsigned long nmsgs = stream->nmsgs; STRING ms; char *data; unsigned long size; char *range; char *prayer_name = session_mailbox_prefs(session, pool); /* Create new status message */ data = options_create_message(options, config, pool); /* Convert simple "char *" string into c-client "STRING *" string */ INIT(&ms, mail_string, data, size = strlen(data)); /* Append new preferences message to end of folder */ if (!ml_append(session, stream, prayer_name, &ms)) return (NIL); /* Double check that append was successful: c-client ignores errors :( */ if (!ml_ping(session, stream) || (stream->nmsgs == nmsgs)) return (NIL); /* Clear out the old preferences if append was successful */ if (nmsgs > 0) { range = pool_strcat(pool, "1:", string_itoa_tmp(nmsgs)); if (!ml_flag(session, stream, range, "\\DELETED", ST_SET)) { session_log(session, ("[session_save_options_to_stream] " "Failed to clear out prefs file: %s"), ml_errmsg()); return (NIL); } } if (!ml_expunge(session, stream)) return (NIL); options->save = NIL; session->prefs_last_ping_time = time(NIL); return (T); } /* session_streams_save_options() **************************************** * * Save user preferences. Catch and report error condition. ************************************************************************/ BOOL session_streams_save_options(struct session * session) { struct request *request = session->request; struct pool *pool = request->pool; char *prayer_name = session_mailbox_prefs(session, pool); ml_clear_error(); if (!session->prefs_stream) session->prefs_stream = ml_open(session, NIL, prayer_name, 0); if (!session->prefs_stream || ml_have_error()) { ml_clear_error(); ml_create(session, session->prefs_stream, prayer_name); if (!ml_have_error()) session->prefs_stream = ml_open(session, session->prefs_stream, prayer_name, 0); } if (session->prefs_stream && !ml_have_error() && session->prefs_stream && session_save_options_to_stream(session, session->prefs_stream)) return (T); session_message(session, "Failed to save preferences: %s", ml_errmsg()); session_log(session, "[session_save_options] Failed to save preferences: %s", ml_errmsg()); if (session->prefs_stream) { ml_close(session, session->prefs_stream); session->prefs_stream = NIL; } return (T); } /* ====================================================================== */ /* session_save_options_and_close_inbox() ******************************* * * Shut down inbox stream, saving options if needed. ***********************************************************************/ static void session_save_options_and_close_inbox(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct pool *pool = request->pool; MAILSTREAM *stream; char *name; char *prefs_folder_name = config->prefs_folder_name; char *prayer_name = session_mailbox_prefs(session, pool); /* Checkpoint inbox stream before recycle attempt */ ml_check(session, session->inbox_stream); ml_clear_error(); stream = ml_open(session, session->inbox_stream, prayer_name, 0); if (!stream) { if (ml_have_error()) { ml_clear_error(); ml_create(session, stream, prayer_name); if (!ml_have_error()) stream = ml_open(session, stream, prayer_name, 0); } if (!stream || ml_have_error() || !((name = stream->mailbox) && (strlen(name) >= strlen(prefs_folder_name)) && (!strcmp(name + strlen(name) - strlen(prefs_folder_name), prefs_folder_name)))) { session_log(session, ("[session_save_options_and_close_inbox]" " Unable to select/create prefs file on exit")); ml_close(session, stream); return; } } if (stream) { session_save_options_to_stream(session, stream); ml_close(session, stream); } } /* ====================================================================== */ /* session_streams_close() ********************************************** * * Shut down IMAP mailstreams associated with a login session ***********************************************************************/ void session_streams_close(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct prefs *prefs = options->prefs; BOOL remove_drafts = NIL; /* Shut down transfer stream */ if (session->xfer_stream) { ml_close(session, session->xfer_stream); session->xfer_stream = NIL; } /* Shut down other stream */ if (session->other_stream) { if (prefs->expunge_on_exit) ml_expunge(session, session->other_stream); ml_close(session, session->other_stream); session->other_stream = NIL; } /* Shut down drafts stream */ if (session->draft_stream) { if (session->draft_foldername && (session->draft_stream->nmsgs == 0)) remove_drafts = T; ml_close(session, session->draft_stream); session->draft_stream = NIL; } /* Shut down preferences stream, flushing options if dirty */ if (session->prefs_stream) { if (options->save) session_streams_save_options(session); ml_close(session, session->prefs_stream); session->prefs_stream = NIL; } /* Remove draft messages folder if empty */ if (remove_drafts) ml_delete(session, session->inbox_stream, session_mailbox(session, request->pool, session->draft_foldername)); /* Shut down inbox stream, flushing options if dirty (and no prefs stream) */ if (session->inbox_stream) { if (prefs->expunge_on_exit) ml_expunge(session, session->inbox_stream); if (options->save) session_save_options_and_close_inbox(session); else ml_close(session, session->inbox_stream); session->inbox_stream = NIL; } } ./prayer-1.3.5/session/stream.h0000644006513000651300000000113211063701636014720 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/stream.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ unsigned long stream_check_uid(struct session *session, MAILSTREAM * stream, unsigned long msgno, unsigned long msguid); unsigned long stream_find_unread(struct session *session, MAILSTREAM * stream); ./prayer-1.3.5/session/mc.c0000644006513000651300000000334011063701636014022 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/mc.c,v 1.2 2008/09/16 09:59:58 dpc22 Exp $ */ #include "prayer_session.h" /* mc_date_to_string() *************************************************** * * Convert (month, day, year) tuple into printable form. * month: month in range 1 to 12 * day: Day in range 1 to 31 * year: Four digit date. * * Returns: Date in printable form ***********************************************************************/ char *mc_date_to_string(MESSAGECACHE *mc) { static char result[64]; static char *date_month[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; if ((mc->month < 1) || (mc->month > 12)) return (""); sprintf(result, "%s %d %d", date_month[mc->month - 1], mc->day, mc->year + BASEYEAR); return (result); } /* mc_date_to_string_full() ********************************************** * * Convert (mins, hours, month, day, year) tuple into printable form. * mins: minutes in range 0:59 * hours: hours in range 0:23 * month: month in range 1 to 12 * day: Day in range 1 to 31 * year: Four digit date. * * Returns: Date in printable form ***********************************************************************/ char *mc_date_to_string_full(MESSAGECACHE *mc) { static char result[64]; static char *date_month[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; if ((mc->month < 1) || (mc->month > 12)) return (""); sprintf(result, "%s %02d %04d %02d:%02d ", date_month[mc->month - 1], mc->day, mc->year + BASEYEAR, mc->hours, mc->minutes); return (result); } ./prayer-1.3.5/session/session.c0000644006513000651300000014243411413374146015117 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/session.c,v 1.11 2010/07/02 14:32:06 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Class containing global data for login sessions (includes large number of * links to subsiduary structures */ /* ====================================================================== */ /* session_log_open() *************************************************** * * Open access and session log files. * session: Global state ***********************************************************************/ BOOL session_log_open(struct session *session) { if (!log_open(session->accesslog, "access_log")) return (NIL); if (!log_open(session->sessionlog, "session_log")) return (NIL); return (T); } /* session_log_ping() *************************************************** * * Reopen access and session log file. * session: Global state ***********************************************************************/ BOOL session_log_ping(struct session * session) { if (!log_ping(session->accesslog)) return (NIL); if (!log_ping(session->sessionlog)) return (NIL); return (T); } /* ====================================================================== */ /* session_create() ***************************************************** * * Create a fresh session structure including its own pool. * config: Prayer configuration * * Returns: Ptr to new session structure ***********************************************************************/ struct session *session_create(struct config *config) { struct pool *p = pool_create(4096); struct session *session = pool_alloc(p, sizeof(struct session)); time_t now = time(NIL); memset(session, 0, sizeof(struct session)); session->pool = p; session->config = config; /* Set up log files */ session->accesslog = log_create(config, p); session->sessionlog = log_create(config, p); session_log_open(session); /* General session stuff */ session->debug = NIL; session->want_disconnect = NIL; string_strdup(&session->dir_filter, ""); /* Directory filter */ session->username = ""; /* No username yet */ session->password = ""; /* No password yet */ session->newpassword = NIL; /* No new password yet */ session->last_cmd = memblock_create(p, 128); /* Last cmd string */ session->last_help = memblock_create(p, 128); /* Help cmd string */ /* Seed connections to support servers */ session->account = account_create(p, session); session->sieve = sieve_create(p, session); session->use_sieve = NIL; /* Location of servers */ session->imapd_server = NIL; session->accountd_server = NIL; session->accountd_nis_server = NIL; /* Persistent session state */ session->rename_foldername = NIL; /* Name of folder to be renamed */ session->aggregate = NIL; /* Aggregate operation */ session->reply_all = NIL; /* Reply to all */ session->half_filter = NIL; /* Half build filter item */ session->upload_name = NIL; /* Name for folder upload */ session->upload_file = NIL; /* Temp file for folder upload */ session->abook_compose_name = NIL; /* Name and address for */ session->abook_compose_email = NIL; /* Abook compose option */ session->help_enabled = NIL; /* Help text enabled */ session->help_toolbar = NIL; /* Toolbar Help text enabled */ session->recips_count_session = 0; /* Running total to spot phishers */ session->sending_allow = NIL; /* Whitelist to override: */ session->sending_block = NIL; /* Shut down compromised accounts */ session->telemetry = NIL; /* Telemetry information */ session->telemetry_all = NIL; session->telemetry_fd = -1; /* HTTP Connection stuff, including request/response */ session->request = NIL; /* No request yet */ session->ipaddr = ipaddr_create(p); /* Record IP address of client */ session->frontend_pid = 0; /* PID of frontend process */ session->sequence = 0; /* Sequence number */ session->sequence_last_change = 0; /* of last folder change */ session->sequence_okay = T; session->use_ssl = NIL; session->frontend_port = 0L; /* Set up by active session */ session->session_port = 0L; session->is_direct = NIL; session->url_prefix = ""; session->url_prefix_icons = ""; session->url_prefix_asession = ""; session->url_prefix_bsession = ""; session->url_prefix_short = ""; session->url_prefix_session = ""; session->sessionid = ""; /* User Interface stuff */ session->use_cookie = NIL; /* Until we know better */ session->use_short = NIL; /* Until we know better */ session->use_gzip = T; /* Until we know better */ session->abook_parent_cmd = "list"; /* Parent cmd for abook stuff */ session->compose_parent_cmd = "list"; /* Parent cmd for compose */ session->take_parent_cmd = "display"; /* Parent cmd for abook_take */ session->copy_parent_cmd = "list"; /* Parent cmd for copy */ session->compose_large = NIL; /* Large compose window */ session->full_hdrs = NIL; /* Show full hdrs */ /* Define main and help themes */ session->theme_main = config->theme_main; session->theme_help = config->theme_help; /* Set up for each new action */ session->template_vals = NIL; /* Folder stuff */ session->personal_hierarchy = config->personal_hierarchy; session->hiersep = config->hiersep; session->foldername = pool_strdup(NIL, "INBOX"); /* Name of current mail folder */ session->other_foldername = NIL; /* Name of "other" mail folder */ session->draft_foldername = NIL; /* Name of "draft" mail folder */ session->stream = NIL; /* Mail stream */ session->inbox_stream = NIL; /* Inbox stream */ session->other_stream = NIL; /* Other stream */ session->draft_stream = NIL; /* Draft stream */ session->prefs_stream = NIL; /* Preferences stream */ session->xfer_stream = NIL; /* Transfer stream */ session->inbox_last_ping_time = now; /* Record current time */ session->other_last_ping_time = now; /* Record current time */ session->draft_last_ping_time = now; /* Record current time */ session->prefs_last_ping_time = now; /* Record current time */ session->xfer_last_ping_time = now; /* Record current time */ session->current = 0L; /* Current message */ session->last_displayed = 0L; /* Last message displayed */ session->zm = msgmap_create(p); /* Zoommap */ session->message = memblock_create(p, 64); /* Feedback message */ session->message_isalert = NIL; session->options = options_create(config, p); /* Set up default options */ session->lookup = lookup_create(session, p); /* List of mailboxes */ session->folderlist = folderlist_create(config->hiersep); session->speller = speller_create(p); /* Spell check */ session->draft = draft_create(session); /* Draft message */ session->draft0 = draft_create(session); /* Previous Draft message */ session->ua_initial = user_agent_create(p); /* Initial User agent config */ session->user_agent = user_agent_create(p); /* User agent config */ return (session); } /* ====================================================================== */ /* session_free() ******************************************************** * * Free session and all subsiduary structures. ***********************************************************************/ void session_free(struct session *session) { log_free(session->accesslog); log_free(session->sessionlog); session_streams_close(session); string_free((void **) &session->dir_filter); memblock_free(session->last_cmd); memblock_free(session->last_help); account_free(session->account); sieve_free(session->sieve); string_free((void **) &session->rename_foldername); if (session->half_filter) filter_free(session->half_filter); if (session->upload_file) { unlink(session->upload_file); string_free((void **) &session->upload_file); } string_free((void **) &session->upload_name); string_free((void **) &session->abook_compose_name); string_free((void **) &session->abook_compose_email); if (session->request) request_free(session->request); string_free((void **) &session->foldername); string_free((void **) &session->other_foldername); string_free((void **) &session->draft_foldername); msgmap_free(session->zm); memblock_free(session->message); options_free(session->options); lookup_free(session->lookup); folderlist_free(session->folderlist); speller_free(session->speller); draft_free(session->draft); draft_free(session->draft0); user_agent_free(session->user_agent); if (session->pool) pool_free(session->pool); } /* ====================================================================== */ /* XXX Should become redundant with templates */ /* session_update_sequence() ******************************************** * * Update various url_prefixes with correct sequence signature. ***********************************************************************/ void session_update_sequence(struct session *session) { struct request *request = session->request; struct pool *pool = (request) ? request->pool : NIL; unsigned char s[3]; unsigned char d[5]; char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-"; s[0] = (session->sequence >> 16) & 255; /* Bits 23->16 */ s[1] = (session->sequence >> 8) & 255; /* Bits 15->8 */ s[2] = (session->sequence) & 255; /* Bits 7->0 */ /* Quick (URL friendly) base64 encode of three byte sequence */ d[0] = v[s[0] >> 2]; d[1] = v[((s[0] << 4) + (s[1] >> 4)) & 0x3f]; d[2] = v[((s[1] << 2) + (s[2] >> 6)) & 0x3f]; d[3] = v[s[2] & 0x3f]; d[4] = '\0'; session->url_prefix_bsession = pool_printf(pool, "%s/%s", session->url_prefix_asession, ((session->use_cookie) ? "" : session->sessionid)); session->url_prefix_short = pool_strdup(pool, (char *) d); session->url_prefix_session = pool_printf(pool, "%s/%s", session->url_prefix_bsession, (char *) d); } /* session_bump_sequence() ********************************************** * * Increase session sequence number. ***********************************************************************/ void session_bump_sequence(struct session *session) { session->sequence++; } /* session_extract_urlstate() ******************************************** * * Extract urlstate information used by the template system; ************************************************************************/ struct template_vals_urlstate * session_extract_urlstate(struct session *session) { struct template_vals_urlstate *urlstate = template_vals_urlstate_create(session->request->pool); urlstate->url_prefix_icons = session->url_prefix_icons; urlstate->url_prefix_bsession = session->url_prefix_bsession; urlstate->sequence = session->sequence; urlstate->use_short = session->use_short; return(urlstate); } /* session_seed_template() ********************************************* * * Seed gloval variables used by the template system. * ***********************************************************************/ void session_seed_template(struct session *session, struct template_vals *tvals) { struct config *config = session->config; struct prefs *prefs = session->options->prefs; struct favourite_list *fl = session->options->favourite_list; struct draft *draft = session->draft; struct config_theme *theme = session->theme_main; struct memblock *m = session->message; struct user_agent *user_agent = session->user_agent; char *msg = NIL; if ((memblock_size(m) > 0)) msg = memblock_data(m); if (session->help_enabled) { template_vals_ulong(tvals, "g_help", 1); theme = session->theme_help; } if (session->help_toolbar) template_vals_ulong(tvals, "g_help_toolbar", 1); template_vals_string(tvals, "g_user", session->username); if (config->login_service_name) template_vals_string(tvals, "g_service_name", config->login_service_name); if (config->dualuse) template_vals_ulong(tvals, "g_dualuse", 1); if (msg && msg[0]) { template_vals_string(tvals, "g_status", msg); if (session->message_isalert) template_vals_ulong(tvals, "g_status_alert", 1); } session_message_clear(session); if (user_agent->use_icons) template_vals_ulong(tvals, "g_use_icons", 1); if (draft->have_draft) template_vals_ulong(tvals, "g_have_draft", 1); template_vals_string(tvals, "g_alt_pad", "    "); template_vals_hash_string(tvals, "g_theme", "name", theme->name); template_vals_hash_string(tvals, "g_theme", "description", theme->description); template_vals_hash_string(tvals, "g_theme", "fgcolor", theme->fgcolor); template_vals_hash_string(tvals, "g_theme", "fgcolor_link", theme->fgcolor_link); template_vals_hash_string(tvals, "g_theme", "bgcolor", theme->bgcolor); template_vals_hash_string(tvals, "g_theme", "bgcolor_banner", theme->bgcolor_banner); template_vals_hash_string(tvals, "g_theme", "bgcolor_row1", theme->bgcolor_row1); template_vals_hash_string(tvals, "g_theme", "bgcolor_row2", theme->bgcolor_row2); template_vals_hash_string(tvals, "g_theme", "bgcolor_status", theme->bgcolor_status); template_vals_hash_string(tvals, "g_theme", "bgcolor_status_none", theme->bgcolor_status_none); template_vals_hash_string(tvals, "g_theme", "fgcolor_quote1", theme->fgcolor_quote1); template_vals_hash_string(tvals, "g_theme", "fgcolor_quote2", theme->fgcolor_quote2); template_vals_hash_string(tvals, "g_theme", "fgcolor_quote3", theme->fgcolor_quote3); template_vals_hash_string(tvals, "g_theme", "fgcolor_quote4", theme->fgcolor_quote4); folderlist_template_vals_list(folderlist_fetch(session), prefs->suppress_dotfiles, tvals, NIL, "@g_mailbox_list"); favourite_template_vals(fl, tvals, "@g_favourites"); template_vals_string(tvals, "$g_preferred", fl->preferred); } /* ====================================================================== */ /* session_make_id() **************************************************** * * Make (crypographically secure) unique session identifier for this * login session. Recorded as session->sessionid. ***********************************************************************/ static void session_make_id(struct session *session) { struct pool *pool = session->pool; struct config *config = session->config; unsigned long srcl = 18; unsigned char *raw; char *encode; unsigned char *s; unsigned char *d; struct ssl_config ssl_config; char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; srcl = (config->session_key_len) ? config->session_key_len : 18; raw = pool_alloc(pool, srcl); encode = pool_alloc(pool, 10 + (srcl * 4) / 3); config_extract_ssl(config, &ssl_config); if (!os_random(&ssl_config, raw, srcl)) { log_fatal("Couldn't read %lu bytes from random number generator", srcl); /* NOTREACHED */ exit(1); } /* Encode binary data to URL friendly form */ s = raw; d = (unsigned char *) encode; while (srcl) { *d++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */ /* byte 2: low 2 bits (1), high 4 bits (2) */ *d++ = v[((s[0] << 4) + (--srcl ? (s[1] >> 4) : 0)) & 0x3f]; /* byte 3: low 4 bits (2), high 2 bits (3) */ *d++ = srcl ? v[((s[1] << 2) + (--srcl ? (s[2] >> 6) : 0)) & 0x3f] : '='; /* byte 4: low 6 bits (3) */ *d++ = srcl ? v[s[2] & 0x3f] : '='; if (srcl) srcl--; /* count third character if processed */ s += 3; /* process tuplets */ } *d = '\0'; session->sessionid = (char *) encode; } /* ====================================================================== */ static void session_setup_namespace(struct session *session) { MAILSTREAM *stream = session->stream; NAMESPACE ***namespacep = mail_parameters(stream, GET_NAMESPACE, NULL); if (namespacep && *namespacep && **namespacep) { NAMESPACE *ns = **namespacep; if (ns->name && ns->name[0]) session->personal_hierarchy = ns->name; if (ns->delimiter) session->hiersep = pool_printf(NIL, "%c", ns->delimiter); } } /* ====================================================================== */ /* NB: session_setup_urls() called at least three times for normal direct * login: Initial, session_inet and user preferences setup. malloc/free * might be better than pool_alloc(session->pool, ...). However its is * only a few bytes that we are talking about here... */ /* session_setup_urls() ************************************************* * * Setup session URLs to correspond to current internal state. Includes * some ghastly magic to include user agent preference overrides in * icon links. ***********************************************************************/ void session_setup_urls(struct session *session) { struct config *config = session->config; struct user_agent *user_agent = session->user_agent; struct pool *p = session->pool; char *icon_opts; char *quoted_user; unsigned long pid = (unsigned long)getpid(); if (user_agent->manual) { struct buffer *b = buffer_create(p, 128); bputs(b, "/opts="); if (user_agent->use_http_1_1) bputs(b, "http_1.1,"); if (user_agent->use_persist) bputs(b, "persist,"); if (user_agent->use_pipelining) bputs(b, "pipelining,"); if (user_agent->use_telemetry_frontend) bputs(b, "telemetry_frontend,"); if (buffer_size(b) > strlen("/opts=")) icon_opts = buffer_fetch(b, 0, buffer_size(b) - 1, NIL); else icon_opts = "/opts="; } else icon_opts = ""; /* Time to define some URLs for this session */ /* Base URL: route back to the login screen */ if (session->use_ssl) { if (session->frontend_port == 443) session->url_prefix = pool_printf(p, "https://%s", config->hostname); else session->url_prefix = pool_printf(p, "https://%s:%d", config->hostname, session->frontend_port); } else { if (session->frontend_port == 80) session->url_prefix = pool_printf(p, "http://%s", config->hostname); else session->url_prefix = pool_printf(p, "http://%s:%d", config->hostname, session->frontend_port); } /* Set up appropriate url_icon_prefix */ session->url_prefix_icons = pool_printf(p, "/icons%s", icon_opts); quoted_user = string_url_encode(p, session->username); /* url_prefix_asession: root for session URLs */ if (session->use_ssl) { if (session->session_port == 443) session->url_prefix_asession = pool_printf(p, "https://%s/session/%s:%lu", config->hostname, quoted_user, pid); else session->url_prefix_asession = pool_printf(p, "https://%s:%d/session/%s:%lu", config->hostname, session->session_port, quoted_user, pid); } else { if (session->session_port == 80) session->url_prefix_asession = pool_printf(p, "http://%s/session/%s:%lu", config->hostname, quoted_user, pid); else session->url_prefix_asession = pool_printf(p, "http://%s:%d/session/%s:%lu", config->hostname, session->session_port, quoted_user, pid); } /* Calculate url_prefix_bsession and url_bsession */ /* NB: Stored in request->pool as updated on each interaction */ session_update_sequence(session); } /* ====================================================================== */ /* A couple of utility routines to extract a string from a comma delimited list e.g: imapd_server = "red, orange, yellow" */ static unsigned long session_server_list_count(char *s) { char c; unsigned long count = 1; while ((c = *s++)) { if (c == ',') count++; } return (count); } static char *session_server_list_select(char *s, unsigned long offset) { char *next; while (offset > 0) { if ((s = strchr(s, ',')) == NIL) return (NIL); s++; offset--; } next = strchr(s, ','); if (next) *next = '\0'; return (string_trim_whitespace(s)); } /* ====================================================================== */ /* session_server_location() ******************************************** * * Derive location of imapd and accountd servers for this user and login * session. Includes CDB database lookups, $user expansion and random * selection from list of possible servers. * * Returns: T if all expansion completed sucessfully. NIL on error. ***********************************************************************/ static BOOL session_server_location(struct session *session) { struct config *config = session->config; char *username = session->username; void *cdb; char *value; session->imapd_server = NIL; session->accountd_server = NIL; session->accountd_nis_server = config->accountd_nis_server; /* Define imapd server location */ if (config->imapd_user_map && config->imapd_user_map[0]) { if (!(cdb = cdb_open(config->imapd_user_map))) { log_panic("Couldn't open imapd user map file: %s\n", config->imapd_user_map); return (NIL); } if (cdb_find(cdb, username, strlen(username), &value)) { session->imapd_server = pool_strdup(session->pool, value); free(value); } cdb_close(cdb); } if (session->imapd_server == NIL) session->imapd_server = config->imapd_server; /* Some ghastly magic to select single IMAP server at random from list * of servers (for multi-ported hosts) if provided */ if (session->imapd_server && strchr(session->imapd_server, ',')) { unsigned long count = session_server_list_count(session->imapd_server); char *source = pool_strdup(session->pool, session->imapd_server); unsigned long offset; /* offset doesn't have to be random, but should be well distributed */ offset = ((unsigned long) getpid() + (unsigned long) time(NIL)) % count; session->imapd_server = session_server_list_select(source, offset); if (session->imapd_server == NIL) { /* Shouldn't be possible! */ log_panic ("[session_server_location(): Invalid offset into list!"); return (NIL); } } /* Define accountd server location */ if (config->accountd_user_map && config->accountd_user_map[0]) { if (!(cdb = cdb_open(config->accountd_user_map))) { log_panic("Couldn't open accountdd user map file: %s\n", config->accountd_user_map); return (NIL); } if (cdb_find(cdb, username, strlen(username), &value)) { session->accountd_server = pool_strdup(session->pool, value); free(value); } cdb_close(cdb); } if (session->accountd_server == NIL) session->accountd_server = config->accountd_server; /* Some ghastly magic to select single Accountd server at random from list * of servers (for multi-ported hosts) if provided */ if (session->accountd_server && strchr(session->accountd_server, ',')) { unsigned long count = session_server_list_count(session->accountd_server); char *source = pool_strdup(session->pool, session->accountd_server); unsigned long offset; /* offset doesn't have to be random, but should be well distributed */ offset = ((unsigned long) getpid() + (unsigned long) time(NIL)) % count; session->accountd_server = session_server_list_select(source, offset); if (session->accountd_server == NIL) { /* Shouldn't be possible! */ log_panic ("[session_server_location(): Invalid offset into list!"); return (NIL); } } /* Define sieved server location */ if (config->sieved_user_map && config->sieved_user_map[0]) { if (!(cdb = cdb_open(config->imapd_user_map))) { log_panic("Couldn't open imapd user map file: %s\n", config->imapd_user_map); return (NIL); } if (cdb_find(cdb, username, strlen(username), &value)) { session->sieved_server = pool_strdup(session->pool, value); free(value); } cdb_close(cdb); } if (session->sieved_server == NIL) session->sieved_server = config->sieved_server; /* Some ghastly magic to select single Sieved server at random from list * of servers (for multi-ported hosts) if provided */ if (session->sieved_server && strchr(session->sieved_server, ',')) { unsigned long count = session_server_list_count(session->sieved_server); char *source = pool_strdup(session->pool, session->sieved_server); unsigned long offset; /* offset doesn't have to be random, but should be well distributed */ offset = ((unsigned long) getpid() + (unsigned long) time(NIL)) % count; session->sieved_server = session_server_list_select(source, offset); if (session->sieved_server == NIL) { /* Shouldn't be possible! */ log_panic ("[session_server_location(): Invalid offset into list!"); return (NIL); } } if (session->sieved_server) session->use_sieve = T; else session->use_sieve = NIL; /* Expand $user prefix in imapd_server and accountd_server */ if (session->imapd_server) { if (!strncmp(session->imapd_server, "$user", strlen("$user"))) session->imapd_server = pool_strcat(session->pool, username, session->imapd_server + strlen("$user")); else if (!strncmp(session->imapd_server, "${user}", strlen("${user}"))) session->imapd_server = pool_strcat(session->pool, username, session->imapd_server + strlen("${user}")); } if (session->accountd_server) { if (!strncmp(session->accountd_server, "$user", strlen("$user"))) session->accountd_server = pool_strcat(session->pool, username, session->accountd_server + strlen("$user")); else if (!strncmp (session->accountd_server, "${user}", strlen("${user}"))) session->accountd_server = pool_strcat(session->pool, username, session->accountd_server + strlen("${user}")); } return (T); } /* ======================================================================*/ /* session_mailbox_prefs() ********************************************** * * Returns c-client format mailbox specifier for the preferences folder. * Can't use session_mailbox() as we don't want this file floating aroun * if maildir changes. * session: * pool: Scratch pool (typically request->pool) * folder: Name of folder. ***********************************************************************/ char *session_mailbox_prefs(struct session *session, struct pool *pool) { char *name = session->config->prefs_folder_name; return (pool_printf(pool, "{%s}%s", session->imapd_server, name)); } /* session_mailbox() **************************************************** * * Convert folder name into c-client format mailbox specifier. * session: * pool: Scratch pool (typically request->pool) * folder: Name of folder. ***********************************************************************/ char *session_mailbox(struct session *session, struct pool *pool, char *folder) { return (pool_printf(pool, "{%s}%s", session->imapd_server, folder)); } /* session_dir() ******************************************************** * * Convert directory name into c-client format directory specifier. * session: * pool: Scratch pool (typically request->pool) * dir: Name of directory. ***********************************************************************/ char *session_dir(struct session *session, struct pool *pool, char *dir) { char *hiersep = session->hiersep; return (pool_printf(pool, "{%s}%s%s", session->imapd_server, dir, hiersep)); } /* ====================================================================== */ /* session_login() ****************************************************** * * Attempt session login. Sucessful login will set up all aspects of the * session structure ready for initial exchange. * session: * username: Username provided by prayer frontend process * password: Password provided by prayer frontend process * port: HTTP port used by login request * use_ssl: SSL enabled in login request? * ua_options: User Agent configuration defined by browser + overrides * ipaddr: IP address of browser. Record for later security. * * Returns: T => Login successful, session primed. * NIL => Login failed. Reason may be recorded in session_log ***********************************************************************/ BOOL session_login(struct session * session, char *username, char *password, unsigned long port, BOOL use_ssl, char *ua_options, struct ipaddr * ipaddr) { struct pool *p = session->pool; struct config *config = session->config; struct user_agent *user_agent = session->user_agent; /* Setup for sucessful login, so client routines can use session */ session->username = pool_strdup(p, username); /* Username */ session->password = pool_strdup(p, password); /* Password */ ml_clear_error(); if (!session_server_location(session)) return (NIL); if (!(session->imapd_server && session->imapd_server[0])) { /* Can't map this account onto a backend server */ /* Probably a typo in the username, so fake a login faked */ sleep(3); ml_set_errmsg("Login incorrect"); ml_set_error(); return(NIL); } if (!strcmp(session->imapd_server, "DEFER")) { ml_set_errmsg("Account undergoing maintenance. " "Please try again in a few minutes."); ml_set_error(); return (NIL); } /* Authenicate against the IMAP server */ session->stream = ml_open(session, NIL, session_mailbox_prefs(session, NIL), OP_HALFOPEN); if (!session->stream) return (NIL); ipaddr_copy(session->ipaddr, ipaddr); /* Use gzip encoding in thie session? */ if (config->gzip_allow_nets && ipaddr_compare_list(ipaddr, config->gzip_allow_nets)) session->use_gzip = T; else if (config->gzip_deny_nets && ipaddr_compare_list(ipaddr, config->gzip_deny_nets)) session->use_gzip = NIL; else session->use_gzip = T; session->inbox_stream = session->stream; session->use_ssl = use_ssl; session->frontend_port = port; session->session_port = port; user_agent_parse(session->ua_initial, ua_options); user_agent_copy(session->user_agent, session->ua_initial); if (config->use_namespace) session_setup_namespace(session); session_make_id(session); session_setup_urls(session); if ((user_agent->use_telemetry || user_agent->use_telemetry_all) && config && config->tmp_dir && config->tmp_dir[0]) { int open_perms = ((config && config->file_perms) ? config->file_perms : 0644); char *name = pool_printf(NIL, "%s/telemetry-%s:%lu", config->tmp_dir, session->username, (unsigned long) getpid()); int fd = open(name, O_CREAT | O_TRUNC | O_APPEND | O_WRONLY, open_perms); if (fd >= 0) { session->telemetry_fd = fd; session->telemetry = T; session->telemetry_all = user_agent->use_telemetry_all; } free(name); } return (T); } /* ====================================================================== */ /* Small utility routine */ /* Translate single character from pseudo-BASE64 to int in range 0->63 */ static int session_translate_char(char c) { if ((c >= 'A') && (c <= 'Z')) return (c - 'A'); if ((c >= 'a') && (c <= 'z')) return ((c - 'a') + 26); if ((c >= '0') && (c <= '9')) return ((c - '0') + 26 + 26); if (c == '.') return (62); if (c == '-') return (63); return (0); } /* session_sequence() **************************************************** * * Convert session sequence string into number for comparison purposes * seqno: Sequence string to convert * * Returns: Equivalent number ************************************************************************/ unsigned long session_sequence(char *seqno) { unsigned char s[4]; unsigned long result; if ((seqno == NIL) || (strlen(seqno) != 4)) return (0L); /* Convert to four bytes in the range 0:63 (i.e: 6 bits in each byte) */ s[0] = (unsigned char) session_translate_char(seqno[0]); s[1] = (unsigned char) session_translate_char(seqno[1]); s[2] = (unsigned char) session_translate_char(seqno[2]); s[3] = (unsigned char) session_translate_char(seqno[3]); /* Squeeze into single 24 bit result and return */ result = (((unsigned long) s[0]) << 18); result += (((unsigned long) s[1]) << 12); result += (((unsigned long) s[2]) << 6); result += (((unsigned long) s[3])); return (result); } /* ====================================================================== */ /* session_use_prefs() *************************************************** * * Apply user preferences to login session * session: * p: User preferences, passed as (void *) to break circular loop. * initial: Initial setup ************************************************************************/ void session_use_prefs(struct session *session, void *p, BOOL initial) { struct config *config = session->config; struct prefs *prefs = (struct prefs *) p; struct request *request = session->request; struct user_agent *ua_request = user_agent_create(request->pool); struct user_agent *ua_initial = session->ua_initial; struct user_agent *user_agent = session->user_agent; if (session->draft_foldername) free(session->draft_foldername); if (prefs->maildir && prefs->maildir[0]) session->draft_foldername = pool_strcat3(NIL, prefs->maildir, session->hiersep, prefs->postponed_folder); else session->draft_foldername = strdup(prefs->postponed_folder); /* Reset session->user_agent to known state before we mask off features */ user_agent_copy(session->user_agent, session->ua_initial); if (!user_agent->use_override) { /* Disable features, unless preferences and ua_initial agree */ user_agent->use_icons = (ua_initial->use_icons && prefs->use_icons); user_agent->use_cookie = (ua_initial->use_cookie && prefs->use_cookie); user_agent->use_substitution = (ua_initial->use_substitution && prefs->use_substitution); user_agent->use_http_1_1 = (ua_initial->use_http_1_1 && prefs->use_http_1_1); user_agent->use_pipelining = (ua_initial->use_pipelining && prefs->use_pipelining); user_agent->use_persist = (ua_initial->use_persist && prefs->use_persist); user_agent->use_short = (ua_initial->use_short && prefs->use_short); user_agent->use_gzip = (ua_initial->use_gzip && prefs->use_gzip); } /* Setup vanilla user_agent for browser to compare against */ user_agent_setup_browser(ua_request, assoc_lookup(request->hdrs, "user-agent")); /* If following options are allowed by browser but not by negotiated values then we need to force manual override at frontend */ if ((user_agent->use_http_1_1 != ua_request->use_http_1_1) || (user_agent->use_pipelining != ua_request->use_pipelining) || (user_agent->use_persist != ua_request->use_persist) || (user_agent->use_pipelining != ua_request->use_pipelining) || (ua_initial->use_telemetry_frontend)) user_agent->manual = T; else user_agent->manual = NIL; if (initial) { session->use_short = (ua_initial->use_short && prefs->use_short); } /* Frontend URLs may have changed */ session_setup_urls(session); msgmap_sort_mode(session->zm, prefs->sort_mode); if (prefs->sort_reverse) msgmap_sort_reverse_enable(session->zm); else msgmap_sort_reverse_disable(session->zm); abook_set_sort(session->options->abook, prefs->abook_sort_mode, prefs->abook_sort_reverse); /* Initialise themes */ session->theme_main = (struct config_theme *) list_lookup_byname(config->theme_list, prefs->theme_main_name); session->theme_help = (struct config_theme *) list_lookup_byname(config->theme_list, prefs->theme_help_name); /* Catch invalid theme names... */ if (!session->theme_main) session->theme_main = config->theme_main; if (!session->theme_help) session->theme_help = config->theme_help; } /* ====================================================================== */ /* session_make_redirect() *********************************************** * * Generate HTTP redirect relative to URL prefix. Used if page * substitution is disabled and when we want to force a redirect. * session: * request: Current HTTP request * location: Target for redirect. ************************************************************************/ void session_make_redirect(struct session *session, struct request *request, char *location) { char *url = pool_strcat(request->pool, session->url_prefix, location); response_redirect(request, url); } /* ====================================================================== */ /* session_make_session_redirect() *************************************** * * Generate HTTP redirect relative to session URL. Used if page * substitution is disabled and when we want to force a redirect. * session: * request: Current HTTP request * cmd: Target for redirect. ************************************************************************/ void session_make_session_redirect(struct session *session, struct request *request, char *cmd) { char *url = pool_strcat3(request->pool, session->url_prefix_session, "/", cmd); if (session->use_short) { unsigned char *s = (unsigned char *) url + strlen(session->url_prefix_session); while (*s) { if (*s == '/') *s = '@'; s++; } } response_redirect(request, url); } /* session_make_session_cookie_redirect() ******************************** * * Generate HTTP redirect relative to session URL. Send a session cookie * (username=sessionid) or (username:port=sessionid) at the same time. * session: * request: Current HTTP request * cmd: Target for redirect. ************************************************************************/ void session_make_session_cookie_redirect(struct session *session, struct request *request, char *cmd) { struct config *config = session->config; char *url = pool_strcat3(request->pool, session->url_prefix_session, "/", cmd); unsigned long pid = (unsigned long)getpid(); char *path = pool_printf(request->pool, "/session/%s:%lu", session->username, pid); char *key; if (session->use_short) { unsigned char *s = (unsigned char *) url + strlen(session->url_prefix_session); while (*s) { if (*s == '/') *s = '@'; s++; } } key = pool_printf(request->pool, "%s:%lu", session->username, pid); response_cookie_redirect(request, url, key, session->sessionid, path, config->hostname, session->use_ssl); } /* session_make_session_clear_cookie_redirect() ************************** * * Generate HTTP redirect relative to session URL. Clears session cookie * (username=sessionid) or (username:port=sessionid) at the same time. * session: * request: Current HTTP request * cmd: Target for redirect. ************************************************************************/ void session_make_session_clear_cookie_redirect(struct session *session, struct request *request, char *cmd) { struct config *config = session->config; unsigned long pid = (unsigned long)getpid(); char *url = pool_strcat3(request->pool, session->url_prefix_session, "/", cmd); char *path = pool_printf(request->pool, "/session/%s:%lu", session->username, pid); char *key; key = pool_printf(request->pool, "%s:%lu", session->username, pid); response_clear_cookie_redirect(request, url, key, session->sessionid, path, config->hostname, session->use_ssl); } /* ====================================================================== */ /* session_redirect() *************************************************** * * Redirect session either as transparent page substiution or HTTP redirect * exchange with browser. (Depends on use_substitution option). * session: * request: Current HTTP request * url: Target URL ***********************************************************************/ void session_redirect(struct session *session, struct request *request, char *url) { BOOL cmd_dispatch(struct session *session, char *text); /* Make sure that msgno and msguid included in any list/display redirect * makes browser history work much better... */ if (!strcmp(url, "list") && (session->stream != NULL)) { unsigned long msgno = session->current; unsigned long msguid = ml_uid(session, session->stream, msgno); url = pool_printf(request->pool, "list/%lu/%lu", msgno, msguid); } else if (!strcmp(url, "display") && (session->stream != NULL)) { unsigned long msgno = session->current; unsigned long msguid = ml_uid(session, session->stream, msgno); url = pool_printf(request->pool, "display/%lu/%lu", msgno, msguid); } if (!session->user_agent->use_substitution) { session_make_session_redirect(session, request, url); return; } session_log(session, "[session_redirect] %s", url); request_forge_redirect(request, url); /* Look for defined session method in redirect */ if (!cmd_dispatch(session, request->argv[0])) response_error(request, 404); } /* ====================================================================== */ /* session_message() **************************************************** * * Record a status message that will be displayed to user at next * opportunity. * session: * fmt: Format string, followed by additional arguments a la printf * ***********************************************************************/ void session_message(struct session *session, char *fmt, ...) { struct memblock *m = session->message; va_list ap; unsigned long size; char *t; if (memblock_size(m) > 0) { if ((t = memblock_data(m)) && (t[0] != '\0')) return; } va_start(ap, fmt); size = memblock_vprintf_size(m, fmt, ap); va_end(ap); memblock_resize(m, size + 1); va_start(ap, fmt); memblock_vprintf(m, fmt, ap); va_end(ap); session->message_isalert = NIL; } /* session_message_clear() *********************************************** * * Clear out existing session message ************************************************************************/ void session_message_clear(struct session *session) { struct memblock *m = session->message; mputs(m, ""); session->message_isalert = NIL; } /* session_alert() ****************************************************** * * Record a status message that will be displayed to user at next * opportunity. Flag this as an "alert" message which will be highlighted. * session: * fmt: Format string, followed by additional arguments a la printf * ***********************************************************************/ void session_alert(struct session *session, char *fmt, ...) { struct memblock *m = session->message; va_list ap; unsigned long size; char *t; if (memblock_size(m) > 0) { if ((t = memblock_data(m)) && (t[0] != '\0')) return; } va_start(ap, fmt); size = memblock_vprintf_size(m, fmt, ap); va_end(ap); memblock_resize(m, size + 1); va_start(ap, fmt); memblock_vprintf(m, fmt, ap); va_end(ap); session->message_isalert = T; } /* ====================================================================== */ /* session_record_last_cmd() ******************************************** * * Record current command so we know where we are on redisplay event. * session: * last_cmd: Command to record. * ***********************************************************************/ void session_record_last_cmd(struct session *session, char *last_cmd) { memblock_puts(session->last_cmd, last_cmd); } /* session_last_cmd() *************************************************** * * Retrieve last recorded command ***********************************************************************/ char *session_last_cmd(struct session *session) { return (memblock_data(session->last_cmd)); } /* ====================================================================== */ /* Interface to log system */ void session_accesslog(struct session *session, struct request *request) { unsigned long size; log_record_peer_pid(session->accesslog, session->frontend_pid); if (request->gzip_buffer) size = buffer_size(request->gzip_buffer); else size = buffer_size(request->write_buffer); log_here(session->accesslog, "[%s] (%lu) %s -> %lu %lu %s", ipaddr_text(session->ipaddr), session->session_port, request->request, request->status, size, ((request->use_http_1_1) ? "1.1" : "1.0")); } void session_log(struct session *session, char *fmt, ...) { va_list ap; unsigned long len; struct pool *pool; if (session->request && session->request->pool) pool = session->request->pool; else pool = NIL; va_start(ap, fmt); len = log_entry_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_ap(session->sessionlog, pool, session->username, len, fmt, ap); va_end(ap); } /* Compatibility Interface to new fangled panic log system... */ void session_paniclog(struct session *session, char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = log_entry_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_panic_ap(session->config, session->username, len, fmt, ap); va_end(ap); } void session_fatal(struct session *session, char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = log_entry_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_panic_ap(session->config, session->username, len, fmt, ap); va_end(ap); abort(); } ./prayer-1.3.5/session/html_secure.h0000644006513000651300000000103311063701636015737 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/html_secure.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ void html_secure(struct session *session, struct buffer *b, BOOL show_images, char *input); void html_secure_strip_all(struct buffer *b, char *input); ./prayer-1.3.5/session/filter.h0000644006513000651300000000350511063701636014720 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/filter.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Data structures for Exim filter file support */ /* Types of filter that we support */ typedef enum { FILTER_UNKNOWN, FILTER_SENDER, FILTER_RECIPIENT, FILTER_SUBJECT, FILTER_BLOCK } FILTER_TYPE; struct filter { struct list_item hdr; /* Linked list */ FILTER_TYPE type; /* Type of filter */ char *local_part; /* For SENDER/RECIPIENT/BLOCK type */ char *domain; /* For SENDER/RECIPIENT/BLOCK type */ char *subject; /* For SUBJECT type */ char *mailbox; /* For SENDER/RECIPIENT/SUBJECT type */ BOOL copy; /* For SENDER/RECIPIENT/SUBJECT type */ }; struct filter *filter_alloc(void); void filter_free(struct filter *filter); void filter_set_type(struct filter *filter, FILTER_TYPE type); void filter_set_local_part(struct filter *filter, char *local_part); void filter_set_domain(struct filter *filter, char *domain); void filter_set_subject(struct filter *filter, char *subject); void filter_set_mailbox(struct filter *filter, char *mailbox); void filter_set_copy(struct filter *filter, BOOL copy); BOOL filter_set_addr(struct filter *filter, struct session *session, char *addr); BOOL filter_test_addr(struct filter *filter, struct session *session, char *addr); void filter_print(struct filter *filter, struct buffer *b); BOOL filter_sieve_print(struct filter *filter, struct buffer *b); void filter_strip8bit(struct filter *filter); ./prayer-1.3.5/session/folderlist.c0000644006513000651300000005150011247173474015602 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/folderlist.c,v 1.7 2009/09/01 10:28:12 dpc22 Exp $ */ /* folderlist caches the mailboxlist used on the server */ #include "prayer_session.h" /* ====================================================================== */ static struct folderitem * folderitem_create(struct pool *pool, char *name) { struct folderitem *result = pool_alloc(pool, sizeof(struct folderitem)); result->next = NIL; result->next = NIL; result->child = NIL; result->name = pool_strdup(pool, name); result->noselect = NIL; result->noinferiors = T; result->haschildren = T; /* Assume true until server tells us otherwise */ result->expanded = NIL; result->size = 0L; return (result); } /* ====================================================================== */ /* Set of routines for creating a folderlist using c-client callbacks */ /* Callback routine that c-client calls when generating a directory list */ static struct { struct pool *pool; BOOL toplevel; char hiersep; struct folderitem *inbox; struct folderitem *first; struct folderitem *last; unsigned long count; char *prefix; unsigned long prefix_length; } callback; static void folderlist_callback(MAILSTREAM * stream, int delimiter, char *name, long attributes) { struct pool *pool = callback.pool; struct folderitem *fi; struct folderitem *last, *current; size_t namelen; callback.count++; if (callback.prefix && callback.prefix[0]) { if (strncmp(name, callback.prefix, callback.prefix_length) != 0) return; /* Didn't match prefix */ name += callback.prefix_length; } /* UW and Dovecot return placeholder for directory when running * . list "mail/" % * * LIST (\NoSelect \HasChildren) "/" mail/ * * LIST (\NoInferiors \UnMarked) "/" mail/gg * * Cyrus does not. * * IMAP specification is ambiguous: '%' matches zero or more * characters, but example in RFC 3501 matches Cyrus result. * * Need to skip the placeholder line if present. */ namelen = strlen(name); if ((namelen > 0) && name[namelen-1] == callback.hiersep) return; if (*name == '\0') return; /* Empty name */ fi = folderitem_create(pool, name); fi->noselect = (attributes & LATT_NOSELECT) ? T : NIL; fi->noinferiors = (attributes & LATT_NOINFERIORS) ? T : NIL; fi->haschildren = (attributes & (LATT_NOINFERIORS|LATT_HASNOCHILDREN)) ? NIL: T; /* Handle inbox at the end to make sorting easier */ if (callback.toplevel && (!strcmp(name, "INBOX"))) { callback.inbox = fi; return; } /* Add to end of the list if definitely at the end */ if (callback.last && strcmp(callback.last->name, name) < 0) { callback.last = callback.last->next = fi; return; } if (!callback.first) { /* New list */ fi->next = NIL; callback.first = fi; callback.last = fi; return; } if (strcmp(callback.first->name, name) > 0) { /* Insert at head of list */ fi->next = callback.first; callback.first = fi; return; } last = callback.first; current = last->next; while (current && (strcmp(current->name, name) < 0)) { last = current; current = current->next; } if (current) { /* Insert in middle of list */ fi->next = current; last->next = fi; } else { /* Insert at end of list */ fi->next = NIL; callback.last = last->next = fi; } } void folderlist_expand(struct session *session, struct folderitem *fi) { struct folderlist *fl = session->folderlist; MAILSTREAM *stream = session->stream; char *prefix = NIL; char *s; if (fi->child) return; prefix = session_dir(session, fl->pool, fi->name); s = strchr(prefix, '}'); callback.prefix = prefix; callback.prefix_length = (s) ? (s+1-prefix) : 0; /* Skip {machine} */ callback.pool = fl->pool; callback.first = NIL; callback.last = NIL; callback.count = 0; callback.toplevel = NIL; callback.hiersep = fl->hiersep; callback.inbox = NIL; mm_register_list_callback(folderlist_callback); if (!ml_list(session, stream, callback.prefix, "%")) return; fi->child = callback.first; fl->need_update = NIL; } static void folderlist_toplevel(struct session *session) { MAILSTREAM *stream = session->stream; struct prefs *prefs = session->options->prefs; struct folderlist *fl = session->folderlist; char *prefix; struct folderitem *fi; char *s; BOOL auto_expand_inbox = T; if (prefs->maildir && prefs->maildir[0]) { prefix = session_dir(session, fl->pool, prefs->maildir); auto_expand_inbox = NIL; } else prefix = session_mailbox(session, fl->pool, ""); s = strchr(prefix, '}'); callback.prefix = prefix; callback.prefix_length = (s) ? (s+1-prefix) : 0; /* Skip {machine} */ callback.pool = fl->pool; callback.first = NIL; callback.last = NIL; callback.count = 0; callback.toplevel = T; callback.hiersep = fl->hiersep; callback.inbox = NIL; mm_register_list_callback(folderlist_callback); if (!ml_list(session, stream, callback.prefix, "%")) return; fl->need_update = NIL; fl->tree = callback.first; if (auto_expand_inbox && callback.inbox) { /* Special handling for dual use inbox */ fi = callback.inbox; if (!fi->noinferiors) { fi->expanded = T; folderlist_expand(session, fi); } } else { /* Add inbox to start of tree */ fi = folderitem_create(fl->pool, "INBOX"); fi->noselect = NIL; fi->haschildren = NIL; } fi->next = fl->tree; fl->tree = fi; } /* ====================================================================== */ /* Public Interface */ struct folderlist * folderlist_create(char *hiersep) { struct pool *pool = pool_create(FOLDERLIST_PREFERRED_POOL_SIZE); struct folderlist *result = pool_alloc(pool, sizeof(struct folderlist)); result->pool = pool; result->tree = NIL; result->need_update = T; result->hiersep = (hiersep && hiersep[0]) ? hiersep[0] : '/'; return (result); } void folderlist_free(struct folderlist *fl) { pool_free(fl->pool); } static void folderlist_copy_expand(struct session *session, struct folderitem *new, struct folderitem *old) { while (old && new) { while (new && (strcmp(new->name, old->name) < 0)) new = new->next; if (new && !strcmp(old->name, new->name)) { new->expanded = NIL; if (old->expanded && new->haschildren) { new->expanded = T; folderlist_expand(session, new); if (old->child && new->child) folderlist_copy_expand(session, new->child, old->child); } new = new->next; } old = old->next; } } struct folderlist *folderlist_fetch(struct session *session) { struct folderlist *old = session->folderlist; struct folderlist *new; if (old && !old->need_update) return(old); session->folderlist = new = folderlist_create(session->hiersep); folderlist_toplevel(session); if (old) { folderlist_copy_expand(session, new->tree, old->tree); folderlist_free(old); } return(new); } static BOOL is_inferior(char *parent, char *name, char hiersep) { int len = strlen(parent); if (!strncmp(parent, name, len) && ((name[len] == hiersep) || (name[len] == '\0'))) return(T); return(NIL); } static struct folderitem * folderlist_lookup_work(struct folderitem *fi, char *name, char hiersep) { struct folderitem *result; while (fi) { /* Only recurse if match possible */ if (fi->child && is_inferior(fi->name, name, hiersep) && (result=folderlist_lookup_work(fi->child, name, hiersep))) return(result); if (!strcmp(fi->name, name)) return(fi); fi = fi->next; } return(NIL); } struct folderitem *folderlist_lookup(struct folderlist *fl, char *name) { return(folderlist_lookup_work(fl->tree, name, fl->hiersep)); } static void folderlist_expand_work(struct folderitem *fi, char *name, char hiersep) { while (fi) { /* Only recurse if match possible */ if (is_inferior(fi->name, name, hiersep)) { fi->expanded = T; if (fi->child) folderlist_expand_work(fi->child, name, hiersep); } fi = fi->next; } } static void folderlist_expand_parents(struct folderlist *fl, char *name) { folderlist_expand_work(fl->tree, name, fl->hiersep); } /* ====================================================================== */ static BOOL folderlist_update_sizes_single(struct folderitem *fi, MAILSTREAM *stream, struct session *session) { unsigned long msgno; MESSAGECACHE *elt; if (!ml_fetch_fast(session, stream, "1:*", 0)) return(NIL); fi->size = 0L; for (msgno = 1; msgno <= stream->nmsgs; msgno++) { if (!(elt = ml_elt(session, stream, msgno))) return (NIL); fi->size += elt->rfc822_size; } return(T); } static BOOL folderlist_update_sizes_work(struct folderitem *fi, MAILSTREAM **streamp, struct session *session) { struct pool *pool = session->request->pool; while (fi) { if (!fi->noselect) { *streamp = ml_open(session, *streamp, session_mailbox(session, pool, fi->name), OP_READONLY); if (!(*streamp)) return(NIL); folderlist_update_sizes_single(fi, *streamp, session); } if (fi->child && fi->expanded) { folderlist_update_sizes_work(fi->child, streamp, session); } fi = fi->next; } return(T); } BOOL folderlist_update_sizes(struct folderlist *fl, struct session *session) { BOOL rc; MAILSTREAM *tmp = ml_open(session, NIL, session_mailbox_prefs(session, NIL), OP_HALFOPEN); if (!tmp) return(NIL); rc = folderlist_update_sizes_work(fl->tree, &tmp, session); if (tmp) ml_close(session, tmp); return(rc); } /* ====================================================================== */ void folderlist_invalidate(struct folderlist *fl) { fl->need_update = T; } /* folderlist_invalidate(fl) is always a safe failback when adding or * removing entries to the folderlist: just forces refetch from the server */ void folderlist_add(struct folderlist *fl, char *name, BOOL noselect, BOOL noinferiors) { struct folderitem *fi; struct folderitem *last, *current; /* Don't try to optimise difficult cases */ if (strchr(name, fl->hiersep)) { folderlist_expand_parents(fl, name); folderlist_invalidate(fl); return; } if (!strcmp(name, "INBOX") || !fl->tree || (strcmp(fl->tree->name, name) > 0)) { folderlist_expand_parents(fl, name); folderlist_invalidate(fl); return; } /* Adding new fi into middle or at end of list */ fi = folderitem_create(fl->pool, name); fi->noselect = noselect; fi->noinferiors = noinferiors; fi->haschildren = NIL; last = fl->tree; current = last->next; while (current && (strcmp(current->name, name) < 0)) { last = current; current = current->next; } if (current && !strcmp(current->name, name)) { folderlist_invalidate(fl); /* Mailbox already has children */ } else { last->next = fi; /* Add to middle or end of list */ fi->next = current; } } void folderlist_delete(struct folderlist *fl, char *name) { struct folderitem *last, *current; /* Don't try to optimise difficult cases */ if (strchr(name, fl->hiersep)) { folderlist_invalidate(fl); return; } if (!fl->tree) return; /* Remove entry from start of list */ if (!strcmp(fl->tree->name, name)) { if (fl->tree->haschildren) folderlist_invalidate(fl); else fl->tree = fl->tree->next; return; } /* Remove entry from middle of list */ last = fl->tree; current = last->next; while (current && (strcmp(name, current->name) != 0)) { last = current; current = current->next; } if (current) { if (current->haschildren) folderlist_invalidate(fl); last->next = current->next; } } void folderlist_rename(struct folderlist *fl, char *oldname, char *newname) { struct folderitem *fi = folderlist_lookup(fl, oldname); if (fi) { folderlist_add(fl, newname, fi->noselect, fi->noinferiors); folderlist_delete(fl, oldname); if (fi->child) folderlist_invalidate(fl); } } /* ====================================================================== */ static int folderlist_count_visible_work(struct folderitem *fi, BOOL suppress_dotfiles) { int result = 0; while (fi) { if (!fi->noselect && (!suppress_dotfiles || fi->name[0] != '.')) result++; if (fi->child && fi->expanded) result += folderlist_count_visible_work(fi->child, suppress_dotfiles); fi = fi->next; } return(result); } int folderlist_count_visible_folders(struct folderlist *fl, BOOL suppress_dotfiles) { return(folderlist_count_visible_work(fl->tree, suppress_dotfiles)); } /* ====================================================================== */ /* XXX Following will all be obsolete when template work is finished XXX */ static void folderlist_showdirs_select_work(struct folderitem *fi, BOOL suppress_dotfiles, struct pool *pool, struct buffer *b, char *selected) { while (fi) { if (!fi->noinferiors && (!suppress_dotfiles || fi->name[0] != '.')) { bprintf(b, "" CRLF); } if (fi->child && fi->expanded) { folderlist_showdirs_select_work(fi->child, suppress_dotfiles, pool, b, selected); } fi = fi->next; } } void folderlist_showdirs_select(struct folderlist *fl, BOOL suppress_dotfiles, struct pool *pool, struct buffer *b, char *parent) { folderlist_showdirs_select_work(fl->tree, suppress_dotfiles, pool, b, parent); } static void folderlist_showfolders_select_work(struct folderitem *fi, BOOL suppress_dotfiles, struct pool *pool, struct buffer *b, char *selected) { while (fi) { if (!fi->noselect && (!suppress_dotfiles || fi->name[0] != '.')) { bprintf(b, "" CRLF); } if (fi->child && fi->expanded) { folderlist_showfolders_select_work(fi->child, suppress_dotfiles, pool, b, selected); } fi = fi->next; } } void folderlist_showfolders_select(struct folderlist *fl, BOOL suppress_dotfiles, struct pool *pool, struct buffer *b, char *selected) { folderlist_showfolders_select_work(fl->tree, suppress_dotfiles, pool, b, selected); } /* ====================================================================== */ static char * mbytes(unsigned long bytes) { static char buf[64]; unsigned long kbytes = bytes / 1024; unsigned long whole = kbytes / (1024); unsigned long fraction = ((kbytes % 1024) * 100) / 1024; if (fraction > 9) sprintf(buf, "%lu.%lu", whole, fraction); else sprintf(buf, "%lu.0%lu", whole, fraction); return(buf); } static void folderlist_tvals_tree_work(struct folderitem *fi, BOOL suppress_dotfiles, char hiersep, struct template_vals *tvals, int *count, int indent, char *array) { char *short_name, *s; struct pool *pool = tvals->pool; char *size_str; while (fi) { if ((s=strrchr(fi->name, hiersep))) short_name = s+1; else short_name = fi->name; if ((!suppress_dotfiles || fi->name[0] != '.')) { template_vals_foreach_init(tvals, array, *count); template_vals_foreach_string(tvals, array, *count, "name", fi->name); template_vals_foreach_string(tvals, array, *count, "short_name", short_name); template_vals_foreach_ulong(tvals, array, *count, "indent", indent); if (fi->noselect) template_vals_foreach_ulong(tvals, array, *count, "noselect", 1); if (fi->noinferiors) template_vals_foreach_ulong(tvals, array, *count, "noinferiors", 1); if (fi->haschildren) template_vals_foreach_ulong(tvals, array, *count, "haschildren", 1); if (fi->expanded) template_vals_foreach_ulong(tvals, array, *count, "expanded", 1); if (*count % 2 == 0) template_vals_foreach_ulong(tvals, array, *count, "even_row", 1); if (fi->size > 0) size_str = pool_printf(pool, "%s MBytes", mbytes(fi->size)); else size_str = "0.00 MBytes"; template_vals_foreach_string(tvals, array, *count, "size", size_str); (*count)++; } if (fi->child && fi->expanded) { folderlist_tvals_tree_work(fi->child, 0, hiersep, tvals, count, indent+1, array); } fi = fi->next; } } void folderlist_template_vals_tree(struct folderlist *fl, BOOL suppress_dotfiles, struct template_vals *tvals, char *array) { int count = 0; folderlist_tvals_tree_work(fl->tree, suppress_dotfiles, fl->hiersep, tvals, &count, 0, array); } static void folderlist_tvals_list_work(struct folderitem *fi, BOOL suppress_dotfiles, struct template_vals *tvals, int *count, BOOL showdirs, char *array) { BOOL showfi; while (fi) { if (suppress_dotfiles && (fi->name[0] == '.')) { fi = fi->next; continue; } if (showdirs) showfi = (fi->noinferiors) ? NIL : T; else showfi = (fi->noselect) ? NIL : T; if (showfi) { template_vals_foreach_init(tvals, array, *count); template_vals_foreach_string(tvals, array, *count, "name", fi->name); (*count)++; } if (fi->child && fi->expanded) { folderlist_tvals_list_work(fi->child, 0, tvals, count, showdirs, array); } fi = fi->next; } } void folderlist_template_vals_list(struct folderlist *fl, BOOL suppress_dotfiles, struct template_vals *tvals, BOOL showdirs, char *array) { int count = 0; folderlist_tvals_list_work(fl->tree, suppress_dotfiles, tvals, &count, showdirs, array); } ./prayer-1.3.5/session/portlist.h0000644006513000651300000000303611063701636015312 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/portlist.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Data structures which describe lists of internet domain sockets and * ports used for HTTP connects direct to Prayer in direct mode operation */ struct port { struct port *next; /* Linked list */ char *name; /* NIL */ int sockfd; /* Socket descriptor associated with this socket */ unsigned long inet_port; /* Internet domain port associated with socket */ pid_t pid; /* Process id associated with port if active */ }; struct portlist { struct list *idle; /* List of idle ports */ struct list *active; /* List of active ports */ unsigned long next; /* Range to draw fresh ports from */ unsigned long last; }; struct portlist *portlist_create(unsigned long first_port, unsigned long count); void portlist_free(struct portlist *pl); struct port *portlist_reserve_port(struct portlist *pl); BOOL portlist_free_port_bypid(struct portlist *pl, pid_t pid); BOOL portlist_free_port(struct portlist *pl, unsigned long inet_port); void portlist_close_all(struct portlist *pl); void portlist_close_all_except(struct portlist *pl, int except_fd); ./prayer-1.3.5/session/account.c0000644006513000651300000003377511747746663015120 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/account.c,v 1.6 2012/05/01 11:49:07 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Auxillary routines for accountd service */ #include "prayer_session.h" /* account_create() ***************************************************** * * Create a fresh account structure based on session defaults. * Returns: account structure ***********************************************************************/ struct account *account_create(struct pool *pool, struct session *session) { struct account *result = pool_alloc(pool, sizeof(struct account)); result->pool = pool; result->session = session; result->stream = NIL; result->last_ping = (time_t) 0L; result->nis_stream = NIL; result->nis_last_ping = (time_t) 0L; result->bused = 0; result->blimit = 0; result->iused = 0; result->ilimit = 0; result->fullname = NIL; result->mail_checked = NIL; result->vacation_enabled = NIL; result->vacation_msg = NIL; result->vacation_aliases = NIL; result->vacation_subject = NIL; result->vacation_days = 31; /* NB: Following are not part of pool. account_reset() rebuilds */ result->filter_list = list_create(NIL, T); result->block_list = list_create(NIL, T); result->redirect_enabled = NIL; result->redirect_copy = NIL; result->redirect_address = NIL; result->spam_enabled = NIL; result->spam_threshold = 0; result->spam_threshold_valid = NIL; result->spam_purge_enabled = T; result->spam_purge_timeout = 60; result->spam_whitelist = NIL; result->have_message = NIL; result->message = memblock_create(pool, 64); result->sieve_have_auto = NIL; return (result); } /* account_reset() ****************************************************** * * Reset filter and block lists to be empty lists. ***********************************************************************/ static void account_reset(struct account *account) { if (account->filter_list) list_free(account->filter_list); if (account->block_list) list_free(account->block_list); account->filter_list = list_create(NIL, T); account->block_list = list_create(NIL, T); } /* account_free() ******************************************************* * * Free account strucure * Closes down main and NIS streams if active. * ***********************************************************************/ void account_free(struct account *account) { if (account->stream) iostream_close(account->stream); if (account->nis_stream) iostream_close(account->nis_stream); string_free((void **) &account->vacation_msg); string_free((void **) &account->vacation_aliases); string_free((void **) &account->vacation_subject); string_free((void **) &account->spam_whitelist); if (!account->pool) memblock_free(account->message); } /* ====================================================================== */ /* account_close() ******************************************************* * * Close down connections to accountd servers ************************************************************************/ void account_timeout_close(struct account *account) { struct session *session = account->session; struct config *config = session->config; time_t now = time(NIL); if (account->stream && (config->accountd_timeout > 0) && ((account->last_ping + config->accountd_timeout) < now)) { iostream_close(account->stream); account->stream = NIL; } if (account->nis_stream && (config->accountd_timeout > 0) && ((account->nis_last_ping + config->accountd_timeout) < now)) { iostream_close(account->nis_stream); account->nis_stream = NIL; } } /* ====================================================================== */ /* account_close() ******************************************************* * * Close down connections to accountd servers ************************************************************************/ void account_close(struct account *account) { if (account->stream) { iostream_close(account->stream); account->stream = NIL; } if (account->nis_stream) { iostream_close(account->nis_stream); account->nis_stream = NIL; } } /* ====================================================================== */ /* account_message() **************************************************** * * Record status message for later feedback to user. * account: * fmt: printf format string, followed by arguments. * ***********************************************************************/ void account_message(struct account *account, char *fmt, ...) { struct memblock *m = account->message; va_list ap; unsigned long size; va_start(ap, fmt); size = memblock_vprintf_size(m, fmt, ap); va_end(ap); memblock_resize(m, size + 1); va_start(ap, fmt); memblock_vprintf(m, fmt, ap); va_end(ap); account->have_message = T; } /* account_fetch_message() ********************************************** * * Record status message for later feedback to user. * account: * fmt: printf format string, followed by arguments. * ***********************************************************************/ char *account_fetch_message(struct account *account) { if (account->have_message) { account->have_message = NIL; return (memblock_data(account->message)); } return (NIL); } /* ====================================================================== */ /* account_filter_add() ************************************************* * * Add filter to account structure * account: * filter: Filter to add * ***********************************************************************/ BOOL account_filter_add(struct account * account, struct filter * filter) { list_unshift(account->filter_list, (struct list_item *) filter, NIL); return (T); } /* account_filter_remove() ********************************************** * * Remove filter (by offset) from account structure * account: * offset: Offset to filter * * Returns: T on sucess. NIL => offset invalid ***********************************************************************/ BOOL account_filter_remove(struct account * account, unsigned long offset) { return (list_remove_byoffset(account->filter_list, offset)); } /* account_block_add() ************************************************* * * Add block to account structure * account: * filter: Block to add * ***********************************************************************/ BOOL account_block_add(struct account * account, struct filter * filter) { list_unshift(account->block_list, (struct list_item *) filter, NIL); return (T); } /* account_block_remove() *********************************************** * * Remove block (by offset) from account structure * account: * offset: Offset to block * * Returns: T on sucess. NIL => offset invalid ***********************************************************************/ BOOL account_block_remove(struct account * account, unsigned long offset) { return (list_remove_byoffset(account->block_list, offset)); } /* ====================================================================== */ /* account_change_password() ******************************************** * * Change password on server. * account: * pool: Scratch stream * old: Old password * new: New password * * Returns: T => sucess * NIL => error (reason sent to account_message). * ***********************************************************************/ BOOL account_change_password(struct account * account, struct pool * pool, char *old, char *new) { return(account_msshell_change_password(account, pool, old, new)); } /* ====================================================================== */ /* account_fullname() **************************************************** * * Change fullname on server. * account: * pool: Scratch stream * * Returns: Fullname string * NIL => error (reason sent to account_message). * ***********************************************************************/ char *account_fullname(struct account *account, struct pool *pool) { return(account_msshell_fullname(account, pool)); } /* account_change_fullname() ******************************************** * * Change fullname on server. * account: * pool: Scratch stream * new: New password * * Returns: T => success * NIL => error (reason sent to account_message). * ***********************************************************************/ BOOL account_change_fullname(struct account *account, struct pool *pool, char *new) { return(account_msshell_change_fullname(account, pool, new)); } /* ====================================================================== */ /* account_check_quota() ************************************************ * * Check disk quota * account: * pool: Scratch stream * * Returns: T => success (quota details records in account structure). * NIL => error (reason sent to account_message). * ***********************************************************************/ BOOL account_check_quota(struct account *account, struct pool *pool) { return(account_msshell_check_quota(account, pool)); } /* account_mail_check() ************************************************ * * Check mail filtering and vacation message using above routines. * account: * pool: Scratch stream * * Returns: T => success (details recorded in account structure) * NIL => error (reason sent to account_message). * ***********************************************************************/ BOOL account_mail_check(struct account * account, struct pool * pool) { struct session *session = account->session; struct options *options = session->options; struct prefs *prefs = options->prefs; if (account->mail_checked) return (T); /* Can get here twice if someone hits update on Advanced page with valid automatic sieve rules. account_reset() clears out the filters and block lists: otherwise everything doubles up */ account_reset(account); if (session->use_sieve) { if (!account_sieve_mail_check(account, pool)) return(NIL); } else { if (!account_msshell_mail_check(account, pool)) return(NIL); } /* XXX Better place for this? */ if (!(account->vacation_aliases && account->vacation_aliases[0]) && prefs->alt_addr && prefs->alt_addr[0]) string_strdup(&account->vacation_aliases, prefs->alt_addr); account->mail_checked = T; return(T); } /* ====================================================================== */ /* account_mail_update() ************************************************ * * Update mail filtering and vacation message to reflect account structure * account: * pool: Scratch stream * * Returns: T => success * NIL => error (reason sent to account_message). * ***********************************************************************/ BOOL account_mail_update(struct account * account, struct pool * pool) { struct session *session = account->session; if (session->use_sieve) return(account_sieve_mail_update(account, pool)); else return(account_msshell_mail_update(account, pool)); } /* ====================================================================== */ BOOL account_vacation_update(struct account * account, struct pool * pool) { struct session *session = account->session; if (session->use_sieve) return(account_sieve_vacation_update(account, pool)); else return(account_msshell_vacation_update(account, pool)); } /* ====================================================================== */ /* account_vaclog_fetch() *********************************************** * * Fetch current vacation log. * account: * pool: Scratch stream * * Returns: Vacation log as NULL terminated string * NIL => error (reason sent to account_message). * ***********************************************************************/ char *account_vaclog_fetch(struct account *account, struct pool *pool) { return(account_msshell_vaclog_fetch(account, pool)); } /* account_vaclog_clear() *********************************************** * * Clear vacation log. * account: * pool: Scratch stream * * Returns: T => success * NIL => error (reason sent to account_message). * ***********************************************************************/ BOOL account_vaclog_clear(struct account * account, struct pool * pool) { return(account_msshell_vaclog_clear(account, pool)); } /* ====================================================================== */ /* account_abook_fetch() ************************************************ * * Fetch .addressbook file from server * account: * pool: Scratch stream * * Returns: Vacation log as NULL terminated string * NIL => error (reason sent to account_message). * ***********************************************************************/ char *account_abook_get(struct account *account, struct pool *pool) { return(account_msshell_abook_get(account, pool)); } /* account_abook_put() **************************************************a * * Clear vacation log. * account: * pool: Scratch stream * * Returns: T => success * NIL => error (reason sent to account_message). * ***********************************************************************/ BOOL account_abook_put(struct account * account, struct pool * pool, char *text) { return(account_msshell_abook_put(account, pool, text)); } ./prayer-1.3.5/session/account_support.c0000644006513000651300000002500111063701636016651 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/account_support.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* XXX Better error handling please */ /* Couple of helper routines and data structures for account_process_filter * See comments below */ struct component { enum { CO_UNKNOWN, CO_VACATION, CO_SPAM, CO_SENDER, CO_RECIPIENT, CO_BLOCK, CO_SUBJECT, CO_REDIRECT } type; char *local_part; char *domain; char *subject; char *mailbox; char *address; BOOL copy; BOOL purge; char *threshold; char *days; }; static void component_reset(struct component *component) { component->type = CO_UNKNOWN; component->local_part = NIL; component->domain = NIL; component->subject = NIL; component->mailbox = NIL; component->address = NIL; component->copy = NIL; component->purge = NIL; component->threshold = NIL; component->days = NIL; } static int component_isvalid(struct component *component) { switch (component->type) { case CO_BLOCK: if (!(component->local_part && component->local_part[0] && component->domain && component->domain[0])) return (NIL); break; case CO_SENDER: case CO_RECIPIENT: if (!(component->local_part && component->local_part[0] && component->domain && component->domain[0])) return (NIL); if (!(component->mailbox && component->mailbox[0])) return (NIL); break; if (!(component->local_part && component->local_part[0] && component->domain && component->domain[0])) return (NIL); if (!(component->mailbox && component->mailbox[0])) return (NIL); break; case CO_SUBJECT: if (!(component->subject && component->subject[0])) return (NIL); break; case CO_REDIRECT: if (!(component->address && component->address[0])) return (NIL); break; case CO_SPAM: if (!(component->threshold && component->threshold[0])) return (NIL); break; case CO_VACATION: break; case CO_UNKNOWN: return (NIL); default: break; } return (T); } static BOOL component_process(struct account *account, struct component *component) { struct session *session = account->session; struct config *config = session->config; struct filter *filter; if (component->type == CO_UNKNOWN) session_fatal(session, "[component_process]: Unknown component type"); if (component->type == CO_VACATION) { if (component->days && component->days[0] && string_isnumber(component->days)) account->vacation_days = atoi(component->days); else account->vacation_days = config->vacation_default_days; account->vacation_enabled = T; return(T); } if (component->type == CO_SPAM) { if (!component->threshold || !string_isnumber(component->threshold)) { account_message(account, "Invalid construct in filter support file"); return(NIL); } account->spam_threshold = atoi(component->threshold); account->spam_enabled = T; account->spam_threshold_valid = T; if (component->days && string_isnumber(component->days)) account->spam_purge_timeout = atoi(component->days); account->spam_purge_enabled = component->purge; return(T); } if (component->type == CO_REDIRECT) { account->redirect_enabled = T; account->redirect_copy = component->copy; /* string_strdup() handles NIL input gracefully */ string_strdup(&account->redirect_address, component->address); return(T); } if (!component_isvalid(component)) { account_message(account, "Invalid construct in filter support file"); return(NIL); } filter = filter_alloc(); if (component->type == CO_SENDER) filter_set_type(filter, FILTER_SENDER); else if (component->type == CO_RECIPIENT) filter_set_type(filter, FILTER_RECIPIENT); else if (component->type == CO_SUBJECT) filter_set_type(filter, FILTER_SUBJECT); else if (component->type == CO_BLOCK) filter_set_type(filter, FILTER_BLOCK); filter_set_local_part(filter, component->local_part); filter_set_domain(filter, component->domain); filter_set_mailbox(filter, component->mailbox); filter_set_subject(filter, component->subject); filter_set_copy(filter, component->copy); if (component->type == CO_BLOCK) list_push(account->block_list, (struct list_item *) filter, NIL); else list_push(account->filter_list, (struct list_item *) filter, NIL); return(T); } /* ====================================================================== */ /* account_support_process_filter() ************************************** * * Convert filter file (downloaded from server) into a list of filter * actions which Prayer can manipulate. * account: * filter: Filter file as text string * pool: Scratch pool nominated by client routine. * * Returns: MSforward text from buffer ***********************************************************************/ BOOL account_support_process_filter(struct account *account, char *filter, struct pool *pool) { struct component component; char *line; char *s; component_reset(&component); while ((line = string_get_line(&filter))) { if (line[0] == '#') /* Ignore comment lines */ continue; for (s = line; *s; s++) { /* Ignore blank lines */ if (!string_isspace(*s)) break; } if (*s == '\0') continue; if ((line[0] != ' ') && (line[0] != '\t')) { /* New action */ if (component.type != CO_UNKNOWN) { if (!component_process(account, &component)) return(NIL); } component_reset(&component); if (!strcmp(line, "vacation")) component.type = CO_VACATION; else if (!strcmp(line, "spam")) component.type = CO_SPAM; else if (!strcmp(line, "block")) component.type = CO_BLOCK; else if (!strcmp(line, "sender")) component.type = CO_SENDER; else if (!strcmp(line, "recip")) component.type = CO_RECIPIENT; else if (!strcmp(line, "subject")) component.type = CO_SUBJECT; else if (!strcmp(line, "redirect")) component.type = CO_REDIRECT; else return (NIL); /* Unknown type */ } else { /* Continuation line */ char *arg0 = string_get_token(&line); char *arg1 = string_next_token(&line); if (!strcmp(arg0, "local_part")) component.local_part = pool_strdup(pool, arg1); else if (!strcmp(arg0, "domain")) component.domain = pool_strdup(pool, arg1); else if (!strcmp(arg0, "subject")) component.subject = pool_strdup(pool, arg1); else if (!strcmp(arg0, "mailbox")) component.mailbox = pool_strdup(pool, arg1); else if (!strcmp(arg0, "address")) component.address = pool_strdup(pool, arg1); else if (!strcmp(arg0, "copy")) component.copy = (!strcmp(arg1, "true")) ? T : NIL; else if (!strcmp(arg0, "purge")) component.purge = (!strcmp(arg1, "true")) ? T : NIL; else if (!strcmp(arg0, "threshold")) component.threshold = pool_strdup(pool, arg1); else if (!strcmp(arg0, "days")) component.days = pool_strdup(pool, arg1); else { account_message(account, "Invalid filter file"); return (NIL); } } } if (component.type != CO_UNKNOWN) { if (!component_process(account, &component)) return(NIL); } return (T); } /* ====================================================================== */ /* account_support_mail_text() ****************************************** * * Convert account filter list to equivaent text which can be uploaded to * accountd server and converted into Exim filter file there. * account: * pool: Scratch pool nominated by client. * sieve: Generating text for Sieve world (=> no vacation log) * * Returns: MSforward text from buffer ***********************************************************************/ char * account_support_mail_text(struct account *account, struct pool *pool, BOOL sieve) { struct session *session = account->session; struct config *config = session->config; struct buffer *b = buffer_create(pool, ACCOUNT_BLOCKSIZE); struct list_item *item; bputs(b, "# MSforward file: change only via Hermes menu system\n"); for (item = account->block_list->head; item; item = item->next) filter_print((struct filter *) item, b); if (account->spam_enabled && account->spam_threshold_valid) { bprintf(b, "spam\n"); bprintf(b, " threshold\t%lu\n", account->spam_threshold); if (!account->spam_purge_enabled || (account->spam_purge_timeout != config->spam_purge_timeout)) { if (account->spam_purge_enabled) bputs(b, " purge true\n"); else bputs(b, " purge false\n"); bprintf(b, " days\t%lu\n", account->spam_purge_timeout); } } if (account->vacation_enabled) { bputs(b, "vacation\n"); if (sieve) bprintf(b, " days %d\n", account->vacation_days); } for (item = account->filter_list->head; item; item = item->next) filter_print((struct filter *) item, b); if (account->redirect_enabled) { bputs(b, "redirect\n"); if (account->redirect_address) bprintf(b, " address\t%s\n", account->redirect_address); if (account->redirect_copy) bprintf(b, " copy\ttrue\n"); } return (buffer_fetch(b, 0, buffer_size(b), NIL)); } ./prayer-1.3.5/session/dictionary.h0000644006513000651300000000207011063701636015574 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/dictionary.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #define DICTIONARY_POOL_SIZE (1024) struct dictionary { struct pool *pool; /* Allocation pool */ struct list *list; /* List of words */ struct assoc *assoc; /* Parrellel associative array for fast lookups */ }; struct dictionary *dictionary_create(void); void dictionary_free(struct dictionary *d); void dictionary_parse_line(struct dictionary *dictionary, char *line, struct session *session); void dictionary_print_options(struct dictionary *dictionary, struct buffer *b); void dictionary_add(struct dictionary *d, char *word); void dictionary_remove(struct dictionary *d, char *word); BOOL dictionary_lookup(struct dictionary *d, char *word); ./prayer-1.3.5/session/wrap.h0000644006513000651300000000132311063701636014400 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/wrap.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #define WRAP_LENGTH (75) #define WRAP_SHORTLINE (50) void wrap_paragraph(struct buffer *b, char *s, unsigned long len); void wrap_line_html(struct session *session, struct buffer *b, char *s, unsigned long wrap_length); void wrap_text_html_quotes(struct buffer *b, char *t, unsigned long line_length, BOOL indent); ./prayer-1.3.5/session/display.c0000644006513000651300000005713411416567713015112 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/display.c,v 1.16 2010/07/12 10:34:51 dpc22 Exp $ */ #include "prayer_session.h" /* ====================================================================== */ static BOOL simple_string_compare(char *s1, char *s2) { if ((s1 == NIL) && (s2 == NIL)) return T; if ((s1 == NIL) || (s2 == NIL)) return NIL; return (!strcmp(s1, s2)); } /* Compare two ADDRESS structures, see if identical * Returns: T => definitely identical, can use shortcuts. * NIL => Not clear whether identical. Don't try to use shortcuts. */ static BOOL simple_address_compare(ADDRESS * addr1, ADDRESS * addr2) { /* Get rid of two difficult cases quickly */ if ((addr1 == NIL) || (addr2 == NIL)) return NIL; if ((addr1->next != NIL) || (addr2->next != NIL)) return NIL; if (simple_string_compare(addr1->personal, addr2->personal) && simple_string_compare(addr1->adl, addr2->adl) && simple_string_compare(addr1->mailbox, addr2->mailbox) && simple_string_compare(addr1->host, addr2->host) && simple_string_compare(addr1->error, addr2->error)) return T; return NIL; } static BOOL display_addr(struct template_vals *tvals, char *array, ADDRESS * addr, struct abook *abook) { struct pool *pool = tvals->pool; ADDRESS *a; char *email; struct abook_entry *abe; unsigned long offset = 0; for (a = addr; a; a = a->next) { template_vals_foreach_init(tvals, array, offset); if (a->next) template_vals_foreach_string(tvals, array, offset, "next", "1"); if (!(a->mailbox && a->host)) { /* Something that we can't parse sensibly */ template_vals_foreach_string(tvals, array, offset, "raw", addr_text(pool, a)); offset++; continue; } email = pool_strcat3(pool, a->mailbox, "@", a->host); template_vals_foreach_string(tvals, array, offset, "email", email); abe = abook_find_email(abook, email); if (abe && abe->alias) { template_vals_foreach_string(tvals, array, offset, "alias", abe->alias); } if (a->personal && a->personal[0]) { unsigned long len = strlen(a->personal) + 20; char *tmp = pool_alloc(pool, len); /* Decoded form smaller */ char *d = (char *) rfc1522_decode((unsigned char *) tmp, len, a->personal, NIL); template_vals_foreach_string(tvals, array, offset, "personal", d); } offset++; } return(T); } BOOL display_addhdrs(struct session *session, MAILSTREAM *stream, unsigned long msgno) { struct template_vals *tvals = session->template_vals; struct abook *abook = session->options->abook; MESSAGECACHE *elt; ENVELOPE *env; if (!((elt = ml_elt(session, stream, msgno)) && (env = ml_fetch_structure(session, stream, msgno, NIL, 0)))) return (NIL); if (session->full_hdrs) template_vals_ulong(tvals, "$full_hdrs", 1); if (env->reply_to && !simple_address_compare(env->reply_to, env->from)) display_addr(tvals, "@reply_to", env->reply_to, abook); display_addr(tvals, "@from", env->from, abook); if (env->to) display_addr(tvals, "@to", env->to, abook); if (env->cc) display_addr(tvals, "@cc", env->cc, abook); if (env->date) template_vals_string(tvals, "$date", (char *)env->date); else template_vals_string(tvals, "$date", "(Unknown date)"); if (env->subject) { char *subject = env->subject; subject = (char *) rfc1522_decode(pool_alloc(tvals->pool, strlen(subject)), strlen(subject), subject, NIL); template_vals_string(tvals, "$subject", subject); } else template_vals_string(tvals, "$subject", "(No subject)"); return(T); } /* ====================================================================== */ BOOL display_addnav(struct session *session, MAILSTREAM *stream, unsigned long msgno) { struct template_vals *tvals = session->template_vals; struct msgmap *zm = session->zm; unsigned long zm_offset = msgmap_find(zm, msgno); unsigned long uid; MESSAGECACHE *elt; if (!(elt = ml_elt(session, stream, msgno))) return (NIL); if (elt->deleted) template_vals_hash_ulong(tvals, "$nav", "deleted", 1); uid = ml_uid(session, stream, msgno); template_vals_hash_ulong(tvals, "$nav", "cur_msg", msgno); template_vals_hash_ulong(tvals, "$nav", "cur_uid", uid); template_vals_hash_ulong(tvals, "$nav", "msg_count",msgmap_size(zm)); if (msgmap_has_mark(zm, msgno)) template_vals_hash_ulong(tvals, "$nav", "marked", 1); if (zm_offset > 1) { msgno = msgmap_value(zm, zm_offset - 1); uid = ml_uid(session, stream, msgno); template_vals_hash_ulong(tvals, "$nav", "prev_msg", msgno); template_vals_hash_ulong(tvals, "$nav", "prev_uid", uid); } if (zm_offset < msgmap_size(zm)) { msgno = msgmap_value(zm, zm_offset + 1); uid = ml_uid(session, stream, msgno); template_vals_hash_ulong(tvals, "$nav", "next_msg", msgno); template_vals_hash_ulong(tvals, "$nav", "next_uid", uid); } return(T); } /* ====================================================================== */ /* Parse RFC 2231 name of form ISO-8859-1''%a3 * * Returns simple UTF-8 string or NIL if the input was NIL. */ static char *parse_2231(char *value, struct pool *pool) { char *s, *t, *charset; if (!value) return(NIL); value = pool_strdup(pool, value); if ((s=strchr(value, '\'')) && ((t=strchr(s+1, '\'')))) { *s++ = '\0'; *t++ = '\0'; charset = value; value = t; string_url_decode(value); if (!strcasecmp(charset, "utf-8")) return(value); if (charset[0] == '\0') charset = "ISO-8859-1"; /* Default not specified by RFC 2231 */ return(utf8_from_string(pool, charset, value, strlen(value))); } return(NIL); } static char *body_get_name(BODY *body, struct pool *pool) { PARAMETER *parameter; char *name = NIL; for (parameter = body->parameter; parameter; parameter = parameter->next) { if (!strcasecmp(parameter->attribute, "NAME*")) { name = parse_2231(parameter->value, pool); } else if (!strcasecmp(parameter->attribute, "NAME")) { name = parameter->value; } } if (!name && body->description) name = body->description; if (!name && body->disposition.type) { for (parameter = body->disposition.parameter; parameter; parameter = parameter->next) { if (!strcasecmp(parameter->attribute, "FILENAME*")) { name = parse_2231(parameter->value, pool); } else if (!strcasecmp(parameter->attribute, "FILENAME")) { name = parameter->value; } } } if (!name) name = ""; return(name); } /* show_structure(): * Recursively render message MIME structure as collection of * nested
    with links to body parts. * * session: * tvals: Template vals to render into * offsetp: Offset into @atts list * msgno: Message that we are rendering * msguid: Message UID * body: Current body part that we are rendering * section: IMAP session number prefix for this body part * i: Offset count for multipart messages. ($section$i gives offset). * (section and i could be combined, this approach requires * fewer temporary copies of strings). */ static void show_structure_simple(struct template_vals *tvals, unsigned long offset, BODY * body) { struct pool *pool = tvals->pool; char *type, *name, *size; name = body_get_name(body, pool); template_vals_foreach_string(tvals, "@atts", offset, "name", name); type = pool_strcat3(pool, body_types[body->type], "/", body->subtype); string_lcase(type); template_vals_foreach_string(tvals, "@atts", offset, "type", type); template_vals_foreach_ulong(tvals, "@atts", offset, "lines", body->size.lines); if (body->size.bytes >= 2048) size = pool_printf(pool, "%lu KBytes", body->size.bytes / 1024); else if (body->size.bytes != 1) size = pool_printf(pool, "%lu bytes", body->size.bytes); else size = "1 byte"; template_vals_foreach_string(tvals, "@atts", offset, "size", size); } static void show_structure(struct template_vals *tvals, unsigned long *offsetp, BODY * body, char *parent, long i) { struct pool *pool = tvals->pool; PART *part; char *section; if (parent) { template_vals_foreach_init(tvals, "@atts", *offsetp); template_vals_foreach_ulong(tvals, "@atts", *offsetp, "start_item", 1); (*offsetp)++; } template_vals_foreach_init(tvals, "@atts", *offsetp); if (parent && parent[0]) section = pool_printf(pool, "%s.%d", parent, i); else section = pool_printf(pool, "%d", i); template_vals_foreach_string(tvals, "@atts", *offsetp, "section", section); switch (body->type) { case TYPEMULTIPART: template_vals_foreach_ulong(tvals, "@atts", *offsetp, "start_list", 1); if (parent) template_vals_foreach_ulong(tvals, "@atts", *offsetp, "nested_multipart", 1); (*offsetp)++; for (i = 1, part = body->nested.part; part != NIL; part = part->next, i++) { show_structure(tvals, offsetp, &part->body, (parent) ? section : "", i); } template_vals_foreach_init(tvals, "@atts", *offsetp); template_vals_foreach_ulong(tvals, "@atts", *offsetp, "end_list", 1); if (parent) template_vals_foreach_ulong(tvals, "@atts", *offsetp, "nested_multipart", 1); (*offsetp)++; break; case TYPEMESSAGE: template_vals_foreach_ulong(tvals, "@atts", *offsetp, "is_msg", 1); show_structure_simple(tvals, *offsetp, body); (*offsetp)++; if (!strcmp(body->subtype, "RFC822") && (body = body->nested.msg->body)) { template_vals_foreach_init(tvals, "@atts", *offsetp); template_vals_foreach_ulong(tvals, "@atts", *offsetp, "start_list", 1); (*offsetp)++; if (body->type == TYPEMULTIPART) { /* Nested multipart message */ for (i = 1, part = body->nested.part; part != NIL; part = part->next, i++) { show_structure(tvals, offsetp, &part->body, section, i); } } else { /* Nested singlepart message */ show_structure(tvals, offsetp, body, section, 1); } template_vals_foreach_init(tvals, "@atts", *offsetp); template_vals_foreach_ulong(tvals, "@atts", *offsetp, "end_list", 1); (*offsetp)++; } break; case TYPETEXT: template_vals_foreach_ulong(tvals, "@atts", *offsetp, "is_text", 1); /* Fall through to default */ default: show_structure_simple(tvals, *offsetp, body); (*offsetp)++; break; } if (parent) { template_vals_foreach_init(tvals, "@atts", *offsetp); template_vals_foreach_ulong(tvals, "@atts", *offsetp, "end_item", 1); (*offsetp)++; } } /* ====================================================================== */ /* show_textpart(): * * Render given text section into output buffer. Code factored out from * cmd_display() so that it can be used for simple text/plain messages, * as well as multipart. Could also be used to display all text bodyparts. * */ static BOOL show_textpart(struct session *session, MAILSTREAM *stream, unsigned long msgno, char *section, BOOL html_show_images, int depth) { struct template_vals *tvals = session->template_vals; struct options *options = session->options; struct prefs *prefs = options->prefs; struct request *request = session->request; struct pool *pool = request->pool; struct buffer *b = request->write_buffer; char *init_msg, *decode_msg; char *charset = "ISO-8859-1"; unsigned long len; BODY *body = NIL; BOOL show_html = NIL; PARAMETER *parameter; if (!(body = ml_body(session, stream, msgno, section))) return(NIL); /* Include section numbers for tree leaves only */ if (section && (depth > 0)) bprintf(b, "

    Part %s:

    "CRLF, section); if (body->type != TYPETEXT) { session_alert(session, "Invalid body type (should never happen)"); session_log(session, "show_textpart(): Invalid bodypart"); return(NIL); } for (parameter = body->parameter; parameter; parameter = parameter->next) { if (strcasecmp(parameter->attribute, "charset") == 0) { charset = parameter->value; break; } } if (!(init_msg = ml_fetchbody(session, stream, msgno, section, &len))) return(NIL); /* Strip off encoding */ switch (body->encoding) { case ENCBASE64: decode_msg = (char *) rfc822_base64((unsigned char *) init_msg, body->size.bytes, &len); if (!decode_msg) { /* Decode failed */ decode_msg = init_msg; len = body->size.bytes; } break; case ENCQUOTEDPRINTABLE: decode_msg = (char *) rfc822_qprint((unsigned char *) init_msg, body->size.bytes, &len); if (!decode_msg) { /* Decode failed */ decode_msg = init_msg; len = body->size.bytes; } break; case ENC7BIT: case ENC8BIT: case ENCBINARY: case ENCOTHER: default: decode_msg = init_msg; len = body->size.bytes; } if ((prefs->html_inline) && body->subtype && !strcasecmp(body->subtype, "html")) show_html = T; else if (prefs->html_inline_auto) { char *s = decode_msg; while ((*s == ' ') || (*s == '\t') || (*s == '\015') || (*s == '\012')) s++; if (!strncasecmp(s, "", strlen(""))) show_html = T; else if (!strncasecmp (s, "html_remote_images) { template_vals_ulong(tvals, "$is_html", 1); if (html_show_images) template_vals_ulong(tvals, "$html_images_shown", 1); template_expand("display_images", tvals, b); } if (decode_msg == init_msg) decode_msg = strdup(init_msg); bputs(b, "
    "CRLF); html_secure(session, b, html_show_images, utf8_from_string(pool, charset, decode_msg, len)); bputs(b, "
    "CRLF); } else { bprintf(b, "
    " CRLF);
            wrap_line_html(session, b,
                           utf8_from_string(pool, charset, decode_msg, len), 80);
            bprintf(b, "
    " CRLF); } if (decode_msg != init_msg) fs_give((void **) &decode_msg); return(T); } /* ====================================================================== */ static STRINGLIST *new_strlst(char **l) { STRINGLIST *sl = mail_newstringlist(); sl->text.data = (unsigned char *) (*l); sl->text.size = strlen(*l); sl->next = (*++l) ? new_strlst(l) : NULL; return (sl); } static BOOL show_message_hdrs(struct session *session, MAILSTREAM *stream, unsigned long msgno, char *section, int depth) { static char *short_hdrs[] = { "from", "to", "cc", "date", "subject", NIL }; static STRINGLIST *hdrslist_cache = NIL; STRINGLIST *hdrslist; struct request *request = session->request; struct buffer *b = request->write_buffer; char *hdr; unsigned long len; if (!hdrslist_cache) hdrslist_cache = new_strlst(short_hdrs); hdrslist = (session->full_hdrs) ? NIL : hdrslist_cache; if (section && (depth > 0)) bprintf(b, "

    Part %s:

    "CRLF, section); bprintf(b, "
    "CRLF);
    
        hdr = ml_fetch_header(session, stream, msgno, section, hdrslist, &len, 0);
        if (!hdr)
            return(NIL);
        html_quote_string(b, hdr);
    
        bprintf(b, "
    "CRLF); return(T); } static BOOL show_message(struct session *session, MAILSTREAM *stream, unsigned long msgno, char *section, int depth) { struct request *request = session->request; struct buffer *b = request->write_buffer; char *msg; unsigned long len; if (!show_message_hdrs(session, stream, msgno, section, depth)) return(NIL); bprintf(b, "
    "CRLF);
    
        msg =  ml_fetch_body(session, stream, msgno, section, &len, 0);
        if (!msg)
            return(NIL);
        html_quote_string(b, msg);  /* No attempt to decode: raw text */
    
        bprintf(b, "
    "CRLF); return(T); } static BOOL show_attachment(struct session *session, MAILSTREAM *stream, unsigned long msgno, char *section, int depth) { struct request *request = session->request; struct buffer *b = request->write_buffer; struct pool *pool = request->pool; BODY *body = NIL; char *type, *name, *size; unsigned long uid = ml_uid(session, stream, msgno); if (!(body = ml_body(session, stream, msgno, section))) return(NIL); name = body_get_name(body, pool); type = pool_strcat3(pool, body_types[body->type], "/", body->subtype); string_lcase(type); if (body->size.bytes >= 2048) size = pool_printf(pool, "%lu KBytes", body->size.bytes / 1024); else if (body->size.bytes != 1) size = pool_printf(pool, "%lu bytes", body->size.bytes); else size = "1 byte"; bprintf(b, "

    Part %s: ", section); /* XXX Evil session URLs. */ bprintf(b, "", session->url_prefix_bsession, msgno, uid, section, string_url_encode(pool, type), string_url_encode(pool, name)); html_quote_string(b, name); bputs(b, " "); html_quote_string(b, type); bprintf(b, " (%s)

    "CRLF, size); return(T); } /* ====================================================================== */ static int find_single_text_section(BODY *body) { PART *part = body->nested.part; int i = 1, body_plain = 0, body_html = 0; for (i = 1; part != NIL; part = part->next, i++) { if (!(body = &part->body)) continue; if ((body->type != TYPETEXT) || !body->subtype) continue; if (!strcasecmp(body->subtype, "plain")) { if (!body_plain) body_plain = i; } else if (!strcasecmp(body->subtype, "html")) { if (!body_html) body_html = i; } } return((body_plain) ? body_plain : body_html); } static BOOL show_tree(struct session *session, MAILSTREAM *stream, unsigned long msgno, BODY *body, char *parent, long i, BOOL html_show_images, int depth) { struct request *request = session->request; struct pool *pool = request->pool; PART *part; char *section; if (parent && parent[0]) { section = pool_printf(pool, "%s.%d", parent, i); } else section = pool_printf(pool, "%d", i); switch (body->type) { case TYPETEXT: if (!show_textpart(session, stream, msgno, section, html_show_images, depth)) return(NIL); break; case TYPEMULTIPART: if (body->subtype && !strcasecmp(body->subtype, "alternative")) { int subsection = find_single_text_section(body); if (subsection) { if (parent) section = pool_printf(pool, "%s.%lu", section, subsection); else section = pool_printf(pool, "%lu", subsection); if (!show_textpart(session, stream, msgno, section, html_show_images, depth)) return(NIL); } } else { for (i = 1, part = body->nested.part; part != NIL; part = part->next, i++) { if (!show_tree(session, stream, msgno, &part->body, (parent) ? section : "", i, html_show_images, depth+1)) return(NIL); } } break; case TYPEMESSAGE: if (!show_message_hdrs(session, stream, msgno, section, depth)) return(NIL); if (!strcmp(body->subtype, "RFC822") && (body = body->nested.msg->body)) { if (body->type == TYPEMULTIPART) { /* Nested multipart message */ for (i = 1, part = body->nested.part; part != NIL; part = part->next, i++) { if (!show_tree(session, stream, msgno, &part->body, section, i, html_show_images, depth+1)) return(NIL); } } else { /* Nested singlepart message */ if (!show_tree(session, stream, msgno, body, section, 1, html_show_images, depth+1)) return(NIL); } } break; default: if (!show_attachment(session, stream, msgno, section, depth)) return(NIL); break; } return(T); } /* ====================================================================== */ BOOL display_body(struct session *session, struct request *request, MAILSTREAM *stream, unsigned long msgno, char *section, char *cmd, BOOL html_show_images) { struct template_vals *tvals = session->template_vals; struct buffer *b = request->write_buffer; BODY *body = NIL; /* Fetch message structure */ if (!ml_fetch_structure(session, stream, msgno, &body, NIL)) { session_redirect(session, request, "restart"); return(NIL); } /* Print out MIME bodystructure if multipart message */ if ((body->type == TYPEMULTIPART) || (body->type == TYPEMESSAGE)) { unsigned long offset = 0; show_structure(tvals, &offset, body, NIL, 1); template_expand("display_mime", tvals, b); } if (section && section[0]) { bprintf(b, "

    Part %s:

    "CRLF, section); template_vals_string(tvals, "$section", section); if ((body = ml_body(session, stream, msgno, section)) == NIL) return(NIL); switch (body->type) { case TYPETEXT: show_textpart(session, stream, msgno, section, html_show_images, 0); break; case TYPEMULTIPART: show_tree(session, stream, msgno, body, section, 1, html_show_images, 0); break; case TYPEMESSAGE: show_message(session, stream, msgno, section, 0); break; } } else { show_tree(session, stream, msgno, body, NIL, 1, html_show_images, 0); } return(T); } ./prayer-1.3.5/session/prayer_session.h0000644006513000651300000000276611415323172016504 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/prayer_session.h,v 1.5 2010/07/08 10:20:42 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* System header files needed by other headers */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include "c-client.h" #include "shared.h" #include "session.h" #include "session_streams.h" #include "addr.h" #include "ml.h" #include "mm.h" #include "mc.h" #include "stream.h" #include "folderlist.h" #include "html_secure.h" #include "html_secure_tidy.h" #include "draft.h" #include "msg.h" #include "msgmap.h" #include "speller.h" #include "abook.h" #include "lookup.h" #include "role.h" #include "dictionary.h" #include "display.h" #include "prefs.h" #include "options.h" #include "rfc1522.h" #include "favourite.h" #include "filter.h" #include "sieve.h" #include "account.h" #include "account_msshell.h" #include "account_sieve.h" #include "account_support.h" #include "checksum.h" #include "wrap.h" #include "utf8_calc.h" ./prayer-1.3.5/session/addr.c0000644006513000651300000002214211063701636014336 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/addr.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Some utility routines for processing address objects */ /* est_size() function stolen directly from ALPINE 1.00: pith/bldaddr.c * * Compute an upper bound on the size of the array required by * rfc822_output_address_list() for this list of addresses. * * Args: adrlist -- The address list. * * Returns -- an integer giving the upper bound */ static int est_size(ADDRESS *a) { int cnt = 0; for (; a; a = a->next){ /* two times personal for possible quoting */ cnt += 2 * (a->personal ? (strlen(a->personal)+1) : 0); cnt += 2 * (a->mailbox ? (strlen(a->mailbox)+1) : 0); cnt += (a->adl ? strlen(a->adl) : 0); cnt += (a->host ? strlen(a->host) : 0); /* * add room for: * possible single space between fullname and addr * left and right brackets * @ sign * possible : for route addr * , * * So I really think that adding 7 is enough. Instead, I'll add 10. */ cnt += 10; } return ((cnt > 50) ? cnt : 50); /* just making sure */ } long dummy_soutr(void *stream, char *string) { fatal("dummy_soutr unexpected call, caught overflow"); return LONGT; } /* ====================================================================== */ /* addr_text() ********************************************************** * * Convert c-client ADDRESS structure to equivalent text in target pool * pool: Target pool * addr: ADDRESS to convert * * Returns: NULL terminated string ***********************************************************************/ char *addr_text(struct pool *pool, ADDRESS * addr) { RFC822BUFFER rbuf; int esize = est_size(addr); char *buf = pool_alloc(pool, esize + 1); buf[0] = '\0'; rbuf.f = dummy_soutr; rbuf.s = NULL; rbuf.beg = buf; rbuf.cur = buf; rbuf.end = &buf[esize]; rfc822_output_address_list(&rbuf, addr, 0L, NULL); *rbuf.cur = '\0'; return (buf); } /* ====================================================================== */ /* addr_text_exclude() ************************************************** * * Convert c-client ADDRESS structure to equivalent text in target pool, * exclusing any component which matches exclude list or session alt-addr * lists. Used to generate list of recipients for a particular message. * session: * pool: Target pool * addr: ADDRESS to convert * exclude: Address list to exclude. * * Returns: NULL terminated string ***********************************************************************/ char *addr_text_exclude(struct session *session, struct pool *pool, ADDRESS * addr, ADDRESS * exclude) { struct config *config = session->config; struct prefs *prefs = session->options->prefs; ADDRESS *a, *alt, *alt_addr = NIL; ADDRESS *head = NIL; ADDRESS *tail = NIL; ADDRESS *new; BOOL flag; char *text, *s; /* Need a temporary copy for rfc822_parse_adrlist() */ if (prefs->from_address && prefs->from_address[0]) { if (prefs->alt_addr && prefs->alt_addr[0]) text = pool_printf(pool, "%s, %s", prefs->from_address, prefs->alt_addr); else text = pool_strdup(pool, prefs->from_address); } else text = pool_strdup(pool, prefs->alt_addr); ml_clear_errmsg(); rfc822_parse_adrlist(&alt_addr, text, ""); if ((s = ml_errmsg()) && s[0]) { mail_free_address(&alt_addr); session_message(session, "Alt-address invalid - %s", s); return (NIL); } for (a = addr; a; a = a->next) { if ((a->mailbox == NIL) || (a->host == NIL)) continue; if (exclude && !strcmp(a->mailbox, exclude->mailbox) && !strcmp(a->host, exclude->host)) continue; /* Alt address? */ flag = NIL; for (alt = alt_addr; alt; alt = alt->next) { if (!strcasecmp(a->mailbox, alt->mailbox) && !strcasecmp(a->host, alt->host)) { flag = T; break; } } if (flag) continue; if (!strcasecmp(a->mailbox, session->username) && config->local_domain_list) { struct list_item *li; /* Check for username@[username_domain]. */ flag = NIL; for (li = config->local_domain_list->head; li; li = li->next) { if (!strcasecmp(li->name, a->host)) { flag = T; break; } } if (flag) continue; } /* Create new address element */ new = pool_alloc(pool, sizeof(ADDRESS)); memcpy(new, a, sizeof(ADDRESS)); new->next = NIL; if (head) tail = tail->next = new; /* Add to end of list */ else head = tail = new; /* Start new list */ } mail_free_address(&alt_addr); return (addr_text(pool, head)); } /* ====================================================================== */ /* Support routine for addr_parse */ static BOOL addr_parse_check_single(ADDRESS *a) { char *s; if ((a->mailbox == NIL) || (a->mailbox[0] == '\0') || (a->host == NIL)) { ml_set_errmsg("Empty address"); return (NIL); } if (a->mailbox && (a->mailbox[0] == '\'')) { ml_errmsg_printf("Invalid \' character in address: %s@%s", a->mailbox, a->host); return (NIL); } if (a->host && (a->host[0] == '\'')) { ml_errmsg_printf("Invalid \' character in address: %s@%s", a->mailbox, a->host); return (NIL); } for (s = a->host ; *s ; s++) { if ((s[0] == '.') && (s[1] == '.')) { ml_errmsg_printf("Invalid .. sequence in address: %s@%s", a->mailbox, a->host); return (NIL); } if (*s == '_') { ml_errmsg_printf("Invalid '_' in address: %s@%s", a->mailbox, a->host); return (NIL); } if (s[1] != '\0') continue; /* Test trailing character */ if (s[0] == '.') { ml_errmsg_printf("Invalid trailing '.' in address: %s@%s", a->mailbox, a->host); return (NIL); } if (s[0] == '\'') { ml_errmsg_printf("Invalid \' character in address: %s@%s", a->mailbox, a->host); return (NIL); } } return(T); } /* addr_parse_destructive() ************************************************ * * Wrapper to c-client rfc822_parse_adrlist() (converts RFC822 address list * into parsed ADDRESS format) which does some additional checks. This * interface trashs the text parameter. * * text: Address to parse * default_domain: Domain to use on unqualified addresses * **************************************************************************/ ADDRESS * addr_parse_destructive(char *text, char *default_domain) { ADDRESS *addr = NIL; ADDRESS *a; char *s; ml_clear_errmsg(); rfc822_parse_adrlist(&addr, text, default_domain); if ((s = ml_errmsg()) && s[0]) { mail_free_address(&addr); return (NIL); } if (addr == NIL) { ml_set_errmsg("Empty address"); return (NIL); } for (a = addr; a; a = a->next) { if (!addr_parse_check_single(a)) { mail_free_address(&addr); return (NIL); } } return(addr); } /* addr_parse() ************************************************************ * * Wrapper to c-client rfc822_parse_adrlist() (converts RFC822 address list * into parsed ADDRESS format) which does some additional checks. This * interface preserves the text parameter. * * pool: Pool for scratch copy of address * text: Address to parse * default_domain: Domain to use on unqualified addresses * **************************************************************************/ ADDRESS * addr_parse(struct pool *pool, char *text, char *default_domain) { text = pool_strdup(pool, text); /* Generate Scratch copy */ return(addr_parse_destructive(text, default_domain)); } /* addr_check_valid() ****************************************************** * * Check whether text corresponds to valid ADDRESS (+ additional checks). * * pool: Pool for scratch copy of address * text: Address to parse * **************************************************************************/ BOOL addr_check_valid(struct pool *pool, char *text) { ADDRESS *addr; text = pool_strdup(pool, text); /* Generate Scratch copy */ if (!(addr = addr_parse_destructive(text, ""))) return(NIL); mail_free_address(&addr); return(T); } ./prayer-1.3.5/session/display.h0000644006513000651300000000103211415401425015063 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/display.h,v 1.4 2010/07/08 16:55:49 dpc22 Exp $ */ BOOL display_addhdrs(struct session *session, MAILSTREAM *stream, unsigned long msgno); BOOL display_addnav(struct session *session, MAILSTREAM *stream, unsigned long msgno); BOOL display_body(struct session *session, struct request *request, MAILSTREAM *stream, unsigned long msgno, char *section, char *cmd, BOOL html_show_images); ./prayer-1.3.5/session/lookup.h0000644006513000651300000000345711063701636014752 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/lookup.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ struct lookup_item { char *userid; /* CRSid */ char *registered_name; /* Registered Name on Jackdaw */ char *display_name; /* Local GeCOS or LDAP displayName */ char *affiliation; /* From local username map or LDAP "ou" */ char *email; /* Constructed from CRSid or LDAP "email" */ char *phone; /* LDAP only */ BOOL cancelled; /* Local lookups only */ }; struct lookup { char *query; struct lookup_item **entries; unsigned long count; unsigned long current; struct pool *master_pool; struct pool *pool; BOOL have_cancelled; BOOL have_phone; struct session *session; /* For session_message() only */ char *local_fullname; /* Configuration for local lookups */ char *local_username; char *local_rpasswd; char *local_rusername; char *ldap_server; /* Configuration details for LDAP lookups */ unsigned long ldap_port; char *ldap_base_dn; unsigned long ldap_timeout; }; struct lookup * lookup_create(struct session *session, struct pool *pool); void lookup_clear(struct lookup *lookup); void lookup_free(struct lookup *lookup); BOOL lookup_local_available(struct lookup *lookup); BOOL lookup_ldap_available(struct lookup *lookup); BOOL lookup_local(struct lookup *lookup, char *text, char *default_domain); BOOL lookup_ldap(struct lookup *lookup, char *text); #define LDAP_DEFAULT_PORT (389) ./prayer-1.3.5/session/abook.c0000644006513000651300000012541511063701636014526 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/abook.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* abook_create() ******************************************************* * * Create a default abook structure. * Retuens: new addressbook structure ***********************************************************************/ struct abook *abook_create() { struct pool *pool = pool_create(ABOOK_POOL_SIZE); struct abook *abook; abook = pool_alloc(pool, sizeof(struct abook)); abook->pool = pool; abook->list = list_create(pool, NIL); abook->hash = assoc_create(pool, 64, NIL); abook->sort = NULL; abook->sort_mode = ABOOK_SORT_ORDER; abook->sort_reverse = NIL; abook->unnamed = 0; abook->current = 0; return (abook); } void abook_free(struct abook *abook) { pool_free(abook->pool); } /* ====================================================================== */ /* abook_parse_line() *************************************************** * * Convert a line (from the preferences file) into an addressbook entry * abook: Addressbook to add to * line: (URL encoded) line to decode * session: For logging purposes only ***********************************************************************/ void abook_parse_line(struct abook *abook, char *line, struct session *session) { char *alias, *name, *fcc, *comment, *email; if (!strncmp(line, "__UNNAMED__ ", strlen("__UNNAMED__ "))) { abook->unnamed = atoi(line + strlen("__UNNAMED__ ")); return; } if ((alias = options_decode(string_get_token(&line))) && (name = options_decode(string_get_token(&line))) && (fcc = options_decode(string_get_token(&line))) && (comment = options_decode(string_get_token(&line))) && (email = options_decode(string_get_token(&line)))) abook_add(abook, alias, name, fcc, comment, email); } /* abook_print_options() ************************************************ * * Convert addressbook into printable representation for prefs file. * Addressbook to dump * Target buffer ***********************************************************************/ void abook_print_options(struct abook *abook, struct buffer *b) { struct list_item *li; if (abook->unnamed > 0) bprintf(b, "__UNNAMED__ %lu" CRLF, abook->unnamed); for (li = abook->list->head; li; li = li->next) { struct abook_entry *abe = (struct abook_entry *) li; unsigned long offset = 0L; options_print_token(b, abe->alias, &offset); options_print_token(b, abe->name, &offset); options_print_token(b, abe->fcc, &offset); options_print_token(b, abe->comment, &offset); options_print_token(b, abe->email, &offset); bputs(b, "" CRLF); } } /* ====================================================================== */ /* Local support routines */ static char *maybe_strdup(struct pool *p, char *s) { return ((s) ? pool_strdup(p, s) : ""); } /* abook_add() ********************************************************** * * Add entry to addressbook. * abook: Addressbook * alias: Alias for new abook entry * name: Personal name for addressbook entry * fcc: Fcc field (not yet used, however is recorded) * comment: Addressbook comment field * email: Email address (can be comment separated list) ***********************************************************************/ void abook_add(struct abook *abook, char *alias, char *name, char *fcc, char *comment, char *email) { struct pool *p; struct abook_entry *abe; p = abook->pool; abe = pool_alloc(p, sizeof(struct abook_entry)); abe->next = NIL; abe->used = NIL; if (alias && alias[0]) abe->alias = maybe_strdup(p, alias); else abe->alias = pool_printf(p, "unnamed_%d", ++abook->unnamed); abe->name = maybe_strdup(p, name); abe->fcc = maybe_strdup(p, fcc); abe->comment = maybe_strdup(p, comment); abe->email = maybe_strdup(p, email); abe->position = 0; list_push(abook->list, (struct list_item *) abe, abe->alias); assoc_update(abook->hash, pool_strdup(p, alias), abe, NIL); abook_clear_sort(abook); } /* abook_replace() ****************************************************** * * Replace existing entry to addressbook. (Not found => abook_add) * abook: Addressbook * alias: Alias for new abook entry * name: Personal name for addressbook entry * fcc: Fcc field (not yet used, however is recorded) * comment: Addressbook comment field * email: Email address (can be comment separated list) ***********************************************************************/ void abook_replace(struct abook *abook, char *alias, char *name, char *fcc, char *comment, char *email) { struct pool *p = abook->pool; struct list_item *li; if (alias && alias[0]) { for (li = abook->list->head; li; li = li->next) { struct abook_entry *abe = (struct abook_entry *) li; if (!strcasecmp(abe->alias, alias)) { abe->alias = maybe_strdup(p, alias); abe->name = maybe_strdup(p, name); abe->fcc = maybe_strdup(p, fcc); abe->comment = maybe_strdup(p, comment); abe->email = maybe_strdup(p, email); return; } } } abook_add(abook, alias, name, fcc, comment, email); abook_clear_sort(abook); } /* abook_remove() ******************************************************* * * Remove entry from addressbook * abook: Addressbook * alias: Alias to be removed ***********************************************************************/ void abook_remove(struct abook *abook, char *alias) { assoc_delete(abook->hash, alias); list_remove_byname(abook->list, alias); abook_clear_sort(abook); } /* abook_lookup() ******************************************************* * * Lookup addressbook entry. * abook: Addressbook * alias: Alias to look up ***********************************************************************/ struct abook_entry *abook_lookup(struct abook *abook, char *alias) { return ((struct abook_entry *) assoc_lookup(abook->hash, alias)); } /* abook_lookup_byoffset() ********************************************** * * Lookup addressbook entry. * abook: Addressbook * offset: Offset into list in the range 0..max-1 ***********************************************************************/ struct abook_entry *abook_lookup_byoffset(struct abook *abook, unsigned long offset) { return ((struct abook_entry *) list_lookup_byoffset(abook->list, offset)); } /* abook_lookup_sorted_byoffset() *************************************** * * Lookup addressbook entry. * abook: Addressbook * offset: Offset into list in the range 0..max-1 ***********************************************************************/ struct abook_entry *abook_lookup_sorted_byoffset(struct abook *abook, unsigned long offset) { if (abook->sort) { unsigned long count = list_length(abook->list); if (offset >= count) return(NIL); if (abook->sort_reverse) return(abook->sort[count-1-offset]); else return(abook->sort[offset]); } else { return ((struct abook_entry *) list_lookup_byoffset(abook->list, offset)); } } /* abook_find_email() *************************************************** * * Look for existing email entry which matches email address. * abook: Addressbook * email: Email address to find. ***********************************************************************/ struct abook_entry *abook_find_email(struct abook *abook, char *email) { struct abook_entry *abe; if (!email) return (NIL); for (abe = (struct abook_entry *) abook->list->head; abe; abe = abe->next) { if (abe->email && !strcmp(abe->email, email)) return (abe); } return (NIL); } /* ====================================================================== */ /* abook_match() ******************************************************* * * Find out if string value from addressbook matches given criteria. * Used as primitive operation by the search routines below. * Used by * test: String to be tested * type: Test of test (e.g: string starts with "value") * value: Value to match against test string. ***********************************************************************/ static BOOL abook_match(char *test, abook_search_type_type type, char *value) { BOOL match = NIL; char *s, c; switch (type) { case ABOOK_SEARCH_TYPE_NONE: /* Treat undefined as match */ match = T; break; case ABOOK_SEARCH_TYPE_IS: if (!strcasecmp(test, value)) match = T; break; case ABOOK_SEARCH_TYPE_BEGINS: if (!strncasecmp(test, value, strlen(value))) match = T; break; case ABOOK_SEARCH_TYPE_ENDS: if (!strncasecmp (test + strlen(test) - strlen(value), value, strlen(value))) match = T; break; case ABOOK_SEARCH_TYPE_CONTAINS: c = value[0]; for (s = test; *s; s++) { if (!strncasecmp(s, value, strlen(value))) { match = T; break; } } break; } return (match); } /* ====================================================================== */ /* abook_search_list_create() ******************************************* * * Create a addressbook search list structure with its own private pool. * match_all: TRUE => All criteria in list must match * FALSE => Any criteria in list must match * * Returns: new addressbook search list ***********************************************************************/ struct abook_search_list *abook_search_list_create(BOOL match_all) { struct pool *p = pool_create(PREFERRED_ASL_POOL_SIZE); struct abook_search_list *asl = pool_alloc(p, sizeof(struct abook_search_list)); asl->pool = p; asl->match_all = match_all; asl->first = NIL; asl->last = NIL; return (asl); } /* abook_search_list_free() ********************************************* * * Free addressbook search list, including any nodes. ***********************************************************************/ void abook_search_list_free(struct abook_search_list *asl) { pool_free(asl->pool); } /* abook_search_list_add() ********************************************** * * Add new entry to existing addressbook search list * asl: Addressbook search list * field: Field to match * type: Type of match * value: Value to match against given field using given type of search ***********************************************************************/ void abook_search_list_add(struct abook_search_list *asl, abook_search_field_type field, abook_search_type_type type, char *value) { struct abook_search_elt *ase = pool_alloc(asl->pool, sizeof(struct abook_search_elt)); ase->next = NIL; ase->field = field; ase->type = type; ase->value = pool_strdup(asl->pool, value); if (asl->first) { asl->last->next = ase; /* Add to end of list */ asl->last = ase; } else { asl->first = ase; /* Start new list */ asl->last = ase; } } /* ====================================================================== */ /* abook_search_init() ************************************************* * * Initialise addressbook for new search * abook: Addressbook to search ***********************************************************************/ void abook_search_init(struct abook *abook) { abook->search = (struct abook_entry *) abook->list->head; } /* abook_search_find_next() ********************************************* * * Find next addressbook entry which matches the search list criteria * abook: Addressbook to search (includes info about where to start search) * asl: Addressbook search list * * Returns: Next addressbook entry to match criteria, NIL if none. ***********************************************************************/ struct abook_entry *abook_search_find_next(struct abook *abook, struct abook_search_list *asl) { BOOL match = NIL; struct abook_entry *abe; struct abook_search_elt *ase; /* Search from last recorded location */ for (abe = abook->search; abe; abe = abe->next) { for (ase = asl->first; ase; ase = ase->next) { switch (ase->field) { case ABOOK_SEARCH_FIELD_NONE: /* Ignore undefined fields */ continue; case ABOOK_SEARCH_FIELD_ALIAS: match = abook_match(abe->alias, ase->type, ase->value); break; case ABOOK_SEARCH_FIELD_NAME: match = abook_match(abe->name, ase->type, ase->value); break; case ABOOK_SEARCH_FIELD_COMMENT: match = abook_match(abe->comment, ase->type, ase->value); break; case ABOOK_SEARCH_FIELD_EMAIL: match = abook_match(abe->email, ase->type, ase->value); break; } if (match && !asl->match_all) /* Only need single match */ break; if (!match && asl->match_all) /* Only need single failure */ break; } if (match) /* Final match in asl suceeded */ break; } /* Set up search engine for the next caller */ abook->search = (abe) ? abe->next : NIL; /* abe points to abook_entry matching all criteria, NIL if none */ return (abe); } /* ====================================================================== */ /* abook_text_to_string() *********************************************** * * Convert addressbook values to string value in the given pool * pool: Addressbook to use * name: Personal name * email: Email address (list) * * Returns: String form ***********************************************************************/ char *abook_text_to_string(struct pool *pool, char *name, char *email) { char *result; if (email == NIL) return (""); /* Just return email string if multiple addresses */ if (strchr(email, ',')) return (pool_strdup(pool, email)); /* Single address */ if (strchr(email, '<')) { /* email contains comment */ result = pool_strdup(pool, email); } else if (name[0]) { if (string_atom_has_special(name)) result = pool_printf(pool, "\"%s\" <%s>", string_atom_quote(pool, name), email); else result = pool_printf(pool, "%s <%s>", name, email); } else result = pool_strdup(pool, email); return (result); } /* abook_entry_to_string() ********************************************** * * Convert addressbook entry to string value in the given pool * pool: Addressbook to use * abe: Addressbook entry to convert * * Returns: String form ***********************************************************************/ char *abook_entry_to_string(struct pool *pool, struct abook_entry *abe) { return (abook_text_to_string(pool, abe->name, abe->email)); } /* ====================================================================== */ /* abook_substitute_recurse() ******************************************* * * Recursive addressbook lookup routine (internal) * session: * abook: * b: Target buffer for string expansion. * string: String to expand * root: Root address for this expansion (for error messages) * toplevel: T => top level of lookup: clear reference counts * * Returns: NIL on error (details sent to session_message). ***********************************************************************/ static BOOL abook_substitute_recurse(struct session *session, struct buffer *b, struct abook *abook, char *string, char *root, BOOL toplevel) { struct config *config = session->config; struct options *options = session->options; struct prefs *prefs = options->prefs; char *default_domain = prefs->default_domain; struct request *request = session->request; struct list_item *li; struct abook_entry *abe; ADDRESS *a, *addr = NIL; if (toplevel) { for (li = abook->list->head; li; li = li->next) { abe = (struct abook_entry *) li; abe->used = NIL; } } if (!(addr=addr_parse(request->pool, string, ""))) { session_message(session, "%s", ml_errmsg()); return (NIL); } for (a = addr; a; a = a->next) { if (!(a->mailbox && a->mailbox[0])) /* Impossible? */ continue; if (a->host && a->host[0]) { /* Component already qualified */ if (a->personal && a->personal[0]) { if (string_atom_has_special(a->personal)) bprintf(b, "\"%s\" <%s@%s>", string_atom_quote(request->pool, a->personal), a->mailbox, a->host); else bprintf(b, "%s <%s@%s>", a->personal, a->mailbox, a->host); } else bprintf(b, "%s@%s", a->mailbox, a->host); } else if ((abe = abook_lookup(abook, a->mailbox))) { if (abe->used) { session_message(session, "Addressbook loop involving:\"%s\"", root); mail_free_address(&addr); return (NIL); } abe->used = T; string = abook_entry_to_string(request->pool, abe); if (!abook_substitute_recurse (session, b, abook, string, root, NIL)) { mail_free_address(&addr); return (NIL); } } else { /* Nothing in personal addressbook */ if (a->personal && a->personal[0]) { if (string_atom_has_special(a->personal)) bprintf(b, "\"%s\" <%s@%s>", string_atom_quote(request->pool, a->personal), a->mailbox, default_domain); else bprintf(b, "%s <%s@%s>", a->personal, a->mailbox, default_domain); } else if (config->local_domain_list) { struct list_item *li; char *value, *v2; for (li = config->local_domain_list->head; li; li = li->next) { struct config_local_domain *cld = (struct config_local_domain *) li; if (cld->cdb_map && !strcmp(default_domain, cld->name)) { if (cdb_find (cld->cdb_map, a->mailbox, strlen(a->mailbox), &v2)) { if (v2 && v2[0] && (value = string_trim_whitespace(v2))) { if (string_atom_has_special(value)) bprintf(b, "\"%s\" <%s@%s>", string_atom_quote(request-> pool, value), a->mailbox, default_domain); else bprintf(b, "%s <%s@%s>", value, a->mailbox, default_domain); free(v2); } else bprintf(b, "%s@%s", a->mailbox, default_domain); break; } else { mail_free_address(&addr); session_message(session, "Address \"%s\" invalid", root); return (NIL); } } } if (li == NIL) /* Not found */ bprintf(b, "%s@%s", a->mailbox, default_domain); } else bprintf(b, "%s@%s", a->mailbox, default_domain); } if (a->next) bputs(b, ", "); } mail_free_address(&addr); return (T); } /* ====================================================================== */ /* abook_substitute() *************************************************** * * Expand email list through addressbook lookup * session: * pool: Target pool for expansion nominated by client * abook: * string: String to expand * * Returns: String form ***********************************************************************/ char *abook_substitute(struct session *session, struct pool *pool, struct abook *abook, char *string) { struct config *config = session->config; struct request *request = session->request; struct buffer *b = buffer_create(pool, 4096); ADDRESS *a, *addr = NIL; if (!(addr=addr_parse(request->pool, string, ""))) { session_message(session, "%s", ml_errmsg()); return (NIL); } /* Treat each address as new toplevel entity */ for (a = addr; a; a = a->next) { if (!(a->mailbox && a->mailbox[0])) /* Impossible? */ continue; if (a->host && a->host[0]) { /* Name already qualified: don't try addressbook lookup */ if (a->personal && a->personal[0]) { /* Make sure that personal name is properly quoted */ if (string_atom_has_special(a->personal)) bprintf(b, "\"%s\" <%s@%s>", string_atom_quote(request->pool, a->personal), a->mailbox, a->host); else bprintf(b, "%s <%s@%s>", a->personal, a->mailbox, a->host); } else if (config->local_domain_list) { /* No personal name provided: try and find one */ struct list_item *li; char *value, *v2; for (li = config->local_domain_list->head; li; li = li->next) { struct config_local_domain *cld = (struct config_local_domain *) li; if (cld->cdb_map && !strcmp(a->host, cld->name) && cdb_find(cld->cdb_map, a->mailbox, strlen(a->mailbox), &v2) && v2 && v2[0] && (value = string_trim_whitespace(v2))) { if (string_atom_has_special(value)) bprintf(b, "\"%s\" <%s@%s>", string_atom_quote(request->pool, value), a->mailbox, a->host); else bprintf(b, "%s <%s@%s>", value, a->mailbox, a->host); free(v2); break; } } if (li == NIL) /* Not found */ bprintf(b, "%s@%s", a->mailbox, a->host); } else bprintf(b, "%s@%s", a->mailbox, a->host); } else if (!abook_substitute_recurse(session, b, abook, a->mailbox, a->mailbox, T)) { mail_free_address(&addr); return (NIL); } if (a->next) bputs(b, ", "); } mail_free_address(&addr); return (buffer_fetch(b, 0, buffer_size(b), NIL)); } /* ====================================================================== */ /* abook_check_loop() *************************************************** * * Check for loops in addressbook (cmd_abook_entry and cmd_abook_update) * pool: Target (scratch) pool for expansion nominated by client * abook: * string: String to expand * toplevel: Toplevel of recursion. * * Returns: String form ***********************************************************************/ BOOL abook_check_loop(struct pool * pool, struct abook * abook, char *string, BOOL toplevel) { struct list_item *li; struct abook_entry *abe; ADDRESS *a, *addr = NIL; if (toplevel) { for (li = abook->list->head; li; li = li->next) { abe = (struct abook_entry *) li; abe->used = NIL; } } if (!(addr=addr_parse(pool, string, ""))) return (NIL); for (a = addr; a; a = a->next) { if (!(a->mailbox && a->mailbox[0])) /* Impossible? */ continue; if (a->host && a->host[0]) continue; if (!(abe = abook_lookup(abook, a->mailbox))) continue; /* If we get this far then "a->mailbox" is live addressbook alias */ if (abe->used) { mail_free_address(&addr); return (NIL); } abe->used = T; if (!(abook_check_loop(pool, abook, abe->email, NIL))) { mail_free_address(&addr); return (NIL); } } mail_free_address(&addr); return (T); } /* ====================================================================== */ /* abook_import_pine_get_entry() **************************************** * * Isolate a single addressbook entry from a string. Almost but not the * same action as string_get_lws_line(): * 1) Lines are folded using one or more SP characters at the start of * a line. * 2) Entry terminates if next line starts with character != SP, * including a tab character. * * Returns: Ptr to this line ***********************************************************************/ static char *abook_import_pine_get_entry(char **sp) { char *s, *t, *result; BOOL quoted = NIL; s = *sp; if (!(s && s[0])) return (NIL); /* Skip leading whitespace */ while ((*s == ' ')) s++; /* Empty string before data proper starts? */ if ((s[0] == '\0')) { *sp = s; return (s); } /* CR, LF or CRLF before data proper starts? */ if ((s[0] == '\015') || (s[0] == '\012')) { result = s; if ((s[0] == '\015') && (s[1] == '\012')) { /* CRLF */ *s = '\0'; s += 2; } else *s++ = '\0'; /* CR or LF */ *sp = s; return (result); } result = t = s; /* Record position of non-LWS */ while (*s) { if ((*s == '\015') || (*s == '\012')) { /* CR, LF or CRLF */ s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; if ((*s != ' ')) break; /* Is a continuation line */ quoted = NIL; /* Is "LWS" allowed? */ if ((t > result) && (t[-1] != ' ')) { /* Replace LWS with SP */ *t++ = ' '; } } else { if (*s == '"') quoted = (quoted) ? NIL : T; /* Toggle quoted bit */ if (t < s) /* Copy faithfully */ *t++ = *s++; else { t++; s++; /* Data hasn't moved yet */ } } } *t = '\0'; /* Tie off result string */ *sp = s; /* Set up for next caller */ return (result); } /* abook_import_pine_get_token() ***************************************** * * Extract single token from Pine addressbok entry ************************************************************************/ static char *abook_import_pine_get_token(char **sp) { char *s = *sp, *result; while ((*s == ' ')) s++; /* Record position of this token */ result = s; /* Find tab character or end of string */ while ((*s) && (*s != '\t')) s++; /* Tie off the string unless \0 already reached */ if (*s) { *s++ = '\0'; while ((*s == ' ')) s++; } /* Record position of first non-whitespace character for next caller */ *sp = s; return (result); } /* abook_import_pine_valid() ********************************************* * * Test for valid Pine addressbook to best of our ability. Looking for * >= 2 TAB characters in first LWS block + lack of binary data. * ************************************************************************/ BOOL abook_import_pine_valid(char *t) { unsigned long tab_count = 0; unsigned char *s = (unsigned char *) t; unsigned char c; if (!strncmp (t, "# Prayer addressbook", strlen("# Prayer addressbook"))) return (T); while ((c = *s++)) { if ((c == '\015') || (c == '\012')) { /* CR or LF */ if ((c == '\015') && (*s == '\012')) /* CRLF */ s++; if (*s != ' ') /* Check for continuation line */ break; } else if ((c == '\t')) tab_count++; else if (c > 0x80) return (NIL); } return ((tab_count >= 2) ? T : NIL); } /* ====================================================================== */ /* abook_import_pine() *************************************************** * * Import PINE format addressbook * abook: Addressbook to import to * text: PINE format addressbook to import * * Returns: Number of abook entries imported ************************************************************************/ /* Import Pine format addressbook */ unsigned long abook_import_pine(struct abook *abook, char *text) { struct pool *pool = pool_create(1024); char *line; char *alias; char *email; char *fcc; char *comment; char *name; char *s; unsigned long count = 0; while ((line = abook_import_pine_get_entry(&text))) { if (line[0] == '#') continue; if (line[0] == '\0') continue; alias = abook_import_pine_get_token(&line); name = abook_import_pine_get_token(&line); email = abook_import_pine_get_token(&line); fcc = abook_import_pine_get_token(&line); comment = abook_import_pine_get_token(&line); if ((s = strchr(name, ','))) { char *first, *last; /* "Last, First" */ *s++ = '\0'; last = name; first = s; name = pool_printf(pool, "%s %s", first, last); } if (email && (email[0] == '(')) { unsigned long len = strlen(email); if ((len >= 2) && (email[len - 1] == ')')) { /* Prune away leading '(' and trailing ')' */ email[len - 1] = '\0'; email++; } } alias = (alias) ? string_trim_whitespace(alias) : ""; name = (name) ? string_trim_whitespace(name) : ""; fcc = (fcc) ? string_trim_whitespace(fcc) : ""; comment = (comment) ? string_trim_whitespace(comment) : ""; email = (email) ? string_trim_whitespace(email) : ""; abook_replace(abook, alias, name, fcc, comment, email); count++; } return (count); } /* ====================================================================== */ /* abook_import_csv_valid() ********************************************** * * Test for valid CSV addressbook to best of our ability. First line * should include some of: Name,Nickname,E-mail Address. * ************************************************************************/ BOOL abook_import_csv_valid(char *s) { char *t; if (!(t=strchr(s, '\n'))) return(NIL); *t = '\0'; if (strstr(s, "E-mail Address") && strstr(s, "Name")) { *t = '\n'; return(T); } *t = '\n'; return(NIL); } /* abook_import_csv() **************************************************** * * Import CSV format addressbook * abook: Addressbook to import to * text: CSV format addressbook to import * * Returns: Number of abook entries imported ************************************************************************/ /* Small utility function to break CSV lines into "tokens". Possible * formats: a,b,c, a,"d, fgg,",c */ static char *csv_item(char **sp) { char *s = *sp; char *t; if ((sp == NIL) || ((s=*sp) == NIL)) return(NIL); if (*s == '"') { s++; if ((t=strstr(s, "\","))) { *t++ = '\0'; t++; *sp = t; } else if ((t=strchr(s, '"'))) { *t++ = '\0'; *sp = t; } else *sp = NIL; return(string_trim_whitespace(s)); } if ((t=strchr(s, ','))) { *t++ = '\0'; *sp = t; return(string_trim_whitespace(s)); } else *sp = NIL; return(string_trim_whitespace(s)); } unsigned long abook_import_csv(struct abook *abook, char *text) { char *line, *item; unsigned long count = 0; int name_offset = (-1); int nick_offset = (-1); int email_offset = (-1); int offset = 0; if (!(line=string_get_line(&text))) return(0); offset = 0; while ((item=csv_item(&line))) { if (!strcmp(item, "Name")) name_offset = offset; else if (!strcmp(item, "Nickname")) nick_offset = offset; else if (!strcmp(item, "E-mail Address")) email_offset = offset; offset++; } if ((name_offset < 0) || (email_offset < 0)) /* Not a valid format */ return(0); while ((line = string_get_line(&text))) { char *alias = ""; char *email = ""; char *name = ""; if (line[0] == '\0') continue; offset = 0; while ((item=csv_item(&line))) { if (offset == name_offset) name = item; else if (offset == nick_offset) alias = item; else if (offset == email_offset) email = item; offset++; } /* abook_add() will make up alias if not provided */ if (email[0]) { abook_replace(abook, alias, name, "", "", email); count++; } } return(count); } /* ====================================================================== */ /* Support functions for abook_export_buffer and abook_export_text */ static void bputc_tab(struct buffer *b, unsigned long *offsetp) { bputc(b, '\t'); *offsetp = 8 * ((*offsetp + 8) % 8); /* Locate next tab stop position */ } static void bputs_offset(struct buffer *b, unsigned long *offsetp, char *s) { unsigned long len; if (!s) s = ""; len = strlen(s); if ((*offsetp + len) > 76) { /* Fold this line */ bputs(b, "\n "); bputs(b, s); *offsetp = len + 3; } else { bputs(b, s); *offsetp += len; } } static void bputs_offset_email_list(struct buffer *b, unsigned long *offsetp, char *s) { char *t; if (!s) s = ""; while (*s == ' ') s++; if ((*offsetp + strlen(s)) < 76) { /* Will fit on this line without any messing around */ bputs_offset(b, offsetp, s); return; } /* Print email address one component at a time * Hopefully means that line wrap will occur in some sensible place! */ while ((t = strchr(s, ','))) { while (*s == ' ') s++; /* Print this address */ *t = '\0'; bputs_offset(b, offsetp, s); bputs_offset(b, offsetp, ","); *t = ','; /* Next address */ s = t + 1; } while (*s == ' ') s++; /* Print remaining string if any */ if (s) bputs_offset(b, offsetp, s); } /* abook_export_pine() *************************************************** * * Export PINE format addressbook to buffer * abook: Addressbook to export * pool: Pool to allocate from ************************************************************************/ void abook_export_pine(struct abook *abook, struct buffer *b) { struct list_item *li; struct pool *pool = b->pool; for (li = abook->list->head; li; li = li->next) { struct abook_entry *abe = (struct abook_entry *) li; unsigned long offset = 0; char *name; bputs_offset(b, &offset, abe->alias); bputc_tab(b, &offset); name = (abe->name && abe->name[0]) ? abe->name : ""; bputs_offset(b, &offset, name); bputc_tab(b, &offset); if (strchr(abe->email, ',')) { name = pool_strcat3(pool, "(", abe->email, ")"); bputs_offset_email_list(b, &offset, name); bputs_offset(b, &offset, "\t"); } else { bputs_offset(b, &offset, abe->email); bputc_tab(b, &offset); } bputs_offset(b, &offset, abe->fcc); bputc_tab(b, &offset); bputs_offset(b, &offset, abe->comment); bputc(b, '\n'); } } /* abook_export_csv() **************************************************** * * Export CSV (Outlook format) addressbook to buffer * abook: Addressbook to export * pool: Pool to allocate from ************************************************************************/ void abook_export_csv(struct abook *abook, struct buffer *b) { struct list_item *li; bputs(b, "Name,Nickname,E-mail Address"CRLF); for (li = abook->list->head; li; li = li->next) { struct abook_entry *abe = (struct abook_entry *) li; char *name; name = (abe->name && abe->name[0]) ? abe->name : ""; if (strchr(abe->email, ',')) bprintf(b, "%s,%s,\"%s\""CRLF, name, abe->alias, abe->email); else bprintf(b, "%s,%s,%s"CRLF, name, abe->alias, abe->email); } } /* abook_export_text() *************************************************** * * Export addressbook to string * abook: Addressbook to export * pool: Pool to allocate from ************************************************************************/ char *abook_export_text(struct abook *abook, struct pool *pool) { struct buffer *b = buffer_create(pool, 4096); abook_export_pine(abook, b); return (buffer_fetch(b, 0, buffer_size(b), NIL)); } /* abook_clear_sort() **************************************************** * * * Sort addressbook on given field: * abook: Addressbook to sort * ************************************************************************/ void abook_clear_sort(struct abook *abook) { if (abook->sort) free(abook->sort); abook->sort = NULL; } /* abook_set_sort() ****************************************************** * * * Define addressbook sort sort * abook: Addressbook to sort * sort_mode: Field to sort on * reverse: Reverse sort * ************************************************************************/ void abook_set_sort(struct abook *abook, abook_sort_mode sort_mode, BOOL reverse) { abook->sort_mode = sort_mode; abook->sort_reverse = reverse; abook_clear_sort(abook); } /* Sort support functions */ static int abook_sort_compare_alias(const void *aptr, const void *bptr) { struct abook_entry *a = *((struct abook_entry **)aptr); struct abook_entry *b = *((struct abook_entry **)bptr); return(strcasecmp(a->alias, b->alias)); } static int abook_sort_compare_comment(const void *aptr, const void *bptr) { struct abook_entry *a = *((struct abook_entry **)aptr); struct abook_entry *b = *((struct abook_entry **)bptr); return(strcasecmp(a->comment, b->comment)); } static int abook_sort_compare_address(const void *aptr, const void *bptr) { struct abook_entry *a = *((struct abook_entry **)aptr); struct abook_entry *b = *((struct abook_entry **)bptr); return(strcasecmp(a->email, b->email)); } static int abook_sort_compare_name(const void *aptr, const void *bptr) { struct abook_entry *a = *((struct abook_entry **)aptr); struct abook_entry *b = *((struct abook_entry **)bptr); char *s; char *firstname1, *lastname1; char *firstname2, *lastname2; int comp; /* Attempt to extract firstname and lastname from plain text field: * "Forename(s) Lastname", "Lastname, Forename(s), or "single name" */ if ((s=strchr(a->name, ','))) { s++; while (*s == ' ') s++; firstname1 = s; lastname1 = a->name; } else if ((s=strrchr(a->name, ' '))) { firstname1 = a->name; lastname1 = s+1; } else { firstname1 = ""; lastname1 = a->name; } if ((s=strchr(b->name, ','))) { s++; while (*s == ' ') s++; firstname2 = s; lastname2 = b->name; } else if ((s=strrchr(b->name, ' '))) { firstname2 = b->name; lastname2 = s+1; } else { firstname2 = ""; lastname2 = b->name; } comp=strcasecmp(lastname1, lastname2); if (comp != 0) return(comp); return(strcasecmp(firstname1, firstname2)); } /* abook_sort() ********************************************************** * * * Sort addressbook on given field: * abook: Addressbook to sort * ************************************************************************/ void abook_sort(struct abook *abook) { unsigned long i, count; struct abook_entry *current; if (abook->sort) /* Cache remains valid until cleared */ return; count = list_length(abook->list); abook->sort = pool_alloc(NIL, (count+1) * sizeof(struct abook_entry *)); for (i = 0, current = (struct abook_entry *)abook->list->head; current && (inext, i++) { abook->sort[i] = current; current->position = i + 1; } if (i != count) log_fatal(("abort_sort(): recorded addressbook length" " does not match actual length")); abook->sort[count] = NULL; if (abook->sort_mode == ABOOK_SORT_ALIAS) qsort(abook->sort, count, sizeof(struct abook_entry *), abook_sort_compare_alias); else if (abook->sort_mode == ABOOK_SORT_NAME) qsort(abook->sort, count, sizeof(struct abook_entry *), abook_sort_compare_name); else if (abook->sort_mode == ABOOK_SORT_COMMENT) qsort(abook->sort, count, sizeof(struct abook_entry *), abook_sort_compare_comment); else if (abook->sort_mode == ABOOK_SORT_EMAIL) qsort(abook->sort, count, sizeof(struct abook_entry *), abook_sort_compare_address); } ./prayer-1.3.5/session/checksum.h0000644006513000651300000000116011063701636015230 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/checksum.h,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* External Interfere Prototypes for checksum.c */ /* XXX Move into config? */ #define CHECKSUM_PREFIX "# END SIEVE FILE. CHECKSUM=" BOOL checksum_test(char *string, struct pool *pool); unsigned long checksum_calculate(char *string, struct pool *pool); ./prayer-1.3.5/session/ml.c0000644006513000651300000004340311063701636014037 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/ml.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Wrapper functions for various c-client routines: * * Original idea was to provide transparent reopen on [CLOSED] events * probably no longer need this: main event loop checkpoints open streams * However this is still a useful way to hide all the ghastly c-client * callback routines from the main program. These routines also trap * mm_exists and mm_expunged events and call msgmap_invalidate if * things change unexpectly beneath our feet. Will be particularly * important with concurrent read-write sessions on IMAP server. * */ #include "prayer_session.h" static struct memblock *errmsg = NIL; /* Must call mm_init before any other fn. mm_init() calls ml_init() */ void ml_init() { errmsg = memblock_create(NIL, 64); mail_parameters(NIL, SET_RSHTIMEOUT, (void *) 0L); mail_parameters(NIL, SET_OPENTIMEOUT, (void *) ML_OPENTIMEOUT); mail_parameters(NIL, SET_READTIMEOUT, (void *) ML_READTIMEOUT); mail_parameters(NIL, SET_WRITETIMEOUT, (void *) ML_WRITETIMEOUT); } /* ====================================================================== */ static BOOL have_error = NIL; /* Have error */ BOOL ml_have_error() { return (have_error); } void ml_clear_error() { have_error = NIL; mputs(errmsg, ""); } void ml_set_error() { have_error = T; } /* Local equivalents: don't rely on automatic inlining */ #define ml_have_error() (have_error) #define ml_clear_error() {have_error = NIL; } #define ml_set_error() {have_error = T;} /* ====================================================================== */ char *ml_errmsg() { return (memblock_string(errmsg)); } BOOL ml_have_errmsg() { char *s = memblock_string(errmsg); return ((s && *s) ? T : NIL); } void ml_clear_errmsg() { mputs(errmsg, ""); } void ml_set_errmsg(char *error) { mputs(errmsg, error); } void ml_errmsg_printf(char *fmt, ...) { struct memblock *m = errmsg; unsigned long size; va_list ap; va_start(ap, fmt); size = memblock_vprintf_size(m, fmt, ap); va_end(ap); memblock_resize(m, size + 1); va_start(ap, fmt); memblock_vprintf(m, fmt, ap); va_end(ap); } /* ====================================================================== */ static BOOL have_try_create = NIL; /* Have try_create */ BOOL ml_have_try_create() { return (have_try_create); } void ml_clear_try_create() { have_try_create = NIL; } void ml_set_try_create() { have_try_create = T; } /* Local equivalents: don't rely on automatic inlining */ #define ml_have_try_create() (have_try_create) #define ml_clear_try_create() {have_try_create = NIL;} #define ml_set_try_create() {have_try_create = T;} /* ====================================================================== */ static BOOL have_close = NIL; /* Stream closed */ BOOL ml_have_close() { return (have_close); } void ml_clear_have_close() { have_close = NIL; } void ml_set_have_close() { have_close = T; } /* Local equivalents: don't rely on automatic inlining */ #define ml_have_close() (have_close) #define ml_clear_have_close() {have_close = NIL;} #define ml_set_have_close() {have_close = T;} /* ====================================================================== */ static BOOL mailbox_update = NIL; /* mm_exists or mm_expunged call */ BOOL ml_mailbox_update() { return (mailbox_update); } void ml_clear_mailbox_update() { mailbox_update = NIL; } void ml_set_mailbox_update() { mailbox_update = T; } /* Local equivalents: don't rely on automatic inlining */ #define ml_mailbox_update() (mailbox_update) #define ml_clear_mailbox_update() {mailbox_update = NIL;} #define ml_set_mailbox_update() {mailbox_update = T;} /* ====================================================================== */ MESSAGECACHE *ml_elt(struct session *session, MAILSTREAM * stream, unsigned long msgno) { MESSAGECACHE *elt; if (msgno < 1 || msgno > stream->nmsgs) { session_message(session, "Bad msgno %lu in mail_elt, nmsgs = %lu", msgno, stream->nmsgs); session_log(session, "[ml_elt] Bad msgno %lu in mail_elt, nmsgs = %lu", msgno, stream->nmsgs); session_paniclog(session, "Bad msgno %lu in mail_elt, nmsgs = %lu", msgno, stream->nmsgs); #if 0 /* Unfriendly now that concurrent access mostly works (though testing for things changing under your feet is hard work) */ abort(); #endif return (NIL); } ml_clear_have_close(); if (!(elt = mail_elt(stream, msgno))) return (NIL); /* No ml_check_update here... */ return (elt); } unsigned long ml_msgno(struct session *session, MAILSTREAM * stream, unsigned long uid) { unsigned long result; ml_clear_have_close(); if (!((result = mail_msgno(stream, uid)) > 0)) return (0L); return (result); } unsigned long ml_uid(struct session *session, MAILSTREAM * stream, unsigned long msgno) { if ((msgno == 0) || (msgno > stream->nmsgs)) return (0); ml_clear_have_close(); return (mail_uid(stream, msgno)); } BOOL ml_fetch_fast(struct session * session, MAILSTREAM * stream, char *seq, unsigned long flags) { ml_clear_have_close(); ml_clear_error(); mail_fetch_fast(stream, seq, flags); if (ml_have_close() || ml_have_error()) return (NIL); return (T); } BOOL ml_fetch_overview(struct session * session, MAILSTREAM * stream, char *sequence, overview_t ofn) { ml_clear_have_close(); ml_clear_error(); mail_fetch_overview(stream, sequence, ofn); if (ml_have_close() || ml_have_error()) return (NIL); return (T); } ENVELOPE *ml_fetch_structure(struct session * session, MAILSTREAM * stream, unsigned long msgno, BODY ** body, long flags) { ENVELOPE *env; ml_clear_have_close(); ml_clear_error(); if (body) { if (!((env = mail_fetch_structure(stream, msgno, body, flags)) && *body)) env = NIL; /* Envelope and body must work */ } else env = mail_fetch_structure(stream, msgno, body, flags); if (ml_have_close() || ml_have_error()) return (NIL); return (env); } char *ml_fetch_message(struct session *session, MAILSTREAM * stream, unsigned long msgno, unsigned long *len, long flags) { char *msg; ml_clear_have_close(); ml_clear_error(); msg = mail_fetch_message(stream, msgno, len, flags); if (ml_have_close() || ml_have_close()) return (NIL); return (msg); } char *ml_fetch_header(struct session *session, MAILSTREAM * stream, unsigned long msgno, char *section, STRINGLIST * lines, unsigned long *len, long flags) { char *hdr; ml_clear_have_close(); ml_clear_error(); hdr = mail_fetch_header(stream, msgno, section, lines, len, flags); if (ml_have_close() || ml_have_error()) return (NIL); return (hdr); } char *ml_fetch_text(struct session *session, MAILSTREAM * stream, unsigned long msgno, char *section, unsigned long *len, long flags) { char *text; ml_clear_have_close(); ml_clear_error(); text = mail_fetch_text(stream, msgno, section, len, flags); if (ml_have_close() || ml_have_error()) return (NIL); return (text); } char *ml_fetch_mime(struct session *session, MAILSTREAM * stream, unsigned long msgno, char *section, unsigned long *len, long flags) { char *mime; ml_clear_have_close(); ml_clear_error(); mime = mail_fetch_mime(stream, msgno, section, len, flags); if (ml_have_close() || ml_have_error()) return (NIL); return (mime); } char *ml_fetch_body(struct session *session, MAILSTREAM * stream, unsigned long msgno, char *section, unsigned long *len, long flags) { char *body; ml_clear_have_close(); ml_clear_error(); body = mail_fetch_body(stream, msgno, section, len, flags); if (ml_have_close() || ml_have_error()) return (NIL); return (body); } BODY *ml_body(struct session * session, MAILSTREAM * stream, unsigned long msgno, char *section) { BODY *body; ml_clear_have_close(); ml_clear_error(); body = mail_body(stream, msgno, (unsigned char *)section); if (ml_have_close() || ml_have_error()) return (NIL); return (body); } /* ====================================================================== */ BOOL ml_ping(struct session * session, MAILSTREAM * stream) { long result; ml_clear_have_close(); ml_clear_error(); result = mail_ping(stream); if (ml_have_close() || ml_have_error()) return (NIL); return ((result != 0) ? T : NIL); } /* ml_append transparently creates target mail folder on TRYCREATE error */ BOOL ml_append(struct session * session, MAILSTREAM * stream, char *mailbox, STRING * message) { STRING spare; char *s; /* mail_append() blats STRING * arg */ memcpy(&spare, message, sizeof(STRING)); ml_clear_try_create(); ml_clear_have_close(); ml_clear_error(); ml_clear_errmsg(); if (mail_append(stream, mailbox, message)) { /* Additional paranoia for append: make all warnings error codes */ /* other than: Cyrus is a bit verbose: APPENDUID is not an error */ if (ml_have_errmsg() && (s = ml_errmsg()) && (strncmp(s, "[APPENDUID ", strlen("[APPENDUID ")) != 0)) { ml_set_error(); return (NIL); } return (T); } if (ml_have_close()) return (NIL); if (!ml_have_try_create()) return (NIL); if (!ml_create(session, stream, mailbox)) return (NIL); ml_clear_try_create(); ml_clear_have_close(); ml_clear_error(); ml_clear_errmsg(); if (mail_append(stream, mailbox, &spare)) { /* Additional paranoia for append: make all warnings error codes */ /* other than: Cyrus is a bit verbose: APPENDUID is not an error */ if (ml_have_errmsg() && (s = ml_errmsg()) && (strncmp(s, "[APPENDUID ", strlen("[APPENDUID ")) != 0)) { ml_set_error(); return (NIL); } return (T); } return (NIL); } BOOL ml_append_multiple(struct session * session, MAILSTREAM * stream, char *mailbox, append_t fn, void *ap) { char *s; ml_clear_try_create(); ml_clear_have_close(); ml_clear_error(); ml_clear_errmsg(); if (mail_append_multiple(stream, mailbox, fn, ap)) { /* Additional paranoia for append: make all warnings error codes */ /* other than: Cyrus is a bit verbose: APPENDUID is not an error */ if (ml_have_errmsg() && (s = ml_errmsg()) && (strncmp(s, "[APPENDUID ", strlen("[APPENDUID ")) != 0)) { ml_set_error(); return (NIL); } return (T); } if (ml_have_close()) return (NIL); if (!ml_have_try_create()) return (NIL); if (!ml_create(session, stream, mailbox)) return (NIL); ml_clear_try_create(); ml_clear_have_close(); ml_clear_error(); ml_clear_errmsg(); if (mail_append_multiple(stream, mailbox, fn, ap)) { /* Additional paranoia for append: make all warnings error codes */ /* other than: Cyrus is a bit verbose: APPENDUID is not an error */ if (ml_have_errmsg() && (s = ml_errmsg()) && (strncmp(s, "[APPENDUID ", strlen("[APPENDUID ")) != 0)) { ml_set_error(); return (NIL); } return (T); } return (NIL); } /* ====================================================================== */ BOOL ml_copy(struct session * session, MAILSTREAM * stream, char *sequence, char *mailbox, long options) { long result; char *s; /* We leave it up to the client routine to handle trycreate */ ml_clear_have_close(); ml_clear_error(); ml_clear_errmsg(); result = mail_copy_full(stream, sequence, mailbox, options); if (ml_have_close() || (result == 0)) return (NIL); /* Additional paranoia for copy: make all warnings error codes */ /* other than: Cyrus is a bit verbose: COPYUID is not an error */ if (ml_have_errmsg() && (s = ml_errmsg()) && (strncmp(s, "[COPYUID ", strlen("[COPYUID ")) != 0)) { ml_set_error(); return (NIL); } return (T); } BOOL ml_check(struct session * session, MAILSTREAM * stream) { ml_clear_have_close(); ml_clear_error(); mail_check(stream); if (ml_have_close() || ml_have_error()) return (NIL); return (T); } void ml_close(struct session *session, MAILSTREAM * stream) { mail_close(stream); /* No point in reopening, just to close */ } BOOL ml_create(struct session *session, MAILSTREAM * stream, char *mailbox) { long result; ml_clear_have_close(); ml_clear_error(); result = mail_create(stream, mailbox); if (ml_have_close() || ml_have_error()) return (NIL); return ((result != 0) ? T : NIL); } BOOL ml_delete(struct session * session, MAILSTREAM * stream, char *mailbox) { long result; ml_clear_have_close(); ml_clear_error(); result = mail_delete(stream, mailbox); if (ml_have_close() || ml_have_error()) return (NIL); return ((result != 0) ? T : NIL); } BOOL ml_expunge(struct session * session, MAILSTREAM * stream) { ml_clear_have_close(); ml_clear_error(); mail_expunge(stream); if (ml_have_close() || ml_have_error()) return (NIL); return (T); } BOOL ml_flag(struct session * session, MAILSTREAM * stream, char *sequence, char *flag, long flags) { ml_clear_have_close(); ml_clear_error(); mail_flag(stream, sequence, flag, flags); if (ml_have_error() || ml_have_close()) return (NIL); return (T); } BOOL ml_list(struct session * session, MAILSTREAM * stream, char *ref, char *pat) { ml_clear_have_close(); ml_clear_error(); mail_list(stream, ref, pat); if (ml_have_close() || ml_have_error()) return (NIL); return (T); } static MAILSTATUS *ml_status_val = NIL; void ml_status_callback(MAILSTATUS *status) { if (ml_status_val) memcpy(ml_status_val, status, sizeof(MAILSTATUS)); } BOOL ml_status(struct session * session, MAILSTREAM * stream, char *mbx, int flags, MAILSTATUS *status) { BOOL result; ml_clear_have_close(); ml_clear_error(); memset(status, 0, sizeof(MAILSTATUS)); ml_status_val = status; result = mail_status(stream, mbx, flags) ? T : NIL; ml_status_val = NIL; if (ml_have_close() || ml_have_error()) return (NIL); return (result); } /* ====================================================================== */ static struct session *this_session = NIL; static void ml_open_login_callback(NETMBX * mb, char *user, char *pwd, long trial) { struct session *session = this_session; if ((trial > 0) && session->newpassword) { session->password = session->newpassword; session->newpassword = NIL; } strcpy(user, this_session->username); strcpy(pwd, this_session->password); } static MAILSTREAM *ml_open_work(struct session *session, MAILSTREAM * oldstream, char *name, long options) { MAILSTREAM *stream; /* Register login callback above, which provides username and password */ this_session = session; mm_register_login_callback(ml_open_login_callback); if (session->newpassword) mail_parameters(NIL, SET_MAXLOGINTRIALS, (void *) 2L); else mail_parameters(NIL, SET_MAXLOGINTRIALS, (void *) 1L); ml_clear_have_close(); ml_clear_error(); /* No mailbox update check: open will always call mm_exists! */ if ((stream = mail_open(oldstream, name, options))) return (stream); if (!oldstream) return (NIL); /* No point in trying to reopen unless was open */ if (ml_have_close()) return (NIL); return (mail_open(NIL, name, options)); } MAILSTREAM *ml_open(struct session * session, MAILSTREAM * oldstream, char *name, long options) { MAILSTREAM *result = ml_open_work(session, oldstream, name, options); char *error; if (result) return (result); error = ml_errmsg(); /* Translate silly default message from imap_login() back into English */ if (!error || !error[0] || !strcmp(error, "Too many login failures")) ml_set_errmsg("Incorrect username or password"); return (NIL); } BOOL ml_rename(struct session * session, MAILSTREAM * stream, char *oldname, char *newname) { long result; ml_clear_have_close(); ml_clear_error(); result = mail_rename(stream, oldname, newname); if (ml_have_close() || ml_have_error()) return (NIL); return ((result != 0) ? T : NIL); } BOOL ml_search_full(struct session * session, MAILSTREAM * stream, char *charset, SEARCHPGM * pgm, long flags) { ml_clear_have_close(); ml_clear_error(); mail_search_full(stream, charset, pgm, flags); if (ml_have_close() || ml_have_error()) return (NIL); return (T); } ./prayer-1.3.5/session/role.c0000644006513000651300000001321311063701636014364 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/role.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Little support routine, seems to turn up all over the place! */ static char *maybe_strdup(struct pool *p, char *s) { return ((s) ? pool_strdup(p, s) : ""); } /* role_add() *********************************************************** * * Add role to list * rl: Role list * personal: Personal name * from: From address * reply_to: Reply to address * fcc: Default Fcc * signature: Signature * ***********************************************************************/ static void role_add(struct list *rl, char *name, char *personal, char *from, char *reply_to, char *fcc, char *signature) { struct role *new = pool_alloc(NIL, sizeof(struct role)); new->next = NIL; new->personal = maybe_strdup(rl->pool, personal); new->from = maybe_strdup(rl->pool, from); new->reply_to = maybe_strdup(rl->pool, reply_to); new->fcc = maybe_strdup(rl->pool, fcc); new->signature = maybe_strdup(rl->pool, signature); list_push(rl, (struct list_item *) new, name); } /* role_update() ******************************************************** * * Update existing role, or add new role to next of list if none exists. * rl: Role list * personal: Personal name * from: From address * reply_to: Reply to address * fcc: Default Fcc * signature: Signature * ***********************************************************************/ void role_update(struct list *rl, char *name, char *personal, char *from, char *reply_to, char *fcc, char *signature) { struct list_item *li; if (!name) return; for (li = rl->head; li; li = li->next) { struct role *current = (struct role *) li; if (!strcmp(current->name, name)) { /* Replace existing entry */ current->name = maybe_strdup(rl->pool, name); current->personal = maybe_strdup(rl->pool, personal); current->from = maybe_strdup(rl->pool, from); current->reply_to = maybe_strdup(rl->pool, reply_to); current->fcc = maybe_strdup(rl->pool, fcc); current->signature = maybe_strdup(rl->pool, signature); break; } } if (li == NIL) role_add(rl, name, personal, from, reply_to, fcc, signature); } /* ====================================================================== */ /* role_delete() ******************************************************** * * Delete role * rl: Role list * name: Name of role to delete * ***********************************************************************/ void role_delete(struct list *rl, char *name) { list_remove_byname(rl, name); } /* role_find() ********************************************************** * * Lookup role * rl: Role list * name: Name of role to find * ***********************************************************************/ struct role *role_find(struct list *rl, char *name) { return ((struct role *) list_lookup_byname(rl, name)); } /* ====================================================================== */ /* role_parse_line() **************************************************** * * Parse a role from line of user preferences file * rl: role list * line: Line to parse * session: For logging purposes only * ***********************************************************************/ void role_parse_line(struct list *rl, char *line, struct session *session) { char *list[6]; char *name, *personal, *from, *reply_to, *fcc, *signature; if (!((list[0] = options_decode(string_get_token(&line))) && (list[1] = options_decode(string_get_token(&line))) && (list[2] = options_decode(string_get_token(&line))) && (list[3] = options_decode(string_get_token(&line))))) return; if (line[0]) { list[4] = options_decode(string_get_token(&line)); list[5] = options_decode(string_get_token(&line)); name = list[0]; personal = list[1]; from = list[2]; reply_to = list[3]; fcc = list[4]; signature = list[5]; } else { name = list[0]; /* Backwards compatibility with old format */ personal = list[1]; from = ""; reply_to = list[2]; fcc = ""; signature = list[3]; session->options->save = T; } role_add(rl, name, personal, from, reply_to, fcc, signature); } /* role_print_options() ************************************************* * * Convert role list to textual representation suitable for user * preferences file on IMAP server. * rl: Role list to print * b: Output buffer * ***********************************************************************/ void role_print_options(struct list *rl, struct buffer *b) { struct list_item *li; struct role *role; for (li = rl->head; li; li = li->next) { unsigned long offset = 0L; role = (struct role *) li; options_print_token(b, role->name, &offset); options_print_token(b, role->personal, &offset); options_print_token(b, role->from, &offset); options_print_token(b, role->reply_to, &offset); options_print_token(b, role->fcc, &offset); options_print_token(b, role->signature, &offset); bputs(b, "" CRLF); } } ./prayer-1.3.5/session/draft.h0000644006513000651300000001044211102104524014514 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/draft.h,v 1.4 2008/10/29 16:03:32 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Data structures for message draft */ struct attlist { /* List of attachments */ struct attlist *next; /* Linked list */ void *hdr; /* Header block associated with attachment */ unsigned long hdr_size; /* Size of the header block */ char *name; /* Filename for this attachment */ char *type; /* Attachment type e.g: "application/octet-stream" */ char *encoding; /* Encoding for attachment e.g: "base64" */ void *body; /* Attachment body */ unsigned long size; /* Attachment body size */ }; struct draft { BOOL have_draft; /* Active draft */ struct session *session; /* Session associated with this draft */ struct pool *pool; /* Pool used for draft msg */ struct role *role; /* Current role */ char *from_personal; /* Personal component of from line */ char *from_address; /* Address component of from line */ char *to; /* To line */ char *cc; /* Cc line */ char *bcc; /* Bcc line */ char *fcc; /* Fcc line */ char *reply_to; /* Reply to line */ char *subject; /* Subject line */ char *body; /* Body */ char *in_reply_to; /* To make threading work */ char *references; /* To make threading work */ struct attlist *attlist; /* Linked list of attachments */ BOOL save_copy; /* Save copy to sent-mail folder */ BOOL line_wrap; /* Line wrap first component on send */ unsigned long reply_validity; /* UID validity for reply folder */ unsigned long reply_msgno; /* Message is reply to this message */ unsigned long reply_msguid; /* Message is reply to this message */ char *reply_folder; /* Message is reply to this message */ BOOL rich_headers; /* Show rich headers */ }; #define PREFERRED_DRAFT_BLOCK_SIZE (4096) struct draft *draft_create(struct session *s); void draft_free(struct draft *d); void draft_copy(struct draft *dst, struct draft *src); void draft_clear_hdrs(struct draft *d); void draft_clear_body(struct draft *d); void draft_init(struct draft *d); void draft_set_reply(struct draft *draft, MAILSTREAM * stream, char *foldername, unsigned long msgno); void draft_update(struct draft *d, struct assoc *h); void draft_update_body(struct draft *d, struct assoc *h); void draft_add_to(struct draft *draft, char *s); void draft_add_cc(struct draft *draft, char *s); void draft_add_bcc(struct draft *draft, char *s); void draft_add_attachment(struct draft *d, char *name, char *type, char *encoding, char *hdr, unsigned long hdr_size, char *msg, unsigned long msg_size); void draft_delete_attachment(struct draft *d, unsigned long number); unsigned long draft_att_count(struct draft *d); unsigned long draft_att_size(struct draft *d); void draft_clear_atts(struct draft *d); void draft_line_wrap_body(struct draft *d); void draft_role_set(struct draft *d, struct role *role); void draft_rich_headers(struct draft *d, BOOL enable); void draft_init_rich_headers(struct draft *d); char *draft_make_recipients(struct draft *draft, unsigned long *len, unsigned long *countp); char *draft_make_msg(struct draft *draft, BOOL postpone, unsigned long *len); /* Operations on postponed message list */ BOOL draft_restore_postponed(struct draft *d, struct pool *pool, MAILSTREAM * stream, long msgno); BOOL draft_write(struct draft *draft); BOOL draft_check(struct session *session); BOOL draft_delete(struct session *session, unsigned long msgno); BOOL draft_is_reply(struct draft *draft); BOOL draft_flag_answered(struct draft *draft); ./prayer-1.3.5/session/filter.c0000644006513000651300000003054711576142443014725 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/filter.c,v 1.4 2011/06/15 14:43:47 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Class for manipulating filter rules which will be converted into Exim * filter file */ /* filter_alloc() ******************************************************** * * Allocate a new filter object. (as NIL pool: subsystem does own memory * managment). ************************************************************************/ struct filter *filter_alloc(void) { struct filter *result = pool_alloc(NIL, sizeof(struct filter)); result->type = FILTER_UNKNOWN; result->local_part = NIL; result->domain = NIL; result->subject = NIL; result->mailbox = NIL; result->copy = NIL; return (result); } /* filter_free() ********************************************************* * * Free a filter object. ************************************************************************/ void filter_free(struct filter *filter) { if (filter->local_part) free(filter->local_part); if (filter->domain) free(filter->domain); if (filter->subject) free(filter->subject); if (filter->mailbox) free(filter->mailbox); free(filter); } /* ====================================================================== */ /* Auxillary routine */ static char *maybe_strdup(char *s) { char *result; if (s == NIL) return (NIL); if ((result = strdup(s))) return (result); fatal("Out of memory"); /* NOTREACHED */ return (NIL); } /* filter_set_type() ***************************************************** * * Set type of filter ************************************************************************/ void filter_set_type(struct filter *filter, FILTER_TYPE type) { filter->type = type; } /* filter_set_local_part() *********************************************** * * Set local_part of filter ************************************************************************/ void filter_set_local_part(struct filter *filter, char *local_part) { filter->local_part = maybe_strdup(local_part); } /* filter_set_domain() *************************************************** * * Set domain of filter ************************************************************************/ void filter_set_domain(struct filter *filter, char *domain) { filter->domain = maybe_strdup(domain); } /* filter_set_subject() ************************************************** * * Set subject of filter ************************************************************************/ void filter_set_subject(struct filter *filter, char *subject) { filter->subject = maybe_strdup(subject); } /* filter_set_mailbox() ************************************************** * * Set mailbox of filter ************************************************************************/ void filter_set_mailbox(struct filter *filter, char *mailbox) { filter->mailbox = maybe_strdup(mailbox); } /* filter_set_copy() ***************************************************** * * Set copy of filter ************************************************************************/ void filter_set_copy(struct filter *filter, BOOL copy) { filter->copy = copy; } /* ====================================================================== */ /* filter_set_addr() ***************************************************** * * Set source address up into local_part and domain components, strdups * these components and assigns to filter object. * filter: * session: Used for default_domain * text: Address to chop up ************************************************************************/ BOOL filter_set_addr(struct filter *filter, struct session *session, char *text) { struct config *config = session->config; struct prefs *prefs = session->options->prefs; struct request *request = session->request; ADDRESS *addr = NIL; if (!(addr=addr_parse(request->pool, text, ""))) { session_message(session, "Invalid filter: %s", ml_errmsg()); return (NIL); } if ((addr->next) || (addr->personal && addr->personal[0])) { mail_free_address(&addr); session_message(session, "Filter must be simple, single address"); return (NIL); } filter->local_part = pool_strdup(NIL, addr->mailbox); if (addr->host && addr->host[0]) filter->domain = pool_strdup(NIL, addr->host); else if (config->filter_domain_pattern) filter->domain = pool_strdup(NIL, config->filter_domain_pattern); else filter->domain = pool_strdup(NIL, prefs->default_domain); mail_free_address(&addr); return (T); } /* filter_test_addr() **************************************************** * * Check whether address/pattern is valid. * filter: * session: Used for default_domain * text: Address to chop up ************************************************************************/ BOOL filter_test_addr(struct filter * filter, struct session * session, char *text) { struct config *config = session->config; struct options *options = session->options; struct prefs *prefs = options->prefs; struct request *request = session->request; struct list_item *li; ADDRESS *addr = NIL; if (!(addr=addr_parse(request->pool, text, ""))) { session_message(session, "Invalid filter: %s", ml_errmsg()); return (NIL); } if ((addr->next) || (addr->personal && addr->personal[0])) { mail_free_address(&addr); session_message(session, "Filter must be simple, single address"); return (NIL); } if (addr->host && addr->host[0]) { mail_free_address(&addr); return (T); } mail_free_address(&addr); /* Account name filters allowed iff local domains defined */ if (config->local_domain_list == NIL) { session_message(session, "Invalid filter: missing domain name"); return (NIL); } /* Look for passwd map entries for current default domain */ for (li = config->local_domain_list->head; li; li = li->next) { struct config_local_domain *cld = (struct config_local_domain *) li; if (cld->cdb_map && !strcmp(prefs->default_domain, cld->name)) { char *value = NIL; BOOL rc = cdb_find(cld->cdb_map, text, strlen(text), &value); if (value) free(value); if (rc) return (T); session_message(session, "Filter doesn't match \"%s\" account", cld->name); return (NIL); } } /* Account name filters allowed iff local domains defined */ session_message(session, "Invalid filter: missing domain name"); return (NIL); } /* ====================================================================== */ /* filter_print() ******************************************************** * * Convert filter into MSforward format string * filter: * b: Target buffer ************************************************************************/ void filter_print(struct filter *filter, struct buffer *b) { switch (filter->type) { case FILTER_SENDER: bputs(b, "sender\n"); break; case FILTER_RECIPIENT: bputs(b, "recip\n"); break; case FILTER_SUBJECT: bputs(b, "subject\n"); break; case FILTER_BLOCK: bputs(b, "block\n"); break; default: /* Need any error handling */ break; } if (filter->copy) bprintf(b, " copy\ttrue\n"); if (filter->domain) bprintf(b, " domain\t%s\n", filter->domain); if (filter->local_part) bprintf(b, " local_part\t%s\n", filter->local_part); if (filter->mailbox) bprintf(b, " mailbox\t%s\n", filter->mailbox); if (filter->subject) bprintf(b, " subject\t%s\n", filter->subject); } /* ====================================================================== */ /* Small utility routines for filter_sieve_print */ /* Look for '?' and '*' wildcards in local_part and domain */ static BOOL filter_address_has_wildcard(struct filter *filter) { if (filter->local_part && (strchr(filter->local_part, '?') || strchr(filter->local_part, '*'))) return(T); if (filter->domain && (strchr(filter->domain, '?') || strchr(filter->domain, '*'))) return(T); return(NIL); } /* Quote " chars */ static void filter_sieve_print_quote(struct buffer *b, char *s) { char c; while ((c=*s++)) { if (c == '\"') bputc(b, '\\'); bputc(b, c); } } static void filter_sieve_print_target(struct filter *filter, struct buffer *b) { bputs(b, " fileinto \""); filter_sieve_print_quote(b, filter->mailbox); bputs(b, "\";"CRLF); if (filter->copy) bputs(b, " keep; stop;"CRLF); else bputs(b, " stop;"CRLF); } static void filter_sieve_print_discard(struct filter *filter, struct buffer *b) { bputs(b, "\""); filter_sieve_print_quote(b, filter->local_part); bputc(b, '@'); filter_sieve_print_quote(b, filter->domain); bputs(b, "\" {"CRLF); bputs(b, " discard; stop;"CRLF); bputs(b, "}"CRLF""CRLF); } /* filter_sieve_print() ************************************************** * * Convert filter into Sieve format string * filter: * b: Target buffer ************************************************************************/ BOOL filter_sieve_print(struct filter *filter, struct buffer *b) { switch (filter->type) { case FILTER_SENDER: if (!(filter->local_part && filter->domain && filter->mailbox)) return(NIL); if (filter_address_has_wildcard(filter)) bputs(b, "if envelope :matches \"from\" \""); else bputs(b, "if envelope :is \"from\" \""); filter_sieve_print_quote(b, filter->local_part); bputc(b, '@'); filter_sieve_print_quote(b, filter->domain); bputs(b, "\" {"CRLF); filter_sieve_print_target(filter, b); bputs(b, "}"CRLF""CRLF); break; case FILTER_RECIPIENT: if (!(filter->local_part && filter->domain && filter->mailbox)) return(NIL); if (filter_address_has_wildcard(filter)) bputs(b, "if address :matches [\"to\", \"cc\"] \""); else bputs(b, "if address :is [\"to\", \"cc\"] \""); filter_sieve_print_quote(b, filter->local_part); bputc(b, '@'); filter_sieve_print_quote(b, filter->domain); bputs(b, "\" {"CRLF); filter_sieve_print_target(filter, b); bputs(b, "}"CRLF""CRLF); break; case FILTER_SUBJECT: if (!(filter->subject && filter->mailbox)) return(NIL); if (strchr(filter->subject, '?') || strchr(filter->subject, '*')) bputs(b, "if header :matches \"subject\" \""); else bprintf(b, "if header :is \"subject\" \""); filter_sieve_print_quote(b, filter->subject); bputs(b, "\" {"CRLF); filter_sieve_print_target(filter, b); bputs(b, "}"CRLF""CRLF); break; case FILTER_BLOCK: if (!(filter->local_part && filter->domain)) return(NIL); if (filter_address_has_wildcard(filter)) bputs(b, "if envelope :matches \"from\" "); else bputs(b, "if envelope :is \"from\" "); filter_sieve_print_discard(filter, b); if (filter_address_has_wildcard(filter)) bputs(b, "if address :all :matches [\"from\", \"sender\"] "); else bputs(b, "if address :all :is [\"from\", \"sender\"] "); filter_sieve_print_discard(filter, b); break; default: return(NIL); } return(T); } /* filter_strip8bit() *************************************************** * * Useful subset of ISO-8859-1 and UTF-8 is ASCII * ************************************************************************/ void filter_strip8bit(struct filter *filter) { string_strip8bit(filter->local_part); string_strip8bit(filter->domain); string_strip8bit(filter->subject); string_strip8bit(filter->mailbox); } ./prayer-1.3.5/session/html_secure_tidy.c0000644006513000651300000002300611576661762017005 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/session/html_secure_tidy.c,v 1.16 2011/06/17 14:25:54 dpc22 Exp $ */ /* Clean up HTML using tidy library. Drop in replacement for html_secure */ #include "prayer_session.h" #ifdef TIDY_ENABLE #ifdef TIDY_IS_TIDYP #include #else #include #endif #include /* ====================================================================== */ /* A couple of static utility functions to quietly unpick CSS character entities, which are \ up to six digits long. Has to be exactly six characters long (pad with leading zeroes) if following character is another valid hex digit, which is reason for tmp buffer */ static void unquote_css_inline(char *s) { char *d = s; char *t; unsigned long unicode; char tmp[7]; while (*s) { if (*s == '\\') { s++; /* Easiest way to isolate hex string from zero to six chars */ strncpy(tmp, s, 6); tmp[6] = '\0'; unicode = strtoul(tmp, &t, 16); *t = '\0'; s += strlen(tmp); if ((unicode > 0) && (unicode < 128)) *d++ = (char)(unicode); /* Caller only cares about ASCII */ } else if (d < s) { *d++ = *s++; } else { d++; s++; } } if (d < s) *d = '\0'; } static char * unquote_css_entities(char *s) { static char *buf = NULL; unsigned long alloc = 0; unsigned long len = strlen(s)+1; if (alloc < len) { alloc = (len > 4096) ? (len*2) : 4096; if (buf) buf = realloc(buf, alloc); /* Always allows buf==NULL? */ else buf = malloc(alloc); if (!buf) log_panic("Out of memory"); } strcpy(buf, s); unquote_css_inline(buf); return(buf); } /* ====================================================================== */ /* Foul layering volation: Tidy doesn't export these functions */ extern void prvTidyDiscardElement( TidyDoc doc, TidyNode node); extern void prvTidyRemoveAttribute( TidyDoc doc, TidyNode node, TidyAttr attr); extern void prvTidyAddAttribute( TidyDoc doc, TidyNode node, const char *attr, const char *value); static BOOL test_element_allowed(const char *name, BOOL show_images) { char *array[] = { "script", "app", "applet", "server", "object", "html", "head", "body", "meta", "title", "frame", "link", "iframe", "embed", "xml", "form", "input", NULL }; int i; if (!name) return(NIL); if (!show_images && !strcasecmp(name, "img")) return(NIL); /* Binary chop would be faster. Quick test shows <1% of time spent here */ for (i=0; array[i]; i++) { if (!strcasecmp(array[i], name)) { return(NIL); } } return(T); } /* Following is strcasecmp, allowing for whitespace around ':' or '(' */ static BOOL mymatch (char *haystack, char *needle) { char c, *p, *np = NULL; for (p = haystack; *p; p++) { if (np) { /* ':' in middle of needle matches \s*:\s* in haystack */ if ((*np == ':') || (*np == '(')) { c = *np++; while (*p && Uisspace(*p)) p++; if (*p == c) { if (*np == '\0') return T; /* Skip over trailing space, but allow for p++ in loop */ p++; while (*p && Uisspace(*p)) p++; p--; } else np = NULL; } else if (Utoupper(*p) == Utoupper(*np)) { np++; if (*np == '\0') return T; } else np = NULL; } else if (Utoupper(*p) == Utoupper(*needle)) { np = needle + 1; } } return NIL; } static BOOL test_style_allowed(const char *value) { char *s = (char *)value; if (!(s && s[0])) return(NIL); if (strchr(s, '\\')) s = unquote_css_entities(s); if (mymatch(s, "expression(")) return(NIL); if (mymatch(s, "javascript:")) return(NIL); if (mymatch(s, "background-image:url(")) return(NIL); if (mymatch(s, "content:url(")) return(NIL); if (mymatch(s, "behaviour:url(")) return(NIL); if (mymatch(s, "url(")) return(NIL); return(T); } static BOOL test_href_allowed(const char *href) { char *array[] = { "http://", "https://", "ftp:", "wais:", "telnet:", "cid:", "#", NULL }; int i; if (!href) return(NIL); for (i=0; array[i]; i++) { if (!strncasecmp(href, array[i], strlen(array[i]))) return(T); } return(NIL); } static BOOL test_href_needs_blank(const char *href) { char *array[] = { "http://", "https://", NULL }; int i; if (!href) return(NIL); for (i=0; array[i]; i++) { if (!strncasecmp(href, array[i], strlen(array[i]))) return(T); } return(NIL); } static BOOL test_attribute_allowed(const char *name, const char *value) { char *array[] = { "target", "code", "codepage", "codetype", "language", NULL }; int i; if (!name) return(NIL); /* includes onload and onmouseover */ if (!strncasecmp(name, "on", 2)) return(NIL); if (!strcasecmp(name, "href") && value) return(test_href_allowed(value)); if (!strcasecmp(name, "style") && !test_style_allowed(value)) return(NIL); for (i=0; array[i]; i++) { if (!strcasecmp(array[i], name)) return(NIL); } return(T); } static void tidy_tree(TidyNode tnod, TidyDoc tdoc, BOOL show_images) { TidyNode child, next_child; TidyAttr attr, nattr; BOOL href_needs_blank = NIL; if (!tnod) return; for ( child = tidyGetChild(tnod); child; child = next_child ) { ctmbstr name; next_child = tidyGetNext(child); switch ( tidyNodeGetType(child) ) { case TidyNode_Root: case TidyNode_DocType: case TidyNode_Comment: case TidyNode_ProcIns: case TidyNode_Text: case TidyNode_CDATA: case TidyNode_Section: case TidyNode_Asp: case TidyNode_Jste: case TidyNode_Php: case TidyNode_XmlDecl: name = "TidyNode"; break; case TidyNode_Start: case TidyNode_End: case TidyNode_StartEnd: default: name = tidyNodeGetName( child ); break; } if (!test_element_allowed(name, show_images)) { prvTidyDiscardElement(tdoc, child); continue; } href_needs_blank = NIL; for (attr=tidyAttrFirst(child); attr; attr=nattr) { ctmbstr atname = tidyAttrName(attr); ctmbstr atvalue = tidyAttrValue(attr); nattr = tidyAttrNext(attr); /* attr Might be removed */ if (!test_attribute_allowed(atname, atvalue)) { prvTidyRemoveAttribute(tdoc, child, attr); } else if (!strcmp(atname, "href")) { href_needs_blank = test_href_needs_blank(atvalue); } } if (!strcasecmp(name, "a") && href_needs_blank) { prvTidyAddAttribute(tdoc, child, "target", "_blank" ); } tidy_tree( child, tdoc, show_images ); } } BOOL html_secure_tidy(struct session *session, struct buffer *b, BOOL show_images, char *input) { TidyBuffer errbuf = {0}; TidyBuffer output = {0}; int rc = -1; TidyDoc tdoc = tidyCreate(); TidyNode tnod; char *s; rc = tidyOptSetBool( tdoc, TidyXhtmlOut, yes ) ? 0 : -1; /* MSIE and Chrome think that is a complete comment. Allows * people to hide scripts inside ./prayer-1.3.5/templates/cam/folders_help.t0000644006513000651300000001240311063707775017177 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/folders_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The Mail Folders screen allows you to either select a different mail folder to view or to create, rename or delete mail folders (mailboxes) and directories. The default set of mail folders on <% $g_service_name |h %> is INBOX, sent-mail and received.

    The bars above and below the folder listing

    Create under with name

    This enables the creation of mail folders or directories. For example selecting mailbox and typing a name such as projects will, once the Create button has been pressed, cause the display to change to include the newly created mail folder. Mailboxes can be created under existing directories.

    Refresh checks the contents of the directory on the <% $g_service_name |h %>.
    Transfer Folders allows you to upload a local mail folder to <% $g_service_name |h %> or download a mail folder from <% $g_service_name |h %> to your local machine.
    Sizes shows you the size of each mailbox on the system
    Favourite Folders displays a screen where you can choose a folder, or folders, to be added to a list of favourite mail folders. This list appears in the pull-down listing in the common toolbar, replacing the list of default folders. Once you have one or more Favourite mail folders an expanded set of actions becomes available. These are described on the help page associated with the Favourites selection screen.

    The folder listing

    You can keep all your mail in different folders in one directory, or you can create a storage system of directories that contain mail folders (the example given in this help text). While you can create mail folders in any directory, you need to be aware that different mail clients default to looking in different places.

    • The Folder icon mailbox indicates that the line refers to a mail folder and also shows the name of the folder and actions that can be performed on that folder, for example:-
      [mailbox] saved-messages Rename Delete
      Selecting the folder icon or the name of the folder will display a listing of the messages in that folder. To return to the folder listing screen again, select the Folders icon in the common toolbar.
      Other actions you can take on a mail folder are:-
      • Rename - takes you to a screen with a form allowing you to rename the mail folder.
      • Delete - deletes the mail folder. Selecting this leads to a screen where you need to choose to confirm or cancel the deletion. Once the mail folder is deleted the display of the mail folders is updated and the Status information reflects the success of the action, for example
        Status: Deleted mailbox: "mail/newtest"
    • The Right arrow [dir] indicates that the line refers to a directory, and shows the name of the directory and the actions that can be performed, for example:-
      [directory]testdir Rename Delete
      Selecting the arrow, or the name of the directory, will display a listing of the mail folders in that directory.
      The other actions are
      • Rename - takes you to a screen with a form allowing you to rename the directory.
      • Delete - deletes the directory. Selecting this leads to a screen where you need to choose to confirm or cancel the deletion.
        Note: You can only delete a directory if it has no mail folders inside it. If the deletion is not successful the Status information reflects the reason, for example if you try to delete a non-empty directory the message is:-
        Status: DELETE failed: Can't delete mailbox mail/testdir/: File exists
    ./prayer-1.3.5/templates/cam/redirect.t0000644006513000651300000000305111071405225016311 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/redirect.t,v 1.2 2008/10/03 12:05:41 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Mail Redirection

    WARNING:

    Support staff within the University and Colleges will not be able to help you with email problems if you forward your email outside Cambridge and the problems involve external systems. Note that there may be issues of privacy and/or reliability with external email systems which you should consider.

    % IFDEF $use_redirect % ELSE % ENDIF % IFDEF $redirect_copy % ELSE % ENDIF
    Enable Redirection
      Redirect address:
    Save copy in this account
    % IFDEF $g_help % CALL redirect_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/include.t0000644006513000651300000000130311063707775016151 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/include.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Include local file in message body

    File
    % IFDEF $g_help % CALL include_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/compose.vars0000644006513000651300000000104511063707775016706 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/compose.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ #$large 1 #$rich_hdrs 1 $hdr_to David Carter

    Once you have selected the Reply option for a message you need to specify who is to receive the message. This screen shows the original sender and any other recipients of the message

    Reply Options

    • Cancel returns you to the Webmail page from whence you came.
    • Reply to sender only prepares a reply that will only go to the original sender.
    • Reply to sender and all recipients prepares a reply that will place the name of the original sender in the To: field and the names of all other recipients in the cc: field.

    If the message has a Reply-To: header, this name will appear as the Sender of the message.

    ./prayer-1.3.5/templates/cam/compose_toolbar.t0000644006513000651300000000212411463516401017703 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/compose_toolbar.t,v 1.5 2010/11/01 10:57:05 dpc22 Exp $
    % IFDEF $g_service_name

    <% $g_service_name |h %> Webmail Service

    % ELSE

    Prayer Webmail Service

    % ENDIF
    ./prayer-1.3.5/templates/cam/prefs_general_help.t0000644006513000651300000000502511066657632020356 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_general_help.t,v 1.2 2008/09/25 09:53:30 dpc22 Exp $
    • Template Set defines the look and feel of the application
    • Enable welcome screen controls whether or not the initial screen "Welcome to the Webmail Service" is displayed when you log in.
    • % IFDEF $raven_enable
    • Allow Raven Logins - most people will want to leave this checked. Can be unchecked to stop Raven Web Single Sign on from applying to this account.
    • % ENDIF
    • Confirm expunge - if this is checked then attempts to expunge messages will generate a screen asking you to confirm or cancel.
    • Confirm Logout - if this is unchecked then selecting "Logout" on any screen will log you out immediately, otherwise you will see a screen asking you to confirm or cancel your logout.
    • Expunge deleted messages from INBOX on logout - automatically expunges messages when enabled
    • Use persistent marks - The Webmail default is to use non-persistent marks. This means that while you can mark more than one message on a screen you must take action on the marked messages, for example copying them all to a folder, before you move to another screen. If you change to another screen, for example listing the next screenful of messages, the marks are not retained.
      If you enable Use persistent marks then each time you mark a message a connection is made to the Webmail server. Because of this interaction with the server working with persistent marks is slower and is only recommended if you are working over a fast connection, for example within the University. Using persistent marks you can work on a whole mail folder rather than just the current screenful of messages. If this option is enabled then the following options can also be used:-
      • Zoom automatically after search controls what happens with the results of a search on a mail folder. If this option is selected then, as well as the messages being marked, the mail folder listing changes to show just the selected messages.
      • Unmark messages after aggregate operation controls what happens after an action has been taken on a group of marked messages, for example saving them to another mail folder. If this option is checked then, on return to the mail folder listing, the mark is removed from the relevant messages.
    ./prayer-1.3.5/templates/cam/container_end.t0000644006513000651300000000036111063707775017341 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/container_end.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %
    • © 2008 Computing Service, University of Cambridge
    ./prayer-1.3.5/templates/cam/spell.t0000644006513000651300000000265311413405210015630 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/spell.t,v 1.2 2010/07/02 15:49:28 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Spell Check

    % IFDEF $have_changes % ENDIF

    Couldn't find highlighted word in following text:

    <% $text |n %>
    

    Options:

    1. Add word to personal dictionary
    2. Accept this spelling for current spell-check run only
    3. Leave word with current spelling, query further occurrences
    4. % IFNEQ $close_count 0
    5. Replace word with close match from dictionary % IFNEQ $close_count 1 (<% $close_count |h %> matches found) % ELSE (1 match found) % ENDIF % FOREACH $w @close % IFDEF $w->break % ENDIF % ENDFOREACH % ENDIF
      <% $w->word |h %> 
    6. Replace with specific text:
    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/filter_select_help.t0000644006513000651300000000332211063707775020365 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/filter_select_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    After selecting the Add filter button from the main Mail Filtering screen you are presented with a list of your mail folders to select the destination folder.

    The Status line on the Select Target Mail Folder... screen will show the current action, for example:

    Status: Adding SENDER filter: "myfriend@someuni.ac.uk"

    The Cancel button at the end of the line immediately below the Select Target Mail Folder... heading returns you to the main mail filtering screen and no action is taken.

    Selecting a folder

    • If the folder you wish to use is shown in the list then choose:-
      • Select (no copy) if you wish the message just to be put in the selected folder.
      • Select (save copy to inbox) to put one copy in the selected folder and one in the inbox.
      A successful filter entry will then take you back to the main filter screen with the status message and display updated to show the new filter.
    • If the folder exists, but you know that it is in another directory, you can expand collapsed directories using the Expand icon.
    • If the folder does not exist create it using the Create dialogue. Once you click the Create button the folder is created and the display of mail folders updated. You can then choose one of the Select options, as described above.
    ./prayer-1.3.5/templates/cam/toolbar_stub_help.t0000644006513000651300000000060111063707775020235 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/toolbar_stub_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    Help Text


    ./prayer-1.3.5/templates/cam/include_help.t0000644006513000651300000000163611063707775017172 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/include_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    This option, reached from the Import button on the main Compose screen, is suitable for plain text files that you want to be included in the main body of the message. Other files (for example word processed documents or pictures) should be sent as attachments.

    Selecting Back to Compose Screen will take you back to the Compose screen you came from and no file will be included in your message.

    To include a file type the name of the file in the File box or use the Browse... button to select one. Once you have chosen the file, selecting the Include button will return you to the main Compose screen, and the text of the file will be included in the body of the message. You can then continue to edit the message.

    ./prayer-1.3.5/templates/cam/dictionary.vars0000644006513000651300000000035011063707775017404 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/dictionary.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $words[0]->word dpc22 $words[1]->word dpc22 $words[2]->word Hllo $words[2]->break 1 $words[3]->word World $g_cmd dictionary ./prayer-1.3.5/templates/cam/folders.t0000644006513000651300000000065711063707775016177 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/folders.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Mail Folders

    % CALL folders_toolbar
    % CALL folderlist, $cmd => "folders" %#
    %# CALL folders_toolbar % IFDEF $g_help % CALL folders_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/spam.vars0000644006513000651300000000032611063707775016202 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/spam.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $enabled 1 $threshold 10 $purge_enabled 1 $days 60 $whitelist *@cam.ac.uk $g_cmd spam ./prayer-1.3.5/templates/cam/redirect_help.t0000644006513000651300000000554611063707775017354 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/redirect_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    If you already have a redirection in place the form will show your current settings, similar to the form above where all mail is being redirected to somenewaddress@newplace.ac.uk, otherwise the two check boxes will be unmarked and the address field will be empty.

    If you have a manually maintained .forward file this cannot be updated from the Webmail interface. In this case the you will not see the form but a message reading

    Error: Manually maintained .forward file?

    To make changes to a manually maintained file you will need to connect to <% $g_service_name |h %> using an SSH or Telnet client and use the menu interface.

    If you do not already have a redirection in place

    To redirect your mail to a new address check the Enable Redirection box and enter the new address in the Redirect address: field. Then select the Apply button. If this is successful you will be returned to the main Account Management screen, and the status line will read

    Status: Updated redirection

    The address you use must be a complete, valid address of the form user@some.place.somewhere. If it is not then, after you have selected Apply, you will remain in the Mail Redirection screen and the status message will read

    Status: Redirection Address must be single, simple and fully qualified email address

    Note: that the check is only that the address appears complete. It cannot check the actual address, so errors in typing an address will not be picked up.

    If you wish one copy of each message to go to the new address and one copy to remain on <% $g_service_name |h %> then check the Save copy in this account box. Note: if you do this then you will need to make sure that you regularly check and delete the copies on <% $g_service_name |h %>, otherwise you may exceed your quota.

    If you already have a redirection in place

    If you wish to alter the Redirect address: enter the new address and then select Apply. Optionally check the Save copy in this account box. Note: if you do this then you will need to make sure that you regularly check and delete the copies on <% $g_service_name |h %>, otherwise you may exceed your quota. The comments made above about the form of an address apply.

    Cancelling a redirection

    If you wish to cancel your redirection then uncheck the Enable Redirection box and, if it is checked, the Save copy in this account. Then select Apply.

    ./prayer-1.3.5/templates/cam/folderlist_folders.t0000644006513000651300000000043511063707775020420 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/folderlist_folders.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % IFEQ $_name "INBOX" % ELSE Rename Delete % ENDIF ./prayer-1.3.5/templates/cam/roles_list.vars0000644006513000651300000000052011063707775017415 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/roles_list.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $roles[0]->alias me $roles[0]->personal David Carter $roles[0]->from dpc22@cam.ac.uk $roles[0]->reply_to dpc22@cam.ac.uk $roles[0]->fcc sent-mail $roles[0]->signature sig $g_cmd roles_list ./prayer-1.3.5/templates/cam/block_fail.t0000644006513000651300000000101211063707775016610 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/block_fail.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Automatic Mail Blocking

    Error: <% $msg |h %>

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/prefs_display.t0000644006513000651300000000551011065141543017361 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_display.t,v 1.3 2008/09/20 09:33:23 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Preferences

    Display Preferences:

    Use icons
    Duplicate icons below message
    Display text/html sections inline.
    Display text/* sections starting <html> inline
    Display remote images in HTML e-mail
    Preserve MIME type when downloading attachments
    Start at first unread message
    % CALL prefs_display_folder_sort % CALL prefs_display_abook_sort
    Messages per page:
    Addressbook entries per page:
    Alt Addresses:

    % IFDEF $g_help % CALL prefs_display1_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/favourites_toolbar.t0000644006513000651300000000044311063707775020443 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/favourites_toolbar.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ ./prayer-1.3.5/templates/cam/transfer.t0000644006513000651300000000106011063707775016352 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/transfer.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Mailbox Transfer

    % CALL transfer_toolbar_top
    % IFDEF $g_favourites[0] Favourite mail folders: % CALL favlist, $cmd => "transfer" Normal mail folders: % ENDIF % CALL folderlist, $cmd => "transfer"
    % CALL transfer_toolbar_bottom % IFDEF $g_help % CALL transfer_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/rename_help.t0000644006513000651300000000224111063707775017007 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/rename_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    Renaming a mail folder.

    The layout of the screen is similar to that in the main Mail Folders screen.

    • The list of mail folders.
    • The second form
      Rename under as new name
      is where you enter the new name of the mail folder.
      • Selecting the Rename button will return you to the mail folder listing screen, with the renamed folder listed. The Status line will be updated
        Status: Renamed mailbox mail/sent-mail to be mail/old-sent-mail
      • Selecting Cancel returns you to the main mail folder listing screen and no changes are made.
    ./prayer-1.3.5/templates/cam/roles_entry.t0000644006513000651300000000237211063707775017102 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/roles_entry.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Roles Entry

    Alias
    From personal name
    From address
    Reply to address
    Fcc

    Signature:

    % IFDEF $g_help % CALL roles_entry_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/abook_add.vars0000644006513000651300000000037211063707775017146 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/abook_add.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $alias Alias goes here $name Name goes here $comment Comment goes here $email Email goes here $g_cmd abook_add ./prayer-1.3.5/templates/cam/list_help.t0000644006513000651300000002376311063707775016527 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/list_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    Reading a message

    To read a message simply select the name of the person in the From column or select the subject in the Subject column.

    The bars above and below the message listing

    These are largely identical. The exceptions are in the centre of each row:-

    Top bar Informative message indicating the current mail folder and the number of messages, for example "INBOX" with 4 messages .
    Bottom bar Shortcut for displaying other pages in a long mail folder listing. For example
    Page: /3
    indicates that the listing spans three pages. To move to a different page enter the required page number in the "Page:" box and then select "Go".

    The identical elements in each bar are:-

    First First displays the first page of messages in the mail folder.
    Previous Previous displays the previous page of messages.
    Next Next displays the next page of messages.
    Last Last displays the last page of messages.
      You can configure how many messages count as one page by using a setting found in Manage -> Preferences -> Display. The relevant icon is greyed out if the choice is not applicable (i.e. you are on the first or last page).
    Messages on a screen can be "marked" (selected) by checking the box by the message number. Marking is useful if you want to do the same thing with several messages on the page, for example deleting them or copying them to the same mail folder. Once messages have been marked various actions can be taken using this pull-down menu.
    Delete marked, Undelete marked perform the obvious actions.
    Flag as read and Flag as unread change the status of the marked messages.
    Forward marked takes you to the compose screen with the messages inserted as the body of the new message.
    Copy marked takes you to the folder display, where you can choose the folder to which you wish to copy the messages.
    Select the action from the pull-down menu and then select Go.
    Note: that after you have marked messages on a screen you must take action on those messages before you do something else, for example move to another page of messages or read a message. If you do something else before you have taken action on the marked messages, the marks are cancelled, unless you have set Manage -> Preferences -> General -> Use persistent marks. Using Persistent marks changes some options on the message list screen, see Using Persistent Marks below.
    Refresh checks for new mail. Please be cautious in your use of this (i.e. use it every few minutes rather than every few seconds) as it can put unnecessary load on <% $g_service_name |h %>.
    Expunge deletes from your mail folder all messages that are marked as deleted. Expunged messages cannot be recovered. Selecting this deletes them immediately - there is no confirmation dialogue.
    Search takes you to a screen where you can choose a subset of the messages in the current mail folder using different criteria including date and text search.

    The message list

    The message list is divided into columns.

    • # - Message. The message number.
    • Mark/Unmark. This allows the selection of one or more messages. Initially all messages are unmarked. Marking a message changes the icon in this column.
    • Unseen (Message status)
      Unseen Unread messages.
      Seen Read messages.
      Answered Message that have been replied to.
      Deleted Deleted messages. These are not actually removed from <% $g_service_name |h %> until Expunge is selected. Until then they can be undeleted either by selecting the Undelete option for that message or by displaying the message and choosing Undelete on that screen.
    • Date. The date on which the message was sent.
    • From. The name of the person who sent the message or, if the message is from the current user, the name of the person to whom the message is addressed.
    • Size. An indication of the size of the message.
    • Subject. The subject of the message.
    • Delete. Delete the message. The option then changes to Undelete.

    Sorting

    The default sort order is by arrival (Message). It is possible to temporarily change how you sort the current mail folder by selecting Date, From, Size or Subject in the column headings. This will sort in ascending order, for example if you sort by Size the smallest messages are listed first. It is possible to reverse the selected sort order by reselecting your chosen column, e.g. to sort by descending size select Size twice.

    You can also Thread messages. Threading uses uses reference headers in the message to work out the order of messages on the same subject. Selecting this sorts the current mail folder by thread.

    Using persistent marks

    If you have Manage -> Preferences -> General -> Use persistent marks set then there are some differences in the appearance of the message list screen and some changes to the actions that can be taken.

    One change is the appearance of extra choices in the bars above and below the message listing. The example below shows the changes to the top bar.

    First Previous Next Last
    "INBOX" with 4 messages
    Refresh | Expunge | Mark All | Zoom | Search
    Mark All marks all the messages.
    Zoom requires that you have marked one or more messages. It displays a listing of just the marked messages. If you are already in a zoomed list (for example as the result of a Search) then this option changes to Unzoom and selecting it will return you to the complete mail folder listing.

    You mark messages by selecting the Mark/Unmark icon by the message. Marking a message changes the icon. It also changes:

    • the Change To: in the common toolbar to include the option Copy marked to: to allow straightforward copying to the mail folders listed in the adjacent pull-down list;
    • the Mark All option in the action bar above and below the message list to UnMark All
    ./prayer-1.3.5/templates/cam/common.vars0000644006513000651300000000223011072663414016515 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/common.vars,v 1.2 2008/10/07 13:41:32 dpc22 Exp $ # # # NB: Get URLs need to have & seperators encoded as & on the way out # Browser will submit as & if clicked. # # Some conventions to start factoring out: # @mailbox_list used by the top selector $g_mailbox_list[0]->name INBOX $g_mailbox_list[1]->name saved-messages $g_mailbox_list[2]->name sent-mail # Global state $g_have_draft 1 $g_testrig 1 #$g_help 1 $g_cmd list $g_user dpc99 $g_service_name Hermes #$g_status Self destruct in 20 seconds $g_use_icons 1 $g_use_tail_banner 1 $g_theme->description Web Safe Blue $g_theme->fgcolor #000000 $g_theme->fgcolor_link #0000ff $g_theme->bgcolor #ccffff $g_theme->bgcolor_banner #66ffff $g_theme->bgcolor_row1 #ccffff $g_theme->bgcolor_row2 #99ffff $g_theme->bgcolor_status #ffffcc $g_theme->bgcolor_status_none #ccffcc $g_altpad      ./prayer-1.3.5/templates/cam/sizes_toolbar.t0000644006513000651300000000041711063707775017412 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/sizes_toolbar.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ % ./prayer-1.3.5/templates/cam/spam_help.t0000644006513000651300000000306411063707775016504 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/spam_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    This option filters messages based on how much they look like junk email (otherwise known as spam) according to a score that is computed by applying a large number of tests to each message and calculating an overall result. Since it isn't possible to decide on technical grounds precisely whether an email is spam or not, the score is heuristic: a higher score means the message is more likely to be spam.

    You pick a threshold score above which messages are filtered to a separate spam folder, which you should check periodically (once a week, say) for misfiled email. If you set a low threshold (below 5) then it is likely to misclassify legitimate messages as spam. Messages that score 10 or more are blocked instead of being delivered, so high thresholds have no effect.

    We recommend setting the threshold to 5 at first, and adjusting it if necessary. For example, the filter is most accurate for English email so if you exchange a lot of foreign-language email you may have to use a higher threshold.

    The purge option (if available and enabled) defines the number of days that mail remains in your spam folder before it is automatically deleted by an overnight job. The default is 60 days.

    The whitelist section is a list of sender addresses (one on each line) which will bypass the spam filter. Wildcard characters are allowed: '?' matches any single character, while '*' matches any number of characters.

    ./prayer-1.3.5/templates/cam/roles_select.t0000644006513000651300000000115611064536756017217 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/roles_select.t,v 1.2 2008/09/18 20:45:34 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Roles

    Roles:

      % FOREACH $r @roles
    1. <% ${r->name} |h %>
    2. % ENDFOREACH
    % IFDEF $g_help % CALL roles_select_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/welcome.vars0000644006513000651300000000021711063707775016674 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/welcome.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $timeout 30 minutes $g_cmd welcome ./prayer-1.3.5/templates/cam/container_start.t0000644006513000651300000000034011063707775017725 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/container_start.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %
    ./prayer-1.3.5/templates/cam/abook_take.t0000644006513000651300000000171111063707775016630 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_take.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Addressbook Entry

    Alias
    Name
    Comment
    Address(es)
    % IFDEF $g_help % CALL abook_take_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/logout_raven.t0000644006513000651300000000043311063707775017235 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/logout_raven.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL container_start

    Logout complete

    You should now shut down your Web browser in order to log out from Raven

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/attachments.vars0000644006513000651300000000036111063707775017554 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/attachments.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $atts[0]->name Attachment Name $atts[0]->size 42 $atts[0]->type application/octet-stream $g_cmd attachments ./prayer-1.3.5/templates/cam/search_size.vars0000644006513000651300000000024211063707775017536 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/search_size.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $selected 17 $count 42 $g_cmd search_size ./prayer-1.3.5/templates/cam/prefs_compose1_help.t0000644006513000651300000000265011063707775020471 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_compose1_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $
    • Personal Name: - this is what appears in the From: field of a message preceding your address. If, for example, your address is someone@somewhere.org and you set Someone Else as your Personal Name then the From: field in outgoing messages will appear as
      Someone Else <someone@somewhere.org>
    • From Address: - this is what appears as your address in an outgoing message. The default is shown on the screen. An address must be valid and it must belong to you. For example a valid alternative to sp999@cam.ac.uk would be sp999@hermes.cam.ac.uk.
    • Default Reply-To: - By default replies will be sent to the address in the From: field of a message. If you wish replies to be sent to another address, or addresses, then you can enter that address, or comma-separated list of addresses, in this field.
    • Signature: - information that appears at the bottom of a message. By convention this is 4 lines or less. It is preceded by a separator line -- . If you create a signature here then the separator line and signature are automatically included in the text field in the Compose screen.
    ./prayer-1.3.5/templates/cam/frontend_compose_timeout.t0000644006513000651300000000245411075051454021635 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/frontend_compose_timeout.t,v 1.4 2008/10/14 08:07:08 dpc22 Exp $ %# % CALL header % CALL container_start

    Couldn't connect to session. Maybe it timed out?

    Copy the following somewhere safe before logging in again.

    % IFNEQ $hdr_bcc "" % ENDIF % IFNEQ $hdr_fcc "" % ENDIF % IFNEQ $hdr_reply_to "" % ENDIF
    To:
    Cc:
    Bcc:
    Fcc:
    Reply-To:
    Subject:

    \ Click here to login again

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/compose_small_top.t0000644006513000651300000000373711063760361020250 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/compose_small_top.t,v 1.3 2008/09/16 16:38:09 dpc22 Exp $ % IFDEF $rich_headers % ELSE % ENDIF
    To:
    Cc:
    Bcc:
    Fcc:
    Reply-To:
    Subject:
    Subject:

                 
    ./prayer-1.3.5/templates/cam/toolbar_left.t0000644006513000651300000000176111063707775017212 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/toolbar_left.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ % % CALL tb_icon, $_cmd => "display", $_icon => "display", $_alt => "Message" % CALL tb_icon, $_cmd => "list", $_icon => "mailbox", $_alt => "Mailbox" % CALL tb_icon, $_cmd => "folders", $_icon => "folders", $_alt => "Folders" % CALL tb_icon, $_cmd => "compose", $_icon => "compose", $_alt => "Compose" % CALL tb_icon, $_cmd => "abook_list", $_icon => "addressbook", $_alt => "Addressbook" % CALL tb_icon, $_cmd => "manage", $_icon => "manage", $_alt => "Manage" % IFDEF $g_use_icons % ENDIF
    Message | Mailbox | Folders | Compose | Addressbook | Manage
    ./prayer-1.3.5/templates/cam/sieve_error.vars0000644006513000651300000000017311063707775017566 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/sieve_error.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $g_cmd sieve_error ./prayer-1.3.5/templates/cam/abook_transfer_help.t0000644006513000651300000000523311063707775020543 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_transfer_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The Webmail system uses its own addressbook. It does not use the same addressbook as, for example, Pine on <% $g_service_name |h %>. If you wish to use either your <% $g_service_name |h %> Pine addressbook, or a local Pine format addressbook, you will need to import it into Webmail.

    Using this screen you can:

    • import a Pine or Outlook format addressbook on your local system into your Webmail addressbook;
    • export your Webmail addressbook to a Pine or Outlook format addressbook on your local system;
    • import your Pine addressbook on <% $g_service_name |h %> into your Webmail addressbook;
    • export your Webmail addressbook for use with Pine on <% $g_service_name |h %>.

    Importing and exporting the addressbook

    The Webmail can import and export two different forms of addressbook. Comma Separated Variable (CSV) format addressbooks are used by Outlook and Outlook Express. PINE format addresses are used by PINE and Mulberry. If you wish to use an addressbook from another mail client, such as Eudora, then you will first need to find a method of saving or exporting the addressbook into the correct format.

    • To transfer a Pine or CSV address book from your local system into the Webmail system, Browse to the location of the address book on your local disk, select the appropriate file, then select Import. The entries will be merged with any entries you already have in your Webmail addressbook. New entries will appear at the end of your Webmail addressbook.
    • To transfer your Webmail address book to your local system, select Export CSV (Outlook) addressbook or Export PINE addressbook or then use your browser's "Save" feature to navigate to where you wish to put the address book.
    • To import your Pine addressbook on <% $g_service_name |h %> into your Webmail addressbook select Import from Unix Pine addressbook. Your Pine addressbook is imported and you are returned to the addressbook listing screen. The entries will be merged with any entries you already have in your Webmail addressbook. New entries will appear at the end of your Webmail addressbook.
    • To export your Webmail addressbook for use with Pine on <% $g_service_name |h %> select Export to Unix Pine adddressbook. Your addressbook is exported and you are returned to the addressbook listing screen.
    ./prayer-1.3.5/templates/cam/display_tail.t0000644006513000651300000000034511063707775017211 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display_tail.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $
    % CALL display_toolbar % IFDEF $g_help % CALL display_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/quota_help.t0000644006513000651300000000143311063707775016673 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/quota_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    This screen shows you information about your disk space quota on <% $g_service_name |h %>. It looks something like:-

    The information returned shows:-

    • File Quota - the number of files in the <% $g_service_name |h %> filestore.
    • Block Quota - the amount of disk space used in the <% $g_service_name |h %> filestore
    • Mailstore Quota - the amount of disk space used in the <% $g_service_name |h %> mailstore

    Warning messages are sent when an account reaches 90% and 95% of quota in either the filestore or mailstore. The Mailstore limit is the one most likely to be reached in normal operation.

    ./prayer-1.3.5/templates/cam/transfer_toolbar_bottom.t0000644006513000651300000000077411063707775021473 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/transfer_toolbar_bottom.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $
    ./prayer-1.3.5/templates/cam/toolbar_help.t0000644006513000651300000001447511463516401017202 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/toolbar_help.t,v 1.2 2010/11/01 10:57:05 dpc22 Exp $

    Help Text


    The common toolbar appears at the top of most Webmail pages and provides shortcuts to the main Webmail functions.

    Message

    This icon will always return you to the current message.

    When you login, the first unread message in your inbox is the current message. If you have no unread messages then the last message in your inbox is the current message.

    If you move to another folder then the last message in that folder is the current message.

    In any folder, once you read a message that becomes the current message. For example, if you were reading message 6 of 8 in your inbox, then move to another screen (e.g. by Mailbox or Folder) then when you re-select Message message 6 is displayed.

    Mailbox
    This icon returns you to a listing of your currently selected mail folder. By default this is your inbox.
    Folders
    Select this to see a listing of your mail folders. You can select a different mail folder to view or you can create, rename or delete mail folders and directories. You can also choose some of your mail folders to be "favourites", which will give you quick access to these folders, or you can transfer mail folders between <% $g_service_name |h %> and your local system.
    Compose
    Select this to start writing a new message. Normally this will take you straight to the message composition screen, but if you have any postponed messages you will be asked whether you want to edit one of these or start a new message. If you have defined one or more "roles" for yourself (see the Manage screens) then you will be asked to select which role you want to use.
    Addressbook
    Selecting this leads you to the main addressbook listing screen where you can edit, delete and add entries. You can also import your <% $g_service_name |h %> addressbook into the Webmail addressbook or export your Webmail addressbook for use in Pine on <% $g_service_name |h %>.
    Manage
    Selecting this leads to screens that let you configure various aspects of the Webmail system either for the current session or for every future session. % IFDEF $accountd_server These include preferences that affect the appearance of the system, account management (e.g. changing your password), mail processing (e.g. setting a vacation message) % ELSE These include preferences that affect the appearance of the system % ENDIF and defining a personal dictionary.
    Change to:

    By default this pull-down list will show all your mail folders. You can change to any listed folder by selecting that from the list and then selecting Go.

    If you have specified any "favourite" mail folders, then the general listing of your mail folders is replaced by a pull-down list showing just the favourites, for example:-

    Change to:
    Help
    The Webmail system has specific help pages for each screen rather than an overall globally available system. Selecting this icon on any screen takes you to the help text relevant to that screen. When you are looking at a help text page this icon changes to
    Back
    and using this takes you back to the screen you came from.
    Logout
    Selecting this will log you out of the Webmail system. Please remember to use this to log out when you have finished a session rather than just leaving your session idle.

    The status information

    This appears immediately below the toolbar and contains:-

    • On the left Status: or Reminder: information. Status messages give feedback about the last command issued. These usually indicate whether an action was successful or not. For example status messages for the Folders screen include:-
      Status: Switched to mailbox: mail/received
      Status: Created mailbox: mail/test2
      Status: Deleted mailbox: mail/test
      The principal reminder is
      Reminder: Logout when you have finished
    • On the right, the account name of the user currently logged in.

    ./prayer-1.3.5/templates/cam/abook_lookup_nav_1_noicons.t0000644006513000651300000000120611063707775022030 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_lookup_nav_1_noicons.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % IFDEF $nav->first_page First % ELSE First % ENDIF | % IFDEF $nav->prev_page Previous % ELSE Previous % ENDIF | % IFDEF $nav->next_page Next % ELSE Next % ENDIF | % IFDEF $nav->last_page Last % ELSE Last % ENDIF ./prayer-1.3.5/templates/cam/error.t0000644006513000651300000000045311063707775015664 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/error.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status Couldn't find URL on this server

    This could caused by either user error or a bug in the server

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/display_help.t0000644006513000651300000001075711063707775017220 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    By default you will see two instances of the bar, as in the example above. You can choose to turn off the bar below the message (or indeed the use of any icons in the Webmail interface) using options found in Manage -> Preferences -> Display.

    Prev Next Previous and Next take you to, respectively, the previous and next message. The relevant icon is greyed out, as in the example above, if the choice is not applicable (i.e. you are on the first or last message).
    Copy takes you to the folder display screen, where you can choose the folder to which you wish to copy the message.
    Delete marks the message as deleted and displays the next message in the mail folder. If you delete the final message in the folder you are returned to the mail folder list. Messages are not removed from the mail folder until Expunge has been selected in the mail folder list screen.
    Reply prepares a reply. Selecting this takes you to the Compose screen and the original message is included in the reply. If there is more than one name on the original recipients list you are asked whether you wish to reply to the sender only or to reply to the sender and all recipients.
    Forward enables you to forward the message to someone else. Selecting this takes you to the Compose screen and the original message is included in the message body.
    Message: 1 out of 4 informative message.
    Show Hdrs Show Headers displays the full set of message headers. This option is most useful when trying to trace a problem. If you select this the option changes to Hide Hdrs and the full headers are shown for every message until you select Hide Hdrs.
    Download Message this presents the entire message, including all the message headers, in a plain form (i.e. without the Webmail icons and actions) suitable for printing or saving to your local system using your browser's printing and saving facilities.

    The message

    The From: and To: headers have links that enable you to take the address into your address book. Selecting one takes you to the Addressbook Entry screen with the entries placed in the Name and Address(es) fields.

    Attachments

    If a message has attachments then information about the message structure, including attachments, will be shown:-


    MIME structure of this message, including any attachments:

    1. (text/plain), 0 lines
    2. [paperclip] MyDocument.rtf (application/octet-stream), 3 K

    In this example part 1. is the text body of the message and part 2. the attachment (indicated by the small paperclip icon [paperclip]). To save the attachment select the link containing the attachment name and use your browser's "Save" feature to navigate to where you wish to put the attachment on your local machine.

    Persistent Marks

    If you have Manage -> Preferences -> General -> Use persistent marks set then there will be an extra option, Mark in the bars above and below the message.

    Mark marks the message so that you can take an action on it later. The next message is then displayed. If you have marked the final message in the folder you are returned to the mail folder list. The icon in the mail folder list screen changes to show the message has been marked. If you return to displaying a marked message before you have taken any action on it the option on this screen is changed to Unmark.

    ./prayer-1.3.5/templates/cam/roles_entry_help.t0000644006513000651300000000250011063707775020103 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/roles_entry_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    Fields

    • Alias - the name by which you want the role to appear in the listing on the main Roles screen.
    • From personal address - added in front of your address.
    • From address - your default address is used unless you have a specific entry in this field.
    • Reply to address - added as the Reply-To header to messages composed using this role.
    • Fcc - allows you to choose a folder into which copies of messages you send using this role will be copied.
    • Signature: - role information to appear at the bottom of a message. By convention this is 4 lines or less. It is preceded by a separator line -- . If you create a signature here then the separator line and signature are automatically included in the text field in the Compose screen.

    Buttons

    • Cancel - returns you to the main Account Management screen, and no changes are made.
    • Add/Update entry - creates a new entry or commits changes to an existing one.
    • Delete entry - remove the entry for that role.
    ./prayer-1.3.5/templates/cam/favourites.t0000644006513000651300000000106711063707775016724 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/favourites.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Favourite mail folders

    % CALL favourites_toolbar
    % IFDEF $g_favourites[0] Favourite mail folders: % CALL favlist, $cmd => "favourites" Normal mail folders: % ENDIF % CALL folderlist, $cmd => "favourites"
    % CALL favourites_toolbar % IFDEF $g_help % CALL favourites_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/search_text.vars0000644006513000651300000000024211063707775017550 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/search_text.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $selected 17 $count 42 $g_cmd search_text ./prayer-1.3.5/templates/cam/upload_select.vars0000644006513000651300000000117611063707775020071 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/upload_select.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $upload_name INBOX $dirlist[0]->name a $folder[0]->name INBOX $folder[0]->short_name INBOX $folder[0]->indent 0 $folder[1]->name a $folder[1]->short_name a $folder[1]->expanded 1 $folder[1]->haschildren 1 $folder[1]->even_row 1 $folder[1]->indent 0 $folder[2]->name a/b $folder[2]->short_name b $folder[2]->indent 1 $folder[3]->name a/c $folder[3]->short_name c $folder[3]->even_row 1 $folder[3]->indent 1 $g_cmd upload_select ./prayer-1.3.5/templates/cam/rename.t0000644006513000651300000000065111063707775016002 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/rename.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Rename folder "<% ${rename_foldername|7} |h %>" to ...

    % CALL rename_toolbar % CALL folderlist, $cmd => "rename" % CALL rename_toolbar % IFDEF $g_help % CALL rename_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/sieve.t0000644006513000651300000000203711063707775015646 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/sieve.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Sieve Filtering

    Either:
    or update sieve file directly here:
    % IFDEF $g_help % CALL sieve_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/compose_postponed_help.t0000644006513000651300000000161711063707775021306 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/compose_postponed_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    This screen is displayed if you have selected the Compose icon and you have a postponed (unsent) message.

    Using postponed messages

    • To continue with a postponed message select the Subject field of the relevant message. You will then see the main Compose page, with the message presented for further editing.
    • To start a new message instead, select the Compose a fresh message button.
    • The Cancel button returns you to the Webmail page from whence you came. The contents of the postponed mail folder are unchanged.
    • If you wish to remove a postponed message you need to select it then, from the main Compose screen, choose Cancel.
    ./prayer-1.3.5/templates/cam/list_nav_1.t0000644006513000651300000000126511063707775016574 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/list_nav_1.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# %# $_agg should be "aggregate" at top "aggregate2" at bottom of screen. %# % IFDEF $g_use_icons % CALL list_nav_1_icons % ELSE % CALL list_nav_1_noicons % ENDIF ./prayer-1.3.5/templates/cam/list_toolbar_top.t0000644006513000651300000000066411063707775020116 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/list_toolbar_top.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL list_nav_1, $_agg => "aggregate" % CALL list_nav_2 ./prayer-1.3.5/templates/cam/spam_fail.t0000644006513000651300000000101311063707775016457 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/spam_fail.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Junk Email (Spam) Filtering

    Error: <% $msg |h %>

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/welcome.t0000644006513000651300000000261111063707775016164 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/welcome.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % IFDEF $g_service_name

    Welcome to the <% $g_service_name |h %> Webmail Service % ELSE

    Welcome to the Prayer Webmail Service % ENDIF

    Please read some important hints about use of this Webmail service.

    Use the navigation icons on the Webmail interface

    The browser navigation buttons will not work reliably.

    Always log out from the Webmail system when you have finished.

    • If you fail to do this, people with access to the computer that you are using may be able to read your mail.
    • Abandoned login sessions consume valuable resources on the server.

    Session Timeout

    This login session will shut down automatically after <% $timeout |h %> of idle time.

     
    Show this screen next time you log in
    % IFDEF $g_help % CALL welcome_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/roles_entry.vars0000644006513000651300000000045511063707775017612 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/roles_entry.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $alias me $personal David Carter $from dpc22@cam.ac.uk $reply_to Reply to goes here $fcc sent-mail $signature Signature goes here $g_cmd roles_entry ./prayer-1.3.5/templates/cam/compose_postponed.vars0000644006513000651300000000043111063707775020777 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/compose_postponed.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $list[0]->msgno 1 $list[0]->date Date goes here $list[0]->name Name of recipient goes here $list[0]->size 42K $g_cmd compose_postponed ./prayer-1.3.5/templates/cam/list_toolbar_bottom.t0000644006513000651300000000070411063707775020613 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/list_toolbar_bottom.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# ./prayer-1.3.5/templates/cam/prefs_folder.vars0000644006513000651300000000051611063707775017715 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/prefs_folder.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $suppress_dotfiles 1 $confirm_rm 1 $maildir Maildir goes here $sent_mail_folder sent-mail $postponed_folder postponed-msgs $g_cmd prefs_folder ./prayer-1.3.5/templates/cam/compose_large_help.t0000644006513000651300000000633611063707775020370 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/compose_large_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    Note that in this Webmail screen the main toolbar is not visible, so the Help and Logout buttons are included as part of this page.

    By default the size of the message body part is 80 columns and 24 rows. You can change this if you wish using an option under Manage -> Preferences -> Extra Compose

    The buttons

    • Above the message body part:-
      • Small - this returns you to the standard Compose screen layout.
      • Help - takes you to this help text.
      • Logout - The Logout button brings up a confirmation screen which lets you logout of your mail session. You must remember to logout when you have finished your session.
    • Below the message body part:-
      • Check Spelling - this will check the body of the message and allow you to accept suggested alterations, leave the word unchanged or add the word to your personal dictionary. Once the spell check has completed the status field will summarise, for example:-
        Status: Spell Check finished (0 changes made)
      • Cancel - cancels the message and returns you to the Webmail page you came from when you originally chose Compose. The status line will change to reflect the action:-
        Status:Draft message cancelled
      • Postpone - the draft is saved to the mail folder defined to hold these messages (default postponed-messages) and you are returned to the Webmail page you came from when you originally chose Compose. The status line will change to reflect the action:-
        Status:Draft message postponed
        If you have messages in the postponed messages folder then when you select Compose you get the option to continue with the postponed message or start a new one.
      • Send - triggers an immediate send and returns you to the Webmail page you came from when you originally chose Compose.
      • Save copy - This check box controls whether a copy is automatically saved. The default for this is set in Manage -> Preferences -> Extra Compose.

    If you have enabled Manage -> Preferences -> Extra Compose -> Enable manual line wrap options then there will be two extra options on the line below the message body part:-

    • Line Wrap - wraps the message to a line length defined in Manage -> Preferences -> Extra Compose -> Line Wrap at. The default is 76 characters.
    • Line Wrap on Send - wraps the text of the message as part of the action of sending the message.
    ./prayer-1.3.5/templates/cam/restart.vars0000644006513000651300000000016311063707775016725 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/restart.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $g_cmd restart ./prayer-1.3.5/templates/cam/prefs_folder_help.t0000644006513000651300000000341111063707775020212 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_folder_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $
    • Suppress dotfiles (files starting '.') from folder listing - unchecking this will show all your files and mail folders, including the files that are normally hidden. Files whose name starts with a '.' are normally in your home directory, and include configuration files such as the addressbook used by Pine (.addressbook)
    • Confirm folder deletion - If this is unchecked then selecting the Delete button against a mail folder name on the Folders screen deletes that folder immediately without asking for confirmation.
    • Mail directory - controls which directory is the default for mail folders. The default is the mail subdirectory of your home directory. Some mail clients (for example Outlook Express) use the home directory by default. If you habitually use one of these clients then you may need to consider making this field blank.
    • Sent Mail Folder - controls which folder is used to hold copies of outgoing mail. Again, if you habitually use a mail client that has a different convention you may wish to change this preference, for example if you are an habitual Outlook Express user you may wish to change it to:-
      Sent Mail Folder:
    • Postponed Messages Folder controls which folder is used to store a message that you wish to postpone and return to later.
    ./prayer-1.3.5/templates/cam/vacation_help.t0000644006513000651300000000531711413321714017333 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/vacation_help.t,v 1.2 2010/07/02 08:31:08 dpc22 Exp $

    Using this option you can set a message that is automatically sent to the sender of a message that is personally addressed to you. Typically it is used to alert a sender that you are away (not necessarily on vacation) and will be replying after you return.

    If you already have a vacation message in place the form will show your current message and the Enable Vacation Message box will be checked.

    If you have a manually maintained Sieve file on <% $g_service_name |h %> this cannot be updated from this interface. In this case the you will not see the form but a status message reading

    Error: Manually maintained Sieve file?

    To make changes to a manually maintained file you will need to connect to <% $g_service_name |h %> using an SSH or Telnet client and use the menu interface.

    Frequency

    Once a vacation message has been sent, no further vacation messages will be sent to the address in question until the given number of days have passed. Please note: This is true even if one vacation message is cleared and a new vacation message is set up. This option does not automatically clear your vacation message after the given number of days.

    Aliases

    Vacation messages are only sent out in response to "personal" messages which have been sent directly to your <% $g_service_name |h %> account, rather than via mailing lists or other means. This is determined by looking to see whether your email address appears in the "To:" and "Cc:" headers of a message.

    The Aliases dialogue can be used to define a comma separated list of additional email addresses which will trigger vacation messages in this way. This is normally used in conjunction with "friendly" email address associated with an institution.

    Subject

    The subject line of messages which are sent out

    Setting up a vacation message

    If you do not already have a vacation message then check the Enable Vacation Message box, enter your text into the form immediately beneath it and finally select the Apply button. You will be returned to the main Account Management screen.

    If you have a message and wish to change it just make the relevant changes in the form and select the Apply button.

    If you do not wish to save any changes then select Cancel at any point and you will be returned to the main Account Management screen.

    Cancelling your vacation message

    Uncheck the Enable Vacation Message box and select the Apply button.

    ./prayer-1.3.5/templates/cam/passwd_help.t0000644006513000651300000000305311063707775017043 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/passwd_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    This screen allows you to change your <% $g_service_name |h %> password. The screen contains some notes specific to <% $g_service_name |h %> passwords, and a form you use to change your password. Some general advice on choosing passwords can be found in a Computing Service information leaflet

    To change your password you need to enter your current password and the new password you would like. You need to enter the new one twice, as this check provides a guard against accidental mistyping.

    If your password change is successful then the Status message will change to

    Status: Changed password

    and you will be returned to the Account Management screen.

    If the attempt is not successful, you will stay in the Change Password screen, and the reason the change failed will be displayed in the Status line. Examples of status messages are:

    Status: Password too short - must be at least 6 characters
    Status: New passwords do not match

    and, if you enter your current password incorrectly:-

    Status: Incorrect password
    ./prayer-1.3.5/templates/cam/manage.vars0000644006513000651300000000016111063707775016467 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/manage.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $g_cmd manage ./prayer-1.3.5/templates/cam/search_size_help.t0000644006513000651300000000117011063707775020037 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/search_size_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The Search screen allows you to select a set of messages from the current mail folder using different criteria. After you have selected your messages you can take action on them, for example, Mark them all and copy them all to the same folder.

    After the initial search has been made it is possible to add another criterion to refine the selection.

    This form allows you to select messages according to whether they are Larger or Smaller than the chosen size.

    ./prayer-1.3.5/templates/cam/list_msgs.t0000644006513000651300000000366711064433073016535 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/list_msgs.t,v 1.4 2008/09/18 11:06:35 dpc22 Exp $ %# % FOREACH $msg @list_msg % IFDEF $msg->even_row % ELSE % ENDIF <% $msg->num |h %>. % IFDEF $use_persist % IFDEF $msg->is_marked \ % IFDEF $g_use_icons Yes % ELSE Yes\ % ENDIF % ELSE \ % IFDEF $g_use_icons No % ELSE No\ % ENDIF % ENDIF % ELSE \ % ENDIF % IFDEF $g_use_icons % IFDEF $msg->is_deleted % ELSE % IFDEF $msg->is_answered % ELSE % IFDEF $msg->is_seen % ELSE % ENDIF % ENDIF % ENDIF % ELSE % IFDEF $msg->is_deleted D % ELSE   % ENDIF % IFDEF $msg->is_seen O % ELSE N % ENDIF % IFDEF $msg->is_answered A % ELSE   % ENDIF % ENDIF <% $msg->date |h %> <% $msg->full_dname |h %> <% $msg->size |h %> % IFDEF $msg->has_attach % ENDIF <% $msg->full_subject |h %> % IFDEF $msg->is_deleted Undelete % ELSE Delete % ENDIF % ENDFOREACH ./prayer-1.3.5/templates/cam/abook_search_help.t0000644006513000651300000000626611064274260020160 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_search_help.t,v 1.2 2008/09/17 21:37:52 dpc22 Exp $

    The selection area

    Simple Search

    To perform a simple search, such as the example given above, select the field to search (the choice is Alias, Name, Comment, Address) and then select the match criterion. Use is if you are sure of the exact term, begins, ends and contains if you are either unsure, or wish to retrieve a possibly wider selection. Finally select the Search button.

    Selecting the link from the Alias column of the address you are interested in brings up the relevant address book entry.

    Advanced Search

    After the initial search has been made it is possible to extend the search term using the Add condition button and the any/all toggle. Using any means that any entries in the addressbook that match one or more criteria are returned, using all means that the addressbook entry must match all the specified criteria.

    The example below was obtained by making an initial Alias is choice, then selecting the Add condition button, choosing any, entering the new criteria (Address contains), and then selecting the Search button.

    Search for entries where of the following conditions hold
    2 matches for those search criteria:
    Alias Name Comment Address
    someone A. Person Sales contact at Somewhere Company somone@somewhere.com
    alien Green Alien   alien@domain.otherplanet.com
    ./prayer-1.3.5/templates/cam/display_addr.t0000644006513000651300000000116211063707775017170 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display_addr.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# %# Display a single address with abook_take link. Inputs: %# $_alias - existing alias, if already exists in addressbook %# $_personal - personal name %# $_email - email address %# $_raw - raw text to display without link, on parse error %# % IFNEQ $_raw "" <% $_raw |h %> % ELSE \ % IFNEQ $_personal "" <% "$_personal <$_email>" |h %> % ELSE <% $_email |h %> % ENDIF % ENDIF % IFEQ $_next "1" , % ENDIF ./prayer-1.3.5/templates/cam/printable_addr.t0000644006513000651300000000102511063707775017501 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/printable_addr.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# %# Display a single address with abook_take link. Inputs: %# $_alias - existing alias, if already exists in addressbook %# $_personal - personal name %# $_email - email address %# $_raw - raw text to display without link, on parse error %# % IFNEQ $_raw "" <% $_raw |h %> % ELSE % IFNEQ $_personal "" <% "$_personal <$_email>" |h %> % ELSE <% $_email |h %> % ENDIF % ENDIF % IFEQ $_next "1" , % ENDIF ./prayer-1.3.5/templates/cam/dictionary_help.t0000644006513000651300000000213311063707775017705 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/dictionary_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    Your Personal Dictionary is where you can build up a list of words that you use that are not in the system dictionary used by the spell checker. Spelling is case sensitive.

    Maintaining your dictionary

    • Any words you have added to your personal dictionary appear, sorted alphabetically, above the fields for adding and removing words. Words starting with a capital appear before those all in lower case.
    • To Add a word type it in the first field (as in the example "hypothetical" above) then select the Add button.
    • To Remove a word
      • either type the word in the field by the Remove button and then select that button
      • or select the relevant word in the listing.
    • Back to Options Screen returns you to the main Account Management screen, and no changes are made to your dictionary.
    ./prayer-1.3.5/templates/cam/compose.t0000644006513000651300000000324411413410146016157 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/compose.t,v 1.2 2010/07/02 16:14:30 dpc22 Exp $ %# % CALL header
    % IFDEF $large % CALL container_start % CALL compose_large_top
    % ELSE % CALL compose_toolbar % CALL container_start % CALL status % CALL compose_small_top
    % ENDIF % IFDEF $line_wrap_advanced % IFDEF $line_wrap % ELSE % ENDIF % ENDIF % IFDEF $copy_outgoing % ELSE % ENDIF
    Line Wrap on Send         Save copy
    % IFDEF $g_help % IFDEF $large % CALL compose_large_help % ELSE % CALL compose_small_help % ENDIF % ENDIF % CALL container_end
    % CALL footer ./prayer-1.3.5/templates/cam/redirect_fail.vars0000644006513000651300000000024511063707775020036 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/redirect_fail.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $msg Error message displayed here $g_cmd redirect_fail ./prayer-1.3.5/templates/cam/abook_take.vars0000644006513000651300000000037311063707775017343 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/abook_take.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $alias Alias goes here $name Name goes here $comment Comment goes here $email Email goes here $g_cmd abook_take ./prayer-1.3.5/templates/cam/search_date_help.t0000644006513000651300000000632411063707775020010 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/search_date_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The Search screen allows you to select a set of messages from the current mail folder using different criteria. After you have selected your messages you can take action on them, for example, Mark them all and copy them all to the same folder.

    After the initial search has been made it is possible to add another criterion to refine the selection.

    With the exception of the field for the year, the form is a set of pull-down menus. By default the selection is to search for messages dated today. In the screen above "today" is 5th June 2001. Other options are to select dates Before (not including), Before (including), Since (including), Since (not including) a selected date.

    Some examples:-
    If the current date is 5th June 2001, then

    • will select messages with dates from 1st January 1990 to 4th June 2001 inclusive;
    • will select messages from 1st January 1990 to 3rd March 2000 inclusive;
    • will select messages from 1st January 2001 until the current day;
    • will select messages from 21st May 1998 until the current day.

    Once you have chosen your date then choosing Search will return you to the mail folder with just the selected message(s) listed.

    ./prayer-1.3.5/templates/cam/logout.vars0000644006513000651300000000016111063707775016550 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/logout.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $g_cmd logout ./prayer-1.3.5/templates/cam/rename_toolbar.t0000644006513000651300000000125411063707775017524 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/rename_toolbar.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %#
    Rename under as new name
    ./prayer-1.3.5/templates/cam/vaclog_help.t0000644006513000651300000000253511063707775017021 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/vaclog_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The Vacation Log is associated with the use of a Vacation Message. It lists people who have been trying to contact you in your absence (and also prevents duplicate messages being sent out).

    Log entries

    If you have a vacation message set up (or have had one and have not cleared the log) then the names of people to whom the auto-reply has been sent will be written to a log file. If there are entries in the log file then when you enter this screen it will look something like the screen above.

    Each entry has the date and time the auto-reply was sent. The first entry for each person contains the name of the respondent and the subject of their mail. Subsequent entries for the same person note that the auto-reply has been previously sent (and hence has not been sent again).

    Each time you set up a new vacation message you need to clear the existing log so that a copy of your new message can be sent to people who have previously received the old message. Selecting the Clear vacation log button does this.

    If there are no entries in your log then the message

    No vacation log at this time

    is displayed in place of the list of names.

    ./prayer-1.3.5/templates/cam/logout.t0000644006513000651300000000120511133137120016013 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/logout.t,v 1.5 2009/01/13 16:16:16 dpc22 Exp $ %# % CALL header % CALL container_start

    Confirm logout from <% $g_service_name |h %> Webmail Service

    % IFDEF $g_have_draft
    Warning: Draft message currently active
      This message will be discarded if you exit now
    % ENDIF
    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/compose_small_help.t0000644006513000651300000001467711063707775020415 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/compose_small_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    This works similarly to other mail clients. To compose a message enter the address of the recipient in the To: field and the address of anyone who should also get a copy in the Cc: field. If you want more than one address in a field put a comma between the addresses. You can use addresses from your addressbook either by typing the nickname (alias) or by selecting the Addressbook icon from the main toolbar and then choosing the recipients you want. Enter the subject of the message into the Subject: field. Then type your message into the main message box. You can also cut-and-paste text into the message box. Once you have finished your message, select the Send button.

    Description of the options obtained by using the buttons on the screen follows.

    The buttons

    This section describes the buttons on the default page. If you have enabled Manage -> Preferences -> Extra Compose -> Enable manual line wrap options there will be some extra buttons on the bottom row. These are described at the bottom of this page.

    • By the headers:-
      • Expand - if you have typed a nickname (alias) from your addressbook you can check that you have chosen the correct one by using this. When you select this button the full address is substituted for the alias. If the alias does not exist in your address book then the default domain (typically @cam.ac.uk, depending on your setting in Manage -> Preferences -> Extra Compose) will be added instead. The status line will change to reflect the result of the action, for example after Expand-ing the To: field:-
        Status:Header To Lookup Complete
      • Rich Headers - the standard header fields are To:, Cc: and Subject:. Selecting the Rich Headers button gives other header fields. These are
        • Bcc: - for use if you wish to send a copy of the message to someone but do not wish the other recipients to see that you have sent a copy to that person
        • Fcc: - in which you can enter the name of a mail folder to which you want the message copied (the default is sent-mail)
        • Reply-To: - by default a reply will come to your address as it appears in the From: field. You can use this if you wish any reply to come to a different address.
    • Above the message body part:
      • Large - takes you to another screen with a larger form area for the body part. The size of this form area is defined in Manage -> Preferences -> Extra Compose.
      • Clear Headers - Clears all message headers.
      • Clear Body - Clears all text entered in the body of the message.
      • Undo - Undoes the last action.
      • Import - takes you to a screen from which you can browse your local file system and choose a text file to include in the body of the message. Files produced by an application such as a word processor cannot be included in the body of a message, but should be attached to the message using the Attachments button.
      • Attachments (0) - takes you to a screen from which you can browse your local file system and choose a file to send as an attachment to the message. Once you have done this the button changes to show the number of attachments that will be sent with the message.
    • Below the message body part:-
      • Check Spelling - this will check the body of the message and allow you to accept suggested alterations, leave the word unchanged or add the word to your personal dictionary. Once the spell check has completed the status field will summarise, for example:-
        Status: Spell Check finished (0 changes made)
      • Cancel - cancels the message and returns you to the Webmail page you came from. The status line will change to reflect the action:-
        Status:Draft message cancelled
      • Postpone - the draft is saved to the mail folder defined to hold these messages (default postponed-messages) and you are returned to the Webmail page you came from. The status line will change to reflect the action:-
        Status:Draft message postponed
        If you have messages in the postponed messages folder then when you select Compose you get the option to continue with a postponed message or start a new one.
      • Send - triggers an immediate send and returns you to the Webmail page you came from.
      • Save copy - This check box controls whether a copy is automatically saved. The default for this, saving a copy to sent-mail, is set in Manage -> Preferences -> Extra Compose.

    Other aspects, such as the size of the text area for the body part, the use of a personal name, and whether a signature is included or not, depend on choices made under Manage -> Preferences -> Compose and Manage -> Preferences -> Extra Compose.

    If you have enabled Manage -> Preferences -> Extra Compose -> Enable manual line wrap options then there will be two extra options on the line below the message body part:

    • Line Wrap - wraps the message to a line length defined in Manage -> Preferences -> Extra Compose -> Line Wrap at . The default is 76 characters.
    • Line Wrap on Send - wraps the text of the message as part of the action of sending the message.
    ./prayer-1.3.5/templates/cam/search_text_help.t0000644006513000651300000000572011063707775020056 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/search_text_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The Search screen allows you to select a set of messages from the current mail folder using different criteria. After you have selected your messages you can take action on them, for example, Mark them all and copy them all to the same folder.

    After the initial search has been made it is possible to add another criterion to refine the selection.

    Text searching allows messages to be selected depending on whether a part of the message Contains or Does not contain the entered string. It is not case sensitive, e.g. choosing web will match both web and Web. The parts (fields) that can be chosen are:

    • From
    • To
    • Cc
    • Recipient - messages with Cc: or To: headers containing the entered string will be selected.
    • Participant - messages with Cc:, To:, or From: headers containing the string will be selected.
    • Subject
    • Text (Expensive!) - this searches all the body text. Please avoid this wherever possible. It puts a heavy strain on <% $g_service_name |h %>.

    Your string does not have to be a complete word or phrase. A search on the Subject string could contain

    When you are searching using an address you do not have to enter the full address, you can use any unique element of that address. Examples are

    Once you have entered your string then choose Search and you will return to the mail folder with just the selected message(s) listed.

    ./prayer-1.3.5/templates/cam/display_images.t0000644006513000651300000000056511415373531017517 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display_images.t,v 1.2 2010/07/08 16:05:45 dpc22 Exp $ %# % IFDEF $html_images_shown

    cur_msg}/${nav->cur_uid}/${section} |s %>">\ Hide unsafe images

    % ELSE

    cur_msg}/${nav->cur_uid}/${section}/show_images |s %>">\ Show unsafe images

    % ENDIF ./prayer-1.3.5/templates/cam/prefs_display.vars0000644006513000651300000000046411063707775020111 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/prefs_display.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $use_icons 1 $use_tail_banner 1 $html_inline 1 $html_inline_auto 1 $preserve_mimetype 1 $sort_combined arrival $abook_sort_combined order $g_cmd prefs_display ./prayer-1.3.5/templates/cam/abook_lookup_help.t0000644006513000651300000001405411063707775020231 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_lookup_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The addressbook search results screen has three areas:

    • A search dialogue that will allow you to search again for users on the local system, or against the University Directory.
    • The top and bottom bars, which allow you to navigate around the list of results. Search which generate a lot of results will be split into pages.
    • One result for the current search on each line, with links that affect or use just that entry.

    Search Dialogue

    The search dialogue allows you to make another search. It works in exactly the same way as the search dialogue on the main addressbook screen. Cancel search will cancel the current addressbook search and return you to the addressbook screen.

    Search <% $g_service_name |h %> Users searches for local users on the <% $g_service_name |h %> system. The search is made against the initial registered name of each user (of the form "A.N. Other") and also against the fullname which can be set using this Webmail interface. Please note: the local search database only stores limited numbers of results. Queries that would return large numbers of results (e.g: Smith) will typically return no results and an explanation to this effect. It is also possible to search for details on a particular <% $g_service_name |h %> username or for usernames which match a given set of initials.

    Search Directory searches the University Directory. The results will be more comprehensive than the local search database, but does not contain information about recently cancelled accounts.

    Top and bottom bars

    These have a group of common elements at the left and right hand sides of the bar, and a unique element in the centre.

    Top bar, unique element

    Search Results (1 entry)

    This provides a summary of the results

    Bottom bar, unique element

    Page: /1

    The search results are presented as a series of pages. The number of entries on each page is set in Manage -> Preferences -> Display. This element shows the current page number and the total number of pages. To change to another page in your addressbook enter the number in the Page: box and then select Go

    Common elements

    The four icons, First Previous Next Last, take you to, respectively, the first, previous, next and last page of addresses. An icon is greyed out, as in the example screen on this page, if the choice is not applicable (in the example there is only one page of addresses).

    Search results

    Each search result appears on a separate line.

    • If there is currently no draft message, the individual results will look like this:
      1.dpc22 David Carter
      (D.P. Carter)
      University Computing Service  Add Compose
      • A second name appears in parenthesis if the given individual has set up a name different from the original, registered name.
      • Selecting Add takes you to the Addressbook Entry screen so that you can add the email address to your addressbook.
      • Selecting Compose takes you to the Compose screen, with the address of your choice present in the To: field of the message.
    • If a draft message is active, each search result will look something like:
      1.dpc22 David Carter
      (D.P. Carter)
      University Computing Service  Add To Cc Bcc

      An extra element will be added at the top right:-

      • A second name appears in parenthesis if the given individual has set up a name different from the original, registered name.
      • Selecting Add takes you to the Addressbook Entry screen so that you can add the email address to your addressbook.
      • Use the check boxes to select addresses for the To:, Cc: or Bcc: fields of your message. Check the boxes you want on one search result page, then select the Add marked to draft button. The Status line will be updated to reflect your action, for example
        Status:Added 2 addresses to draft
        After you have done this you can either move to another page of the search results, or select Compose from the main toolbar to return to the Compose screen. If you have chosen addresses these will be added to the relevant header fields of your message.
    ./prayer-1.3.5/templates/cam/vacation.vars0000644006513000651300000000034311063707775017045 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/vacation.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $use_vacation 1 $days 31 $days David.Carter@ucs.cam.ac.uk $vacation_msg Gone Fishing $g_cmd vacation ./prayer-1.3.5/templates/cam/prefs_display_abook_sort.t0000644006513000651300000000125311063707775021620 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_display_abook_sort.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ Addressbook sort mode: ./prayer-1.3.5/templates/cam/sieve_fail.t0000644006513000651300000000077411063707775016647 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/sieve_fail.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Sieve Filtering

    Error: <% $msg |h %>

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/prefs_display1_help.t0000644006513000651300000000702711063707775020474 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_display1_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $
    • Use icons controls the use of icons and text for links and navigation. If this option is unselected then only text is used. This has additional effects on certain pages. For example in the mail folder list screen the single column (envelope icon) that indicates the status of a message is replaced by three columns D (marked if message deleted), N (showing N for a new message or O for a read message) A (marked if message answered).
    • Duplicate icons below message controls whether a duplicate of the common toolbar (the icons/text appearing at the top of every screen) should appear below messages when they are being viewed.
    • Display text/html sections inline. Many messages have text and HTML parts. If this option is unchecked then, when messages have a Content-Type: text/html header and the HTML section is selected, the raw HTML is shown instead of it being rendered (presented formatted).
    • Display text/* sections starting <html> inline. Some messages are in HTML but do not have the correct (or any) Content-Type headers. These are frequently spam messages. If this option is unchecked these messages are displayed as raw HTML instead of being rendered.
    • Preserve MIME type when downloading attachments controls whether attachments where the type can be handled by the browser (for example images in GIF or JPEG format) are displayed in the browser when the attachment is selected. When the option is checked an attachment of a type the browser can handle is displayed when selected, otherwise the browser's "Save As..." dialogue appears allowing you to save the attachment to your local system for later processing. If the option is unchecked then selecting any attachment will bring up the browser's "Save As..." dialogue.
    • Default folder sort mode affects the way all mail folders are sorted and thus presented. The default is Arrival - messages are presented in the order they arrive in the mail folder. There is a wide range of alternatives, including Date, From and Subject. It is also possible to change the sort order of the current folder in the Mailboxes screen.
    • Messages per page controls the number of messages listed per screen in the message list screen.
    • Addressbook sort mode affects the way that the addressbook is sorted and thus presented. The default is Order - entries are presented in the order they have been added to the addressbook. There is a range of alternatives, including Alias, Name and Comment and Address. It is also possible to change the current sort order on the Addressbook screen.
    • Addressbook entries per page controls the number of addresses listed per screen in the main addressbook screen.
    • Alt Addresses - a comma-separated list of alternative addresses that you use to send email. This controls what is shown in the From column of the message list screen. Messages from any of your defined addresses will show who they are to rather than who they are from.
    ./prayer-1.3.5/templates/cam/login_hermes.t0000644006513000651300000001142711576132512017177 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/login_hermes.t,v 1.9 2011/06/15 13:36:10 dpc22 Exp $ % IFDEF $g_service_name <% $g_service_name |h %> Webmail Service % ELSE Prayer Webmail Service % ENDIF
    % IFDEF $login_banner

    <% $login_banner |h %>

    % ELSE % IFDEF $service_name

    <% $service_name |h %> Webmail Service

    % ELSE

    Prayer Webmail Service

    % ENDIF % ENDIF
    % IFDEF $ssl_available
    Warning:This is an insecure HTTP session.
      It is strongly recommended that you use SSL encryption if your browser supports it.
      ">Click Here for an SSL enabled login session.
    % ENDIF
    % IFDEF $raven_enable Login using Raven % ENDIF
      
    % IFDEF $login_insert2 <% ${login_insert2} |n %> % ENDIF % IFDEF $motd <% ${motd} |n %> % ENDIF
    % IFDEF $login_insert1 <% ${login_insert1} |n %> % ENDIF
    • © 2008 Computing Service, University of Cambridge
    ./prayer-1.3.5/templates/cam/printable_tail.t0000644006513000651300000000016511063707775017524 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/printable_tail.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ ./prayer-1.3.5/templates/cam/block_fail.vars0000644006513000651300000000023711063707775017330 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/block_fail.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $msg Error message displayed here $g_cmd block_fail ./prayer-1.3.5/templates/cam/copy.t0000644006513000651300000000121311063707775015500 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/copy.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % IFNEQ $count "1"

    Copy <% $count | h %> messages to folder...

    % ELSE

    Copy message to folder...

    % ENDIF % CALL copy_toolbar
    % IFDEF $g_favourites[0] Favourite mail folders: % CALL favlist, $cmd => "copy" Normal mail folders: % ENDIF % CALL folderlist, $cmd => "copy" %#
    %# CALL copy_toolbar % IFDEF $g_help % CALL copy_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/expunge.vars0000644006513000651300000000017711063707775016721 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/expunge.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $count 42 $g_cmd expunge ./prayer-1.3.5/templates/cam/raven_blocked.t0000644006513000651300000000072211063707775017330 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/raven_blocked.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL container_start

    Raven logins not allowed

    Raven logins have been disabled for this account. You will need to log in using the normal <% $g_service_name |h %> username and password

    Click here to return to the login screen

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/search_text.t0000644006513000651300000000204511072416767017041 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/search_text.t,v 1.3 2008/10/06 14:17:27 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % CALL submitenter_js % CALL search_header, $_type => "Text" %
    % CALL search_footer % IFDEF $g_help % CALL search_text_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/include.vars0000644006513000651300000000016311063707775016664 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/include.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $g_cmd include ./prayer-1.3.5/templates/cam/manage.t0000644006513000651300000000231311300507007015734 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/manage.t,v 1.4 2009/11/17 11:50:31 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Account management

    % IFDEF $g_help % CALL manage_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/filter.vars0000644006513000651300000000137311063707775016532 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/filter.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $filters[0]->offset 0 $filters[0]->type_strong SUBJECT $filters[0]->type subject $filters[0]->value Test $filters[0]->mailbox a $filters[1]->offset 1 $filters[1]->type_strong RECIPIENT $filters[1]->type recipient $filters[1]->value dpc99@cam.ac.uk $filters[1]->mailbox a $filters[1]->copy 1 $filters[2]->offset 2 $filters[2]->type_strong SENDER $filters[2]->type sender $filters[2]->value dpc22@cam.ac.uk $filters[2]->mailbox a $filters[2]->copy 1 $g_cmd filter ./prayer-1.3.5/templates/cam/toolbar_right.t0000644006513000651300000000117011063707775017367 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/toolbar_right.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ % % IFDEF $g_help % CALL tb_icon, $_cmd => "help/$g_cmd", % $_icon => "back", $_alt => "Back" % ELSE % CALL tb_icon, $_cmd => "help/$g_cmd", $_icon => "help", $_alt => "Help" % ENDIF % CALL tb_icon, $_cmd => "logout/$g_cmd", $_icon => "logout", $_alt => "Logout" % IFDEF $g_use_icons % IFDEF $g_help % ELSE % ENDIF % ENDIF
    BackHelp| Logout
    ./prayer-1.3.5/templates/cam/copy_help.t0000644006513000651300000000525711063707775016524 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/copy_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The layout is similar to the main mail folders screen. If you have any Favourite Mail Folders these will be listed between the INBOX and the main mail folder listing.

    Saving the message

    • If the folder exists, and you can see it, then select the name of the chosen mail folder, or the folder icon by its name.
    • Use [Expand] to expand collapsed directories.
    • If the folder does not exist you will need to create it.
      • For example selecting mailbox and typing a name such as projects will, once the Create button has been pressed, cause the mail folder listing to change to include the newly created mail folder.
      • Once the folder has been created, select its name or the folder icon by its name.

    The message is copied into the destination folder and you are returned to the message display screen where the status line will be updated, for example:-

    Status: Copied message 12 to mail/saved-messages

    The banner line above and below the message also changes to indicate that the original copy is now marked as deleted, for example:-

    Previous Next | Copy | Undelete | Mark | Reply | Forward
    Message: 12 out of 12
    Show Hdrs | Download Message

    When you return to the mailbox list screen the display is also updated to show the status of the message as deleted.

    The bars above and below the folder listing

    Cancel returns you to the message display page, without saving the message into any folder.
    Refresh checks the contents of the directory on the server.
    ./prayer-1.3.5/templates/cam/abook_search.t0000644006513000651300000000602511064275546017151 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_search.t,v 1.4 2008/09/17 21:49:26 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % CALL submitenter_js

    Addressbook Search

    Search for entries where of the following conditions hold

    % FOREACH $f @filters % ENDFOREACH
    % IFDEF $results[0] % IFNEQ $count 1

    <% $count |h %> matches for those search criteria:

    % ELSE

    1 match for those search criteria:

    % ENDIF % FOREACH $r @results % IFDEF $g_have_draft % ELSE % ENDIF % ENDFOREACH
    Alias Name Comment Address  
    <% $r->alias |h %> <% $r->name |h %> <% $r->comment |h %> <% $r->email |h %> To Cc Bcc Compose fresh message
    % ENDIF % IFDEF $g_help % CALL abook_search_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/frontend_timeout.t0000644006513000651300000000051111075051454020100 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/frontend_timeout.t,v 1.3 2008/10/14 08:07:08 dpc22 Exp $ %# % CALL header % CALL container_start

    Couldn't connect to session. Maybe it timed out?

    \ Click here to login again

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/printable_hdrs.t0000644006513000651300000000257611063707775017543 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/printable_hdrs.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %#
    % IFDEF $reply_to[0] % ENDIF % IFDEF $to[0] % ENDIF % IFDEF $cc[0] % ENDIF
    Reply-To: % FOREACH $a @reply_to % CALL printable_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    From: % FOREACH $a @from % CALL printable_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    To: % FOREACH $a @to % CALL printable_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    Cc: % FOREACH $a @cc % CALL printable_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    Date:<% $date |h %>
    Subject:<% $subject |h %>
    ./prayer-1.3.5/templates/cam/abook_add_help.t0000644006513000651300000000727511064274260017444 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_add_help.t,v 1.2 2008/09/17 21:37:52 dpc22 Exp $

    The address book form buttons

    • To create an entry complete the fields and then select the Add entry or Add/Update entry button as relevant;
    • To delete an entry select the Delete entry button;
    • To return to the Webmail screen from whence you came, making no changes to your address book, select the Cancel button

    The address book form fields

    • Alias - the nickname by which the entry is known. This can be used as an address shortcut when composing a message.
    • Name - this is an optional field, but is customarily used for the real name of an individual or a relevant name for a list. The entry in this field will appear in any message sent using the alias.
    • Comment - optional - usually used as a short, relevant memory jogger for example "Contact at This Company Ltd.". It does not appear in any message sent using the alias.
    • Address(es)
      • In most cases this will be a single address, as in the example shown at the top of this page.
      • However you can also use the Addressbook to create an entry for a small group of people. In this case the Address field can either be full email addresses of the group members or the aliases of existing addressbook entries. Addresses must be separated by commas, as in this example which uses aliases already existing in the addressbook.
        Alias
        Name
        Comment
        Address(es)

    Hence the following examples would all be be valid entries.
    Note: that the final entry uses existing alias entries, not full email addresses. Remember that you can only use this form of short address if you have an entry for the individual alias.

    Alias Name Comment Address(es)  
    someone A. Person Sales contact at Somewhere Company someone@somewhere.com Compose fresh message
    alien Green Alien   alien@planet.otherdomain.com Compose fresh message
    group   Small group person@company.co.uk, anotherperson@company.co.uk Compose fresh message
    group2     someone, alien Compose fresh message
    ./prayer-1.3.5/templates/cam/tb_icon.t0000644006513000651300000000120111063707775016140 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/tb_icon.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# %# Arguments: %# $_cmd Command %# $_icon Icon name %# $_alt Alt text for icon %# % IFDEF $g_use_icons % IFEQ $g_cmd $_cmd <% $_alt |h %> % ELSE <% $_alt |h %> % ENDIF % ELSE % IFEQ $g_cmd $_cmd <% $_alt |h %> % ELSE <% $_alt |h %> % ENDIF % ENDIF ./prayer-1.3.5/templates/cam/roles_select_help.t0000644006513000651300000000126111063707775020224 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/roles_select_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    Composing, Replying or Forwarding using Roles

    If you have defined one or more roles then, when you choose to compose, reply to, or forward a message, you will enter this screen where you can select the role that you wish to use by selecting the name of the role (e.g. "helpdesk"). Choose Default if you do not wish to use one of your defined roles.

    Once you have chosen the role and selected the correct entry you will enter the main Compose screen.

    Cancel returns you to the Webmail page you came from.

    ./prayer-1.3.5/templates/cam/filter.t0000644006513000651300000000250511063707775016020 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/filter.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Automatic Mail Filtering

    % IFDEF $filters[0]
      % FOREACH $f @filters
    1. <% $f->type_strong |h %>: Filter messages with <% $f->type |h %> of "<% $f->value |h %>". Remove this filter.
      • Store in mail folder: <% ${f->mailbox|7} |h %>
      • % IFDEF $f->copy
      • Copy message to inbox
      • % ENDIF
    2. % ENDFOREACH
    % ELSE

    No filter actions defined at the current time

    % ENDIF
    % IFDEF $g_help % CALL filter_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/action_stub.t0000644006513000651300000000055311063707775017046 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/action_stub.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Help Text: Action stub

    That was just a help text example.
    Go back to help page % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/filter_select.vars0000644006513000651300000000017711063707775020072 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/filter_select.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $g_cmd filter_select ./prayer-1.3.5/templates/cam/welcome_help.t0000644006513000651300000000062611063707775017200 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/welcome_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    This screen is purely informational. On other screens selecting Help takes you to help text appropriate to that screen. There is no overall, standalone, help facility.

    If you do not wish to see the welcome screen again you can unselect the checkbox above.

    ./prayer-1.3.5/templates/cam/fullname_help.t0000644006513000651300000000332511063707775017347 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/fullname_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    User accounts are set up on Computing Service systems such as <% $g_service_name |h %> using your registered name. Your registered name consists of your initials and surname, as this is the information that is kept in the Computing Service's database. This is also used to set an initial default on another name field (in the Webmail system this is called your Fullname). Enquiries about your account will show both names. It is not possible to change the registered name, but many people like to replace their initials in the other name field with their given name. This is the purpose of this, Change Fullname, option.

    Note: Fullname is also, by default, the name that appears in the From: field of an email. It is possible to have one name returned by an enquiry to your account, and another name used on outgoing messages from Webmail. If you wish to do this you will also need to set your Webmail Personal Name in Manage -> Preferences -> Compose.

    When you enter the screen a check is made against <% $g_service_name |h %> and the result shown as the Current Fullname entry. To change your entry on <% $g_service_name |h %> enter the name you would like to appear in the Fullname field and then select the Change Fullname button.

    The name that you choose should clearly identify you - using just your first name is not likely to uniquely identify you. Please bear in mind that some "joke" names may be offensive to others. The local database containing your real name is updated once every night.

    ./prayer-1.3.5/templates/cam/folderlist_icons.t0000644006513000651300000000330411063707775020073 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/folderlist_icons.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# %# Common code shared by the various folder list screens. %# % FOREACH $f @folder % IFDEF $f->even_row % ELSE % ENDIF %# %# XXX Getting rather messy: better factoring please %# % IFEQ $cmd "folders" % IFNDEF $f->noselect % CALL folderlist_folders, $_name => $f->name, $_type => "mailbox" % ELSE % CALL folderlist_folders, $_name => $f->name, $_type => "directory" % ENDIF % ELSE % IFNDEF $f->noselect % CALL folderlist_nfolders, % $_name => $f->name, $_size => $f->size, $_cmd => $cmd % ELSE % IFEQ $cmd "filter_select" % ELSE % ENDIF % ENDIF % % ENDIF % ENDFOREACH
    % LOOP $f->indent <% $g_alt_pad |n %> % ENDLOOP % IFDEF $f->haschildren % IFDEF $f->expanded <% $g_alt_pad |n %> % ELSE <% $g_alt_pad |n %> % ENDIF % ELSE <% $g_alt_pad |n %> % ENDIF % IFDEF ${fcmd} % IFNDEF $f->noselect [mailbox]  <% ${f->short_name|7} |h %> % ELSE <% $g_alt_pad |n %> <% $f->{short_name|7} |h %> % ENDIF % ELSE [mailbox]  <% $f->{short_name|7} |h %> % ENDIF
    ./prayer-1.3.5/templates/cam/search_status_help.t0000644006513000651300000000135211063707775020412 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/search_status_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The Search screen allows you to select a set of messages from the current mail folder using different criteria. After you have selected your messages you can take action on them, for example, Mark them all and copy them all to the same folder.

    After the initial search has been made it is possible to add another criterion to refine the selection.

    This form allows you to select messages by their status. These are

    • Seen (read)
    • Unseen
    • Deleted
    • Not Deleted
    • Answered
    • Not Answered
    ./prayer-1.3.5/templates/cam/compose_postponed.t0000644006513000651300000000170311064226126020255 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/compose_postponed.t,v 1.2 2008/09/17 16:12:06 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    List of Postponed messages

    % FOREACH $m @list % ENDFOREACH
    Msgno Date First To/Cc/Bcc Size Subject
    <% $m->msgno |h %>. <% $m->date |h %> <% $m->name |h %> <% $m->size |h %> <% $m->subject |h%>

    % IFDEF $g_help % CALL compose_postponed_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/folderlist_noicons.t0000644006513000651300000000264011063707775020432 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/folderlist_noicons.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# %# Common code shared by the various folder list screens. %# % FOREACH $f @folder % IFDEF $f->even_row % ELSE % ENDIF %# %# XXX Getting rather messy: better factoring please %# % IFEQ $cmd "folders" % IFNDEF $f->noselect % CALL folderlist_folders, $_name => $f->name, $_type => "mailbox" % ELSE % CALL folderlist_folders, $_name => $f->name, $_type => "directory" % ENDIF % ELSE % IFNDEF $f->noselect % CALL folderlist_nfolders, % $_name => $f->name, $_size => $f->size, $_cmd => $cmd % ELSE % IFEQ $cmd "filter_select" % ELSE % ENDIF % ENDIF % % ENDIF % ENDFOREACH
    % LOOP $f->indent <% $g_alt_pad |n %>\ % ENDLOOP % IFDEF $f->haschildren % IFDEF $f->expanded [Collapse]\ % ELSE [Expand]\ % ENDIF % ELSE <% $g_alt_pad |n %> % ENDIF   % IFDEF ${fcmd} % IFNDEF $f->noselect [mailbox]  <% ${f->short_name|7} |h %> % ELSE <% $f->{short_name|7} |h %> % ENDIF % ELSE <% $f->{short_name|7} |h %> % ENDIF
    ./prayer-1.3.5/templates/cam/vaclog_fail.vars0000644006513000651300000000024111063707775017504 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/vaclog_fail.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $msg Error message displayed here $g_cmd vaclog_fail ./prayer-1.3.5/templates/cam/vacation_fail.vars0000644006513000651300000000024511063707775020041 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/vacation_fail.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $msg Error message displayed here $g_cmd vacation_fail ./prayer-1.3.5/templates/cam/footer.t0000644006513000651300000000016011063707775016024 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/footer.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# ./prayer-1.3.5/templates/cam/list_title.t0000644006513000651300000000263611070142524016673 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/list_title.t,v 1.4 2008/09/29 12:08:52 dpc22 Exp $ %# #\ % CALL sort_icon, $_value => "arrival" % IFDEF $page_all_marked % IFDEF $g_use_icons None % ELSE None % ENDIF % ELSE % IFDEF $g_use_icons All % ELSE All % ENDIF % ENDIF % IFDEF $g_use_icons \ Status % ELSE D N A % ENDIF Date\ % CALL sort_icon, $_value => "date" From\ % CALL sort_icon, $_value => "from" Size\ % CALL sort_icon, $_value => "size" Subject\ % CALL sort_icon, $_value => "subject" Thread\ % CALL sort_icon, $_value => "references" ./prayer-1.3.5/templates/cam/login_hermes.vars0000644006513000651300000000014611071070745017702 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/login_hermes.vars,v 1.2 2008/10/02 07:01:57 dpc22 Exp $ ./prayer-1.3.5/templates/cam/abook_list_nav_1_noicons.t0000644006513000651300000000103111063707775021466 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_list_nav_1_noicons.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % IFDEF $nav->first_page First % ELSE First % ENDIF | % IFDEF $nav->prev_page Previous % ELSE Previous % ENDIF | % IFDEF $nav->next_page Next % ELSE Next % ENDIF | % IFDEF $nav->last_page Last % ELSE Last % ENDIF ./prayer-1.3.5/templates/cam/prefs_general.t0000644006513000651300000000564411065141543017341 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_general.t,v 1.3 2008/09/20 09:33:23 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Preferences

    General Preferences:

    Template Set:
    % IFDEF $raven_enable % ENDIF
    Enable welcome screen
    Allow Raven logins
    Confirm expunge
    Confirm logout
    Expunge deleted messages from INBOX on logout
    Use persistent marks (slower, sometimes useful)
       - Zoom automatically after search
       - Unmark messages after aggregate operation

    % IFDEF $g_help % CALL prefs_general_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/display.t0000644006513000651300000000076311063707775016204 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % CALL display_toolbar
    % IFNDEF $full_hdrs % CALL display_hdrs % ENDIF %# %# Live system inserts message MIME structure and body by hand here %# % IFDEF $g_testrig <% ${message} |n %>
    % CALL display_toolbar % IFDEF $g_help % CALL display_help % ENDIF % CALL footer % ENDIF ./prayer-1.3.5/templates/cam/fullname.vars0000644006513000651300000000022411063707775017042 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/fullname.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $fullname David Carter $g_cmd fullname ./prayer-1.3.5/templates/cam/upload_select.t0000644006513000651300000000167311063707775017363 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/upload_select.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Upload local folder "<% $upload_name |h %>" as folder


    % CALL folderlist, $cmd => "upload_select"
    Upload folder under with name:
    % IFDEF $g_help % CALL upload_select_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/rm.vars0000644006513000651300000000023711063707775015661 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/rm.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $type mailbox $name Mailbox name $g_cmd rm ./prayer-1.3.5/templates/cam/list.vars0000644006513000651300000000230111063707775016210 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/list.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ # # $nav contains links to adjacent messages $nav->msg_count 675 $nav->page_current 1 $nav->page_count 1 $nav->first_msg 1 $nav->first_uid 2 $nav->prev_msg 14 $nav->prev_uid 15 $nav->next_msg 34 $nav->next_uid 35 $nav->last_msg 168 $nav->last_uid 169 # State specific to the list screen. $list_msg[0]->num 1 $list_msg[0]->uid 1 $list_msg[0]->date Mar 5 2008 $list_msg[0]->dname dpc22@cam.ac.uk $list_msg[0]->subject Hello World $list_msg[0]->size 3K $list_msg[0]->is_deleted 1 $list_msg[1]->num 2 $list_msg[1]->uid 2 $list_msg[1]->date Mar 19 2008 $list_msg[1]->dname David Carter $list_msg[1]->subject 2nd message $list_msg[1]->size 3K $list_msg[1]->even_row 1 $list_msg[1]->is_answered 1 $list_msg[2]->num 3 $list_msg[2]->uid 73 $list_msg[2]->date Mar 19 2008 $list_msg[2]->dname David Carter $list_msg[2]->subject 3rd message $list_msg[2]->size 5.4M $list_msg[2]->is_seen 1 $g_cmd list ./prayer-1.3.5/templates/cam/tb_form.t0000644006513000651300000000044511063757073016160 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/tb_form.t,v 1.3 2008/09/16 16:26:35 dpc22 Exp $ % IFEQ $g_cmd $_cmd \ % ELSE \ % ENDIF ./prayer-1.3.5/templates/cam/error.vars0000644006513000651300000000015711063707775016375 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/error.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $g_cmd error ./prayer-1.3.5/templates/cam/abook_list.t0000644006513000651300000000263611064530540016647 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_list.t,v 1.2 2008/09/18 19:52:00 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % CALL submitenter_js % % IFDEF $have_lookup % CALL abook_list_search
    % ENDIF
    % CALL abook_list_toolbar_top
    % IFDEF $abook[0] % CALL abook_list_title % % FOREACH $a @abook % IFDEF $a->even_row % ELSE % ENDIF % ENDFOREACH
    <% $a->num |h %>. <% $a->alias |h %> <% $a->name |h %> <% $a->comment |h %> <% $a->email |h %> % IFDEF $g_have_draft To Cc Bcc % ELSE Compose % ENDIF
    % CALL abook_list_toolbar_bottom % ENDIF
    % IFDEF $g_help % CALL abook_list_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/manage_help.t0000644006513000651300000000451311463516401016760 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/manage_help.t,v 1.3 2010/11/01 10:57:05 dpc22 Exp $

    From here you can access screens that let you configure various aspects of the Webmail system either for the current session or for every future session. These include preferences that affect aspects of the appearance of the system, account management (e.g. changing your password), mail processing (e.g. setting a vacation message) and defining a personal dictionary.

    The option choices

    The choices fall into several categories. Each category has its own specific help page. The categories are:-

    • Webmail Preferences, covering:
      • User Preferences:
        • General - including whether or not the welcome screen should be displayed, and whether or not a you should be asked to confirm a decision to logout.
        • Display - concerned with how message lists and individual messages are displayed.
        • Compose - includes settings for personal name and whether a signature is included or not.
        • Extra Compose - use of the sent-mail folder, the size of the text area for the body part and the spell check language.
        • Folder - options concerned with the use of, and actions on, mail folders.
      • Personal Dictionary to which you can add words you commonly use that are not in the system dictionary.
      • Roles where, if you have various roles, you can define relevant information - From and Reply-to addresses and a signature.
    • % IFDEF $accountd_server
    • Account Management, covering:
      • Change Password
      • Change Fullname
      • Check Quota
    • Mail Processing, covering:
      • Redirecting your mail to another address
      • Setting up a vacation message
      • Setting up mail filtering and blocks
      • Setting up automatic filtering for Junk Email
      • Advanced Mail filtering, if available on this account
    • % ENDIF
    ./prayer-1.3.5/templates/cam/filter_select.t0000644006513000651300000000103511063707775017354 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/filter_select.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Select Target Mail Folder...

    % CALL filter_select_toolbar % IFDEF $g_favourites[0] Favourite mail folders: % CALL favlist, $cmd => "filter_select" Normal mail folders: % ENDIF % CALL folderlist, $cmd => "filter_select" % CALL filter_select_toolbar % IFDEF $g_help % CALL filter_select_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/passwd.vars0000644006513000651300000000021211063707775016535 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/passwd.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ # # No variables needed. $g_cmd passwd ./prayer-1.3.5/templates/cam/search_header.t0000644006513000651300000000134211063707775017306 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/search_header.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %#

    Mailbox Search (<% $_type |h %>) % IFNEQ $selected 1 (<% $selected |h %> messages out of <% $count |h %> currently selected) % ELSE (1 message out of <% $count |h %> currently selected) % ENDIF

    Search Menus:
    ./prayer-1.3.5/templates/cam/fullname.t0000644006513000651300000000150411063707775016334 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/fullname.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Change Fullname

    Current Fullname: <% $fullname |h %>
    Fullname:
    % IFDEF $delay NB: It can take up to <% $delay |h %> for fullname changes to take effect % ENDIF % IFDEF $g_help % CALL fullname_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/prefs_option.t0000644006513000651300000000103011063707775017232 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_option.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# %# Parameters: %# $_value Value for this select option %# $_desc Description for this select option %# $_current Current value, for "selected" %# ./prayer-1.3.5/templates/cam/display_mime_msg.t0000644006513000651300000000044411415373531020043 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display_mime_msg.t,v 1.2 2010/07/08 16:05:45 dpc22 Exp $ <% "$_name $_type $_size" |h %> Download this section ./prayer-1.3.5/templates/cam/display_mime_other.t0000644006513000651300000000057711063707775020417 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display_mime_other.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ % IFDEF $g_use_icons [paperclip] % ENDIF <% "$_name $_type $_size" |h %> ./prayer-1.3.5/templates/cam/Makefile0000644006513000651300000001333311415035753015776 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/Makefile,v 1.5 2010/07/07 08:33:47 dpc22 Exp $ ifeq ($(strip $(RPM_BUILD)), true) include ../../Config-RPM else include ../../Config endif CFLAGS = $(BASECFLAGS) LDFLAGS = $(BASELDFLAGS) TYPE=cam TARGETS=templates.a templates_frontend.a T_FILES_FRONTEND=login.t login_hermes.t \ frontend_login_error.t frontend_security.t frontend_session.t \ frontend_timeout.t frontend_compose_timeout.t \ header.t footer.t container_start.t container_end.t O_FILES_FRONTEND=_template_index_frontend.o ${T_FILES_FRONTEND:.t=.o} C_FILES_FRONTEND=${O_FILES_FRONTEND:.o=.c} T_FILES=raven_blocked.t \ printable.t printable_tail.t printable_hdrs.t printable_addr.t \ abook_add_help.t abook_add.t abook_list_help.t abook_list_nav_1_icons.t \ abook_list_nav_1_noicons.t abook_list_nav_1.t abook_list_nav_2.t \ abook_list_search.t abook_list.t abook_list_title.t \ abook_list_toolbar_bottom.t abook_list_toolbar_top.t abook_lookup_help.t \ abook_lookup_nav_1_icons.t abook_lookup_nav_1_noicons.t \ abook_lookup_nav_1.t abook_lookup_search.t abook_lookup.t \ abook_search_help.t abook_search.t abook_take_help.t abook_take.t \ abook_transfer_help.t abook_transfer.t abook_update_help.t abook_update.t \ action_stub.t attachments_help.t attachments.t block_fail.t block_help.t \ block.t compose_large_help.t compose_large_top.t compose_postponed_help.t \ compose_postponed.t compose_small_help.t compose_small_top.t compose.t \ compose_toolbar_left.t compose_toolbar_right.t compose_toolbar.t \ container_end.t container_start.t copy_help.t copy.t copy_toolbar.t \ dictionary_help.t dictionary.t display_addr.t display_hdrs.t display_help.t \ display_images.t display_mime_msg.t display_mime_other.t display_mime.t \ display_mime_text.t display.t display_tail.t display_toolbar_icons.t \ display_toolbar_noicons.t display_toolbar.t download_xfer_error.t error.t \ expunge.t favlist_favourites.t favlist.t favourites_help.t favourites.t \ favourites_toolbar.t filter_fail.t filter_help.t filter_select_help.t \ filter_select.t filter_select_toolbar.t filter.t folderlist_folders.t \ folderlist_icons.t folderlist_nfolders.t folderlist_noicons.t \ folderlist_select.t folderlist.t folders_help.t folders.t folders_toolbar.t \ footer.t fullname_help.t fullname.t header.t include_help.t include.t \ list_help.t list_msgs.t list_nav_1_icons.t list_nav_1_noicons.t \ list_nav_1.t list_nav_2.t list.t list_title.t list_toolbar_bottom.t \ list_toolbar_top.t logout_raven.t logout.t manage_help.t manage.t \ passwd_help.t passwd.t prefs_compose1_help.t prefs_compose2_help.t \ prefs_compose2.t prefs_compose.t prefs_display1_help.t \ prefs_display_abook_sort.t prefs_display_folder_sort.t prefs_display.t \ prefs_folder_help.t prefs_folder.t prefs_general_help.t prefs_general.t \ prefs_option.t quota_help.t quota.t redirect_fail.t redirect_help.t \ redirect.t rename_help.t rename.t rename_toolbar.t reply_help.t reply.t \ restart.t rm.t roles_entry_help.t roles_entry.t roles_list_help.t \ roles_list.t roles_select_help.t roles_select.t search_date_help.t \ search_date.t search_footer.t search_header.t search_size_help.t \ search_size.t search_status_help.t search_status.t search_text_help.t \ search_text.t sieve_error.t sieve_error_tail.t sieve_fail.t sieve_help.t \ sieve.t sizes_help.t sizes.t sizes_toolbar.t sort_icon.t spam_fail.t \ spam_help.t spam.t spell.t status.t submitenter_js.t tb_form.t \ tb_icon_form.t tb_icon.t tb_item.t toolbar_help.t toolbar_left.t \ toolbar_right.t toolbar_stub_help.t toolbar.t transfer_help.t transfer.t \ transfer_toolbar_bottom.t transfer_toolbar_top.t upload_select_help.t \ upload_select.t vacation_fail.t vacation_help.t vacation.t vaclog_fail.t \ vaclog_help.t vaclog.t welcome_help.t welcome.t O_FILES=_template_index.o ${T_FILES:.t=.o} C_FILES=${O_FILES:.o=.c} .PRECIOUS: $(C_FILES) HTML=\ abook_add.html abook_list.html abook_lookup.html \ abook_search.html abook_take.html abook_transfer.html abook_update.html \ attachments.html block_fail.html block.html compose_postponed.html \ compose.html copy.html dictionary.html display.html download_xfer_error.html \ error.html expunge.html favourites.html filter_fail.html \ filter_select.html filter.html folders.html fullname.html include.html \ list.html logout.html logout_raven.html manage.html passwd.html \ prefs_compose2.html prefs_compose.html prefs_display.html prefs_folder.html \ prefs_general.html quota.html redirect_fail.html \ redirect.html rename.html reply.html restart.html rm.html roles_entry.html \ roles_list.html roles_select.html search_date.html \ search_size.html search_status.html search_text.html sieve_error.html \ sieve_fail.html sieve.html spam_fail.html spam.html spell.html \ transfer.html upload_select.html vacation_fail.html vacation.html \ vaclog_fail.html vaclog.html welcome.html EXPAND=../src/template_expand COMPILE=../src/template_compile all: $(TARGETS) test: $(HTML) %.html: %.t %.vars common.vars Makefile $(EXPAND) $@ $* common.vars $*.vars templates_frontend.a: $(O_FILES_FRONTEND) rm -f templates_frontend.a ar q templates_frontend.a $(O_FILES_FRONTEND) templates.a: $(O_FILES) rm -f templates.a ar q templates.a $(O_FILES) %.o: %.c Makefile $(CC) $(CFLAGS) -I../../lib -c $< _template_index_frontend.c: ../src/build_index.pl $(TYPE) $(T_FILES_FRONTEND) > _template_index_frontend.c _template_index.c: ../src/build_index.pl $(TYPE) $(T_FILES) > _template_index.c %.c: %.t Makefile $(COMPILE) $(TYPE) $@ $* install: $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_DIR) -d \ $(BROOT)$(PREFIX)/templates/$(TYPE) cp *.t $(BROOT)$(PREFIX)/templates/$(TYPE) cp *.vars $(BROOT)$(PREFIX)/templates/$(TYPE) clean: rm -f $(TARGETS) *.html *.o *.c \#*\# *~ include Makefile.deps ./prayer-1.3.5/templates/cam/favourites_help.t0000644006513000651300000001124211063707775017730 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/favourites_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    The Favourites screen allows you to define a list of favourite mail folders. This list appears in the pull-down listing in the common toolbar, replacing the list of default folders. Once you have one or more Favourite mail folders an expanded set of actions becomes available on the Message List screen.

    The layout of the screen is similar to that in the main Mail Folders screen.

    Cancel returns you to the main Mail Folder screen, and no actions are taken.
    Refresh checks the contents of the directory on the server.

    Use [Expand] to expand collapsed directories.

    Selecting favourites

    The Folder icon mailbox indicates that the line refers to a mail folder, and also shows the name of the folder and actions that can be performed on that folder. To make a folder a favourite simply use the Add to Favourites button by the chosen folder.

    Using favourites

    Once you have selected one or more folders to Add to Favourites the status line is updated, for example

    Status: Added mail/test-folder to favourites list

    and the mail folder listing changes and will look something like the following:-


    Favourite mail folders

    Cancel | Refresh
    [mailbox] INBOX Make Preferred  
    Favourite mail folders:      
    [mailbox] mail/mailing-listA Remove from Favourites Make Preferred
    [mailbox] mail/test-folder Remove from Favourites Make Preferred
    Folder list:     
    [mailbox] mailing-listA Add to Favourites  
    [mailbox] received Add to Favourites  
    [mailbox] saved-messages Add to Favourites  
    [mailbox] sent-mail Add to Favourites  
    [mailbox] test-folder Add to Favourites  
    [directory] testdir    
    Cancel | Refresh

    The Make Preferred option allows you to select one mail folder as a dominant favourite. Once you have selected this, the listing for that folder changes, for example selecting the mail/test-folder mail folder changes that line to:-

    [mailbox] mail/test-folder Remove from Favourites Current Preferred

    If you subsequently wish to change your Preferred folder, simply select a different folder to Make Preferred.

    Having a Preferred folder means that that becomes the default folder listed in the pull-down listing in the common toolbar.

    ./prayer-1.3.5/templates/cam/search_status.vars0000644006513000651300000000024611063707775020113 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/search_status.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $selected 17 $count 42 $g_cmd search_status ./prayer-1.3.5/templates/cam/abook_list_nav_2.t0000644006513000651300000000040011063707775017736 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_list_nav_2.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ Add | \ Transfer | \ Search ./prayer-1.3.5/templates/cam/abook_lookup.t0000644006513000651300000000552211064530540017202 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_lookup.t,v 1.2 2008/09/18 19:52:00 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % CALL submitenter_js % CALL abook_lookup_search
    % IFNEQ $count 1 % ELSE % ENDIF
    % IFDEF $have_cancelled % ENDIF % IFDEF $have_phone % ENDIF % FOREACH $i @list % IFDEF $i->even_row % ELSE % ENDIF % IFDEF ${i->registered_name} % ELSE % ENDIF % IFDEF $have_cancelled % ENDIF % IFDEF $have_phone % ENDIF % IFDEF $g_have_draft % ELSE % ENDIF % ENDFOREACH
    # Userid Name (Registered Name) Primary AffiliationCancelled?PhoneAddressbook % IFDEF $g_have_draft % ELSE   % ENDIF
    <% $i->offset |h %>. <% $i->userid |h %><% $i->display_name |h %>
    (<% $i->registered_name |h %>)
    <% $i->display_name |h %><% $i->affiliation |h %><% "CANCELLED" IFDEF ${i->cancelled} |h %><% $i->phone |h %>Add To Cc Bcc Compose
    % IFDEF $g_help % CALL abook_lookup_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/status.t0000644006513000651300000000132511064231747016045 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/status.t,v 1.4 2008/09/17 16:44:23 dpc22 Exp $ % % IFDEF $g_status % IFDEF $g_status_alert % ELSE
    % ENDIF % ELSE
    Status: <% ${g_status} |h %>
    % ENDIF % IFDEF $g_service_name % else % endif
    Reminder: Logout when you have finished.User currently logged into <% "$g_service_name : $g_user" |h %>User currently logged into Prayer: <% $g_user |h %>
    % IFDEF $g_help % IFDEF $g_help_toolbar % CALL toolbar_help % ELSE % CALL toolbar_stub_help % ENDIF % ENDIF ./prayer-1.3.5/templates/cam/filter_help.t0000644006513000651300000000735511063707775017040 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/filter_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    This screen enables you to set up basic filtering of incoming messages. An example would be saving all messages from a particular address into a nominated folder. If this is the first time you have used this then on entry the screen will look like:-

    If you have filters in place that have been created either using the Webmail system or using the standard configuration options from the menu interface on <% $g_service_name |h %> then when you enter this screen they will be listed, as in the example below.

    1. SENDER: Filter messages from "spammer at spamdomain.com." Remove this filter.
      • Store in mail folder: mail/spam
    2. SUBJECT: Filter messages with subject of "test". Remove this filter.
      • Store in mail folder:mail/test1

    If you have filters created using the advanced configuration option from the menu interface on <% $g_service_name |h %> then your filters should continue to be maintained in that way. Consequently the screen will not display the list of existing filters. Instead the following message will be shown:

    Error: Manually maintained Sieve file?

    Adding a filter

    The options

    It is possible to:-

    • Filter on Sender: - actually "Return-Path" rather than the more obvious "From:".
      Note: These two headers frequently have the same value. However mailing lists often alter the Return-Path address to something that is specific to that list. You can find the "Return-Path:" line for a particular message by using Show Hdrs on the message display screen.
    • Filter on Recipient: - the contents of the "To" and "Cc" fields of a mail message.
    • Filter on Subject: - this option makes a case independent match against the entire subject line. Use wildcards to make a partial match.

    Messages are filtered into nominated mail folders other than the Inbox, or a nominated mail folder as well as the Inbox.

    Entering the address or subject

    After making the initial choice the address or subject on which you want to filter should be entered. The following wildcards can be used:-

    '?' matches a single character
    '*' matches any number of characters

    Hence the following are all valid entries:-

    spammer@spamdomain.com
    *@jiscmail.ac.uk
    ?art?

    If an invalid entry is made the status message will provide information. For example if you are filtering by sender address and enter just Spammer will result in the status line entry

    Status: Invalid filter: Not a valid <% $g_service_name |h %> account and no domain provided

    and the invalid entry will be cleared from the entry field.

    The effect of the Add filter button

    When you selecting the Add filter button will present you with a list of your mail folders so that you can select the destination folder.

    Removing a filter

    To remove a filter simply select the link Remove this filter by the relevant filter. The status message will change to show which filter was removed, for example

    Status: Removed filter number: 1

    and the filter list will be updated on screen.

    ./prayer-1.3.5/templates/cam/login.t0000644006513000651300000000630711133131622015623 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/login.t,v 1.4 2009/01/13 15:30:26 dpc22 Exp $ % IFDEF $g_service_name <% $g_service_name |h %> Webmail Service % ELSE Prayer Webmail Service % ENDIF %
    % IFDEF $login_banner

    <% $login_banner |h %>

    % ELSE % IFDEF $service_name

    <% $service_name |h %> Webmail Service

    % ELSE

    Prayer Webmail Service

    % ENDIF % ENDIF
    %
    % IFDEF $ssl_available
    Warning:This is an insecure HTTP session.
      It is strongly recommended that you use SSL encryption if your browser supports it.
      ">Click Here for an SSL enabled login session.
    % ENDIF
      
    % IFDEF $motd <% ${motd} |n %> % ENDIF
    ./prayer-1.3.5/templates/cam/vaclog_fail.t0000644006513000651300000000100011063707775016766 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/vaclog_fail.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Vacation Log

    Error: <% $msg |h %>

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/spam_fail.vars0000644006513000651300000000023511063707775017174 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/spam_fail.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $msg Error message displayed here $g_cmd spam_fail ./prayer-1.3.5/templates/cam/search_size.t0000644006513000651300000000117411063707775017033 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/search_size.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % CALL submitenter_js % CALL search_header, $_type => "Size" %
    % CALL search_footer % IFDEF $g_help % CALL search_size_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/list.t0000644006513000651300000000133111064526242015467 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/list.t,v 1.6 2008/09/18 19:31:46 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % CALL submitenter_js % % IFDEF $use_persist
    % ELSE % ENDIF % CALL list_toolbar_top
    % IFDEF $list_msg[0] % CALL list_title % CALL list_msgs
    % CALL list_toolbar_bottom % ENDIF
    % IFDEF $g_help % CALL list_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/passwd.t0000644006513000651300000000303311064273101016007 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/passwd.t,v 1.2 2008/09/17 21:27:29 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % IFDEF $g_service_name

    Change <% $g_service_name |h %> Password

    % ELSE

    Change Password

    % ENDIF % IFDEF $raven_enable

    Please note: this page changes your <% $g_service_name |h %> login password. Click here to change your Raven (Web single sign on) password.

    % ENDIF

    Restrictions on passwords:

    • Must be at least six characters in length
    • Must contain at least one letter and one non-letter
    % IFDEF $delay NB: It can take up to <% $delay |h %> for password changes to take effect % ENDIF
    Current Password:
    New Password:
    Confirm New Password:
    % IFDEF $g_help % CALL passwd_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/list_nav_2.t0000644006513000651300000000115211071400477016554 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/list_nav_2.t,v 1.2 2008/10/03 11:25:51 dpc22 Exp $ %# Refresh | Expunge | % IFDEF $use_persist % IFDEF $have_marked Unmark All | % ELSE Mark All | % ENDIF % IFDEF $have_zoom Unzoom | % ELSE Zoom | % ENDIF % ELSE % IFDEF $have_marked Clear Search | % ENDIF % ENDIF Search ./prayer-1.3.5/templates/cam/abook_update.vars0000644006513000651300000000040011063707775017670 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/abook_update.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $alias Alias goes here $name Name goes here $comment Comment goes here $email Email goes here $g_cmd abook_update ./prayer-1.3.5/templates/cam/login.vars0000644006513000651300000000013711071070744016336 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/login.vars,v 1.2 2008/10/02 07:01:56 dpc22 Exp $ ./prayer-1.3.5/templates/cam/prefs_compose.vars0000644006513000651300000000056211063707775020110 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/prefs_compose.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $from_personal David Carter $default_from_personal $from_address dpc22@cam.ac.uk $default_from_address dpc22@hermes.cam.ac.uk $default_reply_to Reply to goes here $signature Signature goes here $g_cmd prefs_compose ./prayer-1.3.5/templates/cam/attachments.t0000644006513000651300000000176611063707775017056 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/attachments.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % IFDEF $atts[0]

    MIME Attachments

    % FOREACH $a @atts % ENDFOREACH
    <% $a->offset |h %>. <% $a->name |h %> (<% $a->size |h %> bytes) of type <% $a->type |h %> Detach

    % ENDIF

    Attach file:

    File
    % IFDEF $g_help % CALL attachments_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/vacation_fail.t0000644006513000651300000000101011063707775017320 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/vacation_fail.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Vacation Message

    Error: <% $msg |h %>

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/folderlist.t0000644006513000651300000000033011063707775016674 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/folderlist.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ % IFDEF $g_use_icons % CALL folderlist_icons, $cmd => $cmd % ELSE % CALL folderlist_noicons, $cmd => $cmd % ENDIF ./prayer-1.3.5/templates/cam/attachments_help.t0000644006513000651300000000255211063707775020060 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/attachments_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    To attach a file

    If you decide that you do not wish to attach any file, select the Back to Compose Screen button to return to the Compose screen you came from.

    To attach a file to your message type the name of the file in the File box or use the Browse... button to select one. Once you have chosen the file, selecting the Attach file button will return you to the Attach file screen. The name of the document, and its size and type will be listed. For example:-

    1. Randomfile.pdf (15152 bytes) of type application/pdf Detach

    This gives you the opportunity to cancel the attachment (by using the Detach link by the file name) or to add further attachments.

    Once you have finished selecting attachments you need to select the Back to Compose Screen button to return to the main Compose screen. You will not see the file name there but the Attachments button will change to show the number of files that will be sent as attachments to your message

    You can then continue to edit the message.

    ./prayer-1.3.5/templates/cam/sizes_help.t0000644006513000651300000000063711063707775016704 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/sizes_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    This page shows the size of each mailbox on Hermes (in MBytes). This should allow you work out where disk space is being used after a quota warning. Disk use will be almost entirely down to messages with large attachments: these can be picked out by sorting large mailboxes by size.

    ./prayer-1.3.5/templates/cam/prefs_compose.t0000644006513000651300000000353111065141543017362 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_compose.t,v 1.3 2008/09/20 09:33:23 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Preferences

    Compose Preferences:

    % IFDEF $default_from_personal % ENDIF % IFDEF $default_from_address % ENDIF
    Personal Name: Default: <% $default_from_personal |h %>
    From Address: Default: <% $default_from_address |h %>
    Default Reply-To:

    Signature:


    % IFDEF $g_help % CALL prefs_compose1_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/sizes.t0000644006513000651300000000064611063707775015674 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/sizes.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Mail Folder Sizes

    % CALL sizes_toolbar
    % CALL folderlist, $cmd => "sizes"
    % CALL sizes_toolbar % IFDEF $g_help % CALL sizes_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/folders_toolbar.t0000644006513000651300000000116511063707775017714 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/folders_toolbar.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %
    %# XXX DPC: Why doesn't
    ./prayer-1.3.5/templates/cam/prefs_display_folder_sort.t0000644006513000651300000000224611063707775022003 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_display_folder_sort.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ Default folder sort mode: ./prayer-1.3.5/templates/cam/quota.t0000644006513000651300000000146311064226126015651 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/quota.t,v 1.2 2008/09/17 16:12:06 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Disk Quota use

    % FOREACH $l @line % ENDFOREACH
    Used Limit Fraction
    <% $l->type |h %> <% $l->used |h %> <% $l->limit |h %> <% $l->percent |h %>
    % IFDEF $g_help % CALL quota_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/vaclog.vars0000644006513000651300000000023111063707775016510 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/vaclog.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $vaclog Vacation log goes here $g_cmd vaclog ./prayer-1.3.5/templates/cam/search_date.t0000644006513000651300000000242311063707775016774 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/search_date.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % CALL search_header, $_type => "Date"
    Date
    % CALL search_footer % IFDEF $g_help % CALL search_date_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/transfer_toolbar_top.t0000644006513000651300000000063211063707775020762 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/transfer_toolbar_top.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $
    ./prayer-1.3.5/templates/cam/transfer_help.t0000644006513000651300000000353111063707775017367 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/transfer_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    Transfer allows you to upload a local mail folder to <% $g_service_name |h %> or download a mail folder from <% $g_service_name |h %> to your local machine.

    The layout of the screen is similar to that in the main Mail Folders screen. If you have any Favourite Folders these will be listed below the INBOX and above the main folder.

    The top and bottom bars have common elements at the right hand side:-

    Cancel returns you to the main Mail Folder screen, and no actions are taken.
    Refresh checks the contents of the directory on <% $g_service_name |h %>.

    The Right arrow [dir] indicates a sub-directory which can be expanded.

    Downloading a folder

    To download a folder (transfer a mail folder from <% $g_service_name |h %> to your local machine) select the Folder icon  or the Download action by your chosen mail folder then use your browser's "Save" feature to navigate to where you wish to put the folder on your local machine.

    Uploading a folder

    To upload a folder (transfer from your local machine to the directory you are in on <% $g_service_name |h %>) use the form at the bottom of the page:-

    File

    You can type in the name of a mail folder or use the Browse... button to select one. Once you have chosen a mail folder to transfer select the Upload button.

    ./prayer-1.3.5/templates/cam/.cvsignore0000644006513000651300000000016411063710201016317 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/.cvsignore,v 1.1 2008/09/16 10:54:57 dpc22 Exp $ *.c *.o *.html *.flc ./prayer-1.3.5/templates/cam/display_mime_text.t0000644006513000651300000000054411415373531020242 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display_mime_text.t,v 1.2 2010/07/08 16:05:45 dpc22 Exp $ % IFNEQ $_lines 1 <% "$_type, $_lines lines" |h %> % ELSE <% "$_type, 1 line" |h %> % ENDIF Download this text ./prayer-1.3.5/templates/cam/spam.t0000644006513000651300000000371111166640254015463 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/spam.t,v 1.2 2009/04/07 12:01:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Junk Email (Spam) Filtering

    This option automatically files mail based on how much it looks like junk email (spam).

    Each message is given a score which is higher if the message has more spam-like features. You pick a threshold score above which messages are filtered to a folder named "spam". Thresholds of 10 or more have no effect because high-scoring email is blocked. Thresholds of 4 or less are likely to misclassify legitimate email as spam. The scoring system is tuned to work best with a threshold of 5.

    % IFDEF $spam_enabled % ELSE % ENDIF % ELSE % ENDIF
    Filter threshold: (currently enabled)(currently disabled)
    % IFDEF $spam_purge_enabled % ELSE % ENDIF % IFDEF $using_sieve Purge after: days
    Whitelist (one address per line):
    % IFDEF $g_help % CALL spam_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/abook_list_title.t0000644006513000651300000000174111067766771020070 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_list_title.t,v 1.2 2008/09/28 20:50:01 dpc22 Exp $ #\ % CALL sort_icon, $_value => "order" Alias\ % CALL sort_icon, $_value => "alias" Name\ % CALL sort_icon, $_value => "name" Comment\ % CALL sort_icon, $_value => "comment" Address(es)\ % CALL sort_icon, $_value => "email" % IFDEF $g_have_draft % ELSE   % ENDIF ./prayer-1.3.5/templates/cam/restart.t0000644006513000651300000000121311063707775016212 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/restart.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start

    Mailbox access error

    % CALL status % IFDEF $raven_token

    If your Raven session timed out you will need to Logout and reconnect

    % ENDIF
    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/tb_icon_form.t0000644006513000651300000000127311063707775017174 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/tb_icon_form.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# %# Arguments: %# $_cmd Command %# $_icon Icon name %# $_alt Alt text for icon %# % IFDEF $g_use_icons % IFEQ $g_cmd $_cmd <% $_alt |h %> % ELSE % ENDIF % ELSE % IFEQ $g_cmd $_cmd <% $_alt |h %> % ELSE % ENDIF % ENDIF ./prayer-1.3.5/templates/cam/abook_transfer.t0000644006513000651300000000206211064276514017521 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_transfer.t,v 1.2 2008/09/17 21:57:32 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Addressbook Transfer

    File:

    % IFDEF $g_help % CALL abook_transfer_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/prefs_compose2.vars0000644006513000651300000000070711063707775020173 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/prefs_compose2.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $use_sent_mail 1 $spell_skip_quoted 1 $line_wrap_on_reply 1 $line_wrap_on_spell 1 $line_wrap_on_send 1 $line_wrap_advanced 1 $line_wrap_len 76 $small_cols 80 $small_rows 14 $large_cols 80 $large_rows 24 $ispell_language british $g_cmd prefs_compose2 ./prayer-1.3.5/templates/cam/roles_list_help.t0000644006513000651300000000165511063707775017727 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/roles_list_help.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $

    Roles are designed to handle cases where you need to compose, reply to, or forward mail wearing another "hat", for example as a webmaster or a member of a helpdesk team. Using Roles you can specify what will appear in the From: and Reply-To: fields of a message and tailor the signature to the role.

    Selecting Add new role brings up a role entry screen to allow the creation of a new role.

    Once you have roles defined these will appear as a list of role names (usually referred to as "aliases") after Existing roles:. Selecting a role name will bring up the roles entry screen to allow alterations to be made to the entry for that role:-

    1. role1
    2. helpdesk
    3. role3
    ./prayer-1.3.5/templates/cam/abook_search.vars0000644006513000651300000000060211063707775017657 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/abook_search.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ #$match_all 1 $filters[0]->count 0 $filters[0]->selected name $filters[0]->value value $count 1 $results[0]->alias alias $results[0]->name name $results[0]->comment comment $results[0]->email email $g_cmd abook_search ./prayer-1.3.5/templates/cam/filter_select_toolbar.t0000644006513000651300000000076611063707775021110 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/filter_select_toolbar.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %
    % CALL folderlist_select
    Refresh | Cancel
    ./prayer-1.3.5/templates/cam/compose_toolbar_right.t0000644006513000651300000000045511063707775021121 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/compose_toolbar_right.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ % IFDEF $g_help % CALL tb_form, $_cmd => "help", $_alt => "Hide Help" % ELSE % CALL tb_form, $_cmd => "help", $_alt => "Help" % ENDIF % CALL tb_form, $_cmd => "logout", $_alt => "Logout" ./prayer-1.3.5/templates/cam/display_toolbar.t0000644006513000651300000000314511415373531017711 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display_toolbar.t,v 1.3 2010/07/08 16:05:45 dpc22 Exp $ %# ./prayer-1.3.5/templates/cam/abook_list_nav_1_icons.t0000644006513000651300000000154411063707775021142 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_list_nav_1_icons.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % IFDEF $nav->first_page First % ELSE First % ENDIF % IFDEF $nav->prev_page Previous % ELSE Previous % ENDIF % IFDEF $nav->next_page Next % ELSE Next % ENDIF % IFDEF $nav->last_page Last % ELSE Last % ENDIF ./prayer-1.3.5/templates/cam/abook_list.vars0000644006513000651300000000061211063707775017366 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/abook_list.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $abook[0]->num 1 $abook[0]->alias dpc22 $abook[0]->name David Carter $abook[0]->email dpc22@cam.ac.uk $abook[0]->update alias=dpc22&name=David%20Carter&comment=&email=dpc22%40cam.ac.uk $entries 1 entry $page_current 1 $page_total 1 $g_cmd abook_list ./prayer-1.3.5/templates/cam/frontend_login_error.t0000644006513000651300000000067711075051454020750 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/frontend_login_error.t,v 1.3 2008/10/14 08:07:08 dpc22 Exp $ %# % CALL header % CALL container_start

    Login Failed


    % IFDEF $value Status: <% $value |h %>
    % ENDIF % IFDEF $user

    Please \ try again

    % ELSE

    Please try again

    % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/prefs_folder.t0000644006513000651300000000372711070102153017165 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_folder.t,v 1.4 2008/09/29 07:31:55 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Preferences

    Folder Listing Preferences:

    Suppress dotfiles (files starting '.') from folder listing
    Confirm folder deletion
    Mail directory:
    Sent Mail Folder:
    Postponed Messages Folder:

    % IFDEF $g_help % CALL prefs_folder_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/prefs_general.vars0000644006513000651300000000145311063707775020060 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/prefs_general.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $theme_main_name gray $theme_help_name help $themes[0]->name blue $themes[0]->fullname Web Safe Blue $themes[1]->name green $themes[1]->fullname Web Safe Green $themes[2]->name yellow $themes[2]->fullname Web Safe Yellow $themes[3]->name gray $themes[3]->fullname Shades of Gray $themes[3]->selected 1 $themes[4]->name high $themes[4]->fullname High Constrast $themes[5]->name help $themes[5]->fullname Default Help Text theme $use_welcome 1 $confirm_expunge 1 $confirm_logout 1 $use_mark_persist 1 $use_search_zoom 1 $use_agg_unmark 1 $g_cmd prefs_general ./prayer-1.3.5/templates/cam/abook_lookup_search.t0000644006513000651300000000151511063707775020544 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_lookup_search.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %#
    ./prayer-1.3.5/templates/cam/redirect_fail.t0000644006513000651300000000101011063707775017315 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/redirect_fail.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Mail Redirection

    Error: <% $msg |h %>

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/roles_select.vars0000644006513000651300000000027611063707775017731 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/roles_select.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $roles[0]->name default $roles[1]->name Testing $g_cmd roles_select ./prayer-1.3.5/templates/cam/abook_lookup.vars0000644006513000651300000000017511063707775017730 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/abook_lookup.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $g_cmd abook_lookup ./prayer-1.3.5/templates/cam/Makefile.deps0000644006513000651300000003413711063707775016746 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/Makefile.deps,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ abook_add.html: abook_add.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t abook_add_help.t header.t footer.t abook_list.html: abook_list.t submitenter_js.t status.t toolbar_help.t toolbar_stub_help.t abook_list_toolbar_top.t abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_nav_2.t toolbar.t tb_item.t container_end.t footer.t abook_list_title.t sort_icon.t abook_list_search.t abook_list_toolbar_bottom.t abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_nav_2.t container_start.t header.t abook_list_help.t abook_list_nav_1.html: abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_title.html: abook_list_title.t sort_icon.t abook_list_toolbar_bottom.html: abook_list_toolbar_bottom.t abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_nav_2.t abook_list_toolbar_top.html: abook_list_toolbar_top.t abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_nav_2.t abook_lookup.html: abook_lookup.t submitenter_js.t status.t toolbar_help.t toolbar_stub_help.t abook_lookup_help.t toolbar.t tb_item.t container_end.t footer.t abook_lookup_search.t abook_lookup_nav_1.t abook_lookup_nav_1_icons.t abook_lookup_nav_1_noicons.t container_start.t header.t abook_lookup_nav_1.html: abook_lookup_nav_1.t abook_lookup_nav_1_icons.t abook_lookup_nav_1_noicons.t abook_search.html: abook_search.t abook_search_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t abook_take.html: abook_take.t abook_take_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t abook_transfer.html: abook_transfer.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t abook_transfer_help.t abook_update.html: abook_update.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t abook_update_help.t container_end.t header.t footer.t action_stub.html: action_stub.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t attachments.html: attachments.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t attachments_help.t container_end.t header.t footer.t block.html: block.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t block_help.t container_end.t header.t footer.t block_fail.html: block_fail.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t compose.html: compose.t compose_toolbar.t compose_toolbar_right.t tb_form.t compose_toolbar_left.t compose_large_top.t compose_large_help.t status.t toolbar_help.t toolbar_stub_help.t container_end.t footer.t compose_small_top.t compose_small_help.t container_start.t header.t compose_postponed.html: compose_postponed.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t compose_postponed_help.t header.t footer.t compose_toolbar.html: compose_toolbar.t compose_toolbar_right.t tb_form.t compose_toolbar_left.t tb_form.t compose_toolbar_left.html: compose_toolbar_left.t tb_form.t compose_toolbar_right.html: compose_toolbar_right.t tb_form.t copy.html: copy.t copy_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t container_end.t favlist.t favlist_favourites.t copy_toolbar.t folderlist_select.t footer.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t container_start.t header.t copy_toolbar.html: copy_toolbar.t folderlist_select.t dictionary.html: dictionary.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t dictionary_help.t header.t footer.t display.html: display.t display_hdrs.t display_addr.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t display_help.t footer.t container_start.t display_toolbar.t display_toolbar_icons.t display_toolbar_noicons.t header.t display_hdrs.html: display_hdrs.t display_addr.t display_mime.html: display_mime.t display_mime_other.t display_mime_text.t display_mime_msg.t display_tail.html: display_tail.t display_help.t container_end.t display_toolbar.t display_toolbar_icons.t display_toolbar_noicons.t footer.t display_toolbar.html: display_toolbar.t display_toolbar_icons.t display_toolbar_noicons.t download_xfer_error.html: download_xfer_error.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t error.html: error.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t expunge.html: expunge.t container_start.t container_end.t header.t footer.t favlist.html: favlist.t favlist_favourites.t favourites.html: favourites.t favourites_toolbar.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t favourites_help.t container_end.t favlist.t favlist_favourites.t footer.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t container_start.t header.t filter.html: filter.t filter_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t filter_fail.html: filter_fail.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t filter_select.html: filter_select.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t container_end.t favlist.t favlist_favourites.t footer.t filter_select_help.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t container_start.t filter_select_toolbar.t folderlist_select.t header.t filter_select_toolbar.html: filter_select_toolbar.t folderlist_select.t folderlist.html: folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.html: folderlist_icons.t folderlist_folders.t folderlist_nfolders.t folderlist_noicons.html: folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folders.html: folders.t folders_toolbar.t folderlist_select.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t container_end.t footer.t folders_help.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t container_start.t header.t folders_toolbar.html: folders_toolbar.t folderlist_select.t fullname.html: fullname.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t fullname_help.t footer.t include.html: include.t include_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t list.html: list.t submitenter_js.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t container_end.t list_toolbar_bottom.t footer.t list_title.t sort_icon.t list_toolbar_top.t list_nav_1.t list_nav_1_icons.t list_nav_1_noicons.t list_nav_2.t container_start.t list_msgs.t header.t list_help.t list_nav_1.html: list_nav_1.t list_nav_1_icons.t list_nav_1_noicons.t list_title.html: list_title.t sort_icon.t list_toolbar_top.html: list_toolbar_top.t list_nav_1.t list_nav_1_icons.t list_nav_1_noicons.t list_nav_2.t logout.html: logout.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t logout_raven.html: logout_raven.t container_start.t container_end.t header.t footer.t manage.html: manage.t manage_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t passwd.html: passwd.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t passwd_help.t header.t footer.t prefs_compose.html: prefs_compose.t status.t toolbar_help.t toolbar_stub_help.t prefs_compose1_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t prefs_compose2.html: prefs_compose2.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t prefs_compose2_help.t header.t footer.t prefs_display.html: prefs_display.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t container_end.t prefs_display_folder_sort.t prefs_option.t prefs_display_abook_sort.t prefs_option.t footer.t container_start.t prefs_display1_help.t header.t prefs_display_abook_sort.html: prefs_display_abook_sort.t prefs_option.t prefs_display_folder_sort.html: prefs_display_folder_sort.t prefs_option.t prefs_folder.html: prefs_folder.t prefs_folder_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t prefs_general.html: prefs_general.t prefs_general_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t quota.html: quota.t quota_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t redirect.html: redirect.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t redirect_help.t container_end.t header.t footer.t redirect_fail.html: redirect_fail.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t rename.html: rename.t rename_toolbar.t rename_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t container_end.t footer.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t container_start.t header.t reply.html: reply.t reply_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t restart.html: restart.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t rm.html: rm.t container_start.t container_end.t header.t footer.t roles_entry.html: roles_entry.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t roles_entry_help.t container_end.t header.t footer.t roles_list.html: roles_list.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t roles_list_help.t container_end.t header.t footer.t roles_select.html: roles_select.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t roles_select_help.t header.t footer.t search_date.html: search_date.t search_date_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t search_footer.t container_end.t search_header.t footer.t container_start.t header.t search_size.html: search_size.t submitenter_js.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t search_footer.t container_end.t search_header.t footer.t container_start.t search_size_help.t header.t search_status.html: search_status.t search_status_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t search_footer.t container_end.t search_header.t footer.t container_start.t header.t search_text.html: search_text.t search_text_help.t submitenter_js.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t search_footer.t container_end.t search_header.t footer.t container_start.t header.t sieve.html: sieve.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t sieve_help.t header.t footer.t sieve_error.html: sieve_error.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t sieve_error_tail.html: sieve_error_tail.t container_end.t footer.t sieve_fail.html: sieve_fail.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t sizes.html: sizes.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t sizes_help.t container_end.t sizes_toolbar.t footer.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t container_start.t header.t spam.html: spam.t spam_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t spam_fail.html: spam_fail.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t spell.html: spell.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t status.html: status.t toolbar_help.t toolbar_stub_help.t toolbar.html: toolbar.t tb_item.t toolbar_left.html: toolbar_left.t tb_icon.t toolbar_right.html: toolbar_right.t tb_icon.t transfer.html: transfer.t transfer_toolbar_bottom.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t container_end.t favlist.t favlist_favourites.t transfer_toolbar_top.t footer.t transfer_help.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t container_start.t header.t upload_select.html: upload_select.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t tb_item.t container_end.t footer.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t upload_select_help.t container_start.t header.t vacation.html: vacation.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t vacation_help.t container_end.t header.t footer.t vacation_fail.html: vacation_fail.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t vaclog.html: vaclog.t vaclog_help.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t vaclog_fail.html: vaclog_fail.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t header.t footer.t welcome.html: welcome.t status.t toolbar_help.t toolbar_stub_help.t container_start.t toolbar.t tb_item.t container_end.t welcome_help.t header.t footer.t ./prayer-1.3.5/templates/cam/abook_list_toolbar_top.t0000644006513000651300000000066111063707775021266 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_list_toolbar_top.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ % % ELSE Addressbook (<% $entries |h %> entries) % ENDIF ./prayer-1.3.5/templates/cam/abook_lookup_nav_1.t0000644006513000651300000000036111063707775020301 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_lookup_nav_1.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % IFDEF $g_use_icons % CALL abook_lookup_nav_1_icons % ELSE % CALL abook_lookup_nav_1_noicons % ENDIF
    ./prayer-1.3.5/templates/cam/sort_icon.t0000644006513000651300000000045011063707775016527 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/sort_icon.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# %# % IFEQ $sort_mode $_value % IFDEF $sort_reverse % ELSE % ENDIF % ENDIF ./prayer-1.3.5/templates/cam/favourites.vars0000644006513000651300000000017111063707775017427 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/favourites.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $g_cmd favourites ./prayer-1.3.5/templates/cam/frontend_security.t0000644006513000651300000000046111071070744020264 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/frontend_security.t,v 1.2 2008/10/02 07:01:56 dpc22 Exp $ %# % CALL header % CALL container_start

    Security Alert

    Login request did not come from <% $url_prefix |h %>

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/frontend_session.t0000644006513000651300000000047111075051454020102 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/frontend_session.t,v 1.3 2008/10/14 08:07:08 dpc22 Exp $ %# % CALL header % CALL container_start

    Couldn't connect to Webmail session server

    \ Try again later

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/roles_list.t0000644006513000651300000000154611063707775016716 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/roles_list.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status % IFNDEF $roles[0]

    No roles defined

    % ELSE

    Existing roles:

      % FOREACH $r @roles
    1. alias|u}&personal=${r->personal|u}&from=${r->from|u}&reply_to=${r->reply_to|u}&fcc=${r->fcc|u}&signature=${r->signature|u}" |s %>"> <% $r->alias |h %>
    2. % ENDFOREACH
    % ENDIF
    % IFDEF $g_help % CALL roles_list_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/folderlist_nfolders.t0000644006513000651300000000141511063707775020575 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/folderlist_nfolders.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % IFEQ $_cmd "transfer" Download % ELSE % IFEQ $_cmd "upload_select" Append % ELSE % IFEQ $_cmd "favourites" Add to favourites % ELSE % IFEQ $_cmd "filter_select" Select (save copy to inbox) Select (no copy) % ELSE % IFEQ $_cmd "sizes" <% $_size |h %> % ELSE % ENDIF % ENDIF % ENDIF % ENDIF % ENDIF ./prayer-1.3.5/templates/cam/display_toolbar_noicons.t0000644006513000651300000000054011415373531021435 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/display_toolbar_noicons.t,v 1.2 2010/07/08 16:05:45 dpc22 Exp $ %# % IFDEF $nav->prev_msg Previous % ELSE Previous % ENDIF | % IFDEF $nav->next_msg Next % ELSE Next % ENDIF ./prayer-1.3.5/templates/cam/make_olist.pl0000644006513000651300000000053011063707775017026 0ustar dpc22dpc22#!/usr/bin/perl # # $Cambridge: hermes/src/prayer/templates/cam/make_olist.pl,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $col=1; print " "; foreach $name (@ARGV) { $len=length($name); $name =~ s/\.t$/.o/; if (($col > 1) and (($col + $len) > 76)) { print "\\\n "; $col = 1; } print "${name} "; $col += $len + 1; } print "\n"; ./prayer-1.3.5/templates/cam/tb_item.t0000644006513000651300000000031311063707775016151 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/tb_item.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $
  1. <% $_text |h %>
  2. ./prayer-1.3.5/templates/cam/search_date.vars0000644006513000651300000000214411063707775017504 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/search_date.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $selected 17 $count 42 $day[0]->day 1 $day[1]->day 2 $day[2]->day 3 $day[3]->day 4 $day[4]->day 5 $day[5]->day 6 $day[6]->day 7 $day[7]->day 8 $day[8]->day 9 $day[9]->day 10 $day[10]->day 11 $day[11]->day 12 $day[12]->day 13 $day[13]->day 14 $day[14]->day 15 $day[15]->day 16 $day[16]->day 17 $day[17]->day 18 $day[18]->day 19 $day[19]->day 20 $day[20]->day 21 $day[21]->day 22 $day[22]->day 23 $day[23]->day 24 $day[24]->day 25 $day[25]->day 26 $day[26]->day 27 $day[27]->day 28 $day[28]->day 29 $day[29]->day 30 $day[30]->day 31 $month[0]->name January $month[1]->name Feburary $month[2]->name March $month[3]->name April $month[4]->name May $month[5]->name June $month[6]->name July $month[7]->name August $month[8]->name September $month[9]->name October $month[10]->name November $month[11]->name December $day[24]->selected 1 $month[3]->selected 1 $year 2008 $g_cmd search_date ./prayer-1.3.5/templates/cam/filter_fail.t0000644006513000651300000000101411063707775017005 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/filter_fail.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Automatic Mail Filtering

    Error: <% $msg |h %>

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/folders.vars0000644006513000651300000000114711063707775016702 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/folders.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $fcmd change $dirlist[0]->name a $folder[0]->name INBOX $folder[0]->short_name INBOX $folder[0]->indent 0 $folder[1]->name a $folder[1]->short_name a $folder[1]->expanded 1 $folder[1]->haschildren 1 $folder[1]->even_row 1 $folder[1]->indent 0 $folder[2]->name a/b $folder[2]->short_name b $folder[2]->indent 1 $folder[3]->name a/c $folder[3]->short_name c $folder[3]->even_row 1 $folder[3]->indent 1 $g_cmd folders ./prayer-1.3.5/templates/cam/abook_list_toolbar_bottom.t0000644006513000651300000000110111063707775021756 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_list_toolbar_bottom.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ ./prayer-1.3.5/templates/cam/download_xfer_error.t0000644006513000651300000000071011063707775020573 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/download_xfer_error.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Download Error:

    Mailbox size <% $size |h %> MBytes exceeds maximum <% $limit |h %> MBytes allowed for transfer.

    Please split the mailbox into sections and try again.

    Back to transfer screen % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/folderlist_select.t0000644006513000651300000000111311063707775020233 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/folderlist_select.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %# % IFDEF $g_dualuse Create mailbox % ELSE Create % ENDIF under with name ./prayer-1.3.5/templates/cam/abook_take_help.t0000644006513000651300000000562611064274260017636 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_take_help.t,v 1.2 2008/09/17 21:37:52 dpc22 Exp $


    This screen is reached when you click on one of the addresses displayed at the top of a message that is being displayed. It is also reached if you add an address to your addressbook from the directory search screen. The screen is a shortcut allowing you to add addresses directly to your personal addressbook.

    • To create an entry complete the fields and then select Add entry
    • To return to the Webmail screen from whence you came, making no changes to your address book, select the Cancel button

    The address book form fields

    • Alias - the nickname by which the entry is known. This can be used as an address shortcut when composing a message.
    • Name - this is an optional field, but is customarily used for the real name of an individual or a relevant name for a list. The entry in this field will appear in any message sent using the alias.
    • Comment - optional - usually used as a short, relevant memory jogger for example "Contact at This Company Ltd.". It does not appear in any message sent using the alias.
    • Address(es)
      • In most cases this will be a single address, as in the example shown at the top of this page.
      • However you can also use the Addressbook to create an entry for a small group of people. In this case the Address field can either be full email addresses of the group members or the aliases of existing addressbook entries. Addresses must be separated by commas.

    Hence the following examples would all be be valid entries.
    Note: that the final entry uses existing alias entries, not full email addresses. Remember that you can only use this form of short address if you have an entry for the individual alias.

    Alias Name Comment Address(es)  
    someone A. Person Sales contact at Somewhere Company someone@somewhere.com Compose fresh message
    alien Green Alien   alien@planet.otherdomain.com Compose fresh message
    group   Small group person@company.co.uk, anotherperson@company.co.uk Compose fresh message
    group2     someone, alien Compose fresh message
    ./prayer-1.3.5/templates/cam/toolbar.t0000644006513000651300000000342211133137120016147 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/toolbar.t,v 1.4 2009/01/13 16:16:16 dpc22 Exp $ %
    % IFDEF $g_service_name

    <% $g_service_name |h %> Webmail Service

    % ELSE

    Prayer Webmail Service

    % ENDIF
    ./prayer-1.3.5/templates/cam/rm.t0000644006513000651300000000063311066735727015152 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/rm.t,v 1.2 2008/09/25 16:27:03 dpc22 Exp $ %# % CALL header % CALL container_start

    Confirm <% $type |h %> deletion: "<% ${name|7} |h %>"

    % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/abook_list_search.t0000644006513000651300000000131111063707775020200 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/abook_list_search.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $
    ./prayer-1.3.5/templates/cam/prefs_compose2.t0000644006513000651300000000664011463516401017451 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/prefs_compose2.t,v 1.5 2010/11/01 10:57:05 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL container_start % CALL status

    Preferences

    Extra Compose Preferences:

    % IFDEF $have_aspell_path % ENDIF
    Use sent-mail folder
    Skip quoted text on spell check
    Line wrap on reply
    Line wrap on spell check
    Line wrap on send
    Enable manual line wrap options
    % IFDEF $domains[1] % ENDIF % IFDEF $langs[0] % ENDIF
    Line Wrap at: columns
    Normal Compose window size: columns rows
    Large Compose window size columns rows
    Default domain:
    Spell Check Language:

    % IFDEF $g_help % CALL prefs_compose2_help % ENDIF % CALL container_end % CALL footer ./prayer-1.3.5/templates/cam/download_xfer_error.vars0000644006513000651300000000024411063707775021305 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/cam/download_xfer_error.vars,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ $size 101 $limit 100 $g_cmd download_xfer_error ./prayer-1.3.5/templates/cam/copy_toolbar.t0000644006513000651300000000072111063707775017225 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/cam/copy_toolbar.t,v 1.1 2008/09/16 10:52:45 dpc22 Exp $ %
    %# XXX DPC: can't use class="nav" here
    ./prayer-1.3.5/templates/src/0000755006513000651300000000000011775262603014367 5ustar dpc22dpc22./prayer-1.3.5/templates/src/build_map_index.pl0000755006513000651300000000112711423303573020043 0ustar dpc22dpc22#!/usr/bin/perl # # $Cambridge: hermes/src/prayer/templates/src/build_map_index.pl,v 1.3 2010/07/26 13:02:51 dpc22 Exp $ @list=@ARGV; @ARGV=(); print << "EOM"; #include "misc.h" #include "template_structs.h" EOM foreach $name (@list) { print << "EOM"; extern struct template_map template_map_${name}[]; extern unsigned long template_map_${name}_count; EOM } print << "EOM"; struct template_map_index template_map_index[] = { EOM foreach $name (@list) { print << "EOM"; { "$name", &template_map_${name}[0], &template_map_${name}_count }, EOM } print << "EOM"; { NIL, NIL, NIL } }; EOM ./prayer-1.3.5/templates/src/log.c0000644006513000651300000000131611063701637015310 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/templates/src/log.c,v 1.3 2008/09/16 09:59:59 dpc22 Exp $*/ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "lib.h" void log_fatal(char *err, ...) { fprintf(stderr, "%s\n", err); exit(1); } void log_misc(char *err, ...) { fprintf(stderr, "%s\n", err); exit(1); } void log_debug(char *err, ...) { fprintf(stderr, "%s\n", err); exit(1); } void log_panic(char *err, ...) { fprintf(stderr, "%s\n", err); exit(1); } ./prayer-1.3.5/templates/src/makedeps.pl0000644006513000651300000000211011415035126016474 0ustar dpc22dpc22#!/usr/bin/perl # # $Cambridge: hermes/src/prayer/templates/src/makedeps.pl,v 1.1 2010/07/07 08:27:02 dpc22 Exp $ # # Generate proper list of dependancies between templates %uses = (); while ($file=shift(@ARGV)) { $file = $1 if ($file =~ /([\w-_]+)\.t/); open(FILE, "<${file}.t") or die "failed to open ${file}: $!\n"; while () { next unless /^%\s+CALL ([\w-_]+)/; $uses{$file} = [] if (not $uses{$file}); push(@{$uses{$file}}, $1); } close(FILE); } foreach $i (sort keys %uses) { # Sort and uniq @{$uses{$i}} = keys %{{ map { $_ => 1 } sort(@{$uses{$i}}) }}; } foreach $i (sort keys %uses) { printf("%s.html: %s.t", $i, $i); foreach $j (@{$uses{$i}}) { @list = (); recurse($j, {}, \@list); foreach $k (@list) { printf(" %s.t", $k); } } printf("\n"); } exit(0); sub recurse { my ($i, $usedref, $listref) = @_; # Remove repeated references to any given template/ return if defined($$usedref{$i}); $$usedref{$i} = 1; push (@{$listref}, $i); foreach $j (@{$uses{$i}}) { recurse($j, $usedref, $listref); } } ./prayer-1.3.5/templates/src/template_compile_main.c0000644006513000651300000000236111063701637021057 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/templates/src/template_compile_main.c,v 1.3 2008/09/16 09:59:59 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "lib.h" int main(int argc, char *argv[]) { struct template *template; struct pool *pool = pool_create(4096); char *prefix; char *target; char *source; FILE *file; char *err; if (argc != 4) { fprintf(stderr, "Usage: prefix target template\n"); exit(1); } prefix = argv[1]; target = argv[2]; source = argv[3]; if (!(template = template_parse(NIL, NIL, source, pool))) { fprintf(stderr, "Unable to read template file %s\n", source); exit(1); } if ((err = str_fetch(template->error)) && err[0]) { fputs(err, stderr); exit(1); } if ((file=fopen(target, "w")) == NULL) { fprintf(stderr, "Failed to open %s: %s\n", target, strerror(errno)); exit(1); } template_compile(prefix, template, file); fclose(file); return(0); } ./prayer-1.3.5/templates/src/template_expand_main.c0000644006513000651300000000542011063701637020705 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/templates/src/template_expand_main.c,v 1.3 2008/09/16 09:59:59 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "lib.h" static BOOL read_var_file(struct pool *pool, struct assoc *h, char *name) { char *data; char **lines; char *s; char *key; if (!(data = template_parse_read_file(name, pool))) { fprintf(stderr, "Var file %s not found\b", name); return(NIL); } lines = template_parse_split_lines(data, pool); while (*lines) { s = *lines; while (*s == ' ' || *s == '\t') s++; if (!s[0] || s[0] == '#') { lines++; continue; } key = template_getvar(&s, NIL, NIL); if (!key) { fprintf(stderr, "Invalid line in key file: %s\n", *lines); lines++; continue; } while ((*s == ' ') || (*s == '\t')) s++; if (!(s && s[0])) s = "1"; if (!(key && key[0] && (key[0] != '#'))) { lines++; continue; } assoc_update(h, key, s, T); /* T: strdup key and value */ if (key[0] == '@') { char *s = strrchr(key, '-'); *s = '\0'; assoc_update(h, key, "1", T); *s = '-'; } lines++; } return(T); } int main(int argc, char *argv[]) { struct template_vals *tvals; struct template_vals_urlstate *urlstate; struct pool *pool = pool_create(4096); struct buffer *b = buffer_create(pool, 1024); char *target; char *source; int i, c; FILE *file; if (argc < 4) { fprintf(stderr, "Usage: target template vars [vars...]\n"); exit(1); } target = argv[1]; source = argv[2]; urlstate = template_vals_urlstate_create(pool); urlstate->url_prefix_icons = "../../files/icons"; urlstate->url_prefix_bsession = ""; urlstate->sequence = 1; urlstate->use_short = NIL; urlstate->test_mode = T; tvals = template_vals_create(pool, NIL, NIL, NIL, NIL, urlstate); for (i = 3; i < argc; i++) read_var_file(pool, tvals->vals, argv[i]); if (!template_expand(source, tvals, b)) { fputs(str_fetch(tvals->error), stderr); exit(1); } if ((file=fopen(target, "w")) == NULL) { fprintf(stderr, "Failed to open %s: %s\n", target, strerror(errno)); exit(1); } buffer_rewind(b); while ((c=bgetc(b)) != EOF) fputc(c, file); fclose(file); return(0); } ./prayer-1.3.5/templates/src/Makefile0000644006513000651300000000135211415316104016013 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/src/Makefile,v 1.5 2010/07/08 09:37:08 dpc22 Exp $ ifeq ($(strip $(RPM_BUILD)), true) include ../../Config-RPM else include ../../Config endif CFLAGS = $(BASECFLAGS) LDFLAGS = $(BASELDFLAGS) LIB= ../../lib/lib_nossl.a all: template_expand template_compile template_expand: template_expand_main.o log.o empty.o $(LIB) $(CC) $(LDFLAGS) -o template_expand log.o empty.o template_expand_main.o $(LIB) $(BASE_LIBS) template_compile: template_compile_main.o log.o empty.o $(LIB) $(CC) $(LDFLAGS) -o template_compile log.o empty.o template_compile_main.o $(LIB) $(BASE_LIBS) %.o: %.c Makefile $(CC) $(CFLAGS) -I../../lib -c $< install: clean: rm -f template_expand template_compile *.o *~ \#*\# ./prayer-1.3.5/templates/src/.cvsignore0000644006513000651300000000020011063701637016352 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/src/.cvsignore,v 1.3 2008/09/16 09:59:59 dpc22 Exp $ template_compile template_expand ./prayer-1.3.5/templates/src/build_index.pl0000755006513000651300000000136311423245734017214 0ustar dpc22dpc22#!/usr/bin/perl # # $Cambridge: hermes/src/prayer/templates/src/build_index.pl,v 1.4 2010/07/26 08:48:28 dpc22 Exp $ $prefix = shift(@ARGV); $count = 0; @templates = (); foreach $i (@ARGV) { if ($i =~ /(\S+)\.t/) { push(@templates, $1); } else { push(@templates, $i); } $count++; } @ARGV = (); @templates = sort(@templates); print <<'EOM'; #include "misc.h" #include "template_structs.h" EOM foreach $i (@templates) { print "struct template _template_${prefix}_${i};\n"; } print <<"EOM"; struct template_map template_map_${prefix}[] = { EOM foreach $i (@templates) { print <<"EOM"; { "${i}", &_template_${prefix}_${i} }, EOM } print <<"EOM"; { NIL, NIL } }; unsigned long template_map_${prefix}_count = ${count}; EOM ./prayer-1.3.5/templates/src/empty.c0000644006513000651300000000027511063701637015670 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/templates/src/empty.c,v 1.5 2008/09/16 09:59:59 dpc22 Exp $ */ #include "lib.h" struct template_map_index template_map_index[] = { {NIL, NIL, NIL} }; ./prayer-1.3.5/templates/Makefile0000644006513000651300000000144011160500433015217 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/Makefile,v 1.15 2009/03/19 17:30:03 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2008 # See the file NOTICE for conditions of use and distribution. ifeq ($(strip $(RPM_BUILD)), true) include ../Config-RPM else include ../Config endif TEMPLATES = old cam SUBDIRS = src $(TEMPLATES) BASECFLAGS = -I../lib MYCFLAGS = $(BASECFLAGS) all: index.o for i in $(SUBDIRS); do $(MAKE) -C $$i all; done install: for i in $(SUBDIRS); do $(MAKE) -C $$i install; done clean: for i in $(SUBDIRS); do $(MAKE) -C $$i clean; done rm -f index.o index.c index_frontend.o index_frontend.c index.o: index.c $(CC) $(MYCFLAGS) -c index.c index.c: ./src/build_map_index.pl ./src/build_map_index.pl $(TEMPLATES) > index.c ./prayer-1.3.5/templates/xhtml/0000755006513000651300000000000011775262603014734 5ustar dpc22dpc22./prayer-1.3.5/templates/xhtml/.cvsignore0000644006513000651300000000016611063701643016727 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/xhtml/.cvsignore,v 1.3 2008/09/16 10:00:03 dpc22 Exp $ *.c *.o *.html *.flc ./prayer-1.3.5/templates/old/0000755006513000651300000000000011775262603014356 5ustar dpc22dpc22./prayer-1.3.5/templates/old/redirect.vars0000644006513000651300000000027211063710000017030 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/redirect.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $use_redirect 1 $redirect_addr dpc22@gmail.com $save_copy 1 $g_cmd redirect ./prayer-1.3.5/templates/old/reply.t0000644006513000651300000000145311063710000015654 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/reply.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Reply Options

    Sender: <% $sender |h %>
    Recipients: <% $recipients |h %>
    Subject: <% $subject |h %>
    % IFDEF $g_help % CALL reply_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/block.vars0000644006513000651300000000026211063710000016320 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/block.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $blocks[0]->offset 0 $blocks[0]->value dpc22@cam.ac.uk $g_cmd block ./prayer-1.3.5/templates/old/list_nav_1_noicons.t0000644006513000651300000000123311063710000020304 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list_nav_1_noicons.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFDEF $nav->first_msg First % ELSE First % ENDIF | % IFDEF $nav->prev_msg Previous % ELSE Previous % ENDIF | % IFDEF $nav->next_msg Next % ELSE Next % ENDIF | % IFDEF $nav->last_msg Last % ELSE Last % ENDIF ./prayer-1.3.5/templates/old/compose_toolbar_left.t0000644006513000651300000000204711063710000020722 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose_toolbar_left.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % CALL tb_icon_form, % $_cmd => "display", $_icon => "display", $_alt => "Message" % CALL tb_icon_form, % $_cmd => "list", $_icon => "mailbox", $_alt => "Mailbox" % CALL tb_icon_form, % $_cmd => "folders", $_icon => "folders", $_alt => "Folders" % CALL tb_icon_form, % $_cmd => "compose", $_icon => "compose", $_alt => "Compose" % CALL tb_icon_form, % $_cmd => "abook_list", $_icon => "addressbook", $_alt => "Addressbook" % CALL tb_icon_form, % $_cmd => "manage", $_icon => "manage", $_alt => "Manage" % IFDEF $g_use_icons % ENDIF
    Message | Mailbox | Folders | Compose | Addressbook | Manage
    ./prayer-1.3.5/templates/old/favlist.t0000644006513000651300000000227311063710000016172 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/favlist.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# %# % FOREACH $f @g_favourites % IFDEF $f->even_row % ELSE % ENDIF % IFEQ $cmd "favourites" % CALL favlist_favourites, $_name => $f->name, $_preferred => $g_preferred % ELSE % IFEQ $cmd "transfer" % ENDIF % ENDIF % ENDFOREACH
    % LOOP $f->indent <% $g_alt_pad |n %> % ENDLOOP % IFDEF $f->haschildren % IFDEF $f->expanded <% $g_alt_pad |n %> % ELSE <% $g_alt_pad |n %> % ENDIF % ELSE <% $g_alt_pad |n %> % ENDIF % IFDEF ${fcmd} [mailbox]  <% ${f->name|7} |h %> % ELSE [mailbox] <% $f->{name|7} |h %> % ENDIF Download
    ./prayer-1.3.5/templates/old/abook_transfer.vars0000644006513000651300000000020111063710000020216 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/abook_transfer.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd abook_transfer ./prayer-1.3.5/templates/old/sieve_help.t0000644006513000651300000000104311063710000016637 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/sieve_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This screen allows you to set up an manually maintained Sieve mail filter. This option is for advanced users only and disables the normal automatic mail filtering options.

    The best overview for Sieve documentation that we have found was written by Cyrusoft (now bankrupt). A copy of their documentation is available courtesy of Fastmail.fm.

    ./prayer-1.3.5/templates/old/abook_update.t0000644006513000651300000000212311063710000017151 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_update.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Addressbook Entry Update

    Alias
    Name
    Comment
    Address(es)
    % IFDEF $g_help % CALL abook_update_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/sieve_error_tail.t0000644006513000651300000000051311063710000020052 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/sieve_error_tail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    % CALL footer ./prayer-1.3.5/templates/old/upload_select_help.t0000644006513000651300000000103711063710000020352 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/upload_select_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    • If you wish to upload the folder keeping the name it had on your local machine and creating a new mail folder on <% $g_service_name |h %> select Create
    • If you wish to add the folder to the end of an exisiting mail folder, change the name to that of the mail folder on <% $g_service_name |h %> and then select Append
    • To cancel the upload select Cancel
    ./prayer-1.3.5/templates/old/transfer.vars0000644006513000651300000000112211063710000017046 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/transfer.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $dirlist[0]->name a $folder[0]->name INBOX $folder[0]->short_name INBOX $folder[0]->indent 0 $folder[1]->name a $folder[1]->short_name a $folder[1]->expanded 1 $folder[1]->haschildren 1 $folder[1]->even_row 1 $folder[1]->indent 0 $folder[2]->name a/b $folder[2]->short_name b $folder[2]->indent 1 $folder[3]->name a/c $folder[3]->short_name c $folder[3]->even_row 1 $folder[3]->indent 1 $g_cmd transfer ./prayer-1.3.5/templates/old/sieve_error.t0000644006513000651300000000043711063710000017046 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/sieve_error.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Sieve Filtering

    Failed to upload script. Sieve server reported: % IFDEF $g_testrig % CALL footer % ENDIF ./prayer-1.3.5/templates/old/compose_large_top.t0000644006513000651300000000075011063710000020221 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose_large_top.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % IFDEF $g_help % ELSE % ENDIF
        
    ./prayer-1.3.5/templates/old/search_footer.t0000644006513000651300000000122411063710000017340 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_footer.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFEQ $selected 0 % ELSE % IFEQ $selected $count % ELSE % ENDIF % ENDIF
    ./prayer-1.3.5/templates/old/rename.vars0000644006513000651300000000016111063710000016473 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/rename.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd rename ./prayer-1.3.5/templates/old/abook_list_help.t0000644006513000651300000001514611063710000017663 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The addressbook screen has three areas:

    • A search dialogue that will allow you to search for users on the local system, or against the University Directory.
    • the top and bottom bars, which contain information about the addressbook and links that affect, or act on, the whole addressbook;
    • the one-entry-per-line listing of addresses, with links that affect or use just that entry.

    Search Dialogue

    Search <% $g_service_name |h %> Users searches for local users on the <% $g_service_name |h %> system. The search is made against the initial registered name of each user (of the form "A.N. Other") and also against the fullname which can be set using this Webmail interface. Please note: the local search database only stores limited numbers of results. Queries that would return large numbers of results (e.g: Smith) will typically return no results and an explanation to this effect. It is also possible to search for details on a particular <% $g_service_name |h %> username or for usernames which match a given set of initials.

    Search Directory searches the University Directory. The results will be more comprehensive than the local search database, but does not contain information about recently cancelled accounts.

    Top and bottom bars

    These have a group of common elements at the left and right hand sides of the bar, and a unique element in the centre.

    Top bar, unique element

    Addressbook (3 entries)

    This provides a summary of the number of entries in your addressbook.

    Bottom bar, unique element

    Page: /1

    The addressbook is presented as a series of pages. The number of entries on each page is set in Manage -> Preferences -> Display. This element shows the current page number and the total number of pages. To change to another page in your addressbook enter the number in the Page: box and then select Go

    Common elements

    The four icons, First Previous Next Last, take you to, respectively, the first, previous, next and last page of addresses. An icon is greyed out, as in the example screen on this page, if the choice is not applicable (in the example there is only one page of addresses).

    Add takes you to a blank Addressbook Entry screen.

    Remove Marked Entries will remove any entries which have been tagged in the main section.

    Transfer takes you to a screen from which you can

    • import a Pine-format addressbook on your local system into your Webmail addressbook,
    • export your Webmail addressbook to a Pine-format addressbook on your local system,
    • import your Pine addressbook on <% $g_service_name |h %> into your Webmail addressbook
    • export your Webmail addressbook for use with Pine on <% $g_service_name |h %>.

    Search takes you to a screen from which you can search for entries matching your chosen criteria.

    Addressbook list

    Each addressbook entry appears on a separate line. There is a difference in the display depending on what screen you were in when you selected Addressbook.

    • If you select Addressbook from the majority of screens in Webmail, an individual entry will look like this:
      someone A. Person Sales contact at Somewhere Company someone@somewhere.com Compose
      • Selecting an entry from the first (Alias) column takes you to the Addressbook Entry screen for that alias, where you can update or delete the entry.
      • Selecting Compose takes you to the Compose screen, with the address of your choice present in the To: field of the message.
    • If you select Addressbook from the Compose screen, an entry will look like this:
      someone A. Person Sales contact at Somewhere Company someone@somewhere.com To Cc Bcc

      An extra element will be added at the top right:-

      • Selecting an entry from the first (Alias) column takes you to the Addressbook Entry screen for that alias, where you can update or delete the entry.
      • Use the check boxes to select addresses for the To:, Cc: or Bcc: fields of your message. Check the boxes you want on one addressbook page, then select the Add marked to draft button. The Status line will be updated to reflect your action, for example
        Status:Added 2 addresses to draft
        After you have done this you can either move to another page of your addressbook, or select Compose from the main toolbar to return to the Compose screen. If you have chosen addresses these will be added to the relevant header fields of your message.

    Sorting

    It is possible to temporarily change how you sort the addressbook by selecting Alias, Name, Comment or Address(es) in the column headings. This will sort in ascending order; it is possible to reverse the selected sort order by reselecting your chosen column.

    ./prayer-1.3.5/templates/old/list_nav_1_icons.t0000644006513000651300000000171311063710000017752 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list_nav_1_icons.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFDEF $nav->first_msg First % ELSE First % ENDIF % IFDEF $nav->prev_msg Previous % ELSE Previous % ENDIF % IFDEF $nav->next_msg Next % ELSE Next % ENDIF % IFDEF $nav->last_msg Last % ELSE Last % ENDIF ./prayer-1.3.5/templates/old/printable.t0000644006513000651300000000051611063710000016500 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/printable.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL printable_hdrs %# %# Live system inserts message MIME structure and body by hand here %# % IFDEF $g_testrig <% ${message} |n %> % CALL footer % ENDIF ./prayer-1.3.5/templates/old/abook_list_nav_1.t0000644006513000651300000000050311063710000017726 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list_nav_1.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFDEF $g_use_icons % CALL abook_list_nav_1_icons % ELSE % CALL abook_list_nav_1_noicons % ENDIF
    ./prayer-1.3.5/templates/old/block.t0000644006513000651300000000163311063710000015613 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/block.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Manual Address Blacklist

    % IFDEF $blocks[0]
      % FOREACH $b @blocks
    1. BLOCK: Blocking all messages from "<% $b->value |h %>". Remove this block.
    2. % ENDFOREACH
    % ELSE

    No block actions defined at the current time

    % ENDIF
    Block:
    % IFDEF $g_help % CALL block_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/copy.vars0000644006513000651300000000114311063710000016177 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/copy.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $fcmd copy_msg $dirlist[0]->name a $folder[0]->name INBOX $folder[0]->short_name INBOX $folder[0]->indent 0 $folder[1]->name a $folder[1]->short_name a $folder[1]->expanded 1 $folder[1]->haschildren 1 $folder[1]->even_row 1 $folder[1]->indent 0 $folder[2]->name a/b $folder[2]->short_name b $folder[2]->indent 1 $folder[3]->name a/c $folder[3]->short_name c $folder[3]->even_row 1 $folder[3]->indent 1 $g_cmd copy ./prayer-1.3.5/templates/old/favlist_favourites.t0000644006513000651300000000051111063710000020432 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/favlist_favourites.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# Remove from Favourites % IFEQ $_name $_preferred Current Preferred % ELSE Make Preferred % ENDIF ./prayer-1.3.5/templates/old/display_hdrs.t0000644006513000651300000000256411063710000017212 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_hdrs.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %#
    % IFDEF $reply_to[0] % ENDIF % IFDEF $to[0] % ENDIF % IFDEF $cc[0] % ENDIF
    Reply-To: % FOREACH $a @reply_to % CALL display_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    From: % FOREACH $a @from % CALL display_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    To: % FOREACH $a @to % CALL display_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    Cc: % FOREACH $a @cc % CALL display_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    Date:<% $date |h %>
    Subject:<% $subject |h %>
    ./prayer-1.3.5/templates/old/quota.vars0000644006513000651300000000066511063710000016366 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/quota.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $line[0]->type File Quota $line[0]->used 0 $line[0]->limit 2000 $line[0]->percent 0.00% $line[1]->type Block Quota (MBytes) $line[1]->used 1 $line[1]->limit 100 $line[1]->percent 1.00% $line[2]->type Mailstore Quota (MBytes) $line[2]->used 2 $line[2]->limit 100 $line[2]->percent 2.00% $g_cmd quota ./prayer-1.3.5/templates/old/abook_add.t0000644006513000651300000000163211063710000016423 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_add.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Addressbook Entry

    Alias
    Name
    Comment
    Address(es)
    % IFDEF $g_help % CALL abook_add_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/display.vars0000644006513000651300000000204511063710000016674 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/display.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ # # # NB: Get URLs need to have & seperators encoded as & on the way out # Browser will submit as & if clicked. $from[0]->personal David Carter $from[0]->email dpc22@cam.ac.uk $from[0]->alias me $to[0]->personal David Carter $to[0]->email dpc22@cam.ac.uk $to[0]->alias me $to[0]->next 1 $to[1]->personal David Carter $to[1]->email dpc22@cam.ac.uk $to[1]->alias me $cc[0]->personal David Carter $cc[0]->email dpc22@cam.ac.uk $cc[0]->alias me $date Mon, 20 Mar 2008 14:16:44 +0000 $subject The subject # Up to caller to get quoting correct, given need for HTML, links etc # Use callback here!? $message
    Test message
    $nav->prev_msg 14 $nav->prev_uid 15 $nav->cur_msg 15 $nav->cur_uid 45 $nav->next_msg 34 $nav->next_uid 35 $nav->msg_count 168 $g_cmd display ./prayer-1.3.5/templates/old/expunge.t0000644006513000651300000000156111063710000016174 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/expunge.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % IFNEQ $count 1

    Confirm expunge for <% $count |h %> messages

    % ELSE

    Confirm expunge for 1 message

    % ENDIF % IFDEF $g_use_icons
    Cancel Okay
    Cancel Okay
    % ELSE
    Cancel Okay
    % ENDIF % CALL footer ./prayer-1.3.5/templates/old/spell.vars0000644006513000651300000000031211063710000016341 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/spell.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $word Hllo $close_count 2 $close[0]->word Hello $close[1]->word Halo $g_cmd spell ./prayer-1.3.5/templates/old/vaclog.t0000644006513000651300000000101611063710000015767 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/vaclog.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Vacation log

    <% $vaclog |h %>
    
    % IFDEF $g_help % CALL vaclog_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/search_status.t0000644006513000651300000000114711063710000017371 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_status.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % CALL search_header, $_type => "Status"
    % CALL search_footer % IFDEF $g_help % CALL search_status_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/display_mime.t0000644006513000651300000000276311415375101017214 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_mime.t,v 1.3 2010/07/08 16:18:09 dpc22 Exp $

    MIME structure of this message, including any attachments:

    %# %# @atts is flattened tree, where $a->start_list and $a->end_list indicating %# nesting, any other node is a section which can be downloaded. %# % FOREACH $a @atts % IFDEF $a->start_item
  3. % ELSE % IFDEF $a->end_item
  4. % ELSE % IFDEF $a->start_list <% "Multipart:" IFDEF $a->nested_multipart |h %>
      % ELSE % IFDEF $a->end_list
    % ELSE % IFDEF $a->is_text % CALL display_mime_text, % $_msg => $nav->cur_msg, $_uid => $nav->cur_uid, % $_section => $a->section, $_name => $a->name, % $_type => $a->type, $_lines => $a->lines % ELSE % IFDEF $a->is_msg % CALL display_mime_msg, % $_msg => $nav->cur_msg, $_uid => $nav->cur_uid, % $_section => $a->section, $_name => $a->name, % $_type => $a->type, $_size => $a->size % ELSE % CALL display_mime_other, % $_msg => $nav->cur_msg, $_uid => $nav->cur_uid, % $_section => $a->section, $_name => $a->name, % $_type => $a->type, $_size => $a->size % ENDIF % ENDIF % ENDIF % ENDIF % ENDIF % ENDIF % ENDFOREACH
    ./prayer-1.3.5/templates/old/abook_update_help.t0000644006513000651300000000535711063710000020175 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_update_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The address book form buttons

    • To create an entry complete the fields and then select the Add entry or Add/Update entry button as relevant;
    • To delete an entry select the Delete entry button;
    • To return to the Webmail screen from whence you came, making no changes to your address book, select the Cancel button

    The address book form fields

    • Alias - the nickname by which the entry is known. This can be used as an address shortcut when composing a message.
    • Name - this is an optional field, but is customarily used for the real name of an individual or a relevant name for a list. The entry in this field will appear in any message sent using the alias.
    • Comment - optional - usually used as a short, relevant memory jogger for example "Contact at This Company Ltd.". It does not appear in any message sent using the alias.
    • Address(es)
      • In most cases this will be a single address, as in the example shown at the top of this page.
      • However you can also use the Addressbook to create an entry for a small group of people. In this case the Address field can either be full email addresses of the group members or the aliases of existing addressbook entries. Addresses must be separated by commas.

    Hence the following examples would all be be valid entries.
    Note: that the final entry uses existing alias entries, not full email addresses. Remember that you can only use this form of short address if you have an entry for the individual alias.

    Alias Name Comment Address(es)  
    someone A. Person Sales contact at Somewhere Company someone@somewhere.com Compose fresh message
    alien Green Alien   alien@planet.otherdomain.com Compose fresh message
    group   Small group person@company.co.uk, anotherperson@company.co.uk Compose fresh message
    group2     someone, alien Compose fresh message
    ./prayer-1.3.5/templates/old/reply.vars0000644006513000651300000000033011063710000016355 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/reply.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $sender Sender goes here $recipients Recipients goes here $subject Subject goes here $g_cmd reply ./prayer-1.3.5/templates/old/prefs_compose2_help.t0000644006513000651300000000410311063710000020452 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_compose2_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    • Use sent-mail folder - when this is checked a copy of all mail you send is saved to the mail folder you have named as your Sent Mail Folder. The default is mail/sent-mail, the choice is set in the Preferences -- screen.
    • Skip quoted text on spell check - when this is enabled the spell check will ignore quoted lines which start with < characters.
    • Line wrap on reply - wraps the text of the message to which you are replying if, after inserting the quoting characters 'Line Wrap at: below (default 76 characters).
    • Line wrap on spell check - wraps the text of the message as part of the spell check action.
    • Line wrap on send - wraps the text of the message as part of the action of sending the message.
    • Enable manual line wrap options - if this is enabled then extra line wrapping options appear in the Compose screen. These can be used in conjunction with the automatic options above.
    • Line Wrap at: - controls the number of characters (columns) which can appear in a line before the line is wrapped. Many people use an 80-character window, so 76 allows a good fit.
    • Normal Compose window size - controls the size of the text body area visible in the standard Compose screen.
    • Large Compose window size - controls the size of the text body area visible if the Large button is selected from the standard Compose screen.
    • Spell Check language controls which dictionary is used. At present the only languages are British English and American English. The choice of which language affects several aspects, for example the use of -ise rather than -ize for words such as "itemise". It is hoped that future releases will offer more languages.
    ./prayer-1.3.5/templates/old/dictionary.t0000644006513000651300000000215611063710000016667 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/dictionary.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Personal Dictionary Maintenance

    % IFDEF $words[0]

    Personal Dictionary (click links to remove entries):

    % FOREACH $w @words % IFDEF $w->break % ENDIF % ENDFOREACH
    <% $w->word |h %>
    % ELSE

    Personal Dictionary (currently empty)

    % ENDIF

    Add or remove specific words from the list:

    % IFDEF $g_help % CALL dictionary_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/display_toolbar_icons.t0000644006513000651300000000104111415373531021113 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_toolbar_icons.t,v 1.2 2010/07/08 16:05:45 dpc22 Exp $ %# % IFDEF $nav->prev_msg Previous % ELSE Previous % ENDIF % IFDEF $nav->next_msg Next % ELSE Next % ENDIF ./prayer-1.3.5/templates/old/sieve.vars0000644006513000651300000000025711063710000016345 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/sieve.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $rows 14 $script $g_cmd sieve ./prayer-1.3.5/templates/old/sieve_fail.vars0000644006513000651300000000023711063710000017336 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/sieve_fail.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $msg Error message displayed here $g_cmd sieve_fail ./prayer-1.3.5/templates/old/filter_fail.vars0000644006513000651300000000024111063710000017503 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/filter_fail.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $msg Error message displayed here $g_cmd filter_fail ./prayer-1.3.5/templates/old/abook_lookup_nav_1_icons.t0000644006513000651300000000166611063710000021472 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_lookup_nav_1_icons.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFDEF $nav->first_page First % ELSE First % ENDIF % IFDEF $nav->prev_page Previous % ELSE Previous % ENDIF % IFDEF $nav->next_page Next % ELSE Next % ENDIF % IFDEF $nav->last_page Last % ELSE Last % ENDIF ./prayer-1.3.5/templates/old/header.t0000644006513000651300000000141011133125515015753 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/header.t,v 1.2 2009/01/13 14:55:09 dpc22 Exp $ %# % IFDEF $g_service_name <% $g_service_name |h %> Webmail Service % ELSE Prayer Webmail Service % ENDIF ./prayer-1.3.5/templates/old/vacation.t0000644006513000651300000000240511413321714016334 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/vacation.t,v 1.2 2010/07/02 08:31:08 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Vacation Message

    % IFDEF $use_vacation % ELSE % ENDIF
    Enable Vacation Message.

    % IFDEF $using_sieve % ENDIF
    Frequency:  (days between vacation mesages to a given sender)
    Aliases:
    Subject:
    % IFDEF $g_help % CALL vacation_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/block_help.t0000644006513000651300000000611411063710000016622 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/block_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This screen enables you to set up a list of sender addresses which you wish to blacklist. Any addresses sent from these addresses will be silently discarded.

    If you have blocks in place that have been created either using the Webmail system or using the standard configuration options from the menu interface on <% $g_service_name |h %> then when you enter this screen they will be listed, as in the example below.

    1. BLOCK: Blocking all messages from "spammer" at "spamdomain.com". Remove this block.
    2. BLOCK: Blocking all messages from "noone" at "nowhere.com". Remove this block.

    If you have filters created using the advanced configuration option from the menu interface on <% $g_service_name |h %> then your filters should continue to be maintained in that way. Consequently the screen will not display the list of existing filters. Instead the following message will be shown:

    Error: Manually maintained .forward file?

    Adding a filter

    Entering the address

    Blocks are on the envelope sender address (a copy of which appears in the message as a header "Return-Path") address rather than the more obvious "From:". These two headers frequently have the same value, however this is rarely the case with junk email. Mailing lists often alter the Return-Path address to something that is specific to the list. You can find the "Return-Path:" for a particular message by using Show Hdrs on the message display screen.

    The following wildcards can be used:-

    '?' matches a single character
    '*' matches any number of characters

    Hence the following are all valid entries:-

    spammer@spamdomain.com
    *@jiscmail.ac.uk
    ?art?

    If an invalid address is been provided the status message will provide information. For example if you enter just Spammer will result in the status line entry

    Status: Invalid filter: Not a valid <% $g_service_name |h %> account and no domain provided

    and the invalid entry will be cleared from the entry field.

    The effect of the Add filter button

    When you select the Add filter button, the status message will change to

    Status: Added BLOCK filter

    and the list will be updated to display the new block.

    Removing a block

    To remove a block simply select the link Remove this block by the relevant filter. The status message will change to show which filter was removed, for example

    Status: Removed block number: 1

    and the block list will be updated on screen.

    ./prayer-1.3.5/templates/old/folders_help.t0000644006513000651300000001240311063710000017164 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/folders_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The Mail Folders screen allows you to either select a different mail folder to view or to create, rename or delete mail folders (mailboxes) and directories. The default set of mail folders on <% $g_service_name |h %> is INBOX, sent-mail and received.

    The bars above and below the folder listing

    Create under with name

    This enables the creation of mail folders or directories. For example selecting mailbox and typing a name such as projects will, once the Create button has been pressed, cause the display to change to include the newly created mail folder. Mailboxes can be created under existing directories.

    Refresh checks the contents of the directory on the <% $g_service_name |h %>.
    Transfer Folders allows you to upload a local mail folder to <% $g_service_name |h %> or download a mail folder from <% $g_service_name |h %> to your local machine.
    Sizes shows you the size of each mailbox on the system
    Favourite Folders displays a screen where you can choose a folder, or folders, to be added to a list of favourite mail folders. This list appears in the pull-down listing in the common toolbar, replacing the list of default folders. Once you have one or more Favourite mail folders an expanded set of actions becomes available. These are described on the help page associated with the Favourites selection screen.

    The folder listing

    You can keep all your mail in different folders in one directory, or you can create a storage system of directories that contain mail folders (the example given in this help text). While you can create mail folders in any directory, you need to be aware that different mail clients default to looking in different places.

    • The Folder icon mailbox indicates that the line refers to a mail folder and also shows the name of the folder and actions that can be performed on that folder, for example:-
      [mailbox] saved-messages Rename Delete
      Selecting the folder icon or the name of the folder will display a listing of the messages in that folder. To return to the folder listing screen again, select the Folders icon in the common toolbar.
      Other actions you can take on a mail folder are:-
      • Rename - takes you to a screen with a form allowing you to rename the mail folder.
      • Delete - deletes the mail folder. Selecting this leads to a screen where you need to choose to confirm or cancel the deletion. Once the mail folder is deleted the display of the mail folders is updated and the Status information reflects the success of the action, for example
        Status: Deleted mailbox: "mail/newtest"
    • The Right arrow [dir] indicates that the line refers to a directory, and shows the name of the directory and the actions that can be performed, for example:-
      [directory]testdir Rename Delete
      Selecting the arrow, or the name of the directory, will display a listing of the mail folders in that directory.
      The other actions are
      • Rename - takes you to a screen with a form allowing you to rename the directory.
      • Delete - deletes the directory. Selecting this leads to a screen where you need to choose to confirm or cancel the deletion.
        Note: You can only delete a directory if it has no mail folders inside it. If the deletion is not successful the Status information reflects the reason, for example if you try to delete a non-empty directory the message is:-
        Status: DELETE failed: Can't delete mailbox mail/testdir/: File exists
    ./prayer-1.3.5/templates/old/redirect.t0000644006513000651300000000277511071405225016343 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/redirect.t,v 1.2 2008/10/03 12:05:41 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Mail Redirection

    WARNING:

    Support staff within the University and Colleges will not be able to help you with email problems if you forward your email outside Cambridge and the problems involve external systems. Note that there may be issues of privacy and/or reliability with external email systems which you should consider.

    % IFDEF $use_redirect % ELSE % ENDIF % IFDEF $redirect_copy % ELSE % ENDIF
    Enable Redirection
      Redirect address:
    Save copy in this account
    % IFDEF $g_help % CALL redirect_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/include.t0000644006513000651300000000122711063710000016143 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/include.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Include local file in message body

    File
    % IFDEF $g_help % CALL include_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/compose.vars0000644006513000651300000000104511063710000016673 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/compose.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ #$large 1 #$rich_hdrs 1 $hdr_to David Carter

    Once you have selected the Reply option for a message you need to specify who is to receive the message. This screen shows the original sender and any other recipients of the message

    Reply Options

    • Cancel returns you to the Webmail page from whence you came.
    • Reply to sender only prepares a reply that will only go to the original sender.
    • Reply to sender and all recipients prepares a reply that will place the name of the original sender in the To: field and the names of all other recipients in the cc: field.

    If the message has a Reply-To: header, this name will appear as the Sender of the message.

    ./prayer-1.3.5/templates/old/compose_toolbar.t0000644006513000651300000000115011063710000017702 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose_toolbar.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    % CALL compose_toolbar_left Change to: % CALL compose_toolbar_right
    ./prayer-1.3.5/templates/old/prefs_general_help.t0000644006513000651300000000525711066657632020403 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_general_help.t,v 1.2 2008/09/25 09:53:30 dpc22 Exp $
    • Template Set defines the look and feel of the application<./li>
    • Main theme and Help theme set the colours that are used for the main Webmail pages and the help text pages respectively.
    • Enable welcome screen controls whether or not the initial screen "Welcome to the Webmail Service" is displayed when you log in.
    • % IFDEF $raven_enable
    • Allow Raven Logins - most people will want to leave this checked. Can be unchecked to stop Raven Web Single Sign on from applying to this account.
    • % ENDIF
    • Confirm expunge - if this is checked then attempts to expunge messages will generate a screen asking you to confirm or cancel.
    • Confirm Logout - if this is unchecked then selecting "Logout" on any screen will log you out immediately, otherwise you will see a screen asking you to confirm or cancel your logout.
    • Expunge deleted messages from INBOX on logout - automatically expunges messages when enabled
    • Use persistent marks - The Webmail default is to use non-persistent marks. This means that while you can mark more than one message on a screen you must take action on the marked messages, for example copying them all to a folder, before you move to another screen. If you change to another screen, for example listing the next screenful of messages, the marks are not retained.
      If you enable Use persistent marks then each time you mark a message a connection is made to the Webmail server. Because of this interaction with the server working with persistent marks is slower and is only recommended if you are working over a fast connection, for example within the University. Using persistent marks you can work on a whole mail folder rather than just the current screenful of messages. If this option is enabled then the following options can also be used:-
      • Zoom automatically after search controls what happens with the results of a search on a mail folder. If this option is selected then, as well as the messages being marked, the mail folder listing changes to show just the selected messages.
      • Unmark messages after aggregate operation controls what happens after an action has been taken on a group of marked messages, for example saving them to another mail folder. If this option is checked then, on return to the mail folder listing, the mark is removed from the relevant messages.
    ./prayer-1.3.5/templates/old/spell.t0000644006513000651300000000254211413405210015643 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/spell.t,v 1.2 2010/07/02 15:49:28 dpc22 Exp $ %# % CALL header

    Spell Check

    % IFDEF $have_changes % ENDIF

    Couldn't find highlighted word in following text:

    <% $text |n %>
    

    Options:

    1. Add word to personal dictionary
    2. Accept this spelling for current spell-check run only
    3. Leave word with current spelling, query further occurrences
    4. % IFNEQ $close_count 0
    5. Replace word with close match from dictionary % IFNEQ $close_count 1 (<% $close_count |h %> matches found) % ELSE (1 match found) % ENDIF % FOREACH $w @close % IFDEF $w->break % ENDIF % ENDFOREACH % ENDIF
      <% $w->word |h %> 
    6. Replace with specific text:
    % CALL footer ./prayer-1.3.5/templates/old/filter_select_help.t0000644006513000651300000000332211063710000020352 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/filter_select_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    After selecting the Add filter button from the main Mail Filtering screen you are presented with a list of your mail folders to select the destination folder.

    The Status line on the Select Target Mail Folder... screen will show the current action, for example:

    Status: Adding SENDER filter: "myfriend@someuni.ac.uk"

    The Cancel button at the end of the line immediately below the Select Target Mail Folder... heading returns you to the main mail filtering screen and no action is taken.

    Selecting a folder

    • If the folder you wish to use is shown in the list then choose:-
      • Select (no copy) if you wish the message just to be put in the selected folder.
      • Select (save copy to inbox) to put one copy in the selected folder and one in the inbox.
      A successful filter entry will then take you back to the main filter screen with the status message and display updated to show the new filter.
    • If the folder exists, but you know that it is in another directory, you can expand collapsed directories using the Expand icon.
    • If the folder does not exist create it using the Create dialogue. Once you click the Create button the folder is created and the display of mail folders updated. You can then choose one of the Select options, as described above.
    ./prayer-1.3.5/templates/old/toolbar_stub_help.t0000644006513000651300000000060111063710000020222 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/toolbar_stub_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Help Text


    ./prayer-1.3.5/templates/old/include_help.t0000644006513000651300000000163611063710000017157 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/include_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This option, reached from the Import button on the main Compose screen, is suitable for plain text files that you want to be included in the main body of the message. Other files (for example word processed documents or pictures) should be sent as attachments.

    Selecting Back to Compose Screen will take you back to the Compose screen you came from and no file will be included in your message.

    To include a file type the name of the file in the File box or use the Browse... button to select one. Once you have chosen the file, selecting the Include button will return you to the main Compose screen, and the text of the file will be included in the body of the message. You can then continue to edit the message.

    ./prayer-1.3.5/templates/old/dictionary.vars0000644006513000651300000000035011063710000017371 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/dictionary.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $words[0]->word dpc22 $words[1]->word dpc22 $words[2]->word Hllo $words[2]->break 1 $words[3]->word World $g_cmd dictionary ./prayer-1.3.5/templates/old/folders.t0000644006513000651300000000051511063710000016155 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/folders.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Mail Folders

    % CALL folders_toolbar % CALL folderlist, $cmd => "folders" % CALL folders_toolbar % IFDEF $g_help % CALL folders_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/spam.vars0000644006513000651300000000032611063710000016167 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/spam.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $enabled 1 $threshold 10 $purge_enabled 1 $days 60 $whitelist *@cam.ac.uk $g_cmd spam ./prayer-1.3.5/templates/old/redirect_help.t0000644006513000651300000000554611063710000017341 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/redirect_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    If you already have a redirection in place the form will show your current settings, similar to the form above where all mail is being redirected to somenewaddress@newplace.ac.uk, otherwise the two check boxes will be unmarked and the address field will be empty.

    If you have a manually maintained .forward file this cannot be updated from the Webmail interface. In this case the you will not see the form but a message reading

    Error: Manually maintained .forward file?

    To make changes to a manually maintained file you will need to connect to <% $g_service_name |h %> using an SSH or Telnet client and use the menu interface.

    If you do not already have a redirection in place

    To redirect your mail to a new address check the Enable Redirection box and enter the new address in the Redirect address: field. Then select the Apply button. If this is successful you will be returned to the main Account Management screen, and the status line will read

    Status: Updated redirection

    The address you use must be a complete, valid address of the form user@some.place.somewhere. If it is not then, after you have selected Apply, you will remain in the Mail Redirection screen and the status message will read

    Status: Redirection Address must be single, simple and fully qualified email address

    Note: that the check is only that the address appears complete. It cannot check the actual address, so errors in typing an address will not be picked up.

    If you wish one copy of each message to go to the new address and one copy to remain on <% $g_service_name |h %> then check the Save copy in this account box. Note: if you do this then you will need to make sure that you regularly check and delete the copies on <% $g_service_name |h %>, otherwise you may exceed your quota.

    If you already have a redirection in place

    If you wish to alter the Redirect address: enter the new address and then select Apply. Optionally check the Save copy in this account box. Note: if you do this then you will need to make sure that you regularly check and delete the copies on <% $g_service_name |h %>, otherwise you may exceed your quota. The comments made above about the form of an address apply.

    Cancelling a redirection

    If you wish to cancel your redirection then uncheck the Enable Redirection box and, if it is checked, the Save copy in this account. Then select Apply.

    ./prayer-1.3.5/templates/old/folderlist_folders.t0000644006513000651300000000043511063710000020405 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/folderlist_folders.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFEQ $_name "INBOX" % ELSE Rename Delete % ENDIF ./prayer-1.3.5/templates/old/roles_list.vars0000644006513000651300000000052011063710000017402 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/roles_list.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $roles[0]->alias me $roles[0]->personal David Carter $roles[0]->from dpc22@cam.ac.uk $roles[0]->reply_to dpc22@cam.ac.uk $roles[0]->fcc sent-mail $roles[0]->signature sig $g_cmd roles_list ./prayer-1.3.5/templates/old/block_fail.t0000644006513000651300000000073611063710000016611 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/block_fail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Automatic Mail Blocking

    Error: <% $msg |h %>

    % CALL footer ./prayer-1.3.5/templates/old/prefs_display.t0000644006513000651300000000537311063710000017372 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_display.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Preferences

    Display Preferences:

    Use icons
    Duplicate icons below message
    Display text/html sections inline.
    Display text/* sections starting <html> inline
    Display remote images in HTML e-mail
    Preserve MIME type when downloading attachments
    Start at first unread message
    % CALL prefs_display_folder_sort % CALL prefs_display_abook_sort
    Messages per page:
    Addressbook entries per page:
    Alt Addresses:

    % IFDEF $g_help % CALL prefs_display1_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/favourites_toolbar.t0000644006513000651300000000052011063710000020424 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/favourites_toolbar.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    Cancel | Refresh
    ./prayer-1.3.5/templates/old/transfer.t0000644006513000651300000000072211063710000016343 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/transfer.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Mailbox Transfer

    % CALL transfer_toolbar_top % IFDEF $g_favourites[0] Favourite mail folders: % CALL favlist, $cmd => "transfer" Normal mail folders: % ENDIF % CALL folderlist, $cmd => "transfer" % CALL transfer_toolbar_bottom % IFDEF $g_help % CALL transfer_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/rename_help.t0000644006513000651300000000224111063710000016774 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/rename_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Renaming a mail folder.

    The layout of the screen is similar to that in the main Mail Folders screen.

    • The list of mail folders.
    • The second form
      Rename under as new name
      is where you enter the new name of the mail folder.
      • Selecting the Rename button will return you to the mail folder listing screen, with the renamed folder listed. The Status line will be updated
        Status: Renamed mailbox mail/sent-mail to be mail/old-sent-mail
      • Selecting Cancel returns you to the main mail folder listing screen and no changes are made.
    ./prayer-1.3.5/templates/old/roles_entry.t0000644006513000651300000000231611063710000017065 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/roles_entry.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Roles Entry

    Alias
    From personal name
    From address
    Reply to address
    Fcc

    Signature:

    % IFDEF $g_help % CALL roles_entry_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/abook_add.vars0000644006513000651300000000037211063710000017133 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/abook_add.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $alias Alias goes here $name Name goes here $comment Comment goes here $email Email goes here $g_cmd abook_add ./prayer-1.3.5/templates/old/list_help.t0000644006513000651300000002376311063710000016514 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Reading a message

    To read a message simply select the name of the person in the From column or select the subject in the Subject column.

    The bars above and below the message listing

    These are largely identical. The exceptions are in the centre of each row:-

    Top bar Informative message indicating the current mail folder and the number of messages, for example "INBOX" with 4 messages .
    Bottom bar Shortcut for displaying other pages in a long mail folder listing. For example
    Page: /3
    indicates that the listing spans three pages. To move to a different page enter the required page number in the "Page:" box and then select "Go".

    The identical elements in each bar are:-

    First First displays the first page of messages in the mail folder.
    Previous Previous displays the previous page of messages.
    Next Next displays the next page of messages.
    Last Last displays the last page of messages.
      You can configure how many messages count as one page by using a setting found in Manage -> Preferences -> Display. The relevant icon is greyed out if the choice is not applicable (i.e. you are on the first or last page).
    Messages on a screen can be "marked" (selected) by checking the box by the message number. Marking is useful if you want to do the same thing with several messages on the page, for example deleting them or copying them to the same mail folder. Once messages have been marked various actions can be taken using this pull-down menu.
    Delete marked, Undelete marked perform the obvious actions.
    Flag as read and Flag as unread change the status of the marked messages.
    Forward marked takes you to the compose screen with the messages inserted as the body of the new message.
    Copy marked takes you to the folder display, where you can choose the folder to which you wish to copy the messages.
    Select the action from the pull-down menu and then select Go.
    Note: that after you have marked messages on a screen you must take action on those messages before you do something else, for example move to another page of messages or read a message. If you do something else before you have taken action on the marked messages, the marks are cancelled, unless you have set Manage -> Preferences -> General -> Use persistent marks. Using Persistent marks changes some options on the message list screen, see Using Persistent Marks below.
    Refresh checks for new mail. Please be cautious in your use of this (i.e. use it every few minutes rather than every few seconds) as it can put unnecessary load on <% $g_service_name |h %>.
    Expunge deletes from your mail folder all messages that are marked as deleted. Expunged messages cannot be recovered. Selecting this deletes them immediately - there is no confirmation dialogue.
    Search takes you to a screen where you can choose a subset of the messages in the current mail folder using different criteria including date and text search.

    The message list

    The message list is divided into columns.

    • # - Message. The message number.
    • Mark/Unmark. This allows the selection of one or more messages. Initially all messages are unmarked. Marking a message changes the icon in this column.
    • Unseen (Message status)
      Unseen Unread messages.
      Seen Read messages.
      Answered Message that have been replied to.
      Deleted Deleted messages. These are not actually removed from <% $g_service_name |h %> until Expunge is selected. Until then they can be undeleted either by selecting the Undelete option for that message or by displaying the message and choosing Undelete on that screen.
    • Date. The date on which the message was sent.
    • From. The name of the person who sent the message or, if the message is from the current user, the name of the person to whom the message is addressed.
    • Size. An indication of the size of the message.
    • Subject. The subject of the message.
    • Delete. Delete the message. The option then changes to Undelete.

    Sorting

    The default sort order is by arrival (Message). It is possible to temporarily change how you sort the current mail folder by selecting Date, From, Size or Subject in the column headings. This will sort in ascending order, for example if you sort by Size the smallest messages are listed first. It is possible to reverse the selected sort order by reselecting your chosen column, e.g. to sort by descending size select Size twice.

    You can also Thread messages. Threading uses uses reference headers in the message to work out the order of messages on the same subject. Selecting this sorts the current mail folder by thread.

    Using persistent marks

    If you have Manage -> Preferences -> General -> Use persistent marks set then there are some differences in the appearance of the message list screen and some changes to the actions that can be taken.

    One change is the appearance of extra choices in the bars above and below the message listing. The example below shows the changes to the top bar.

    First Previous Next Last
    "INBOX" with 4 messages
    Refresh | Expunge | Mark All | Zoom | Search
    Mark All marks all the messages.
    Zoom requires that you have marked one or more messages. It displays a listing of just the marked messages. If you are already in a zoomed list (for example as the result of a Search) then this option changes to Unzoom and selecting it will return you to the complete mail folder listing.

    You mark messages by selecting the Mark/Unmark icon by the message. Marking a message changes the icon. It also changes:

    • the Change To: in the common toolbar to include the option Copy marked to: to allow straightforward copying to the mail folders listed in the adjacent pull-down list;
    • the Mark All option in the action bar above and below the message list to UnMark All
    ./prayer-1.3.5/templates/old/common.vars0000644006513000651300000000222711063710000016521 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/common.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ # # # NB: Get URLs need to have & seperators encoded as & on the way out # Browser will submit as & if clicked. # # Some conventions to start factoring out: # @mailbox_list used by the top selector $g_mailbox_list[0]->name INBOX $g_mailbox_list[1]->name saved-messages $g_mailbox_list[2]->name sent-mail # Global state $g_have_draft 1 $g_testrig 1 #$g_help 1 $g_cmd list $g_user dpc99 $g_service_name Hermes $g_status Self destruct in 20 seconds $g_use_icons 1 $g_use_tail_banner 1 $g_theme->description Web Safe Blue $g_theme->fgcolor #000000 $g_theme->fgcolor_link #0000ff $g_theme->bgcolor #ccffff $g_theme->bgcolor_banner #66ffff $g_theme->bgcolor_row1 #ccffff $g_theme->bgcolor_row2 #99ffff $g_theme->bgcolor_status #ffffcc $g_theme->bgcolor_status_none #ccffcc $g_altpad      ./prayer-1.3.5/templates/old/sizes_toolbar.t0000644006513000651300000000052211063710000017374 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/sizes_toolbar.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %
    Cancel| Refresh
    ./prayer-1.3.5/templates/old/spam_help.t0000644006513000651300000000306411063710000016471 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/spam_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This option filters messages based on how much they look like junk email (otherwise known as spam) according to a score that is computed by applying a large number of tests to each message and calculating an overall result. Since it isn't possible to decide on technical grounds precisely whether an email is spam or not, the score is heuristic: a higher score means the message is more likely to be spam.

    You pick a threshold score above which messages are filtered to a separate spam folder, which you should check periodically (once a week, say) for misfiled email. If you set a low threshold (below 5) then it is likely to misclassify legitimate messages as spam. Messages that score 10 or more are blocked instead of being delivered, so high thresholds have no effect.

    We recommend setting the threshold to 5 at first, and adjusting it if necessary. For example, the filter is most accurate for English email so if you exchange a lot of foreign-language email you may have to use a higher threshold.

    The purge option (if available and enabled) defines the number of days that mail remains in your spam folder before it is automatically deleted by an overnight job. The default is 60 days.

    The whitelist section is a list of sender addresses (one on each line) which will bypass the spam filter. Wildcard characters are allowed: '?' matches any single character, while '*' matches any number of characters.

    ./prayer-1.3.5/templates/old/roles_select.t0000644006513000651300000000110211064536756017224 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/roles_select.t,v 1.2 2008/09/18 20:45:34 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Roles

    Roles:

      % FOREACH $r @roles
    1. <% ${r->name} |h %>
    2. % ENDFOREACH
    % IFDEF $g_help % CALL roles_select_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/welcome.vars0000644006513000651300000000021711063710001016662 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/welcome.vars,v 1.1 2008/09/16 10:52:49 dpc22 Exp $ $timeout 30 minutes $g_cmd welcome ./prayer-1.3.5/templates/old/abook_take.t0000644006513000651300000000163511063710000016622 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_take.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Addressbook Entry

    Alias
    Name
    Comment
    Address(es)
    % IFDEF $g_help % CALL abook_take_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/logout_raven.t0000644006513000651300000000035711063710000017227 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/logout_raven.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header

    Logout complete

    You should now shut down your Web browser in order to log out from Raven

    % CALL footer ./prayer-1.3.5/templates/old/attachments.vars0000644006513000651300000000036111063710000017541 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/attachments.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $atts[0]->name Attachment Name $atts[0]->size 42 $atts[0]->type application/octet-stream $g_cmd attachments ./prayer-1.3.5/templates/old/search_size.vars0000644006513000651300000000024211063710000017523 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/search_size.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $selected 17 $count 42 $g_cmd search_size ./prayer-1.3.5/templates/old/prefs_compose1_help.t0000644006513000651300000000265011063710000020456 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_compose1_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    • Personal Name: - this is what appears in the From: field of a message preceding your address. If, for example, your address is someone@somewhere.org and you set Someone Else as your Personal Name then the From: field in outgoing messages will appear as
      Someone Else <someone@somewhere.org>
    • From Address: - this is what appears as your address in an outgoing message. The default is shown on the screen. An address must be valid and it must belong to you. For example a valid alternative to sp999@cam.ac.uk would be sp999@hermes.cam.ac.uk.
    • Default Reply-To: - By default replies will be sent to the address in the From: field of a message. If you wish replies to be sent to another address, or addresses, then you can enter that address, or comma-separated list of addresses, in this field.
    • Signature: - information that appears at the bottom of a message. By convention this is 4 lines or less. It is preceded by a separator line -- . If you create a signature here then the separator line and signature are automatically included in the text field in the Compose screen.
    ./prayer-1.3.5/templates/old/frontend_compose_timeout.t0000644006513000651300000000240111075051454021643 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/frontend_compose_timeout.t,v 1.4 2008/10/14 08:07:08 dpc22 Exp $ %# % CALL header

    Couldn't connect to session. Maybe it timed out?

    Copy the following somewhere safe before logging in again.

    % IFNEQ $hdr_bcc "" % ENDIF % IFNEQ $hdr_fcc "" % ENDIF % IFNEQ $hdr_reply_to "" % ENDIF
    To:
    Cc:
    Bcc:
    Fcc:
    Reply-To:
    Subject:

    \ Click here to login again

    % CALL footer ./prayer-1.3.5/templates/old/compose_small_top.t0000644006513000651300000000351511063710000020241 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose_small_top.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % IFDEF $rich_headers % ELSE % ENDIF
    To:
    Cc:
    Bcc:
    Fcc:
    Reply-To:
    Subject:
    Subject:

                 
    ./prayer-1.3.5/templates/old/toolbar_left.t0000644006513000651300000000176111063710000017177 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/toolbar_left.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % % CALL tb_icon, $_cmd => "display", $_icon => "display", $_alt => "Message" % CALL tb_icon, $_cmd => "list", $_icon => "mailbox", $_alt => "Mailbox" % CALL tb_icon, $_cmd => "folders", $_icon => "folders", $_alt => "Folders" % CALL tb_icon, $_cmd => "compose", $_icon => "compose", $_alt => "Compose" % CALL tb_icon, $_cmd => "abook_list", $_icon => "addressbook", $_alt => "Addressbook" % CALL tb_icon, $_cmd => "manage", $_icon => "manage", $_alt => "Manage" % IFDEF $g_use_icons % ENDIF
    Message | Mailbox | Folders | Compose | Addressbook | Manage
    ./prayer-1.3.5/templates/old/sieve_error.vars0000644006513000651300000000017311063710000017553 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/sieve_error.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd sieve_error ./prayer-1.3.5/templates/old/abook_transfer_help.t0000644006513000651300000000523311063710000020530 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_transfer_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The Webmail system uses its own addressbook. It does not use the same addressbook as, for example, Pine on <% $g_service_name |h %>. If you wish to use either your <% $g_service_name |h %> Pine addressbook, or a local Pine format addressbook, you will need to import it into Webmail.

    Using this screen you can:

    • import a Pine or Outlook format addressbook on your local system into your Webmail addressbook;
    • export your Webmail addressbook to a Pine or Outlook format addressbook on your local system;
    • import your Pine addressbook on <% $g_service_name |h %> into your Webmail addressbook;
    • export your Webmail addressbook for use with Pine on <% $g_service_name |h %>.

    Importing and exporting the addressbook

    The Webmail can import and export two different forms of addressbook. Comma Separated Variable (CSV) format addressbooks are used by Outlook and Outlook Express. PINE format addresses are used by PINE and Mulberry. If you wish to use an addressbook from another mail client, such as Eudora, then you will first need to find a method of saving or exporting the addressbook into the correct format.

    • To transfer a Pine or CSV address book from your local system into the Webmail system, Browse to the location of the address book on your local disk, select the appropriate file, then select Import. The entries will be merged with any entries you already have in your Webmail addressbook. New entries will appear at the end of your Webmail addressbook.
    • To transfer your Webmail address book to your local system, select Export CSV (Outlook) addressbook or Export PINE addressbook or then use your browser's "Save" feature to navigate to where you wish to put the address book.
    • To import your Pine addressbook on <% $g_service_name |h %> into your Webmail addressbook select Import from Unix Pine addressbook. Your Pine addressbook is imported and you are returned to the addressbook listing screen. The entries will be merged with any entries you already have in your Webmail addressbook. New entries will appear at the end of your Webmail addressbook.
    • To export your Webmail addressbook for use with Pine on <% $g_service_name |h %> select Export to Unix Pine adddressbook. Your addressbook is exported and you are returned to the addressbook listing screen.
    ./prayer-1.3.5/templates/old/display_tail.t0000644006513000651300000000035211063710000017174 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_tail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % CALL display_toolbar % IFDEF $use_tail_banner % CALL toolbar % ENDIF % IFDEF $g_help % CALL display_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/quota_help.t0000644006513000651300000000143311063710000016660 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/quota_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This screen shows you information about your disk space quota on <% $g_service_name |h %>. It looks something like:-

    The information returned shows:-

    • File Quota - the number of files in the <% $g_service_name |h %> filestore.
    • Block Quota - the amount of disk space used in the <% $g_service_name |h %> filestore
    • Mailstore Quota - the amount of disk space used in the <% $g_service_name |h %> mailstore

    Warning messages are sent when an account reaches 90% and 95% of quota in either the filestore or mailstore. The Mailstore limit is the one most likely to be reached in normal operation.

    ./prayer-1.3.5/templates/old/transfer_toolbar_bottom.t0000644006513000651300000000107511063710000021453 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/transfer_toolbar_bottom.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    File:
    Cancel | Refresh
    ./prayer-1.3.5/templates/old/toolbar_help.t0000644006513000651300000001611011063710000017167 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/toolbar_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Help Text


    The common toolbar appears at the top of most Webmail pages and provides shortcuts to the main Webmail functions.

    Message
    Message

    This icon will always return you to the current message.

    When you login, the first unread message in your inbox is the current message. If you have no unread messages then the last message in your inbox is the current message.

    If you move to another folder then the last message in that folder is the current message.

    In any folder, once you read a message that becomes the current message. For example, if you were reading message 6 of 8 in your inbox, then move to another screen (e.g. by Mailbox or Folder) then when you re-select Message message 6 is displayed.

    Mailbox
    Mailbox
    This icon returns you to a listing of your currently selected mail folder. By default this is your inbox.
    Folders
    Folders
    Select this to see a listing of your mail folders. You can select a different mail folder to view or you can create, rename or delete mail folders and directories. You can also choose some of your mail folders to be "favourites", which will give you quick access to these folders, or you can transfer mail folders between <% $g_service_name |h %> and your local system.
    Compose
    Compose
    Select this to start writing a new message. Normally this will take you straight to the message composition screen, but if you have any postponed messages you will be asked whether you want to edit one of these or start a new message. If you have defined one or more "roles" for yourself (see the Manage screens) then you will be asked to select which role you want to use.
    Addressbook
    Addressbook
    Selecting this leads you to the main addressbook listing screen where you can edit, delete and add entries. You can also import your <% $g_service_name |h %> addressbook into the Webmail addressbook or export your Webmail addressbook for use in Pine on <% $g_service_name |h %>.
    Manage
    Manage
    Selecting this leads to screens that let you configure various aspects of the Webmail system either for the current session or for every future session. These include preferences that affect the appearance of the system, account management (e.g. changing your password), mail processing (e.g. setting a vacation message) and defining a personal dictionary.

    Once you have selected an option from the toolbar, and moved to the relevant screen, that option is "greyed out" (shown as inactive) on the toolbar. For example when you are viewing a message the message icon will appear as shown below:-
    Message

    Change to:

    By default this pull-down list will show all your mail folders. You can change to any listed folder by selecting that from the list and then selecting Go.

    If you have specified any "favourite" mail folders, then the general listing of your mail folders is replaced by a pull-down list showing just the favourites, for example:-

    Change to:
    Help
    Help
    The Webmail system has specific help pages for each screen rather than an overall globally available system. Selecting this icon on any screen takes you to the help text relevant to that screen. When you are looking at a help text page this icon changes to
    Back
    Back
    and using this takes you back to the screen you came from.
    Logout
    Logout
    Selecting this will log you out of the Webmail system. Please remember to use this to log out when you have finished a session rather than just leaving your session idle.

    The status information

    This appears immediately below the toolbar and contains:-

    • On the left Status: or Reminder: information. Status messages give feedback about the last command issued. These usually indicate whether an action was successful or not. For example status messages for the Folders screen include:-
      Status: Switched to mailbox: mail/received
      Status: Created mailbox: mail/test2
      Status: Deleted mailbox: mail/test
      The principal reminder is
      Reminder: Logout when you have finished
    • On the right, the account name of the user currently logged in.

    ./prayer-1.3.5/templates/old/abook_lookup_nav_1_noicons.t0000644006513000651300000000120611063710000022015 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_lookup_nav_1_noicons.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFDEF $nav->first_page First % ELSE First % ENDIF | % IFDEF $nav->prev_page Previous % ELSE Previous % ENDIF | % IFDEF $nav->next_page Next % ELSE Next % ENDIF | % IFDEF $nav->last_page Last % ELSE Last % ENDIF ./prayer-1.3.5/templates/old/error.t0000644006513000651300000000037711063710000015656 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/error.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status Couldn't find URL on this server

    This could caused by either user error or a bug in the server

    % CALL footer ./prayer-1.3.5/templates/old/display_help.t0000644006513000651300000001075711063710000017205 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    By default you will see two instances of the bar, as in the example above. You can choose to turn off the bar below the message (or indeed the use of any icons in the Webmail interface) using options found in Manage -> Preferences -> Display.

    Prev Next Previous and Next take you to, respectively, the previous and next message. The relevant icon is greyed out, as in the example above, if the choice is not applicable (i.e. you are on the first or last message).
    Copy takes you to the folder display screen, where you can choose the folder to which you wish to copy the message.
    Delete marks the message as deleted and displays the next message in the mail folder. If you delete the final message in the folder you are returned to the mail folder list. Messages are not removed from the mail folder until Expunge has been selected in the mail folder list screen.
    Reply prepares a reply. Selecting this takes you to the Compose screen and the original message is included in the reply. If there is more than one name on the original recipients list you are asked whether you wish to reply to the sender only or to reply to the sender and all recipients.
    Forward enables you to forward the message to someone else. Selecting this takes you to the Compose screen and the original message is included in the message body.
    Message: 1 out of 4 informative message.
    Show Hdrs Show Headers displays the full set of message headers. This option is most useful when trying to trace a problem. If you select this the option changes to Hide Hdrs and the full headers are shown for every message until you select Hide Hdrs.
    Download Message this presents the entire message, including all the message headers, in a plain form (i.e. without the Webmail icons and actions) suitable for printing or saving to your local system using your browser's printing and saving facilities.

    The message

    The From: and To: headers have links that enable you to take the address into your address book. Selecting one takes you to the Addressbook Entry screen with the entries placed in the Name and Address(es) fields.

    Attachments

    If a message has attachments then information about the message structure, including attachments, will be shown:-


    MIME structure of this message, including any attachments:

    1. (text/plain), 0 lines
    2. [paperclip] MyDocument.rtf (application/octet-stream), 3 K

    In this example part 1. is the text body of the message and part 2. the attachment (indicated by the small paperclip icon [paperclip]). To save the attachment select the link containing the attachment name and use your browser's "Save" feature to navigate to where you wish to put the attachment on your local machine.

    Persistent Marks

    If you have Manage -> Preferences -> General -> Use persistent marks set then there will be an extra option, Mark in the bars above and below the message.

    Mark marks the message so that you can take an action on it later. The next message is then displayed. If you have marked the final message in the folder you are returned to the mail folder list. The icon in the mail folder list screen changes to show the message has been marked. If you return to displaying a marked message before you have taken any action on it the option on this screen is changed to Unmark.

    ./prayer-1.3.5/templates/old/roles_entry_help.t0000644006513000651300000000250011063710000020070 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/roles_entry_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Fields

    • Alias - the name by which you want the role to appear in the listing on the main Roles screen.
    • From personal address - added in front of your address.
    • From address - your default address is used unless you have a specific entry in this field.
    • Reply to address - added as the Reply-To header to messages composed using this role.
    • Fcc - allows you to choose a folder into which copies of messages you send using this role will be copied.
    • Signature: - role information to appear at the bottom of a message. By convention this is 4 lines or less. It is preceded by a separator line -- . If you create a signature here then the separator line and signature are automatically included in the text field in the Compose screen.

    Buttons

    • Cancel - returns you to the main Account Management screen, and no changes are made.
    • Add/Update entry - creates a new entry or commits changes to an existing one.
    • Delete entry - remove the entry for that role.
    ./prayer-1.3.5/templates/old/favourites.t0000644006513000651300000000073111063710000016706 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/favourites.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Favourite mail folders

    % CALL favourites_toolbar % IFDEF $g_favourites[0] Favourite mail folders: % CALL favlist, $cmd => "favourites" Normal mail folders: % ENDIF % CALL folderlist, $cmd => "favourites" % CALL favourites_toolbar % IFDEF $g_help % CALL favourites_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/search_text.vars0000644006513000651300000000024211063710000017535 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/search_text.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $selected 17 $count 42 $g_cmd search_text ./prayer-1.3.5/templates/old/upload_select.vars0000644006513000651300000000117611063710000020056 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/upload_select.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $upload_name INBOX $dirlist[0]->name a $folder[0]->name INBOX $folder[0]->short_name INBOX $folder[0]->indent 0 $folder[1]->name a $folder[1]->short_name a $folder[1]->expanded 1 $folder[1]->haschildren 1 $folder[1]->even_row 1 $folder[1]->indent 0 $folder[2]->name a/b $folder[2]->short_name b $folder[2]->indent 1 $folder[3]->name a/c $folder[3]->short_name c $folder[3]->even_row 1 $folder[3]->indent 1 $g_cmd upload_select ./prayer-1.3.5/templates/old/rename.t0000644006513000651300000000057511063710000015774 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/rename.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Rename folder "<% ${rename_foldername|7} |h %>" to ...

    % CALL rename_toolbar % CALL folderlist, $cmd => "rename" % CALL rename_toolbar % IFDEF $g_help % CALL rename_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/sieve.t0000644006513000651300000000176411725145030015653 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/sieve.t,v 1.2 2012/03/05 14:13:44 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Sieve Filtering

    Either:
    or update sieve file directly here:
    % IFDEF $g_help % CALL sieve_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/compose_postponed_help.t0000644006513000651300000000161711063710000021273 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose_postponed_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This screen is displayed if you have selected the Compose icon and you have a postponed (unsent) message.

    Using postponed messages

    • To continue with a postponed message select the Subject field of the relevant message. You will then see the main Compose page, with the message presented for further editing.
    • To start a new message instead, select the Compose a fresh message button.
    • The Cancel button returns you to the Webmail page from whence you came. The contents of the postponed mail folder are unchanged.
    • If you wish to remove a postponed message you need to select it then, from the main Compose screen, choose Cancel.
    ./prayer-1.3.5/templates/old/list_nav_1.t0000644006513000651300000000131211063710000016552 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list_nav_1.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# %# $_agg should be "aggregate" at top "aggregate2" at bottom of screen. %# % IFDEF $g_use_icons % CALL list_nav_1_icons % ELSE % CALL list_nav_1_noicons % ENDIF ./prayer-1.3.5/templates/old/list_toolbar_top.t0000644006513000651300000000111711063710000020075 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list_toolbar_top.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %#
    % CALL list_nav_1, $_agg => "aggregate"
    % IFEQ $nav->msg_count "1" "<% ${foldername|7} |h %>" with 1 message % ELSE "<% ${foldername|7} |h %>" with <% $nav->msg_count |h %> messages % ENDIF % CALL list_nav_2
    ./prayer-1.3.5/templates/old/spam_fail.t0000644006513000651300000000073711063710000016460 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/spam_fail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Junk Email (Spam) Filtering

    Error: <% $msg |h %>

    % CALL footer ./prayer-1.3.5/templates/old/welcome.t0000644006513000651300000000253511063710001016157 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/welcome.t,v 1.1 2008/09/16 10:52:49 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % IFDEF $g_service_name

    Welcome to the <% $g_service_name |h %> Webmail Service % ELSE

    Welcome to the Prayer Webmail Service % ENDIF

    Please read some important hints about use of this Webmail service.

    Use the navigation icons on the Webmail interface

    The browser navigation buttons will not work reliably.

    Always log out from the Webmail system when you have finished.

    • If you fail to do this, people with access to the computer that you are using may be able to read your mail.
    • Abandoned login sessions consume valuable resources on the server.

    Session Timeout

    This login session will shut down automatically after <% $timeout |h %> of idle time.

     
    Show this screen next time you log in
    % IFDEF $g_help % CALL welcome_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/roles_entry.vars0000644006513000651300000000045511063710000017577 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/roles_entry.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $alias me $personal David Carter $from dpc22@cam.ac.uk $reply_to Reply to goes here $fcc sent-mail $signature Signature goes here $g_cmd roles_entry ./prayer-1.3.5/templates/old/compose_postponed.vars0000644006513000651300000000043111063710000020764 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/compose_postponed.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $list[0]->msgno 1 $list[0]->date Date goes here $list[0]->name Name of recipient goes here $list[0]->size 42K $g_cmd compose_postponed ./prayer-1.3.5/templates/old/list_toolbar_bottom.t0000644006513000651300000000120611063710000020576 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list_toolbar_bottom.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %#
    % CALL list_nav_1, $_agg => "aggregate2"
    Page: /<% $nav->page_count |h %>
    % CALL list_nav_2
    ./prayer-1.3.5/templates/old/prefs_folder.vars0000644006513000651300000000051611063710000017702 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/prefs_folder.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $suppress_dotfiles 1 $confirm_rm 1 $maildir Maildir goes here $sent_mail_folder sent-mail $postponed_folder postponed-msgs $g_cmd prefs_folder ./prayer-1.3.5/templates/old/compose_large_help.t0000644006513000651300000000633611063710000020355 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose_large_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Note that in this Webmail screen the main toolbar is not visible, so the Help and Logout buttons are included as part of this page.

    By default the size of the message body part is 80 columns and 24 rows. You can change this if you wish using an option under Manage -> Preferences -> Extra Compose

    The buttons

    • Above the message body part:-
      • Small - this returns you to the standard Compose screen layout.
      • Help - takes you to this help text.
      • Logout - The Logout button brings up a confirmation screen which lets you logout of your mail session. You must remember to logout when you have finished your session.
    • Below the message body part:-
      • Check Spelling - this will check the body of the message and allow you to accept suggested alterations, leave the word unchanged or add the word to your personal dictionary. Once the spell check has completed the status field will summarise, for example:-
        Status: Spell Check finished (0 changes made)
      • Cancel - cancels the message and returns you to the Webmail page you came from when you originally chose Compose. The status line will change to reflect the action:-
        Status:Draft message cancelled
      • Postpone - the draft is saved to the mail folder defined to hold these messages (default postponed-messages) and you are returned to the Webmail page you came from when you originally chose Compose. The status line will change to reflect the action:-
        Status:Draft message postponed
        If you have messages in the postponed messages folder then when you select Compose you get the option to continue with the postponed message or start a new one.
      • Send - triggers an immediate send and returns you to the Webmail page you came from when you originally chose Compose.
      • Save copy - This check box controls whether a copy is automatically saved. The default for this is set in Manage -> Preferences -> Extra Compose.

    If you have enabled Manage -> Preferences -> Extra Compose -> Enable manual line wrap options then there will be two extra options on the line below the message body part:-

    • Line Wrap - wraps the message to a line length defined in Manage -> Preferences -> Extra Compose -> Line Wrap at. The default is 76 characters.
    • Line Wrap on Send - wraps the text of the message as part of the action of sending the message.
    ./prayer-1.3.5/templates/old/restart.vars0000644006513000651300000000016311063710000016712 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/restart.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd restart ./prayer-1.3.5/templates/old/prefs_folder_help.t0000644006513000651300000000341111063710000020177 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_folder_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    • Suppress dotfiles (files starting '.') from folder listing - unchecking this will show all your files and mail folders, including the files that are normally hidden. Files whose name starts with a '.' are normally in your home directory, and include configuration files such as the addressbook used by Pine (.addressbook)
    • Confirm folder deletion - If this is unchecked then selecting the Delete button against a mail folder name on the Folders screen deletes that folder immediately without asking for confirmation.
    • Mail directory - controls which directory is the default for mail folders. The default is the mail subdirectory of your home directory. Some mail clients (for example Outlook Express) use the home directory by default. If you habitually use one of these clients then you may need to consider making this field blank.
    • Sent Mail Folder - controls which folder is used to hold copies of outgoing mail. Again, if you habitually use a mail client that has a different convention you may wish to change this preference, for example if you are an habitual Outlook Express user you may wish to change it to:-
      Sent Mail Folder:
    • Postponed Messages Folder controls which folder is used to store a message that you wish to postpone and return to later.
    ./prayer-1.3.5/templates/old/vacation_help.t0000644006513000651300000000531711413321714017351 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/vacation_help.t,v 1.2 2010/07/02 08:31:08 dpc22 Exp $

    Using this option you can set a message that is automatically sent to the sender of a message that is personally addressed to you. Typically it is used to alert a sender that you are away (not necessarily on vacation) and will be replying after you return.

    If you already have a vacation message in place the form will show your current message and the Enable Vacation Message box will be checked.

    If you have a manually maintained Sieve file on <% $g_service_name |h %> this cannot be updated from this interface. In this case the you will not see the form but a status message reading

    Error: Manually maintained Sieve file?

    To make changes to a manually maintained file you will need to connect to <% $g_service_name |h %> using an SSH or Telnet client and use the menu interface.

    Frequency

    Once a vacation message has been sent, no further vacation messages will be sent to the address in question until the given number of days have passed. Please note: This is true even if one vacation message is cleared and a new vacation message is set up. This option does not automatically clear your vacation message after the given number of days.

    Aliases

    Vacation messages are only sent out in response to "personal" messages which have been sent directly to your <% $g_service_name |h %> account, rather than via mailing lists or other means. This is determined by looking to see whether your email address appears in the "To:" and "Cc:" headers of a message.

    The Aliases dialogue can be used to define a comma separated list of additional email addresses which will trigger vacation messages in this way. This is normally used in conjunction with "friendly" email address associated with an institution.

    Subject

    The subject line of messages which are sent out

    Setting up a vacation message

    If you do not already have a vacation message then check the Enable Vacation Message box, enter your text into the form immediately beneath it and finally select the Apply button. You will be returned to the main Account Management screen.

    If you have a message and wish to change it just make the relevant changes in the form and select the Apply button.

    If you do not wish to save any changes then select Cancel at any point and you will be returned to the main Account Management screen.

    Cancelling your vacation message

    Uncheck the Enable Vacation Message box and select the Apply button.

    ./prayer-1.3.5/templates/old/passwd_help.t0000644006513000651300000000305311063710000017030 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/passwd_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This screen allows you to change your <% $g_service_name |h %> password. The screen contains some notes specific to <% $g_service_name |h %> passwords, and a form you use to change your password. Some general advice on choosing passwords can be found in a Computing Service information leaflet

    To change your password you need to enter your current password and the new password you would like. You need to enter the new one twice, as this check provides a guard against accidental mistyping.

    If your password change is successful then the Status message will change to

    Status: Changed password

    and you will be returned to the Account Management screen.

    If the attempt is not successful, you will stay in the Change Password screen, and the reason the change failed will be displayed in the Status line. Examples of status messages are:

    Status: Password too short - must be at least 6 characters
    Status: New passwords do not match

    and, if you enter your current password incorrectly:-

    Status: Incorrect password
    ./prayer-1.3.5/templates/old/manage.vars0000644006513000651300000000016111063710000016454 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/manage.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd manage ./prayer-1.3.5/templates/old/search_size_help.t0000644006513000651300000000117011063710000020024 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_size_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The Search screen allows you to select a set of messages from the current mail folder using different criteria. After you have selected your messages you can take action on them, for example, Mark them all and copy them all to the same folder.

    After the initial search has been made it is possible to add another criterion to refine the selection.

    This form allows you to select messages according to whether they are Larger or Smaller than the chosen size.

    ./prayer-1.3.5/templates/old/list_msgs.t0000644006513000651300000000365511063710000016533 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list_msgs.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % FOREACH $msg @list_msg % IFDEF $msg->even_row % ELSE % ENDIF <% $msg->num |h %>. % IFDEF $use_persist % IFDEF $msg->is_marked \ % IFDEF $g_use_icons Yes % ELSE Yes\ % ENDIF % ELSE \ % IFDEF $g_use_icons No % ELSE No\ % ENDIF % ENDIF % ELSE \ % ENDIF % IFDEF $g_use_icons % IFDEF $msg->is_deleted % ELSE % IFDEF $msg->is_answered % ELSE % IFDEF $msg->is_seen % ELSE % ENDIF % ENDIF % ENDIF % ELSE % IFDEF $msg->is_deleted D % ELSE   % ENDIF % IFDEF $msg->is_seen O % ELSE N % ENDIF % IFDEF $msg->is_answered A % ELSE   % ENDIF % ENDIF <% $msg->date |h %> <% $msg->dname |h %> <% $msg->size |h %> % IFDEF $msg->has_attach % ENDIF <% $msg->subject |h %> % IFDEF $msg->is_deleted Undelete % ELSE Delete % ENDIF % ENDFOREACH ./prayer-1.3.5/templates/old/abook_search_help.t0000644006513000651300000000626411063710000020156 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_search_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The selection area

    Simple Search

    To perform a simple search, such as the example given above, select the field to search (the choice is Alias, Name, Comment, Address) and then select the match criterion. Use is if you are sure of the exact term, begins, ends and contains if you are either unsure, or wish to retrieve a possibly wider selection. Finally select the Search button.

    Selecting the link from the Alias column of the address you are interested in brings up the relevant address book entry.

    Advanced Search

    After the initial search has been made it is possible to extend the search term using the Add condition button and the any/all toggle. Using any means that any entries in the addressbook that match one or more criteria are returned, using all means that the addressbook entry must match all the specified criteria.

    The example below was obtained by making an initial Alias is choice, then selecting the Add condition button, choosing any, entering the new criteria (Address contains), and then selecting the Search button.

    Search for entries where of the following conditions hold
    2 matches for those search criteria:
    Alias Name Comment Address
    someone A. Person Sales contact at Somewhere Company somone@somewhere.com
    alien Green Alien   alien@domain.otherplanet.com
    ./prayer-1.3.5/templates/old/display_addr.t0000644006513000651300000000116211063710000017155 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_addr.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# %# Display a single address with abook_take link. Inputs: %# $_alias - existing alias, if already exists in addressbook %# $_personal - personal name %# $_email - email address %# $_raw - raw text to display without link, on parse error %# % IFNEQ $_raw "" <% $_raw |h %> % ELSE \ % IFNEQ $_personal "" <% "$_personal <$_email>" |h %> % ELSE <% $_email |h %> % ENDIF % ENDIF % IFEQ $_next "1" , % ENDIF ./prayer-1.3.5/templates/old/printable_addr.t0000644006513000651300000000102511063710000017466 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/printable_addr.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# %# Display a single address with abook_take link. Inputs: %# $_alias - existing alias, if already exists in addressbook %# $_personal - personal name %# $_email - email address %# $_raw - raw text to display without link, on parse error %# % IFNEQ $_raw "" <% $_raw |h %> % ELSE % IFNEQ $_personal "" <% "$_personal <$_email>" |h %> % ELSE <% $_email |h %> % ENDIF % ENDIF % IFEQ $_next "1" , % ENDIF ./prayer-1.3.5/templates/old/dictionary_help.t0000644006513000651300000000213311063710000017672 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/dictionary_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Your Personal Dictionary is where you can build up a list of words that you use that are not in the system dictionary used by the spell checker. Spelling is case sensitive.

    Maintaining your dictionary

    • Any words you have added to your personal dictionary appear, sorted alphabetically, above the fields for adding and removing words. Words starting with a capital appear before those all in lower case.
    • To Add a word type it in the first field (as in the example "hypothetical" above) then select the Add button.
    • To Remove a word
      • either type the word in the field by the Remove button and then select that button
      • or select the relevant word in the listing.
    • Back to Options Screen returns you to the main Account Management screen, and no changes are made to your dictionary.
    ./prayer-1.3.5/templates/old/compose.t0000644006513000651300000000321611413410146016174 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose.t,v 1.2 2010/07/02 16:14:30 dpc22 Exp $ %# % CALL header
    % IFNDEF $large % CALL compose_toolbar % CALL status % ENDIF % IFDEF $large
    % CALL compose_large_top
    % ELSE
    % CALL compose_small_top
    % ENDIF % IFDEF $line_wrap_advanced % IFDEF $line_wrap % ELSE % ENDIF % ENDIF % IFDEF $copy_outgoing % ELSE % ENDIF
    Line Wrap on Send         Save copy
    % IFDEF $g_help % IFDEF $large % CALL compose_large_help % ELSE % CALL compose_small_help % ENDIF % ENDIF % CALL footer ./prayer-1.3.5/templates/old/redirect_fail.vars0000644006513000651300000000024511063710000020023 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/redirect_fail.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $msg Error message displayed here $g_cmd redirect_fail ./prayer-1.3.5/templates/old/abook_take.vars0000644006513000651300000000037311063710000017330 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/abook_take.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $alias Alias goes here $name Name goes here $comment Comment goes here $email Email goes here $g_cmd abook_take ./prayer-1.3.5/templates/old/search_date_help.t0000644006513000651300000000632411063710000017775 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_date_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The Search screen allows you to select a set of messages from the current mail folder using different criteria. After you have selected your messages you can take action on them, for example, Mark them all and copy them all to the same folder.

    After the initial search has been made it is possible to add another criterion to refine the selection.

    With the exception of the field for the year, the form is a set of pull-down menus. By default the selection is to search for messages dated today. In the screen above "today" is 5th June 2001. Other options are to select dates Before (not including), Before (including), Since (including), Since (not including) a selected date.

    Some examples:-
    If the current date is 5th June 2001, then

    • will select messages with dates from 1st January 1990 to 4th June 2001 inclusive;
    • will select messages from 1st January 1990 to 3rd March 2000 inclusive;
    • will select messages from 1st January 2001 until the current day;
    • will select messages from 21st May 1998 until the current day.

    Once you have chosen your date then choosing Search will return you to the mail folder with just the selected message(s) listed.

    ./prayer-1.3.5/templates/old/logout.vars0000644006513000651300000000016111063710000016535 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/logout.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd logout ./prayer-1.3.5/templates/old/rename_toolbar.t0000644006513000651300000000125411063710000017511 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/rename_toolbar.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %#
    Rename under as new name
    ./prayer-1.3.5/templates/old/vaclog_help.t0000644006513000651300000000253511063710000017006 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/vaclog_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The Vacation Log is associated with the use of a Vacation Message. It lists people who have been trying to contact you in your absence (and also prevents duplicate messages being sent out).

    Log entries

    If you have a vacation message set up (or have had one and have not cleared the log) then the names of people to whom the auto-reply has been sent will be written to a log file. If there are entries in the log file then when you enter this screen it will look something like the screen above.

    Each entry has the date and time the auto-reply was sent. The first entry for each person contains the name of the respondent and the subject of their mail. Subsequent entries for the same person note that the auto-reply has been previously sent (and hence has not been sent again).

    Each time you set up a new vacation message you need to clear the existing log so that a copy of your new message can be sent to people who have previously received the old message. Selecting the Clear vacation log button does this.

    If there are no entries in your log then the message

    No vacation log at this time

    is displayed in place of the list of names.

    ./prayer-1.3.5/templates/old/logout.t0000644006513000651300000000200611063710000016025 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/logout.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header

    Confirm logout from <% $g_service_name |h %> Webmail system

    % IFDEF $g_use_icons
    Cancel Okay
    Cancel Okay
    % ELSE
    Cancel Okay
    % ENDIF % IFDEF $g_have_draft
    Warning: Draft message currently active
      This message will be discarded if you exit now
    % ENDIF % CALL footer ./prayer-1.3.5/templates/old/compose_small_help.t0000644006513000651300000001467711063710000020402 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose_small_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This works similarly to other mail clients. To compose a message enter the address of the recipient in the To: field and the address of anyone who should also get a copy in the Cc: field. If you want more than one address in a field put a comma between the addresses. You can use addresses from your addressbook either by typing the nickname (alias) or by selecting the Addressbook icon from the main toolbar and then choosing the recipients you want. Enter the subject of the message into the Subject: field. Then type your message into the main message box. You can also cut-and-paste text into the message box. Once you have finished your message, select the Send button.

    Description of the options obtained by using the buttons on the screen follows.

    The buttons

    This section describes the buttons on the default page. If you have enabled Manage -> Preferences -> Extra Compose -> Enable manual line wrap options there will be some extra buttons on the bottom row. These are described at the bottom of this page.

    • By the headers:-
      • Expand - if you have typed a nickname (alias) from your addressbook you can check that you have chosen the correct one by using this. When you select this button the full address is substituted for the alias. If the alias does not exist in your address book then the default domain (typically @cam.ac.uk, depending on your setting in Manage -> Preferences -> Extra Compose) will be added instead. The status line will change to reflect the result of the action, for example after Expand-ing the To: field:-
        Status:Header To Lookup Complete
      • Rich Headers - the standard header fields are To:, Cc: and Subject:. Selecting the Rich Headers button gives other header fields. These are
        • Bcc: - for use if you wish to send a copy of the message to someone but do not wish the other recipients to see that you have sent a copy to that person
        • Fcc: - in which you can enter the name of a mail folder to which you want the message copied (the default is sent-mail)
        • Reply-To: - by default a reply will come to your address as it appears in the From: field. You can use this if you wish any reply to come to a different address.
    • Above the message body part:
      • Large - takes you to another screen with a larger form area for the body part. The size of this form area is defined in Manage -> Preferences -> Extra Compose.
      • Clear Headers - Clears all message headers.
      • Clear Body - Clears all text entered in the body of the message.
      • Undo - Undoes the last action.
      • Import - takes you to a screen from which you can browse your local file system and choose a text file to include in the body of the message. Files produced by an application such as a word processor cannot be included in the body of a message, but should be attached to the message using the Attachments button.
      • Attachments (0) - takes you to a screen from which you can browse your local file system and choose a file to send as an attachment to the message. Once you have done this the button changes to show the number of attachments that will be sent with the message.
    • Below the message body part:-
      • Check Spelling - this will check the body of the message and allow you to accept suggested alterations, leave the word unchanged or add the word to your personal dictionary. Once the spell check has completed the status field will summarise, for example:-
        Status: Spell Check finished (0 changes made)
      • Cancel - cancels the message and returns you to the Webmail page you came from. The status line will change to reflect the action:-
        Status:Draft message cancelled
      • Postpone - the draft is saved to the mail folder defined to hold these messages (default postponed-messages) and you are returned to the Webmail page you came from. The status line will change to reflect the action:-
        Status:Draft message postponed
        If you have messages in the postponed messages folder then when you select Compose you get the option to continue with a postponed message or start a new one.
      • Send - triggers an immediate send and returns you to the Webmail page you came from.
      • Save copy - This check box controls whether a copy is automatically saved. The default for this, saving a copy to sent-mail, is set in Manage -> Preferences -> Extra Compose.

    Other aspects, such as the size of the text area for the body part, the use of a personal name, and whether a signature is included or not, depend on choices made under Manage -> Preferences -> Compose and Manage -> Preferences -> Extra Compose.

    If you have enabled Manage -> Preferences -> Extra Compose -> Enable manual line wrap options then there will be two extra options on the line below the message body part:

    • Line Wrap - wraps the message to a line length defined in Manage -> Preferences -> Extra Compose -> Line Wrap at . The default is 76 characters.
    • Line Wrap on Send - wraps the text of the message as part of the action of sending the message.
    ./prayer-1.3.5/templates/old/search_text_help.t0000644006513000651300000000572011063710000020043 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_text_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The Search screen allows you to select a set of messages from the current mail folder using different criteria. After you have selected your messages you can take action on them, for example, Mark them all and copy them all to the same folder.

    After the initial search has been made it is possible to add another criterion to refine the selection.

    Text searching allows messages to be selected depending on whether a part of the message Contains or Does not contain the entered string. It is not case sensitive, e.g. choosing web will match both web and Web. The parts (fields) that can be chosen are:

    • From
    • To
    • Cc
    • Recipient - messages with Cc: or To: headers containing the entered string will be selected.
    • Participant - messages with Cc:, To:, or From: headers containing the string will be selected.
    • Subject
    • Text (Expensive!) - this searches all the body text. Please avoid this wherever possible. It puts a heavy strain on <% $g_service_name |h %>.

    Your string does not have to be a complete word or phrase. A search on the Subject string could contain

    When you are searching using an address you do not have to enter the full address, you can use any unique element of that address. Examples are

    Once you have entered your string then choose Search and you will return to the mail folder with just the selected message(s) listed.

    ./prayer-1.3.5/templates/old/display_images.t0000644006513000651300000000056511415373531017535 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_images.t,v 1.2 2010/07/08 16:05:45 dpc22 Exp $ %# % IFDEF $html_images_shown

    cur_msg}/${nav->cur_uid}/${section} |s %>">\ Hide unsafe images

    % ELSE

    cur_msg}/${nav->cur_uid}/${section}/show_images |s %>">\ Show unsafe images

    % ENDIF ./prayer-1.3.5/templates/old/prefs_display.vars0000644006513000651300000000046411063710000020076 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/prefs_display.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $use_icons 1 $use_tail_banner 1 $html_inline 1 $html_inline_auto 1 $preserve_mimetype 1 $sort_combined arrival $abook_sort_combined order $g_cmd prefs_display ./prayer-1.3.5/templates/old/abook_lookup_help.t0000644006513000651300000001405411063710000020216 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_lookup_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The addressbook search results screen has three areas:

    • A search dialogue that will allow you to search again for users on the local system, or against the University Directory.
    • The top and bottom bars, which allow you to navigate around the list of results. Search which generate a lot of results will be split into pages.
    • One result for the current search on each line, with links that affect or use just that entry.

    Search Dialogue

    The search dialogue allows you to make another search. It works in exactly the same way as the search dialogue on the main addressbook screen. Cancel search will cancel the current addressbook search and return you to the addressbook screen.

    Search <% $g_service_name |h %> Users searches for local users on the <% $g_service_name |h %> system. The search is made against the initial registered name of each user (of the form "A.N. Other") and also against the fullname which can be set using this Webmail interface. Please note: the local search database only stores limited numbers of results. Queries that would return large numbers of results (e.g: Smith) will typically return no results and an explanation to this effect. It is also possible to search for details on a particular <% $g_service_name |h %> username or for usernames which match a given set of initials.

    Search Directory searches the University Directory. The results will be more comprehensive than the local search database, but does not contain information about recently cancelled accounts.

    Top and bottom bars

    These have a group of common elements at the left and right hand sides of the bar, and a unique element in the centre.

    Top bar, unique element

    Search Results (1 entry)

    This provides a summary of the results

    Bottom bar, unique element

    Page: /1

    The search results are presented as a series of pages. The number of entries on each page is set in Manage -> Preferences -> Display. This element shows the current page number and the total number of pages. To change to another page in your addressbook enter the number in the Page: box and then select Go

    Common elements

    The four icons, First Previous Next Last, take you to, respectively, the first, previous, next and last page of addresses. An icon is greyed out, as in the example screen on this page, if the choice is not applicable (in the example there is only one page of addresses).

    Search results

    Each search result appears on a separate line.

    • If there is currently no draft message, the individual results will look like this:
      1.dpc22 David Carter
      (D.P. Carter)
      University Computing Service  Add Compose
      • A second name appears in parenthesis if the given individual has set up a name different from the original, registered name.
      • Selecting Add takes you to the Addressbook Entry screen so that you can add the email address to your addressbook.
      • Selecting Compose takes you to the Compose screen, with the address of your choice present in the To: field of the message.
    • If a draft message is active, each search result will look something like:
      1.dpc22 David Carter
      (D.P. Carter)
      University Computing Service  Add To Cc Bcc

      An extra element will be added at the top right:-

      • A second name appears in parenthesis if the given individual has set up a name different from the original, registered name.
      • Selecting Add takes you to the Addressbook Entry screen so that you can add the email address to your addressbook.
      • Use the check boxes to select addresses for the To:, Cc: or Bcc: fields of your message. Check the boxes you want on one search result page, then select the Add marked to draft button. The Status line will be updated to reflect your action, for example
        Status:Added 2 addresses to draft
        After you have done this you can either move to another page of the search results, or select Compose from the main toolbar to return to the Compose screen. If you have chosen addresses these will be added to the relevant header fields of your message.
    ./prayer-1.3.5/templates/old/vacation.vars0000644006513000651300000000034311063710000017032 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/vacation.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $use_vacation 1 $days 31 $days David.Carter@ucs.cam.ac.uk $vacation_msg Gone Fishing $g_cmd vacation ./prayer-1.3.5/templates/old/prefs_display_abook_sort.t0000644006513000651300000000125311063710000021605 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_display_abook_sort.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ Addressbook sort mode: ./prayer-1.3.5/templates/old/sieve_fail.t0000644006513000651300000000072011063710000016623 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/sieve_fail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Sieve Filtering

    Error: <% $msg |h %>

    % CALL footer ./prayer-1.3.5/templates/old/prefs_display1_help.t0000644006513000651300000000702711063710000020461 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_display1_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    • Use icons controls the use of icons and text for links and navigation. If this option is unselected then only text is used. This has additional effects on certain pages. For example in the mail folder list screen the single column (envelope icon) that indicates the status of a message is replaced by three columns D (marked if message deleted), N (showing N for a new message or O for a read message) A (marked if message answered).
    • Duplicate icons below message controls whether a duplicate of the common toolbar (the icons/text appearing at the top of every screen) should appear below messages when they are being viewed.
    • Display text/html sections inline. Many messages have text and HTML parts. If this option is unchecked then, when messages have a Content-Type: text/html header and the HTML section is selected, the raw HTML is shown instead of it being rendered (presented formatted).
    • Display text/* sections starting <html> inline. Some messages are in HTML but do not have the correct (or any) Content-Type headers. These are frequently spam messages. If this option is unchecked these messages are displayed as raw HTML instead of being rendered.
    • Preserve MIME type when downloading attachments controls whether attachments where the type can be handled by the browser (for example images in GIF or JPEG format) are displayed in the browser when the attachment is selected. When the option is checked an attachment of a type the browser can handle is displayed when selected, otherwise the browser's "Save As..." dialogue appears allowing you to save the attachment to your local system for later processing. If the option is unchecked then selecting any attachment will bring up the browser's "Save As..." dialogue.
    • Default folder sort mode affects the way all mail folders are sorted and thus presented. The default is Arrival - messages are presented in the order they arrive in the mail folder. There is a wide range of alternatives, including Date, From and Subject. It is also possible to change the sort order of the current folder in the Mailboxes screen.
    • Messages per page controls the number of messages listed per screen in the message list screen.
    • Addressbook sort mode affects the way that the addressbook is sorted and thus presented. The default is Order - entries are presented in the order they have been added to the addressbook. There is a range of alternatives, including Alias, Name and Comment and Address. It is also possible to change the current sort order on the Addressbook screen.
    • Addressbook entries per page controls the number of addresses listed per screen in the main addressbook screen.
    • Alt Addresses - a comma-separated list of alternative addresses that you use to send email. This controls what is shown in the From column of the message list screen. Messages from any of your defined addresses will show who they are to rather than who they are from.
    ./prayer-1.3.5/templates/old/printable_tail.t0000644006513000651300000000016511063710000017511 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/printable_tail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ ./prayer-1.3.5/templates/old/block_fail.vars0000644006513000651300000000023711063710000017315 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/block_fail.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $msg Error message displayed here $g_cmd block_fail ./prayer-1.3.5/templates/old/copy.t0000644006513000651300000000067011063710000015473 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/copy.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Copy message to folder...

    % CALL copy_toolbar % IFDEF $g_favourites[0] Favourite mail folders: % CALL favlist, $cmd => "copy" Normal mail folders: % ENDIF % CALL folderlist, $cmd => "copy" % CALL copy_toolbar % IFDEF $g_help % CALL copy_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/expunge.vars0000644006513000651300000000017711063710000016706 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/expunge.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $count 42 $g_cmd expunge ./prayer-1.3.5/templates/old/raven_blocked.t0000644006513000651300000000064711063710000017323 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/raven_blocked.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header

    Raven logins not allowed

    Raven logins have been disabled for this account. You will need to log in using the normal <% $g_service_name |h %> username and password

    Click here to return to the login screen

    % CALL footer ./prayer-1.3.5/templates/old/search_text.t0000644006513000651300000000154511063710000017034 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_text.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % CALL search_header, $_type => "Text"
    % CALL search_footer % IFDEF $g_help % CALL search_text_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/include.vars0000644006513000651300000000016311063710000016651 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/include.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd include ./prayer-1.3.5/templates/old/manage.t0000644006513000651300000000321211243457414015765 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/manage.t,v 1.2 2009/08/21 08:47:08 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Account Management

    User Preferences:
    % IFDEF $accountd_server
    Account Management:
    Mail Processing:
    % IFNDEF $using_sieve % ENDIF
    % ENDIF
    Miscellaneous:
    % IFDEF $g_help % CALL manage_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/filter.vars0000644006513000651300000000137311063710000016517 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/filter.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $filters[0]->offset 0 $filters[0]->type_strong SUBJECT $filters[0]->type subject $filters[0]->value Test $filters[0]->mailbox a $filters[1]->offset 1 $filters[1]->type_strong RECIPIENT $filters[1]->type recipient $filters[1]->value dpc99@cam.ac.uk $filters[1]->mailbox a $filters[1]->copy 1 $filters[2]->offset 2 $filters[2]->type_strong SENDER $filters[2]->type sender $filters[2]->value dpc22@cam.ac.uk $filters[2]->mailbox a $filters[2]->copy 1 $g_cmd filter ./prayer-1.3.5/templates/old/toolbar_right.t0000644006513000651300000000117011063710000017354 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/toolbar_right.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % % IFDEF $g_help % CALL tb_icon, $_cmd => "help/$g_cmd", % $_icon => "back", $_alt => "Back" % ELSE % CALL tb_icon, $_cmd => "help/$g_cmd", $_icon => "help", $_alt => "Help" % ENDIF % CALL tb_icon, $_cmd => "logout/$g_cmd", $_icon => "logout", $_alt => "Logout" % IFDEF $g_use_icons % IFDEF $g_help % ELSE % ENDIF % ENDIF
    BackHelp| Logout
    ./prayer-1.3.5/templates/old/copy_help.t0000644006513000651300000000525711063710000016511 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/copy_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The layout is similar to the main mail folders screen. If you have any Favourite Mail Folders these will be listed between the INBOX and the main mail folder listing.

    Saving the message

    • If the folder exists, and you can see it, then select the name of the chosen mail folder, or the folder icon by its name.
    • Use [Expand] to expand collapsed directories.
    • If the folder does not exist you will need to create it.
      • For example selecting mailbox and typing a name such as projects will, once the Create button has been pressed, cause the mail folder listing to change to include the newly created mail folder.
      • Once the folder has been created, select its name or the folder icon by its name.

    The message is copied into the destination folder and you are returned to the message display screen where the status line will be updated, for example:-

    Status: Copied message 12 to mail/saved-messages

    The banner line above and below the message also changes to indicate that the original copy is now marked as deleted, for example:-

    Previous Next | Copy | Undelete | Mark | Reply | Forward
    Message: 12 out of 12
    Show Hdrs | Download Message

    When you return to the mailbox list screen the display is also updated to show the status of the message as deleted.

    The bars above and below the folder listing

    Cancel returns you to the message display page, without saving the message into any folder.
    Refresh checks the contents of the directory on the server.
    ./prayer-1.3.5/templates/old/abook_search.t0000644006513000651300000000562311063710000017144 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_search.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Addressbook Search

    Search for entries where of the following conditions hold

    % FOREACH $f @filters % ENDFOREACH
    % IFDEF $results[0] % IFNEQ $count 1

    <% $count |h %> matches for those search criteria:

    % ELSE

    1 match for those search criteria:

    % ENDIF % FOREACH $r @results % IFDEF $g_have_draft % ELSE % ENDIF % ENDFOREACH
    Alias Name Comment Address  
    <% $r->alias |h %> <% $r->name |h %> <% $r->comment |h %> <% $r->email |h %> To Cc Bcc Compose fresh message
    % ENDIF % IFDEF $g_help % CALL abook_search_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/frontend_timeout.t0000644006513000651300000000043511075051454020123 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/frontend_timeout.t,v 1.3 2008/10/14 08:07:08 dpc22 Exp $ %# % CALL header

    Couldn't connect to session. Maybe it timed out?

    \ Click here to login again

    % CALL footer ./prayer-1.3.5/templates/old/printable_hdrs.t0000644006513000651300000000257611063710000017530 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/printable_hdrs.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %#
    % IFDEF $reply_to[0] % ENDIF % IFDEF $to[0] % ENDIF % IFDEF $cc[0] % ENDIF
    Reply-To: % FOREACH $a @reply_to % CALL printable_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    From: % FOREACH $a @from % CALL printable_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    To: % FOREACH $a @to % CALL printable_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    Cc: % FOREACH $a @cc % CALL printable_addr, $_alias => $a->alias, $_personal => $a->personal, % $_email => $a->email, $_raw => $a->raw, $_next => $a->next % ENDFOREACH
    Date:<% $date |h %>
    Subject:<% $subject |h %>
    ./prayer-1.3.5/templates/old/abook_add_help.t0000644006513000651300000000727311063710000017442 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_add_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The address book form buttons

    • To create an entry complete the fields and then select the Add entry or Add/Update entry button as relevant;
    • To delete an entry select the Delete entry button;
    • To return to the Webmail screen from whence you came, making no changes to your address book, select the Cancel button

    The address book form fields

    • Alias - the nickname by which the entry is known. This can be used as an address shortcut when composing a message.
    • Name - this is an optional field, but is customarily used for the real name of an individual or a relevant name for a list. The entry in this field will appear in any message sent using the alias.
    • Comment - optional - usually used as a short, relevant memory jogger for example "Contact at This Company Ltd.". It does not appear in any message sent using the alias.
    • Address(es)
      • In most cases this will be a single address, as in the example shown at the top of this page.
      • However you can also use the Addressbook to create an entry for a small group of people. In this case the Address field can either be full email addresses of the group members or the aliases of existing addressbook entries. Addresses must be separated by commas, as in this example which uses aliases already existing in the addressbook.
        Alias
        Name
        Comment
        Address(es)

    Hence the following examples would all be be valid entries.
    Note: that the final entry uses existing alias entries, not full email addresses. Remember that you can only use this form of short address if you have an entry for the individual alias.

    Alias Name Comment Address(es)  
    someone A. Person Sales contact at Somewhere Company someone@somewhere.com Compose fresh message
    alien Green Alien   alien@planet.otherdomain.com Compose fresh message
    group   Small group person@company.co.uk, anotherperson@company.co.uk Compose fresh message
    group2     someone, alien Compose fresh message
    ./prayer-1.3.5/templates/old/tb_icon.t0000644006513000651300000000120111063710000016125 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/tb_icon.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# %# Arguments: %# $_cmd Command %# $_icon Icon name %# $_alt Alt text for icon %# % IFDEF $g_use_icons % IFEQ $g_cmd $_cmd <% $_alt |h %> % ELSE <% $_alt |h %> % ENDIF % ELSE % IFEQ $g_cmd $_cmd <% $_alt |h %> % ELSE <% $_alt |h %> % ENDIF % ENDIF ./prayer-1.3.5/templates/old/roles_select_help.t0000644006513000651300000000126111063710000020211 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/roles_select_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Composing, Replying or Forwarding using Roles

    If you have defined one or more roles then, when you choose to compose, reply to, or forward a message, you will enter this screen where you can select the role that you wish to use by selecting the name of the role (e.g. "helpdesk"). Choose Default if you do not wish to use one of your defined roles.

    Once you have chosen the role and selected the correct entry you will enter the main Compose screen.

    Cancel returns you to the Webmail page you came from.

    ./prayer-1.3.5/templates/old/filter.t0000644006513000651300000000243111063710000016003 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/filter.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Automatic Mail Filtering

    % IFDEF $filters[0]
      % FOREACH $f @filters
    1. <% $f->type_strong |h %>: Filter messages with <% $f->type |h %> of "<% $f->value |h %>". Remove this filter.
      • Store in mail folder: <% ${f->mailbox|7} |h %>
      • % IFDEF $f->copy
      • Copy message to inbox
      • % ENDIF
    2. % ENDFOREACH
    % ELSE

    No filter actions defined at the current time

    % ENDIF
    % IFDEF $g_help % CALL filter_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/action_stub.t0000644006513000651300000000047711063710000017040 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/action_stub.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Help Text: Action stub

    That was just a help text example.
    Go back to help page % CALL footer ./prayer-1.3.5/templates/old/filter_select.vars0000644006513000651300000000017711063710000020057 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/filter_select.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd filter_select ./prayer-1.3.5/templates/old/welcome_help.t0000644006513000651300000000062611063710001017166 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/welcome_help.t,v 1.1 2008/09/16 10:52:49 dpc22 Exp $

    This screen is purely informational. On other screens selecting Help takes you to help text appropriate to that screen. There is no overall, standalone, help facility.

    If you do not wish to see the welcome screen again you can unselect the checkbox above.

    ./prayer-1.3.5/templates/old/fullname_help.t0000644006513000651300000000332511063710000017334 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/fullname_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    User accounts are set up on Computing Service systems such as <% $g_service_name |h %> using your registered name. Your registered name consists of your initials and surname, as this is the information that is kept in the Computing Service's database. This is also used to set an initial default on another name field (in the Webmail system this is called your Fullname). Enquiries about your account will show both names. It is not possible to change the registered name, but many people like to replace their initials in the other name field with their given name. This is the purpose of this, Change Fullname, option.

    Note: Fullname is also, by default, the name that appears in the From: field of an email. It is possible to have one name returned by an enquiry to your account, and another name used on outgoing messages from Webmail. If you wish to do this you will also need to set your Webmail Personal Name in Manage -> Preferences -> Compose.

    When you enter the screen a check is made against <% $g_service_name |h %> and the result shown as the Current Fullname entry. To change your entry on <% $g_service_name |h %> enter the name you would like to appear in the Fullname field and then select the Change Fullname button.

    The name that you choose should clearly identify you - using just your first name is not likely to uniquely identify you. Please bear in mind that some "joke" names may be offensive to others. The local database containing your real name is updated once every night.

    ./prayer-1.3.5/templates/old/folderlist_icons.t0000644006513000651300000000331011063710000020055 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/folderlist_icons.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# %# Common code shared by the various folder list screens. %# % FOREACH $f @folder % IFDEF $f->even_row % ELSE % ENDIF %# %# XXX Getting rather messy: better factoring please %# % IFEQ $cmd "folders" % IFNDEF $f->noselect % CALL folderlist_folders, $_name => $f->name, $_type => "mailbox" % ELSE % CALL folderlist_folders, $_name => $f->name, $_type => "directory" % ENDIF % ELSE % IFNDEF $f->noselect % CALL folderlist_nfolders, % $_name => $f->name, $_size => $f->size, $_cmd => $cmd % ELSE % IFEQ $cmd "filter_select" % ELSE % ENDIF % ENDIF % % ENDIF % ENDFOREACH
    % LOOP $f->indent <% $g_alt_pad |n %> % ENDLOOP % IFDEF $f->haschildren % IFDEF $f->expanded <% $g_alt_pad |n %> % ELSE <% $g_alt_pad |n %> % ENDIF % ELSE <% $g_alt_pad |n %> % ENDIF % IFDEF ${fcmd} % IFNDEF $f->noselect [mailbox]  <% ${f->short_name|7} |h %> % ELSE <% $g_alt_pad |n %> <% $f->{short_name|7} |h %> % ENDIF % ELSE [mailbox]  <% $f->{short_name|7} |h %> % ENDIF
    ./prayer-1.3.5/templates/old/search_status_help.t0000644006513000651300000000135211063710000020377 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_status_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The Search screen allows you to select a set of messages from the current mail folder using different criteria. After you have selected your messages you can take action on them, for example, Mark them all and copy them all to the same folder.

    After the initial search has been made it is possible to add another criterion to refine the selection.

    This form allows you to select messages by their status. These are

    • Seen (read)
    • Unseen
    • Deleted
    • Not Deleted
    • Answered
    • Not Answered
    ./prayer-1.3.5/templates/old/compose_postponed.t0000644006513000651300000000162511063710000020262 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose_postponed.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    List of Postponed messages

    % FOREACH $m @list % ENDFOREACH
    Msgno Date First To/Cc/Bcc Size Subject
    <% $m->msgno |h %>. <% $m->date |h %> <% $m->name |h %> <% $m->size |h %> <% $m->subject |h%>

    % IFDEF $g_help % CALL compose_postponed_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/folderlist_noicons.t0000644006513000651300000000264411063710000020423 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/folderlist_noicons.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# %# Common code shared by the various folder list screens. %# % FOREACH $f @folder % IFDEF $f->even_row % ELSE % ENDIF %# %# XXX Getting rather messy: better factoring please %# % IFEQ $cmd "folders" % IFNDEF $f->noselect % CALL folderlist_folders, $_name => $f->name, $_type => "mailbox" % ELSE % CALL folderlist_folders, $_name => $f->name, $_type => "directory" % ENDIF % ELSE % IFNDEF $f->noselect % CALL folderlist_nfolders, % $_name => $f->name, $_size => $f->size, $_cmd => $cmd % ELSE % IFEQ $cmd "filter_select" % ELSE % ENDIF % ENDIF % % ENDIF % ENDFOREACH
    % LOOP $f->indent <% $g_alt_pad |n %>\ % ENDLOOP % IFDEF $f->haschildren % IFDEF $f->expanded [Collapse]\ % ELSE [Expand]\ % ENDIF % ELSE <% $g_alt_pad |n %> % ENDIF   % IFDEF ${fcmd} % IFNDEF $f->noselect [mailbox]  <% ${f->short_name|7} |h %> % ELSE <% $f->{short_name|7} |h %> % ENDIF % ELSE <% $f->{short_name|7} |h %> % ENDIF
    ./prayer-1.3.5/templates/old/vaclog_fail.vars0000644006513000651300000000024111063710000017471 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/vaclog_fail.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $msg Error message displayed here $g_cmd vaclog_fail ./prayer-1.3.5/templates/old/vacation_fail.vars0000644006513000651300000000024511063710000020026 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/vacation_fail.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $msg Error message displayed here $g_cmd vacation_fail ./prayer-1.3.5/templates/old/footer.t0000644006513000651300000000016011063710000016011 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/footer.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# ./prayer-1.3.5/templates/old/list_title.t0000644006513000651300000000214511063710000016674 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list_title.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# # % IFDEF $page_all_marked % IFDEF $g_use_icons None % ELSE None % ENDIF % ELSE % IFDEF $g_use_icons All % ELSE All % ENDIF % ENDIF % IFDEF $g_use_icons Status % ELSE DNA % ENDIF Date From Size Subject Thread Messages ./prayer-1.3.5/templates/old/abook_list_nav_1_noicons.t0000644006513000651300000000117411063710000021463 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list_nav_1_noicons.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFDEF $nav->first_page First % ELSE First % ENDIF | % IFDEF $nav->prev_page Previous % ELSE Previous % ENDIF | % IFDEF $nav->next_page Next % ELSE Next % ENDIF | % IFDEF $nav->last_page Last % ELSE Last % ENDIF ./prayer-1.3.5/templates/old/prefs_general.t0000644006513000651300000000675311063710000017345 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_general.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Preferences

    General Preferences:

    Template Set:
    Main theme:
    Help theme:
    % IFDEF $raven_enable % ENDIF
    Enable welcome screen
    Allow Raven logins
    Confirm expunge
    Confirm logout
    Expunge deleted messages from INBOX on logout
    Use persistent marks (slower, sometimes useful)
       - Zoom automatically after search
       - Unmark messages after aggregate operation

    % IFDEF $g_help % CALL prefs_general_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/display.t0000644006513000651300000000074211063710000016166 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % CALL display_toolbar % IFNDEF $full_hdrs % CALL display_hdrs % ENDIF %# %# Live system inserts message MIME structure and body by hand here %# % IFDEF $g_testrig <% ${message} |n %> % CALL display_toolbar % IFDEF $use_tail_banner % CALL toolbar % ENDIF % IFDEF $g_help % CALL display_help % ENDIF % CALL footer % ENDIF ./prayer-1.3.5/templates/old/fullname.vars0000644006513000651300000000022411063710000017027 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/fullname.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $fullname David Carter $g_cmd fullname ./prayer-1.3.5/templates/old/upload_select.t0000644006513000651300000000161711063710000017346 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/upload_select.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Upload local folder "<% $upload_name |h %>" as folder


    % CALL folderlist, $cmd => "upload_select"
    Upload folder under with name:
    % IFDEF $g_help % CALL upload_select_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/rm.vars0000644006513000651300000000023711063710000015646 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/rm.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $type mailbox $name Mailbox name $g_cmd rm ./prayer-1.3.5/templates/old/list.vars0000644006513000651300000000230111063710000016175 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/list.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ # # $nav contains links to adjacent messages $nav->msg_count 675 $nav->page_current 1 $nav->page_count 1 $nav->first_msg 1 $nav->first_uid 2 $nav->prev_msg 14 $nav->prev_uid 15 $nav->next_msg 34 $nav->next_uid 35 $nav->last_msg 168 $nav->last_uid 169 # State specific to the list screen. $list_msg[0]->num 1 $list_msg[0]->uid 1 $list_msg[0]->date Mar 5 2008 $list_msg[0]->dname dpc22@cam.ac.uk $list_msg[0]->subject Hello World $list_msg[0]->size 3K $list_msg[0]->is_deleted 1 $list_msg[1]->num 2 $list_msg[1]->uid 2 $list_msg[1]->date Mar 19 2008 $list_msg[1]->dname David Carter $list_msg[1]->subject 2nd message $list_msg[1]->size 3K $list_msg[1]->even_row 1 $list_msg[1]->is_answered 1 $list_msg[2]->num 3 $list_msg[2]->uid 73 $list_msg[2]->date Mar 19 2008 $list_msg[2]->dname David Carter $list_msg[2]->subject 3rd message $list_msg[2]->size 5.4M $list_msg[2]->is_seen 1 $g_cmd list ./prayer-1.3.5/templates/old/error.vars0000644006513000651300000000015711063710000016362 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/error.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd error ./prayer-1.3.5/templates/old/abook_list.t0000644006513000651300000000242511063710000016647 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % IFDEF $have_lookup % CALL abook_list_search % ENDIF
    % CALL abook_list_toolbar_top % IFDEF $abook[0] % CALL abook_list_title % % FOREACH $a @abook % IFDEF $a->even_row % ELSE % ENDIF % ENDFOREACH
    <% $a->num |h %>. <% $a->alias |h %> <% $a->name |h %> <% $a->comment |h %> <% $a->email |h %> % IFDEF $g_have_draft To Cc Bcc % ELSE Compose % ENDIF
    % CALL abook_list_toolbar_bottom % ENDIF
    % IFDEF $g_help % CALL abook_list_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/manage_help.t0000644006513000651300000000444711063710000016767 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/manage_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    From here you can access screens that let you configure various aspects of the Webmail system either for the current session or for every future session. These include preferences that affect aspects of the appearance of the system, account management (e.g. changing your password), mail processing (e.g. setting a vacation message) and defining a personal dictionary.

    The option choices

    The choices fall into several categories. Each category has its own specific help page. The categories are:-

    • User Preferences, covering:
      • General - including whether or not the welcome screen should be displayed, and whether or not a you should be asked to confirm a decision to logout.
      • Display - concerned with how message lists and individual messages are displayed.
      • Compose - includes settings for personal name and whether a signature is included or not.
      • Extra Compose - use of the sent-mail folder, the size of the text area for the body part and the spell check language.
      • Folder - options concerned with the use of, and actions on, mail folders.
    • Account Management, covering:
      • Change Password
      • Change Fullname
      • Check Quota
    • Mail Processing, covering:
      • Redirecting your mail to another address
      • Setting up a vacation message
      • Setting up mail filtering and blocks
      • Setting up automatic filtering for Junk Email
      • Advanced Mail filtering, if available on this account
    • Miscellaneous, covering:
      • Personal Dictionary to which you can add words you commonly use that are not in the system dictionary.
      • Roles where, if you have various roles, you can define relevant information - From and Reply-to addresses and a signature.
    ./prayer-1.3.5/templates/old/filter_select.t0000644006513000651300000000076111063710000017346 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/filter_select.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Select Target Mail Folder...

    % CALL filter_select_toolbar % IFDEF $g_favourites[0] Favourite mail folders: % CALL favlist, $cmd => "filter_select" Normal mail folders: % ENDIF % CALL folderlist, $cmd => "filter_select" % CALL filter_select_toolbar % IFDEF $g_help % CALL filter_select_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/passwd.vars0000644006513000651300000000021211063710000016522 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/passwd.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ # # No variables needed. $g_cmd passwd ./prayer-1.3.5/templates/old/search_header.t0000644006513000651300000000134211063710000017273 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_header.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %#

    Mailbox Search (<% $_type |h %>) % IFNEQ $selected 1 (<% $selected |h %> messages out of <% $count |h %> currently selected) % ELSE (1 message out of <% $count |h %> currently selected) % ENDIF

    Search Menus:
    ./prayer-1.3.5/templates/old/fullname.t0000644006513000651300000000143011063710000016317 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/fullname.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Change Fullname

    Current Fullname: <% $fullname |h %>
    Fullname:
    % IFDEF $delay NB: It can take up to <% $delay |h %> for fullname changes to take effect % ENDIF % IFDEF $g_help % CALL fullname_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/prefs_option.t0000644006513000651300000000103011063710000017217 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_option.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# %# Parameters: %# $_value Value for this select option %# $_desc Description for this select option %# $_current Current value, for "selected" %# ./prayer-1.3.5/templates/old/display_mime_msg.t0000644006513000651300000000044411415373531020061 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_mime_msg.t,v 1.2 2010/07/08 16:05:45 dpc22 Exp $ <% "$_name $_type $_size" |h %> Download this section ./prayer-1.3.5/templates/old/display_mime_other.t0000644006513000651300000000057711063710000020404 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_mime_other.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % IFDEF $g_use_icons [paperclip] % ENDIF <% "$_name $_type $_size" |h %> ./prayer-1.3.5/templates/old/Makefile0000644006513000651300000001312511415035753016013 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/Makefile,v 1.4 2010/07/07 08:33:47 dpc22 Exp $ ifeq ($(strip $(RPM_BUILD)), true) include ../../Config-RPM else include ../../Config endif CFLAGS = $(BASECFLAGS) LDFLAGS = $(BASELDFLAGS) TYPE=old TARGETS=templates.a templates_frontend.a T_FILES_FRONTEND=login.t \ frontend_login_error.t frontend_security.t frontend_session.t \ frontend_timeout.t frontend_compose_timeout.t header.t footer.t O_FILES_FRONTEND=_template_index_frontend.o ${T_FILES_FRONTEND:.t=.o} C_FILES_FRONTEND=${O_FILES_FRONTEND:.o=.c} T_FILES=raven_blocked.t \ printable.t printable_tail.t printable_hdrs.t printable_addr.t \ abook_add_help.t abook_add.t abook_list_help.t abook_list_nav_1_icons.t \ abook_list_nav_1_noicons.t abook_list_nav_1.t abook_list_nav_2.t \ abook_list_search.t abook_list.t abook_list_title.t \ abook_list_toolbar_bottom.t abook_list_toolbar_top.t abook_lookup_help.t \ abook_lookup_nav_1_icons.t abook_lookup_nav_1_noicons.t \ abook_lookup_nav_1.t abook_lookup_search.t abook_lookup.t \ abook_search_help.t abook_search.t abook_take_help.t abook_take.t \ abook_transfer_help.t abook_transfer.t abook_update_help.t abook_update.t \ action_stub.t attachments_help.t attachments.t block_fail.t block_help.t \ block.t compose_large_help.t compose_large_top.t compose_postponed_help.t \ compose_postponed.t compose_small_help.t compose_small_top.t compose.t \ compose_toolbar_left.t compose_toolbar_right.t compose_toolbar.t \ copy_help.t copy.t copy_toolbar.t dictionary_help.t dictionary.t \ display_addr.t display_hdrs.t display_help.t display_mime_msg.t \ display_mime_other.t display_mime.t display_mime_text.t \ display.t display_images.t \ display_tail.t display_toolbar_icons.t display_toolbar_noicons.t \ display_toolbar.t download_xfer_error.t error.t expunge.t \ favlist_favourites.t favlist.t favourites_help.t favourites.t \ favourites_toolbar.t filter_fail.t filter_help.t filter_select_help.t \ filter_select.t filter_select_toolbar.t filter.t folderlist_folders.t \ folderlist_icons.t folderlist_nfolders.t folderlist_noicons.t \ folderlist_select.t folderlist.t folders_help.t folders.t folders_toolbar.t \ footer.t fullname_help.t fullname.t header.t include_help.t include.t \ list_help.t list_msgs.t list_nav_1_icons.t list_nav_1_noicons.t \ list_nav_1.t list_nav_2.t list.t list_title.t list_toolbar_bottom.t \ list_toolbar_top.t logout.t logout_raven.t \ manage_help.t manage.t passwd_help.t passwd.t \ prefs_compose1_help.t prefs_compose2_help.t prefs_compose2.t \ prefs_compose.t prefs_display1_help.t prefs_display_abook_sort.t \ prefs_display_folder_sort.t prefs_display.t prefs_folder_help.t \ prefs_folder.t prefs_general_help.t prefs_general.t prefs_option.t \ quota_help.t quota.t redirect_fail.t redirect_help.t redirect.t \ rename_help.t rename.t rename_toolbar.t reply_help.t reply.t restart.t rm.t \ roles_entry_help.t roles_entry.t roles_list_help.t roles_list.t \ roles_select_help.t roles_select.t search_date_help.t search_date.t \ search_footer.t search_header.t search_size_help.t search_size.t \ search_status_help.t search_status.t search_text_help.t search_text.t \ sieve_error.t sieve_error_tail.t sieve_fail.t sieve_help.t sieve.t \ spam_fail.t spam_help.t spam.t spell.t status.t tb_icon_form.t tb_icon.t \ toolbar_help.t toolbar_left.t toolbar_right.t toolbar_stub_help.t toolbar.t \ transfer_help.t transfer.t transfer_toolbar_bottom.t transfer_toolbar_top.t \ upload_select_help.t upload_select.t vacation_fail.t vacation_help.t \ vacation.t vaclog_fail.t vaclog_help.t vaclog.t welcome_help.t welcome.t \ sizes.t sizes_help.t sizes_toolbar.t O_FILES=_template_index.o ${T_FILES:.t=.o} C_FILES=${O_FILES:.o=.c} .PRECIOUS: $(C_FILES) HTML=\ abook_add.html abook_list.html abook_lookup.html \ abook_search.html abook_take.html abook_transfer.html abook_update.html \ attachments.html block_fail.html block.html compose_postponed.html \ compose.html copy.html dictionary.html display.html download_xfer_error.html \ error.html expunge.html favourites.html filter_fail.html \ filter_select.html filter.html folders.html fullname.html include.html \ list.html logout.html logout_raven.html manage.html passwd.html \ prefs_compose2.html prefs_compose.html prefs_display.html prefs_folder.html \ prefs_general.html quota.html redirect_fail.html \ redirect.html rename.html reply.html restart.html rm.html roles_entry.html \ roles_list.html roles_select.html search_date.html \ search_size.html search_status.html search_text.html sieve_error.html \ sieve_fail.html sieve.html spam_fail.html spam.html spell.html \ transfer.html upload_select.html vacation_fail.html vacation.html \ vaclog_fail.html vaclog.html welcome.html EXPAND=../src/template_expand COMPILE=../src/template_compile all: $(TARGETS) test: $(HTML) %.html: %.t %.vars common.vars Makefile $(EXPAND) $@ $* common.vars $*.vars templates_frontend.a: $(O_FILES_FRONTEND) rm -f templates_frontend.a ar q templates_frontend.a $(O_FILES_FRONTEND) templates.a: $(O_FILES) rm -f templates.a ar q templates.a $(O_FILES) %.o: %.c Makefile $(CC) $(CFLAGS) -I../../lib -c $< _template_index_frontend.c: ../src/build_index.pl $(TYPE) $(T_FILES_FRONTEND) > _template_index_frontend.c _template_index.c: ../src/build_index.pl $(TYPE) $(T_FILES) > _template_index.c %.c: %.t Makefile $(COMPILE) $(TYPE) $@ $* install: $(INSTALL) -o $(RO_USER) -g $(RO_GROUP) -m $(PUBLIC_DIR) -d \ $(BROOT)$(PREFIX)/templates/$(TYPE) cp *.t $(BROOT)$(PREFIX)/templates/$(TYPE) cp *.vars $(BROOT)$(PREFIX)/templates/$(TYPE) clean: rm -f $(TARGETS) *.html *.o *.c \#*\# *~ include Makefile.deps ./prayer-1.3.5/templates/old/favourites_help.t0000644006513000651300000001124211063710000017715 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/favourites_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    The Favourites screen allows you to define a list of favourite mail folders. This list appears in the pull-down listing in the common toolbar, replacing the list of default folders. Once you have one or more Favourite mail folders an expanded set of actions becomes available on the Message List screen.

    The layout of the screen is similar to that in the main Mail Folders screen.

    Cancel returns you to the main Mail Folder screen, and no actions are taken.
    Refresh checks the contents of the directory on the server.

    Use [Expand] to expand collapsed directories.

    Selecting favourites

    The Folder icon mailbox indicates that the line refers to a mail folder, and also shows the name of the folder and actions that can be performed on that folder. To make a folder a favourite simply use the Add to Favourites button by the chosen folder.

    Using favourites

    Once you have selected one or more folders to Add to Favourites the status line is updated, for example

    Status: Added mail/test-folder to favourites list

    and the mail folder listing changes and will look something like the following:-


    Favourite mail folders

    Cancel | Refresh
    [mailbox] INBOX Make Preferred  
    Favourite mail folders:      
    [mailbox] mail/mailing-listA Remove from Favourites Make Preferred
    [mailbox] mail/test-folder Remove from Favourites Make Preferred
    Folder list:     
    [mailbox] mailing-listA Add to Favourites  
    [mailbox] received Add to Favourites  
    [mailbox] saved-messages Add to Favourites  
    [mailbox] sent-mail Add to Favourites  
    [mailbox] test-folder Add to Favourites  
    [directory] testdir    
    Cancel | Refresh

    The Make Preferred option allows you to select one mail folder as a dominant favourite. Once you have selected this, the listing for that folder changes, for example selecting the mail/test-folder mail folder changes that line to:-

    [mailbox] mail/test-folder Remove from Favourites Current Preferred

    If you subsequently wish to change your Preferred folder, simply select a different folder to Make Preferred.

    Having a Preferred folder means that that becomes the default folder listed in the pull-down listing in the common toolbar.

    ./prayer-1.3.5/templates/old/search_status.vars0000644006513000651300000000024611063710000020100 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/search_status.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $selected 17 $count 42 $g_cmd search_status ./prayer-1.3.5/templates/old/abook_list_nav_2.t0000644006513000651300000000045711063710000017737 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list_nav_2.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    Add | Transfer | Search
    ./prayer-1.3.5/templates/old/abook_lookup.t0000644006513000651300000000602611063710000017206 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_lookup.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % CALL abook_lookup_search
    % IFNEQ $count 1 % ELSE % ENDIF
    % CALL abook_lookup_nav_1 Search Results (<% $count |h %> entries) Search Results (1 entry)
     
    % IFDEF $have_cancelled % ENDIF % IFDEF $have_phone % ENDIF % FOREACH $i @list % IFDEF $i->even_row % ELSE % ENDIF % IFDEF ${i->registered_name} % ELSE % ENDIF % IFDEF $have_cancelled % ENDIF % IFDEF $have_phone % ENDIF % IFDEF $g_have_draft % ELSE % ENDIF % ENDFOREACH
    # Userid Name (Registered Name) Primary AffiliationCancelled?PhoneAddressbook % IFDEF $g_have_draft % ELSE   % ENDIF
    <% $i->offset |h %>. <% $i->userid |h %><% $i->display_name |h %>
    (<% $i->registered_name |h %>)
    <% $i->display_name |h %><% $i->affiliation |h %><% "CANCELLED" IFDEF ${i->cancelled} |h %><% $i->phone |h %>Add To Cc Bcc Compose
    % CALL abook_lookup_nav_1
    Page: /<% $page_total |h %>
     
    % IFDEF $g_help % CALL abook_lookup_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/status.t0000644006513000651300000000121711063710000016042 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/status.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % % IFDEF $g_status % ELSE % ENDIF % IFDEF $g_service_name % else % endif
    Status: <% ${g_status} |h %>
    Reminder: Logout when you have finished.User currently logged into <% "$g_service_name : $g_user" |h %>User currently logged into Prayer: <% $g_user |h %>
    % IFDEF $g_help % IFDEF $g_help_toolbar % CALL toolbar_help % ELSE % CALL toolbar_stub_help % ENDIF % ENDIF ./prayer-1.3.5/templates/old/filter_help.t0000644006513000651300000000735511063710000017025 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/filter_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This screen enables you to set up basic filtering of incoming messages. An example would be saving all messages from a particular address into a nominated folder. If this is the first time you have used this then on entry the screen will look like:-

    If you have filters in place that have been created either using the Webmail system or using the standard configuration options from the menu interface on <% $g_service_name |h %> then when you enter this screen they will be listed, as in the example below.

    1. SENDER: Filter messages from "spammer at spamdomain.com." Remove this filter.
      • Store in mail folder: mail/spam
    2. SUBJECT: Filter messages with subject of "test". Remove this filter.
      • Store in mail folder:mail/test1

    If you have filters created using the advanced configuration option from the menu interface on <% $g_service_name |h %> then your filters should continue to be maintained in that way. Consequently the screen will not display the list of existing filters. Instead the following message will be shown:

    Error: Manually maintained Sieve file?

    Adding a filter

    The options

    It is possible to:-

    • Filter on Sender: - actually "Return-Path" rather than the more obvious "From:".
      Note: These two headers frequently have the same value. However mailing lists often alter the Return-Path address to something that is specific to that list. You can find the "Return-Path:" line for a particular message by using Show Hdrs on the message display screen.
    • Filter on Recipient: - the contents of the "To" and "Cc" fields of a mail message.
    • Filter on Subject: - this option makes a case independent match against the entire subject line. Use wildcards to make a partial match.

    Messages are filtered into nominated mail folders other than the Inbox, or a nominated mail folder as well as the Inbox.

    Entering the address or subject

    After making the initial choice the address or subject on which you want to filter should be entered. The following wildcards can be used:-

    '?' matches a single character
    '*' matches any number of characters

    Hence the following are all valid entries:-

    spammer@spamdomain.com
    *@jiscmail.ac.uk
    ?art?

    If an invalid entry is made the status message will provide information. For example if you are filtering by sender address and enter just Spammer will result in the status line entry

    Status: Invalid filter: Not a valid <% $g_service_name |h %> account and no domain provided

    and the invalid entry will be cleared from the entry field.

    The effect of the Add filter button

    When you selecting the Add filter button will present you with a list of your mail folders so that you can select the destination folder.

    Removing a filter

    To remove a filter simply select the link Remove this filter by the relevant filter. The status message will change to show which filter was removed, for example

    Status: Removed filter number: 1

    and the filter list will be updated on screen.

    ./prayer-1.3.5/templates/old/login.t0000644006513000651300000000420611071070745015646 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/login.t,v 1.2 2008/10/02 07:01:57 dpc22 Exp $ % IFDEF $g_service_name <% $g_service_name |h %> Webmail service % ELSE Prayer Webmail service % ENDIF % % IFDEF $login_banner

    <% $login_banner |h %>

    % ELSE % IFDEF $service_name

    <% $service_name |h %> Webmail Service

    % ELSE

    Prayer Webmail Service

    % ENDIF % ENDIF %
    Username
    Password
     
    % % IFDEF $ssl_available
    Warning:This is an insecure HTTP session.
      It is strongly recommended that you use SSL encryption if your browser supports it.
      ">Click Here for an SSL enabled login session.
    % ENDIF % ./prayer-1.3.5/templates/old/vaclog_fail.t0000644006513000651300000000072411063710000016767 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/vaclog_fail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Vacation Log

    Error: <% $msg |h %>

    % CALL footer ./prayer-1.3.5/templates/old/spam_fail.vars0000644006513000651300000000023511063710000017161 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/spam_fail.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $msg Error message displayed here $g_cmd spam_fail ./prayer-1.3.5/templates/old/search_size.t0000644006513000651300000000077211063710000017023 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_size.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % CALL search_header, $_type => "Size"
    % CALL search_footer % IFDEF $g_help % CALL search_size_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/list.t0000644006513000651300000000114011063710000015465 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % IFDEF $use_persist
    % ELSE % ENDIF % CALL list_toolbar_top % IFDEF $list_msg[0] % CALL list_title % CALL list_msgs
    % CALL list_toolbar_bottom % ENDIF
    % IFDEF $g_help % CALL list_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/passwd.t0000644006513000651300000000275711064273101016041 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/passwd.t,v 1.2 2008/09/17 21:27:29 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % IFDEF $g_service_name

    Change <% $g_service_name |h %> Password

    % ELSE

    Change Password

    % ENDIF % IFDEF $raven_enable

    Please note: this page changes your <% $g_service_name |h %> login password. Click here to change your Raven (Web single sign on) password.

    % ENDIF

    Restrictions on passwords:

    • Must be at least six characters in length
    • Must contain at least one letter and one non-letter
    % IFDEF $delay NB: It can take up to <% $delay |h %> for password changes to take effect % ENDIF
    Current Password:
    New Password:
    Confirm New Password:
    % IFDEF $g_help % CALL passwd_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/list_nav_2.t0000644006513000651300000000135411063710000016561 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/list_nav_2.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFDEF $use_persist % IFDEF $have_marked % ELSE % ENDIF % IFDEF $have_zoom % ELSE % ENDIF % ELSE % IFDEF $have_marked % ENDIF % ENDIF
    Refresh| Expunge| Unmark All| Mark All| Unzoom| Zoom| Clear Search| Search
    ./prayer-1.3.5/templates/old/abook_update.vars0000644006513000651300000000040011063710000017655 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/abook_update.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $alias Alias goes here $name Name goes here $comment Comment goes here $email Email goes here $g_cmd abook_update ./prayer-1.3.5/templates/old/login.vars0000644006513000651300000000013711071070745016355 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/login.vars,v 1.2 2008/10/02 07:01:57 dpc22 Exp $ ./prayer-1.3.5/templates/old/prefs_compose.vars0000644006513000651300000000056211063710000020075 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/prefs_compose.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $from_personal David Carter $default_from_personal $from_address dpc22@cam.ac.uk $default_from_address dpc22@hermes.cam.ac.uk $default_reply_to Reply to goes here $signature Signature goes here $g_cmd prefs_compose ./prayer-1.3.5/templates/old/attachments.t0000644006513000651300000000171211063710000017032 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/attachments.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % IFDEF $atts[0]

    MIME Attachments

    % FOREACH $a @atts % ENDFOREACH
    <% $a->offset |h %>. <% $a->name |h %> (<% $a->size |h %> bytes) of type <% $a->type |h %> Detach

    % ENDIF

    Attach file:

    File
    % IFDEF $g_help % CALL attachments_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/vacation_fail.t0000644006513000651300000000073411063710000017321 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/vacation_fail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Vacation Message

    Error: <% $msg |h %>

    % CALL footer ./prayer-1.3.5/templates/old/folderlist.t0000644006513000651300000000033011063710000016661 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/folderlist.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % IFDEF $g_use_icons % CALL folderlist_icons, $cmd => $cmd % ELSE % CALL folderlist_noicons, $cmd => $cmd % ENDIF ./prayer-1.3.5/templates/old/attachments_help.t0000644006513000651300000000255211063710000020045 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/attachments_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    To attach a file

    If you decide that you do not wish to attach any file, select the Back to Compose Screen button to return to the Compose screen you came from.

    To attach a file to your message type the name of the file in the File box or use the Browse... button to select one. Once you have chosen the file, selecting the Attach file button will return you to the Attach file screen. The name of the document, and its size and type will be listed. For example:-

    1. Randomfile.pdf (15152 bytes) of type application/pdf Detach

    This gives you the opportunity to cancel the attachment (by using the Detach link by the file name) or to add further attachments.

    Once you have finished selecting attachments you need to select the Back to Compose Screen button to return to the main Compose screen. You will not see the file name there but the Attachments button will change to show the number of files that will be sent as attachments to your message

    You can then continue to edit the message.

    ./prayer-1.3.5/templates/old/sizes_help.t0000644006513000651300000000063711063710000016671 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/sizes_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    This page shows the size of each mailbox on Hermes (in MBytes). This should allow you work out where disk space is being used after a quota warning. Disk use will be almost entirely down to messages with large attachments: these can be picked out by sorting large mailboxes by size.

    ./prayer-1.3.5/templates/old/prefs_compose.t0000644006513000651300000000341411063710000017364 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_compose.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Preferences

    Compose Preferences:

    % IFDEF $default_from_personal % ENDIF % IFDEF $default_from_address % ENDIF
    Personal Name: Default: <% $default_from_personal |h %>
    From Address: Default: <% $default_from_address |h %>
    Default Reply-To:

    Signature:


    % IFDEF $g_help % CALL prefs_compose1_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/sizes.t0000644006513000651300000000051011063710000015647 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/sizes.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Mail Folder Sizes

    % CALL sizes_toolbar % CALL folderlist, $cmd => "sizes" % CALL sizes_toolbar % IFDEF $g_help % CALL sizes_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/folders_toolbar.t0000644006513000651300000000116311063710000017677 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/folders_toolbar.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %
    % CALL folderlist_select
    Refresh | Transfer Folders | Sizes | Favourite Folders
    ./prayer-1.3.5/templates/old/prefs_display_folder_sort.t0000644006513000651300000000224611063710000021770 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_display_folder_sort.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ Default folder sort mode: ./prayer-1.3.5/templates/old/quota.t0000644006513000651300000000140511063710000015647 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/quota.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Disk Quota use

    % FOREACH $l @line % ENDFOREACH
    Used Limit Fraction
    <% $l->type |h %> <% $l->used |h %> <% $l->limit |h %> <% $l->percent |h %>
    % IFDEF $g_help % CALL quota_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/vaclog.vars0000644006513000651300000000023111063710000016475 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/vaclog.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $vaclog Vacation log goes here $g_cmd vaclog ./prayer-1.3.5/templates/old/search_date.t0000644006513000651300000000234711063710000016766 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/search_date.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % CALL search_header, $_type => "Date"
    Date
    % CALL search_footer % IFDEF $g_help % CALL search_date_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/transfer_toolbar_top.t0000644006513000651300000000071511063710000020751 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/transfer_toolbar_top.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    Cancel| Refresh
    ./prayer-1.3.5/templates/old/transfer_help.t0000644006513000651300000000353111063710000017354 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/transfer_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Transfer allows you to upload a local mail folder to <% $g_service_name |h %> or download a mail folder from <% $g_service_name |h %> to your local machine.

    The layout of the screen is similar to that in the main Mail Folders screen. If you have any Favourite Folders these will be listed below the INBOX and above the main folder.

    The top and bottom bars have common elements at the right hand side:-

    Cancel returns you to the main Mail Folder screen, and no actions are taken.
    Refresh checks the contents of the directory on <% $g_service_name |h %>.

    The Right arrow [dir] indicates a sub-directory which can be expanded.

    Downloading a folder

    To download a folder (transfer a mail folder from <% $g_service_name |h %> to your local machine) select the Folder icon  or the Download action by your chosen mail folder then use your browser's "Save" feature to navigate to where you wish to put the folder on your local machine.

    Uploading a folder

    To upload a folder (transfer from your local machine to the directory you are in on <% $g_service_name |h %>) use the form at the bottom of the page:-

    File

    You can type in the name of a mail folder or use the Browse... button to select one. Once you have chosen a mail folder to transfer select the Upload button.

    ./prayer-1.3.5/templates/old/.cvsignore0000644006513000651300000000016411063710201016335 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/.cvsignore,v 1.1 2008/09/16 10:54:57 dpc22 Exp $ *.c *.o *.html *.flc ./prayer-1.3.5/templates/old/display_mime_text.t0000644006513000651300000000054411415373531020260 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_mime_text.t,v 1.2 2010/07/08 16:05:45 dpc22 Exp $ % IFNEQ $_lines 1 <% "$_type, $_lines lines" |h %> % ELSE <% "$_type, 1 line" |h %> % ENDIF Download this text ./prayer-1.3.5/templates/old/spam.t0000644006513000651300000000357611063710000015471 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/spam.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Junk Email (Spam) Filtering

    This option automatically files mail based on how much it looks like junk email (spam).

    Each message is given a score which is higher if the message has more spam-like features. You pick a threshold score above which messages are filtered to a folder named "spam". Thresholds of 10 or more have no effect because high-scoring email is blocked. Thresholds of 4 or less are likely to misclassify legitimate email as spam. The scoring system is tuned to work best with a threshold of 5.

    % IFDEF $spam_enabled % ELSE % ENDIF % ELSE % ENDIF
    Filter threshold: (currently enabled)(currently disabled)
    % IFDEF $spam_purge_enabled % ELSE % ENDIF % IFDEF $using_sieve Purge after: days
    Whitelist (one address per line):
    % IFDEF $g_help % CALL spam_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/abook_list_title.t0000644006513000651300000000144711063710000020053 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list_title.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ # Alias Name Comment Address(es) % IFDEF $g_have_draft % ELSE   % ENDIF ./prayer-1.3.5/templates/old/restart.t0000644006513000651300000000112111063710000016175 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/restart.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header

    Mailbox access error

    % CALL status % IFDEF $raven_token

    If your Raven session timed out you will need to log out and reconnect

    % ENDIF
    % CALL footer ./prayer-1.3.5/templates/old/tb_icon_form.t0000644006513000651300000000127311063710000017161 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/tb_icon_form.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# %# Arguments: %# $_cmd Command %# $_icon Icon name %# $_alt Alt text for icon %# % IFDEF $g_use_icons % IFEQ $g_cmd $_cmd <% $_alt |h %> % ELSE % ENDIF % ELSE % IFEQ $g_cmd $_cmd <% $_alt |h %> % ELSE % ENDIF % ENDIF ./prayer-1.3.5/templates/old/abook_transfer.t0000644006513000651300000000227011063710000017516 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_transfer.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Addressbook Transfer

    Cancel | Export CSV (Outlook) addressbook | Export PINE addressbook
    File:
    % IFDEF $local_pine_abook
    Import from <% $g_service_name |h %> Pine addressbook | Export to <% $g_service_name |h %> Pine addressbook
    % ENDIF % IFDEF $g_help % CALL abook_transfer_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/prefs_compose2.vars0000644006513000651300000000070711063710000020160 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/prefs_compose2.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $use_sent_mail 1 $spell_skip_quoted 1 $line_wrap_on_reply 1 $line_wrap_on_spell 1 $line_wrap_on_send 1 $line_wrap_advanced 1 $line_wrap_len 76 $small_cols 80 $small_rows 14 $large_cols 80 $large_rows 24 $ispell_language british $g_cmd prefs_compose2 ./prayer-1.3.5/templates/old/roles_list_help.t0000644006513000651300000000165511063710000017714 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/roles_list_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $

    Roles are designed to handle cases where you need to compose, reply to, or forward mail wearing another "hat", for example as a webmaster or a member of a helpdesk team. Using Roles you can specify what will appear in the From: and Reply-To: fields of a message and tailor the signature to the role.

    Selecting Add new role brings up a role entry screen to allow the creation of a new role.

    Once you have roles defined these will appear as a list of role names (usually referred to as "aliases") after Existing roles:. Selecting a role name will bring up the roles entry screen to allow alterations to be made to the entry for that role:-

    1. role1
    2. helpdesk
    3. role3
    ./prayer-1.3.5/templates/old/abook_search.vars0000644006513000651300000000060211063710000017644 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/abook_search.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ #$match_all 1 $filters[0]->count 0 $filters[0]->selected name $filters[0]->value value $count 1 $results[0]->alias alias $results[0]->name name $results[0]->comment comment $results[0]->email email $g_cmd abook_search ./prayer-1.3.5/templates/old/filter_select_toolbar.t0000644006513000651300000000076611063710000021075 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/filter_select_toolbar.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %
    % CALL folderlist_select
    Refresh | Cancel
    ./prayer-1.3.5/templates/old/compose_toolbar_right.t0000644006513000651300000000115711063710000021106 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/compose_toolbar_right.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % IFDEF $g_help % CALL tb_icon_form, $_cmd => "help", $_icon => "back", $_alt => "Back" % ELSE % CALL tb_icon_form, $_cmd => "help", $_icon => "help", $_alt => "Help" % ENDIF % CALL tb_icon_form, % $_cmd => "logout", $_icon => "logout", $_alt => "Logout" % IFDEF $g_use_icons % IFDEF $g_help % ELSE % ENDIF % ENDIF
    BackHelp| Logout
    ./prayer-1.3.5/templates/old/display_toolbar.t0000644006513000651300000000367311415373531017735 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_toolbar.t,v 1.3 2010/07/08 16:05:45 dpc22 Exp $ %#
    % IFDEF $g_use_icons % CALL display_toolbar_icons % ELSE % CALL display_toolbar_noicons % ENDIF % IFDEF $nav->deleted % ELSE % ENDIF % IFDEF $use_persist % IFDEF $nav->marked % ELSE % ENDIF % ENDIF % IFDEF $is_postponed_folder % ENDIF
    | cur_msg}/${nav->cur_uid}" |s %>"> Copy| Undelete| Delete| Unmark| Mark| Reply| Forward| Resume
    <% "Message: $nav->cur_msg out of $nav->msg_count" |h %>
    % IFDEF $full_hdrs cur_msg}/${nav->cur_uid}" |s %>">Hide Hdrs % ELSE cur_msg}/${nav->cur_uid}" |s %>">Show Hdrs % ENDIF | cur_msg}/${nav->cur_uid}" |S %>"> Download Message | % IFDEF $section_url cur_msg}/${nav->cur_uid}/${section_url}" |s %>"> Printable Version % ELSE cur_msg}/${nav->cur_uid}" |s %>"> Printable Version % ENDIF
    ./prayer-1.3.5/templates/old/abook_list_nav_1_icons.t0000644006513000651300000000165411063710000021131 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list_nav_1_icons.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFDEF $nav->first_page First % ELSE First % ENDIF % IFDEF $nav->prev_page Previous % ELSE Previous % ENDIF % IFDEF $nav->next_page Next % ELSE Next % ENDIF % IFDEF $nav->last_page Last % ELSE Last % ENDIF ./prayer-1.3.5/templates/old/abook_list.vars0000644006513000651300000000061211063710000017353 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/abook_list.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $abook[0]->num 1 $abook[0]->alias dpc22 $abook[0]->name David Carter $abook[0]->email dpc22@cam.ac.uk $abook[0]->update alias=dpc22&name=David%20Carter&comment=&email=dpc22%40cam.ac.uk $entries 1 entry $page_current 1 $page_total 1 $g_cmd abook_list ./prayer-1.3.5/templates/old/frontend_login_error.t0000644006513000651300000000062211075051454020754 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/frontend_login_error.t,v 1.3 2008/10/14 08:07:08 dpc22 Exp $ %# % CALL header

    Login Failed


    % IFDEF $value Status: <% $value |h %>
    % ENDIF % IFDEF $user

    Please \ try again

    % ELSE

    Please try again

    % ENDIF % CALL footer ./prayer-1.3.5/templates/old/prefs_folder.t0000644006513000651300000000361211070102153017174 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_folder.t,v 1.2 2008/09/29 07:31:55 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Preferences

    Folder Listing Preferences:

    Suppress dotfiles (files starting '.') from folder listing
    Confirm folder deletion
    Mail directory:
    Sent Mail Folder:
    Postponed Messages Folder:

    % IFDEF $g_help % CALL prefs_folder_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/prefs_general.vars0000644006513000651300000000145311063710000020045 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/prefs_general.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $theme_main_name gray $theme_help_name help $themes[0]->name blue $themes[0]->fullname Web Safe Blue $themes[1]->name green $themes[1]->fullname Web Safe Green $themes[2]->name yellow $themes[2]->fullname Web Safe Yellow $themes[3]->name gray $themes[3]->fullname Shades of Gray $themes[3]->selected 1 $themes[4]->name high $themes[4]->fullname High Constrast $themes[5]->name help $themes[5]->fullname Default Help Text theme $use_welcome 1 $confirm_expunge 1 $confirm_logout 1 $use_mark_persist 1 $use_search_zoom 1 $use_agg_unmark 1 $g_cmd prefs_general ./prayer-1.3.5/templates/old/abook_lookup_search.t0000644006513000651300000000144011063710000020526 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_lookup_search.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %#
    Surname:
    ./prayer-1.3.5/templates/old/redirect_fail.t0000644006513000651300000000073411063710000017316 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/redirect_fail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Mail Redirection

    Error: <% $msg |h %>

    % CALL footer ./prayer-1.3.5/templates/old/roles_select.vars0000644006513000651300000000027611063710000017716 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/roles_select.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $roles[0]->name default $roles[1]->name Testing $g_cmd roles_select ./prayer-1.3.5/templates/old/abook_lookup.vars0000644006513000651300000000017511063710000017715 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/abook_lookup.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd abook_lookup ./prayer-1.3.5/templates/old/Makefile.deps0000644006513000651300000003251011063710000016724 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/Makefile.deps,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ abook_add.html: abook_add.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t abook_add_help.t header.t footer.t abook_list.html: abook_list.t status.t toolbar_help.t toolbar_stub_help.t abook_list_toolbar_top.t abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_nav_2.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t footer.t abook_list_title.t abook_list_search.t abook_list_toolbar_bottom.t abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_nav_2.t abook_list_help.t header.t abook_list_nav_1.html: abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_toolbar_bottom.html: abook_list_toolbar_bottom.t abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_nav_2.t abook_list_toolbar_top.html: abook_list_toolbar_top.t abook_list_nav_1.t abook_list_nav_1_icons.t abook_list_nav_1_noicons.t abook_list_nav_2.t abook_lookup.html: abook_lookup.t abook_lookup_search.t abook_lookup_nav_1.t abook_lookup_nav_1_icons.t abook_lookup_nav_1_noicons.t status.t toolbar_help.t toolbar_stub_help.t abook_lookup_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t abook_lookup_nav_1.html: abook_lookup_nav_1.t abook_lookup_nav_1_icons.t abook_lookup_nav_1_noicons.t abook_search.html: abook_search.t abook_search_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t abook_take.html: abook_take.t abook_take_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t abook_transfer.html: abook_transfer.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t abook_transfer_help.t abook_update.html: abook_update.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t abook_update_help.t header.t footer.t action_stub.html: action_stub.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t attachments.html: attachments.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t attachments_help.t header.t footer.t block.html: block.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t block_help.t header.t footer.t block_fail.html: block_fail.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t compose.html: compose.t compose_small_top.t compose_toolbar.t compose_toolbar_right.t tb_icon_form.t compose_toolbar_left.t compose_small_help.t compose_large_top.t compose_large_help.t status.t toolbar_help.t toolbar_stub_help.t header.t footer.t compose_postponed.html: compose_postponed.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t compose_postponed_help.t header.t footer.t compose_toolbar.html: compose_toolbar.t compose_toolbar_right.t tb_icon_form.t compose_toolbar_left.t tb_icon_form.t compose_toolbar_left.html: compose_toolbar_left.t tb_icon_form.t compose_toolbar_right.html: compose_toolbar_right.t tb_icon_form.t copy.html: copy.t copy_help.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t favlist.t favlist_favourites.t copy_toolbar.t folderlist_select.t header.t footer.t copy_toolbar.html: copy_toolbar.t folderlist_select.t dictionary.html: dictionary.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t dictionary_help.t header.t footer.t display.html: display.t display_hdrs.t display_addr.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t display_help.t display_toolbar.t display_toolbar_icons.t display_toolbar_noicons.t header.t footer.t display_hdrs.html: display_hdrs.t display_addr.t display_mime.html: display_mime.t display_mime_other.t display_mime_text.t display_mime_msg.t display_tail.html: display_tail.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t display_help.t display_toolbar.t display_toolbar_icons.t display_toolbar_noicons.t footer.t display_toolbar.html: display_toolbar.t display_toolbar_icons.t display_toolbar_noicons.t download_xfer_error.html: download_xfer_error.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t error.html: error.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t expunge.html: expunge.t header.t footer.t favlist.html: favlist.t favlist_favourites.t favourites.html: favourites.t favourites_toolbar.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t favourites_help.t favlist.t favlist_favourites.t footer.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t header.t filter.html: filter.t filter_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t filter_fail.html: filter_fail.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t filter_select.html: filter_select.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t filter_select_toolbar.t folderlist_select.t favlist.t favlist_favourites.t header.t footer.t filter_select_help.t filter_select_toolbar.html: filter_select_toolbar.t folderlist_select.t folderlist.html: folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.html: folderlist_icons.t folderlist_folders.t folderlist_nfolders.t folderlist_noicons.html: folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folders.html: folders.t folders_help.t folders_toolbar.t folderlist_select.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t folders_toolbar.html: folders_toolbar.t folderlist_select.t fullname.html: fullname.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t fullname_help.t footer.t include.html: include.t include_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t list.html: list.t list_title.t list_toolbar_top.t list_nav_1.t list_nav_1_icons.t list_nav_1_noicons.t list_nav_2.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t list_msgs.t list_toolbar_bottom.t list_nav_1.t list_nav_1_icons.t list_nav_1_noicons.t list_nav_2.t list_help.t header.t footer.t list_nav_1.html: list_nav_1.t list_nav_1_icons.t list_nav_1_noicons.t list_toolbar_bottom.html: list_toolbar_bottom.t list_nav_1.t list_nav_1_icons.t list_nav_1_noicons.t list_nav_2.t list_toolbar_top.html: list_toolbar_top.t list_nav_1.t list_nav_1_icons.t list_nav_1_noicons.t list_nav_2.t logout.html: logout.t header.t footer.t manage.html: manage.t manage_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t passwd.html: passwd.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t passwd_help.t header.t footer.t prefs_compose.html: prefs_compose.t status.t toolbar_help.t toolbar_stub_help.t prefs_compose1_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t prefs_compose2.html: prefs_compose2.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t prefs_compose2_help.t header.t footer.t prefs_display.html: prefs_display.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t prefs_display1_help.t prefs_display_folder_sort.t prefs_option.t prefs_display_abook_sort.t prefs_option.t header.t footer.t prefs_display_abook_sort.html: prefs_display_abook_sort.t prefs_option.t prefs_display_folder_sort.html: prefs_display_folder_sort.t prefs_option.t prefs_folder.html: prefs_folder.t prefs_folder_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t prefs_general.html: prefs_general.t prefs_general_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t quota.html: quota.t quota_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t redirect.html: redirect.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t redirect_help.t header.t footer.t redirect_fail.html: redirect_fail.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t rename.html: rename.t rename_toolbar.t rename_help.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t reply.html: reply.t reply_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t restart.html: restart.t status.t toolbar_help.t toolbar_stub_help.t header.t footer.t rm.html: rm.t header.t footer.t roles_entry.html: roles_entry.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t roles_entry_help.t header.t footer.t roles_list.html: roles_list.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t roles_list_help.t header.t footer.t roles_select.html: roles_select.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t roles_select_help.t header.t footer.t search_date.html: search_date.t search_date_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t search_footer.t search_header.t header.t footer.t search_size.html: search_size.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t search_footer.t search_size_help.t search_header.t header.t footer.t search_status.html: search_status.t search_status_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t search_footer.t search_header.t header.t footer.t search_text.html: search_text.t search_text_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t search_footer.t search_header.t header.t footer.t sieve.html: sieve.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t sieve_help.t header.t footer.t sieve_error.html: sieve_error.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t sieve_error_tail.html: sieve_error_tail.t footer.t sieve_fail.html: sieve_fail.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t spam.html: spam.t spam_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t spam_fail.html: spam_fail.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t spell.html: spell.t header.t footer.t status.html: status.t toolbar_help.t toolbar_stub_help.t toolbar.html: toolbar.t toolbar_right.t tb_icon.t toolbar_left.t tb_icon.t toolbar_left.html: toolbar_left.t tb_icon.t toolbar_right.html: toolbar_right.t tb_icon.t transfer.html: transfer.t transfer_toolbar_bottom.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t favlist.t favlist_favourites.t transfer_toolbar_top.t footer.t transfer_help.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t header.t upload_select.html: upload_select.t upload_select_help.t folderlist.t folderlist_noicons.t folderlist_folders.t folderlist_nfolders.t folderlist_icons.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t vacation.html: vacation.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t vacation_help.t header.t footer.t vacation_fail.html: vacation_fail.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t vaclog.html: vaclog.t vaclog_help.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t vaclog_fail.html: vaclog_fail.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t header.t footer.t welcome.html: welcome.t status.t toolbar_help.t toolbar_stub_help.t toolbar.t toolbar_right.t tb_icon.t toolbar_left.t welcome_help.t header.t footer.t ./prayer-1.3.5/templates/old/abook_list_toolbar_top.t0000644006513000651300000000077711063710000021263 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list_toolbar_top.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ % % ELSE Addressbook (<% $entries |h %> entries) % ENDIF
    % CALL abook_list_nav_1 % IFEQ $entries "1" Addressbook (1 entry) % CALL abook_list_nav_2
    ./prayer-1.3.5/templates/old/abook_lookup_nav_1.t0000644006513000651300000000036111063710000020266 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_lookup_nav_1.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFDEF $g_use_icons % CALL abook_lookup_nav_1_icons % ELSE % CALL abook_lookup_nav_1_noicons % ENDIF
    ./prayer-1.3.5/templates/old/favourites.vars0000644006513000651300000000017111063710000017414 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/favourites.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $g_cmd favourites ./prayer-1.3.5/templates/old/frontend_security.t0000644006513000651300000000040511071070745020301 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/frontend_security.t,v 1.2 2008/10/02 07:01:57 dpc22 Exp $ %# % CALL header

    Security Alert

    Login request did not come from <% $url_prefix |h %>

    % CALL footer ./prayer-1.3.5/templates/old/frontend_session.t0000644006513000651300000000041511075051454020116 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/frontend_session.t,v 1.3 2008/10/14 08:07:08 dpc22 Exp $ %# % CALL header

    Couldn't connect to Webmail session server

    \ Try again later

    % CALL footer ./prayer-1.3.5/templates/old/roles_list.t0000644006513000651300000000147211063710000016701 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/roles_list.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status % IFNDEF $roles[0]

    No roles defined

    % ELSE

    Existing roles:

      % FOREACH $r @roles
    1. alias|u}&personal=${r->personal|u}&from=${r->from|u}&reply_to=${r->reply_to|u}&fcc=${r->fcc|u}&signature=${r->signature|u}" |s %>"> <% $r->alias |h %>
    2. % ENDFOREACH
    % ENDIF
    % IFDEF $g_help % CALL roles_list_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/folderlist_nfolders.t0000644006513000651300000000141511063710000020562 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/folderlist_nfolders.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % IFEQ $_cmd "transfer" Download % ELSE % IFEQ $_cmd "upload_select" Append % ELSE % IFEQ $_cmd "favourites" Add to favourites % ELSE % IFEQ $_cmd "filter_select" Select (save copy to inbox) Select (no copy) % ELSE % IFEQ $_cmd "sizes" <% $_size |h %> % ELSE % ENDIF % ENDIF % ENDIF % ENDIF % ENDIF ./prayer-1.3.5/templates/old/display_toolbar_noicons.t0000644006513000651300000000062011415373531021452 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/display_toolbar_noicons.t,v 1.2 2010/07/08 16:05:45 dpc22 Exp $ %# % IFDEF $nav->prev_msg Previous % ELSE Previous % ENDIF | % IFDEF $nav->next_msg Next % ELSE Next % ENDIF ./prayer-1.3.5/templates/old/make_olist.pl0000644006513000651300000000053011063710000017013 0ustar dpc22dpc22#!/usr/bin/perl # # $Cambridge: hermes/src/prayer/templates/old/make_olist.pl,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $col=1; print " "; foreach $name (@ARGV) { $len=length($name); $name =~ s/\.t$/.o/; if (($col > 1) and (($col + $len) > 76)) { print "\\\n "; $col = 1; } print "${name} "; $col += $len + 1; } print "\n"; ./prayer-1.3.5/templates/old/search_date.vars0000644006513000651300000000214411063710000017471 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/search_date.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $selected 17 $count 42 $day[0]->day 1 $day[1]->day 2 $day[2]->day 3 $day[3]->day 4 $day[4]->day 5 $day[5]->day 6 $day[6]->day 7 $day[7]->day 8 $day[8]->day 9 $day[9]->day 10 $day[10]->day 11 $day[11]->day 12 $day[12]->day 13 $day[13]->day 14 $day[14]->day 15 $day[15]->day 16 $day[16]->day 17 $day[17]->day 18 $day[18]->day 19 $day[19]->day 20 $day[20]->day 21 $day[21]->day 22 $day[22]->day 23 $day[23]->day 24 $day[24]->day 25 $day[25]->day 26 $day[26]->day 27 $day[27]->day 28 $day[28]->day 29 $day[29]->day 30 $day[30]->day 31 $month[0]->name January $month[1]->name Feburary $month[2]->name March $month[3]->name April $month[4]->name May $month[5]->name June $month[6]->name July $month[7]->name August $month[8]->name September $month[9]->name October $month[10]->name November $month[11]->name December $day[24]->selected 1 $month[3]->selected 1 $year 2008 $g_cmd search_date ./prayer-1.3.5/templates/old/filter_fail.t0000644006513000651300000000074011063710000016777 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/filter_fail.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Automatic Mail Filtering

    Error: <% $msg |h %>

    % CALL footer ./prayer-1.3.5/templates/old/folders.vars0000644006513000651300000000114711063710000016667 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/folders.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $fcmd change $dirlist[0]->name a $folder[0]->name INBOX $folder[0]->short_name INBOX $folder[0]->indent 0 $folder[1]->name a $folder[1]->short_name a $folder[1]->expanded 1 $folder[1]->haschildren 1 $folder[1]->even_row 1 $folder[1]->indent 0 $folder[2]->name a/b $folder[2]->short_name b $folder[2]->indent 1 $folder[3]->name a/c $folder[3]->short_name c $folder[3]->even_row 1 $folder[3]->indent 1 $g_cmd folders ./prayer-1.3.5/templates/old/abook_list_toolbar_bottom.t0000644006513000651300000000111611063710000021751 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list_toolbar_bottom.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    % CALL abook_list_nav_1
    Page: /<% $page_total |h %>
    % CALL abook_list_nav_2
    ./prayer-1.3.5/templates/old/download_xfer_error.t0000644006513000651300000000063411063710000020565 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/download_xfer_error.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Download Error:

    Mailbox size <% $size |h %> MBytes exceeds maximum <% $limit |h %> MBytes allowed for transfer.

    Please split the mailbox into sections and try again.

    Back to transfer screen % CALL footer ./prayer-1.3.5/templates/old/folderlist_select.t0000644006513000651300000000115611063710000020227 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/folderlist_select.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %#
    % IFDEF $g_dualuse Create mailbox % ELSE Create % ENDIF under with name
    ./prayer-1.3.5/templates/old/abook_take_help.t0000644006513000651300000000562411063710000017634 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_take_help.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $


    This screen is reached when you click on one of the addresses displayed at the top of a message that is being displayed. It is also reached if you add an address to your addressbook from the directory search screen. The screen is a shortcut allowing you to add addresses directly to your personal addressbook.

    • To create an entry complete the fields and then select Add entry
    • To return to the Webmail screen from whence you came, making no changes to your address book, select the Cancel button

    The address book form fields

    • Alias - the nickname by which the entry is known. This can be used as an address shortcut when composing a message.
    • Name - this is an optional field, but is customarily used for the real name of an individual or a relevant name for a list. The entry in this field will appear in any message sent using the alias.
    • Comment - optional - usually used as a short, relevant memory jogger for example "Contact at This Company Ltd.". It does not appear in any message sent using the alias.
    • Address(es)
      • In most cases this will be a single address, as in the example shown at the top of this page.
      • However you can also use the Addressbook to create an entry for a small group of people. In this case the Address field can either be full email addresses of the group members or the aliases of existing addressbook entries. Addresses must be separated by commas.

    Hence the following examples would all be be valid entries.
    Note: that the final entry uses existing alias entries, not full email addresses. Remember that you can only use this form of short address if you have an entry for the individual alias.

    Alias Name Comment Address(es)  
    someone A. Person Sales contact at Somewhere Company someone@somewhere.com Compose fresh message
    alien Green Alien   alien@planet.otherdomain.com Compose fresh message
    group   Small group person@company.co.uk, anotherperson@company.co.uk Compose fresh message
    group2     someone, alien Compose fresh message
    ./prayer-1.3.5/templates/old/toolbar.t0000644006513000651300000000153011063710000016157 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/toolbar.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %
    % CALL toolbar_left Change to: % CALL toolbar_right
    ./prayer-1.3.5/templates/old/rm.t0000644006513000651300000000146211063710000015137 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/rm.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %# % CALL header

    Confirm <% $type |h %> deletion: "<% ${name|7} |h %>"

    % IFDEF $g_use_icons
    Cancel Okay
    Cancel Okay
    % ELSE
    Cancel Okay
    % ENDIF % CALL footer ./prayer-1.3.5/templates/old/abook_list_search.t0000644006513000651300000000130511063710000020170 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/abook_list_search.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $
    % IFDEF $have_local_lookup % ELSE value="Search Prayer Users" /> % ENDIF % ENDIF % IFDEF $have_ldap_lookup % ENDIF
    Surname:
    ./prayer-1.3.5/templates/old/prefs_compose2.t0000644006513000651300000000652311070102153017454 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/prefs_compose2.t,v 1.2 2008/09/29 07:31:55 dpc22 Exp $ %# % CALL header % CALL toolbar % CALL status

    Preferences

    Extra Compose Preferences:

    % IFDEF $have_aspell_path % ENDIF
    Use sent-mail folder
    Skip quoted text on spell check
    Line wrap on reply
    Line wrap on spell check
    Line wrap on send
    Enable manual line wrap options
    % IFDEF $domains[0] % ENDIF % IFDEF $langs[0] % ENDIF
    Line Wrap at: columns
    Normal Compose window size: columns rows
    Large Compose window size columns rows
    Default domain:
    Spell Check Language:

    % IFDEF $g_help % CALL prefs_compose2_help % ENDIF % CALL footer ./prayer-1.3.5/templates/old/download_xfer_error.vars0000644006513000651300000000024411063710000021272 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/old/download_xfer_error.vars,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ $size 101 $limit 100 $g_cmd download_xfer_error ./prayer-1.3.5/templates/old/copy_toolbar.t0000644006513000651300000000074711063710000017222 0ustar dpc22dpc22%# $Cambridge: hermes/src/prayer/templates/old/copy_toolbar.t,v 1.1 2008/09/16 10:52:48 dpc22 Exp $ %
    % CALL folderlist_select
    Cancel | Refresh
    ./prayer-1.3.5/templates/.cvsignore0000644006513000651300000000016411063701636015573 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/templates/.cvsignore,v 1.2 2008/09/16 09:59:58 dpc22 Exp $ index.c index_frontend.c ./prayer-1.3.5/man/0000755006513000651300000000000011775262602012354 5ustar dpc22dpc22./prayer-1.3.5/man/prayer-ssl-prune.80000644006513000651300000000236011063701635015670 0ustar dpc22dpc22.\" -*- nroff -*- .\" $Cambridge: hermes/src/prayer/man/prayer-ssl-prune.8,v 1.2 2008/09/16 09:59:57 dpc22 Exp $ .Dd 17 August 2008 .Os "The Prayer Webmail Interface" .ds volume-operating-system .Dt PRAYER-SSL-PRUNE 8 .Sh NAME .Nm prayer-ssl-prune .Nd purge stale SSL session data .Sh SYNOPSIS .Nm .Oo Fl -config-file .Ar file Oc .Oo Oo Fl -config-option .Ar name Ns = Ns Ar value Oc .Ar ... Oc . .Sh DESCRIPTION .Nm should be run periodically (e.g. once a day) when using SSL session caching .Cd ( ssl_session_timeout No > 0 in .Pa prayer.cf ) . It removes old transaction logs and stale session data. It accepts the same configuration-overriding options as .Xr prayer 8 and .Xr prayer-session 8 . . .Sh ENVIRONMENT . .Bl -tag -width ".Ev PRAYER_CONFIG_FILE " .It Ev PRAYER_CONFIG_FILE Can be set to specify the configuration file to use. .El . .Sh FILES . .Bl -tag -compact .It Pa /usr/local/prayer/etc/prayer.cf Default configuration file. .It Pa /var/spool/prayer/ssl_scache/ Default location of the SSL session cache database. .El . .Sh SEE ALSO . .Xr prayer 8 , .Xr prayer.cf 5 . .Sh AUTHORS . This manual page was put together by .An "Magnus Holmgren" using documentation written by .An "David Carter" . .\" .Sh BUGS ./prayer-1.3.5/man/prayer.80000644006513000651300000000512011063701635013737 0ustar dpc22dpc22.\" -*- nroff -*- .\" $Cambridge: hermes/src/prayer/man/prayer.8,v 1.2 2008/09/16 09:59:57 dpc22 Exp $ .Dd 17 August 2008 .Os "The Prayer Webmail Interface" .ds volume-operating-system .Dt PRAYER 8 .Sh NAME .Nm prayer .Nd standalone IMAP-based webmail server .Sh SYNOPSIS .Nm .Oo Fl -config-file .Ar file Oc .Oo Oo Fl -config-option .Ar name Ns = Ns Ar value Oc .Ar ... Oc .Op Fl -foreground | -disable-prefork .Oo Fl -disable-session | - .Ar session-options Ar ... Oc . .Sh DESCRIPTION .Nm is the normal frontend daemon in the Prayer Webmail system. It is a simple HTTP server and proxy that serves icons and other static files, but firstly and foremostly forwards requests to the correct backend daemons based on session IDs passed either in cookies or as part of the URL. .Pp The master daemon normally preforks a number of child processes that each will serve a configurable number of requests. The total number of child processes is limited to prevent denial of service attacks. .Pp .Nm accepts the following command-line options: .Bl -tag -width indent .It Fl -config-file Ar file Reads configuration from .Ar file instead of the default. .It Fl -config-option Ar name Ns = Ns Ar value Sets (overrides) the configuration option .Ar name No to Ar value . Any number of options can be specified in this manner. .It Fl -foreground Debug mode. Run a single process in the foreground. .It Fl -disable-prefork Disable preforking. The master daemon will listen for connections on the configured ports and spawn child processes one at a time. .It Fl -disable-session Do not start the session server, .Xr prayer-session 8 . .It Fl - End of .Nm options; remaining options will be passed to .Xr prayer-session 8 . .El . .Sh ENVIRONMENT . .Bl -tag -width ".Ev PRAYER_CONFIG_FILE " .It Ev PRAYER_CONFIG_FILE Can be set to specify the configuration file to use. .It Ev PRAYER_HOSTNAME Local hostname. Overrides the .Cd hostname setting in the configuration file as well as on the command line. .El . .Sh FILES . .Bl -tag -compact .It Pa /usr/local/prayer/etc/prayer.cf Default configuration file. .It Pa /usr/local/prayer/icons/ Location of the standard icons used by the interface. .It Pa /usr/local/prayer/static/ Directory containing other static files; currently only CSS files. .It Pa /var/spool/prayer/sockets/ Pre-configured location of sockets for frontend to backend communication. .El . .Sh SEE ALSO . .Xr prayer-session 8 , .Xr prayer.cf 5 . .Sh AUTHORS . This manual page was put together by .An -nosplit .An "Magnus Holmgren" .No using documentation written by An "David Carter" . .\" .Sh BUGS ./prayer-1.3.5/man/Makefile0000644006513000651300000000200711063701635014005 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/man/Makefile,v 1.2 2008/09/16 09:59:57 dpc22 Exp $ # # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2008 # See the file NOTICE for conditions of use and distribution. ifeq ($(strip $(RPM_BUILD)), true) include ../Config-RPM else include ../Config endif install: PREFIX=$(BROOT)$(PREFIX) VAR_PREFIX=$(BROOT)$(VAR_PREFIX) \ RO_USER=$(RO_USER) RO_GROUP=$(RO_GROUP) \ RW_USER=$(RW_USER) RW_GROUP=$(RW_GROUP) \ PUBLIC_DIR=$(PUBLIC_DIR) PRIVATE_DIR=$(PRIVATE_DIR) \ PUBLIC_FILE=$(PUBLIC_FILE) PRIVATE_FILE=$(PRIVATE_FILE) \ PUBLIC_EXEC=$(PUBLIC_FILE) PRIVATE_EXEC=$(PRIVATE_EXEC) \ BIN_DIR=$(BIN_DIR) INSTALL=$(INSTALL) \ mkdir -p $(BROOT)$(PREFIX)/man mkdir -p $(BROOT)$(PREFIX)/man/man5 mkdir -p $(BROOT)$(PREFIX)/man/man8 $(INSTALL) prayer.cf.5 $(BROOT)$(PREFIX)/man/man5 $(INSTALL) prayer.8 $(BROOT)$(PREFIX)/man/man8 $(INSTALL) prayer-session.8 $(BROOT)$(PREFIX)/man/man8 $(INSTALL) prayer-ssl-prune.8 $(BROOT)$(PREFIX)/man/man8 ./prayer-1.3.5/man/prayer.cf.50000644006513000651300000007637511102315173014337 0ustar dpc22dpc22.\" -*- nroff -*- .\" $Cambridge: hermes/src/prayer/man/prayer.cf.5,v 1.4 2008/10/30 11:28:59 dpc22 Exp $ .Dd 17 August 2008 .Os "The Prayer Webmail Interface" .ds volume-operating-system .Dt PRAYER.CF 5 .Sh NAME .Nm prayer.cf .Nd main Prayer configuration file . .Sh DESCRIPTION . .Pa prayer.cf is the configuration file of .Xr prayer 8 and .Xr prayer-session 8 . . .Sh SYNTAX For the most part, prayer.cf consists of .Ar option No = Ar value pairs, but some configuration items are more complex. All values may be enclosed in double quotes, which are stripped. Quotes must be used if a value contains a .Ql # character. Otherwise, everything following it is treated as a comment. Any line can be folded using a .Ql \(rs character at the end of the line; any linear white space at the beginning of the next line is removed. .Pp Simple options can be of the following types: .Bl -tag . .It Vt string No particular restrictions. .It Vt path A file or directory name. The configuration parser expands occurences of a few macros in settings of this type. See .Cd prefix .No and Cd var_prefix below. .It Vt boolean The following forms are interpreted as .Sy true : .Ql true , .Ql t , and .Ql 1 . The following forms are interpreted as .Sy false : .Ql false , .Ql nil , .Ql 0 . Capitalisation does not matter. . .It Vt number An integer number (sequence of digits 0-9), optionally immediately followed by a single letter .Ql K , causing the number to be multiplied by 1024, or .Ql M multiplying it by 1024 \(pc 1024. . .It Vt time An integer number (sequence of digits 0-9) of seconds, optionally immediately followed by a single case-insignificant letter .Ql s , which has no effect, .Ql m , causing the number to be multiplied by 60, .Ql h , multiplying it by 60 \(pc 60, or .Ql d , for a multiple of 24 \(pc 60 \(pc 60. .It Vt perm A file permission mode; an octal number of exactly four digits, where the first digit must be 0. .El . .Sh OPTIONS . .Bl -tag -width Ds . .It Cd prefix Vt ( string ) , Cd var_prefix Vt ( string ) The values of these options can be referred to as .Li $prefix (or .Li ${prefix} ) , and .Li $var_prefix (or .Li ${var_prefix} ) , respectively, in settings of type .Vt path in the rest of the file. .Pp .Sy Default : No none. Need to be set only if referenced later. . .It Cd prayer_user Vt ( string ) , Cd prayer_uid Vt ( number ) User name or ID to .Xr setuid 2 to if started as root. Either, but not both, must be set and must not specify .Li uid 0 . .Sy Default : none. . .It Cd prayer_group Vt ( string ) , Cd prayer_gid Vt ( number ) Group name or ID to .Xr setgid 2 to if we start off as root. In addition, prayer calls .Xr initgroups 3 if .Cd prayer_user is set. .Sy Default : none. . .It Cd prayer_background Vt ( boolean ) Run prayer as background process. If true, prayer will return as soon as valid configuration is found. .Sy Default : Li true . .It Cd file_perms Vt ( perm ) Create mode for new files. .Sy Default : Li 0640 No if Cd prayer_uid No or Cd prayer_user No is set, otherwise Li 0644 . . .It Cd directory_perms Vt ( perm ) Create mode for new directories. .Sy Default : Li 0750 No if Cd prayer_uid No or Cd prayer_user No is set, otherwise Li 0755 . . .It Cd check_directory_perms Vt ( boolean ) Check existing directories under .Li ${var_prefix} ? .El . .Ss Mail server settings . .Bl -tag -width Ds .It Cd imapd_server Vt ( string ) Specifies the default IMAP server(s) using libc-client syntax: .Bd -literal -offset indent .Sm Ar host Oo : Ar port Oc Op / Ar flag Oo / Ar flag Oc Ar ... .Sm on .Ed .Pp Multiple server specifications can be listed, separated by commas. Common flags are: .Bl -tag -compact .It Li /ssl Use SSL-on-connect (on port 993 by default). .It Li /tls Force use of TLS (using STARTTLS on the normal IMAP port) to encrypt the session. Recommended if the server is remote, since otherwise a downgrade attack is possible. .It Li /notls Don't issue STARTTLS even if the server supports it. Recommended if the server is .Li localhost . .It Li /novalidate-cert Don't check the integrity of the server certificate. .El For the full list of flags, see naming.txt.gz in the current libc-client package. . .It Cd imapd_user_map Vt ( path ) CDB lookup map overriding default imapd_server location. For information on CDB, see .Bl -bullet -compact .It http://cr.yp.to/cdb.html .It http://en.wikipedia.org/wiki/Constant_Data_Base .El . .It Cd prefs_folder_name Vt ( string ) Name of Prayer user preferences folder on IMAP server. . .It Cd use_namespace ( Vt boolean ) Use IMAP NAMESPACE command to find .Cd personal_hierarchy No and Cd hiersep . .Sy Default : Li true . . .It Cd personal_hierarchy ( Vt string ) If not supplied by NAMESPACE. .Sy Default : Li """""" . . .It Cd hiersep ( Vt string ) If not supplied by NAMESPACE. .Sy Default : Li """/""" . . .It Cd dualuse ( Vt boolean ) Hint to Prayer that new mailboxes are dual use (i.e. can contain both mail and inferior mailboxes). Things will mostly work if dualuse set to .Li false No on a server which supports it, but people will be unable to create children of newly created mailboxes without refreshing the view. .Pp .Sy Default : Li false . . .It Cd sieved_server Vt ( string ) Talk to Cyrus timsieved using MANAGESIEVE protocol. Syntax is similar to .Cd imapd_server , except the only recognised flag is .Li /ssl . . .It Cd sieved_user_map Vt ( path ) Can be used to provide individualised imapd_server settings in the form of a CDB file. . .It Cd sieved_timeout Vt ( time ) Default timsieved timeout is 10 minutes .El . .Ss Mail domain configuration . .Bl -tag -width Ds . .It Cd local_domain Define a valid local domain, and optionally the valid local parts in that domain. This is a special directive that can appear multiple times and does not use an equals sign: .Bd -unfilled .Cd local_domain Ar domain Op Ar map .Ed .Pp .No Without Ar map , Cd local_domain simply defines a domain which will appear on the list visible to user preferences. With .Ar map , it also defines a list a CDB map file which defines valid entries in that domain; used for personal name expansion and checking for valid addresses: The keys are the valid local parts and the values are the corresponding full names of the users. .Pp .Sy Default : No A single entry which corresponds to .Cd default_domain . . .It Cd return_path_domain Vt ( string ) Domain used in the return address given to .Xr sendmail 8 . .Sy Default : No the default domain. . .It Cd filter_domain_pattern Vt ( string ) A filter pattern which is equivalent to, or at least approximates the list of local domains. .Sy Default : No the default domain. . .It Cd hostname Vt ( string ) Hostname is the canonical name for this particular system, used in session and icon URLs which are generated by Prayer. This is derived automatically using .Xr gethostname 2 .No and Xr gethostbyname 3 if no value is provided. However, there are situations, especially involving SSL certificates, where the default hostname may not be appropriate. The special value .Ql __UNDEFINED__ here means the startup script or command line must provide a hostname using a .Fl -config-option override or via the environment variable .Ev PRAYER_HOSTNAME . This is just a safeguard for systems which use DNS round robining to distribute load across a number of machines. . .It Cd hostname_service Vt ( string ) Host name common for all Prayer installations part of the same webmail service. (Only) useful for large installations using DNS round robin for load balancing (example: webmail.hermes.cam.ac.uk is an alias for webmail[123].hermes.cam.ac.uk). This setting is used for two things: The user is redirected to this hostname after logging out, and HTTP requests are sanity checked against it in addition to the canonical hostname. .Pp .Sy Default : No none . .It Cd fix_from_address ( Vt boolean ) suppresses the From address option from the Preferences and Roles screens. .Sy Default : Li false . . .It Cd lookup_rpasswd ( Vt path ) Path to a CDB file that maps arbitrary search keys to colon- or comma-separated lists of user names. .Sy Note : No Keys must be Em lowercase ; Prayer converts search strings to lowercase in order to provide case-insensitive lookup. . .It Cd lookup_rusername ( Vt path ) Path to a second CDB file that maps arbitrary search keys to colon- or comma-separated lists of user names. .Pp If the user enters a valid and existing username according to .Xr getpwnam 3 , Prayer does not search these first two CDB files, but skips directly to the second stage of looking up user information. . .It Cd lookup_username ( Vt path ) Path to a CDB file that maps usernames to records consisting of the user's .Dq registered name and his/her affiliation (department), separated by a vertical bar .Ql ( "|" ) . Additionally, if a second vertical bar follows, the account is regarded as cancelled. .Pp When presenting the search results, the usernames found are combined with the .Cd default_domain to form email addresses. It is not possible at this time to let users search for addresses in more than one domain using this facility. . .It Cd lookup_fullname ( Vt path ) Path to a CDB file that maps usernames to .Dq display names , possibly provided by the users themselves in some way. The display name of a user is used together with the email address in recipient fields .Pp Note that all four lookup options must be set to valid CDB files for the local lookup to work, but more than one option may conceivably point to the same file. . .It Cd ldap_server ( Vt string ) Name or address of LDAP server. . .It Cd ldap_base_dn ( Vt string ) Base DN to search. After binding anonymously, Prayer performs a one-level-scope search for entries with .Li surname No or Li mail No attributes containing the search string. The following attributes are fetched and presented: .Bl -bullet -compact .It .Li uid .It .Li displayName .It .Li cn Dq ( registered name ) .It .Li ou Dq ( affiliation ) .It .Li mail .It .Li telephoneNumber .El . .It Cd ldap_timeout ( Vt time ) Search timeout. .Sy Default : Li 30s . .El . .Ss HTTP and other frontend settings . .Bl -tag -width Ds . .It Cd use_http_port , use_https_port Define a single HTTP[S] port to bind to. You can define an arbitary list of ports of both kinds by using a series of separate .Cd use_http_port No and Cd use_https_port directives, with one port on each line. Syntax: .Bd -literal -offset indent .Cd use_http_port Oo Ar interface : Oc Ns Ar port .Cd use_https_port Oo Ar interface : Oc Ns Ar port .Ed .Pp .Ar interface can be an IP (v4 or v6) address or a hostname. If provided, it is passed to .Xr getaddrinfo 3 for resolution, and the first resulting address is used to bind to. Otherwise, .Xr prayer 8 .No binds to Ar port No on all interfaces. . .It Cd ssl_default_port Vt ( number ) Prayer will put a warning on the login page for HTTP connections if both HTTP and HTTPS sessions are available. This will provide a link to the SSL version of the service, defaulting to port 443 or failing that the first defined HTTPS port. ssl_default_port overrides the built in logic. .Pp Should be rarely required now that Prayer automatically derives an appropriate port if none is provided here. . .It Cd ssl_cert_file Vt ( path ) Locatation of SSL certificate file (only used if SSL ports defined). Required if we are going to provide SSL services. . .It Cd ssl_privatekey_file Vt ( path ) Location of SSL private key file (only used if SSL ports defined). Required if we are going to provide SSL services. . .It Cd ssl_rsakey_lifespan Vt ( time ) Master server will regenerate shared RSA key at this interval. .Sy Default : Li 15m . . .It Cd ssl_rsakey_freshen Vt ( time ) RSA key remains fresh in child process for this long after first actual use. .Sy Default : Li 15m . . .It Cd ssl_session_timeout Vt ( time ) SSL session cache TTL. .Sy Default : Li 0 No (SSL session cache not used). .Xr prayer-ssl-prune 8 should be run periodically to purge any stale session data from the DBD database. . .It Cd egd_socket Vt ( path ) Path to entropy gathering daemon socket. If provided, it will be used in place of or in addition to .Pa /dev/urandom . .It Cd contact_email Vt ( string ) System administrator email address. .Sy This setting is currently not used. If you want to display support information to your users, customise the templates. . .It Cd fatal_dump_core Vt ( boolean ) Dump core on .Fn fatal error. .Sy Default : No false. . .It Cd log_debug Vt ( boolean ) Enable somewhat more verbose logging, mainly in relation to SSL. .Sy Default : No false. . .It Cd fix_client_ipaddr Vt ( boolean ) Client must connect from consistent IP addresses. May be useful as a security measure in LAN environments. Painful for dialup users whose connections may drop out. .Sy Default : No false. . .It Cd gzip_allow_nets Vt ( string ) , Cd gzip_deny_nets Vt ( string ) .Xr prayer-session 8 gzip-compresses pages sent to clients if: .Bl -enum -compact .It gzip compression enabled at compile time, .It .Cd use_gzip No is set in user preferences, .It User agent is known to support Content-Encoding: gzip, .It User agent asks for Content-Encoding: gzip or x-gzip, .It IP address of client appears in .Cd gzip_allow_nets .Em or No IP address of client does Em not No appear in Cd gzip_deny_nets . .El .Pp The format of these options is a sequence of .Ar ipaddr Ns Op / Ns Ar masklen items, separated by colons .Em and No whitespace (to allow for IPv6 addresses to be parsed easily). If .Ar masklen No is omitted, the item is interpreted as a full host address. . .It Cd log_name_nets Vt ( string ) A network list in the same format as .Cd gzip_allow_nets above. To avoid delay when a user logs in, .Xr prayer-session 8 only performs a reverse lookup of the remote address if matches this list. .Sy Default : No empty; no reverse lookup are performed. . .It Cd limit_vm Vt ( number ) Virtual memory limit imposed on each process to stop runaway process killing system. See .Xr setrlimit 2 . .Sy Default : No no limit. . .It Cd http_max_method_size Vt ( number ) Prayer should in theory be able to cope with input of arbitrary size. In practice however, the incoming request has to be stored somewhere and without limits an attacker may exhaust available memory, causing a denial of service attack. .Pp This sets the maximum size of the initial line of an HTTP request. .Sy Default : No no limit. . .It Cd http_max_hdr_size Vt ( number ) Maximum for headers associated with this request. . .It Cd http_max_body_size Vt ( number ) Maximum for HTTP payload. This is the most significant one in normal use. . .It Cd draft_att_single_max ( Vt number ) Maximum size of a single attachment when composing a mail. .Sy Default : Li 0 No (unlimited). . .It Cd draft_att_total_max ( Vt number ) Maximum size of all attachments. .Sy Default : Li 0 No (unlimited). . .It Cd http_min_servers Vt ( number ) Minimum number of preforked .Xr prayer 8 HTTP servers. The master process forks new slave processes whenever the number of idle slaves falls below this number, unless the total number of slaves would exceed .Cd http_max_servers . .Sy Default : Li 4. . .It Cd http_max_servers Vt ( number ) Maximum number of preforked .Xr prayer 8 HTTP servers (active and idle). The master process does not, however, enforce any maximum number of .Em idle No slave processes; they have to terminate voluntarily by timing out or serving the maximum number of connections. .Sy Default : Li 64 . . .It Cd http_max_connections Vt ( number ) Maximum number of connections that each frontend server will process. .Sy Default : Li 0 No (no limit). . .It Cd http_timeout_idle Vt ( time ) Timeout for (dirty) spare server waiting for another HTTP connection. .Sy Default : Li 30s . . .It Cd http_timeout_icons Vt ( time ) Timeout for HTTP connection that last served static content. .Sy Default : Li 10s . . .It Cd http_timeout_session Vt ( time ) Timeout for HTTP connection that last served a session URL or has not served anything yet. .Sy Default : Li 60s . . .It Cd http_cookie_use_port Vt ( boolean ) Present HTTP cookies to browser as .Dq Li username:port=value rather than .Dq Li username=value . Allows simultaneous login sessions from a single client browser. However can leave a trail of cookies behind. Probably don't want this in the long term, it's here for experimentation purposes only at the moment. . .It Cd icon_expire_timeout Vt ( time ) The amount of time in the future to set the HTTP .Li Expires: No field for static content. .Sy Default : Li 7d . (In contrast sessions URLs expire immediately: Browsers really shouldn't be trying to cache this stuff, especially when it is coming in over HTTPS). .El . .Ss Session specific configuration . .Bl -tag -width Ds . .It Cd session_idle_time Vt ( time ) Session switches to idle mode after this much time: connections to IMAP and accountd servers are shut down. .Sy Default : Li 0 No (idle mode disabled). . .It Cd session_timeout Vt ( time ) Session terminates after this much idle time. .Ql 0 means session never times out. .Sy Default : Li 4h . . .It Cd session_timeout_compose Vt ( time ) Session terminates after this much idle time instead when the last command was .Ql compose .No or Ql sieve . It should probably not be set lower than .Cd session_timeout . .Sy Default : Li 0 No (always use the same timeout). . .It Cd stream_ping_interval Vt ( time ) Ping INBOX, Other, and Draft streams at this interval. .Sy Default : Li 5m . . .It Cd stream_checkpoint Vt ( boolean ) .No Use Li CHECKPOINT No instead of Li PING Li to \(lqping\(rq streams. .Sy Default : Li true . . .It Cd stream_misc_timeout Vt ( time ) Shut down Postponed, Preferences and Transfer streams entirely after this much idle time, but only if idle mode doesn't beat us to it. .Sy Default : Li 0 No (disabled). . .It Cd log_ping_interval Vt ( time ) .Xr stat 2 log files at this interval to see if target file has been renamed or removed. .Ql 0s means stat() log file every time something is logged. .Sy Default : Li 5m . . .It Cd db_ping_interval Vt ( time ) Interval at which to re-read CDB files containing the local domain. .Sy Default : Li 30m . . .It Cd recips_max_msg Vt ( number ) Maximum number of recipients per message. .Sy Default : Li 0 (unlimited). . .It Cd recips_max_session Vt ( number ) Maximum number of recipients per session. Automatically creates file in .Cd sending_block_dir if limit reached and that is defined. .Sy Default : Li 0 (unlimited). . .It Cd sending_allow_dir Vt ( path ) Create empty file named user in this directory to disable .Cd recips_max_session for that user. . .It Cd sending_block_dir Vt ( path ) Create empty file named user in this directory to disable outgoing email for that user (automatic defense against phishing attacks). . .El .Ss Display specific configuration . .Bl -tag -width Ds .It Cd login_banner Vt ( string ) Used in the .Li and heading of the login page .Sy Default : Li """Webmail Service Login""" . . .It Cd login_service_name Vt ( string ) Used in the .Li <title> No and elsewhere to refer to the webmail system .Em after No the user has logged in. .Sy Default : Li """Prayer""" . . .It Cd login_template Vt ( string ) Template to use on the login screen. . .It Cd login_insert1_path Vt ( path ) Optional file to include in login page template (as $login_insert1). . .It Cd login_insert2_path Vt ( path ) Optional file to include in login page template (as $login_insert2). . .It Cd motd_path Vt ( path ) File to use as the part of the login page immediately following the login form. . . .It Cd ssl_encouraged ( Vt boolean ) If the user connects over unencrypted HTTP, do not show the login form on the start .Pa ( / ) No page. A link to Pa /login , No where the form is still displayed, is still provided. .Sy Default : Li false . No Ignored if Cd ssl_redirect No or Cd ssl_required No is Li true . . .It Cd ssl_redirect ( Vt boolean ) If the user connects over unencrypted HTTP, return a .Ql 302 redirect to the default SSL port. Only the start .Pa ( / ) No page is redirected and it may be possible to switch between http and https after loggin in, subject to cookie rules. .Pp .Sy Default : Li false . . .It Cd ssl_required ( Vt boolean ) Return a .Ql 403 Forbidden error if the user tries to access anything over unencrypted HTTP. .Cd ssl_redirect No still has effect, however. . .It Cd list_addr_maxlen Vt ( number ) The maximum number of characters to show from addresses on the mailbox list screen. .Sy Default : Li 30 . . .It Cd list_subject_maxlen Vt ( number ) The maximum number of characters to show from the subject on the mailbox list screen. .Sy Default : Li 30 . . .It Cd change_max_folders ( Vt number ) The maximum number of folders allowed in the quick folder change dropdown list. If there would be too many folders, the quick list is disabled altogether. Only folders that are expanded in the folder view are included. .Pp .Sy Default : Li 20 . . .It Cd template_path ( Vt path ) Path to uncompiled template sets (directories). .Sy Default : Li """../templates""" No (relative to .Cd tmp_dir ) . . .It Cd template_set ( Vt string ) Template set to use. .Sy Default : Li """xhtml_strict""" . . .It Cd template_use_compiled ( Vt boolean ) Use the compiled-in templates, ignoring .Cd template_path . .Sy Default : Li true . . .It Cd theme Define themes and their colors. .Em Semi-deprecated ; No Colours set with this directive are only used by the .Li xhtml_transitional No template set. The .Li xhtml_strict No template set, as well as the login screen, use CSS instead. It is still necessary to tell Prayer which themes are available, however. .Pp Syntax: .Bd -literal -offset indent .Cd theme Ar name Li description Ar description .Cd theme Ar name element colour .Cd theme Ar name element colour \&... .Ed .Pp .Ar description No is the label shown in the theme dropdown lists on the General Preferences page. .Pp .Ar element No is one of .Li fgcolor , fgcolor_link , bgcolor , bgcolor_banner , bgcolor_row1 , bgcolor_row2 , .Li bgcolor_status , bgcolor_status_none , fgcolor_quote1 , fgcolor_quote2 , .Li fgcolor_quote3 , No and Li fgcolor_quote4 . The first three are not used by any standard template set, but are available. Please study the templates to understand how the rest are used. .Pp .Ar colour No is any valid HTML Vt %Color No value. Remember that strings containing hash marks need to be quoted. .It Cd theme_default_main ( Vt string ) .No The Ar name No of the default theme. . .It Cd theme_default_main ( Vt string ) .No The Ar name No of the default theme in help mode. . .It Cd use_ispell_language Ispell languages that we want to support, with some descriptive text for the preferences screen. Syntax: .Bd -literal -offset indent .Cd use_ispell_language Ar wordlist Ar description .Ed .Pp Example: .Bd -literal -offset indent .Li use_ispell_language british Qq British English .Ed .El . .Ss Paths etc. . .Bl -tag -width Ds . .It Cd aspell_path ( Vt path ) Location of Aspell Binary (takes precedence over .Cd ispell_path ) . . .It Cd bin_dir ( Vt path ) Location of Prayer binaries .Xr ( prayer 8 and .Xr prayer-session 8 ) . .Sy Default : No none. Sy Must be set. . .It Cd icon_dir ( Vt path ) Location of icon files. .Sy Default : No none. Sy Must be set. . .It Cd ispell_path ( Vt path ) Location of Ispell Binary (backwards compatibility only). . .It Cd log_dir ( Vt path ) Location of log files. .Sy Default : No none. Sy Must be set. . .It Cd pid_dir ( Vt path ) Location for PID files of prayer and prayer-session master processes. .Sy Default : No none. Sy Must be set. . .It Cd sendmail_path ( Vt path ) Location of sendmail binary or drop in replacement such as Exim. .Sy Default : Pa /usr/lib/sendmail . . .It Cd socket_dir ( Vt path ) Location for unix domain sockets which connect .Xr ( prayer 8 to .Xr prayer-session 8 ) . . .It Cd socket_split_dir ( Vt boolean ) Split socket directory into 64 subdirs keyed on first letter of sessionID. It is possible to switch back and forth without moving sockets or killing sessions, since .Xr prayer 8 tries both variants. \&In effect, this setting merely controls where .Xr prayer-session 8 creates the socket files. .Sy Default : Li false . . .It Cd init_socket_name ( Vt string ) Name of Unix domain socket (in .Cd socket_dir ) No used for initial handshake between prayer and prayer-session processes when a user logs in. .Sy Default : No none. Sy Must be set. . .It Cd ssl_session_dir ( Vt path ) Location of the SSL session cache database. .Sy Default : No none. Sy Must be set , No even if the SSL session cache is disabled. . .It Cd static_dir ( Vt path ) Location of other static files (CSS). .Sy Default : No none. If unset, Prayer will not serve CSS files. . .It Cd tmp_dir ( Vt path ) As the directory both daemons .Xr chdir 2 to at startup, it is where temporary files, such as attachments and folders in transist during upload and download operations, are written. Core files also end up here. .Sy Default : No none. Sy Must be set. .El . .Ss Defaults for user preferences . .Bl -tag -width Ds . .It Cd confirm_logout ( Vt boolean ) Confirmation dialogue when user logs out. .Sy Default : Li true . . .It Cd confirm_expunge ( Vt boolean ) Confirmation dialogue when user hits expunge. .Sy Default : Li false . . .It Cd confirm_rm ( Vt boolean ) Confirmation dialogue when user deletes mail folder or directory. .Sy Default : Li true . . .It Cd default_domain Vt ( string ) Default domain for outgoing mail. Defaults to .Cd hostname No setting. . .It Cd expunge_on_exit ( Vt boolean ) Expunge deleted messages from inbox automatically on logout. .Sy Default : Li false . . .It Cd html_inline ( Vt boolean ) Show text/html bodyparts inline. Content is scrubbed to remove dangerous tags. text/html will be displayed in preference to text/plain if this is set .Sy Default : Li true . . .It Cd html_remote_images ( Vt boolean ) Show remote images automatically. If this is not set, "Show unsafe images" links will appear on pages showing HTML mail. .Sy Default : Li false . . .It Cd html_inline_auto ( Vt boolean ) Same as above for text/* bodyparts which start "<HTML>" (case-independent!) Does anyone other than spammers actually use this? .Sy Default : Li true . . .It Cd ispell_language ( Vt string ) Language for ispell. .Sy Default : Li """british""" . . .It Cd msgs_per_page ( Vt number ) Number of messages per screen on message list screen. .Sy Default : Li 12 . . .It Cd msgs_per_page_max ( Vt number ) Maximum value that users are allowed to set .Cd msgs_per_page No to. .Sy Default : Li 50 . . .It Cd msgs_per_page_min ( Vt number ) Minimum value that users are allowed to set .Cd msgs_per_page No to. .Sy Default : Li 4 . . .It Cd abook_per_page ( Vt number ) Number of addressbook entries per page on address book list screen. .Sy Default : Li 12 . . .It Cd abook_per_page_max ( Vt number ) Maximum value that users are allowed to set .Cd abook_per_page No to. .Sy Default : Li 50 . . .It Cd abook_per_page_min ( Vt number ) Minimum value that users are allowed to set .Cd abook_per_page No to. .Sy Default : Li 4 . . .It Cd maildir ( Vt string ) Mail directory in user's account. .Sy Default : Li """""" . Typically needed with uw-imap. Typically not needed with e.g. Dovecot or Courier. . .It Cd suppress_dotfiles ( Vt boolean ) Supress dotfiles from directory listing. .Sy Default : Li true . . .It Cd postponed_folder ( Vt string ) Name of the folder where messages to be sent later, a.k.a. drafts, are stored. .Sy Default : Li """postponed-msgs""" . . .It Cd sent_mail_folder ( Vt string ) Name of folder for sent mail. .Sy Default : Li """sent-mail""" . . .It Cd small_cols ( Vt number ) Width of small compose textarea in columns. .Sy Default : Li 80 . . .It Cd small_rows ( Vt number ) Height of small compose textarea in lines. .Sy Default : Li 18 . . .It Cd large_cols ( Vt number ) Width of large compose textarea in columns. .Sy Default : Li 80 . . .It Cd large_rows ( Vt number ) Height of large compose textarea in lines. .Sy Default : Li 32 . . .It Cd sort_mode ( Vt string ) Default Sort mode for mailbox list. One of .Li ARRIVAL , DATE , FROM , TO , CC , SIZE , SUBJECT , REFERENCES , ORDEREDSUBJECT . .Sy Default : Li ARRIVAL No is most efficient, and recommended. . .It Cd sort_reverse ( Vt boolean ) Favour reverse sort rather than normal sort order? .Sy Default : Li false . . .It Cd abook_sort_mode ( Vt string ) Default Sort mode for addressbook list. One of: .Li ORDERED , ALIAS , NAME , COMMENT , ADDRESS . .Sy Default : Li ORDERED . . .It Cd abook_sort_reverse ( Vt boolean ) Favour reverse sort rather than normal sort order? .Sy Default : Li false . . .It Cd line_wrap_len ( Vt number ) Wrap lines at this many characters. .Sy Default : Li 76 . . .It Cd line_wrap_advanced ( Vt boolean ) Enable advanced line wrap options? .Sy Default : Li false . . .It Cd line_wrap_on_reply ( Vt boolean ) Line wrap automatically on reply. .Sy Default : Li true . . .It Cd line_wrap_on_spell ( Vt boolean ) Line wrap automatically on spell check. .Sy Default : Li true . . .It Cd line_wrap_on_send ( Vt boolean ) Line wrap automatically on send. .Sy Default : Li true . . .It Cd preserve_mimetype ( Vt boolean ) Send message Content-Type through to browser. If .Li false , No Content-Type is replaced with .Ql application/octet-stream which should force download to local disk, bypassing any automatic processing of bodyparts by the User-Agent. Unclear at the moment whether we need to do this, or whether this should be done selectively based on the User-Agent. .Sy Default : Li true . . .It Cd use_sent_mail ( Vt boolean ) .No Make the Dq Save copy checkbox on the compose screen checked default. .Sy Default : Li true . . .It Cd use_mark_persist ( Vt boolean ) Use persistent mark for aggregate operations. .Sy Default : Li false . . .It Cd use_search_zoom ( Vt boolean ) Zoom automatically after sucessful search .Sy Default : Li true . . .It Cd use_agg_unmark ( Vt boolean ) Unmark messages after sucessful aggregate operation. .Sy Default : Li true . . .It Cd use_icons ( Vt boolean ) Use icons: may be overriden by value of User-Agent. .Sy Default : Li true . . .It Cd use_welcome ( Vt boolean ) Enable welcome screen . .Sy Default : Li true . . .It Cd use_tail_banner ( Vt boolean ) Duplicate banner icons (toolbar) at the bottom of the Message screen. .Sy Default : Li true . .El . .Ss Hidden preferences . The following options are internally handled as user preferences, but the Preferences screen no longer provides any means for changing them. . .Bl -tag -width Ds .It Cd use_cookie ( Vt boolean ) Use HTTP cookie for Session-ID, if the browser supports cookies If disabled, or user rejects the cookie, then the session-ID is stored in the URL. .Sy Default : Li true . . .It Cd use_substitution ( Vt boolean ) Use page substiution rather than HTTP redirects. Faster, but the URLs that are generated are less predictable. Page substitution and browser history mechanism don't coexist well at the moment (Prayer would need to cache final page value for each substiution event). .Pp .Sy Default : Li true . . .It Cd use_http_1_1 ( Vt boolean ) Allow HTTP/1.1, if the browser supports it. .Sy Default : Li true . . .It Cd use_pipelining ( Vt boolean ) Allow HTTP/1.1 pipelining, if the browser supports it. .Sy Default : Li true . . .It Cd use_persist ( Vt boolean ) Allow persistent HTTP/1.1 and HTTP/1.0 persistent connections, if the browser supports them. .Sy Default : Li true . . .It Cd use_short ( Vt boolean ) Allow short URLs, if the browser supports them. .Sy Default : Li true . . .It Cd use_gzip ( Vt boolean ) Allow gzip compression, if the browser supports it. .Sy Default : Li true . . .El . .Sh SEE ALSO . .Xr prayer 8 , .Xr prayer-session 8 . .Sh AUTHORS . This manual page was put together by .An "Magnus Holmgren" <holmgren@debian.org> using documentation written by .An "David Carter" <dpc22@cam.ac.uk> . �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/man/prayer-session.8�����������������������������������������������������������������0000644�0065130�0065130�00000004707�11266104700�015425� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" -*- nroff -*- .\" $Cambridge: hermes/src/prayer/man/prayer-session.8,v 1.3 2009/10/16 14:57:04 dpc22 Exp $ .Dd 17 August 2008 .Os "The Prayer Webmail Interface" .ds volume-operating-system .Dt PRAYER-SESSION 8 .Sh NAME .Nm prayer-session .Nd Prayer user session backend daemon .Sh SYNOPSIS .Nm .Oo Fl -config-file .Ar file Oc .Oo Oo Fl -config-option .Ar name Ns = Ns Ar value Oc .Ar ... Oc .Op Fl -foreground .Sh DESCRIPTION .Nm is the backend process in the Prayer Webmail system. A fresh .Nm backend is forked off whenever a user logs in. .Pp This process contains all of the permanent state associated with that login session including one or more connections to a IMAP server and possibly connections to accountd servers. prayer-session communicates with the user using HTML over HTTP connections via the .Xr prayer 8 proxy. Each login has a session ID that the front end processes use to find the correct backend. .Pp Backend server processes move into a dormant state after a certain period of inactivity, shutting down IMAP and accountd connections which can be easily resuscitated when the session wakes up. After a long period of inactivity, typically several hours the session process shuts down. .Pp .Nm accepts the following command-line options: .Bl -tag -width Ds .It Fl -config-file Ar file Reads configuration from .Ar file instead of the default .Pa /etc/prayer/prayer.cf . .It Fl -config-option Ar name Ns = Ns Ar value Sets (overrides) the configuration option .Ar name to .Ar value . Any number of options can be specified in this manner. .It Fl -foreground Debug mode. Run a single process in the foreground. .El . .Sh ENVIRONMENT . .Bl -tag -width Ds .It Ev PRAYER_CONFIG_FILE Can be set to specify the configuration file to use. The .Fl -config-file option takes precedence over this variable. .It Ev PRAYER_HOSTNAME Local hostname. Overrides the .Cd hostname setting in the configuration file as well as on the command line. .El .Sh FILES .Bl -tag -width Ds .It Pa /usr/local/prayer/etc/prayer.cf Default configuration file. .It /usr/local/prayer/templates/ Location of standard templates. The templates are compiled into .Nm for performance reasons, so the template files are actually not used, but they are available for customization. .El .Sh SEE ALSO . .Xr prayer 8 , .Xr prayer.cf 5 . .Sh AUTHORS . This manual page was put together by .An "Magnus Holmgren" <holmgren@debian.org> using documentation written by .An "David Carter" <dpc22@cam.ac.uk> . .\" .Sh BUGS ���������������������������������������������������������./prayer-1.3.5/cmd/���������������������������������������������������������������������������������0000755�0065130�0065130�00000000000�11775262602�012344� 5����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_roles_entry.c����������������������������������������������������������������0000644�0065130�0065130�00000013152�11064236131�015667� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_roles_entry.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static char * mylookup(struct assoc *h, char *val) { char *s = assoc_lookup(h, val); return((s) ? s : ""); } static void generate_form(struct session *session, struct assoc *h) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; if (h) { template_vals_string(tvals, "alias", mylookup(h, "alias")); template_vals_string(tvals, "personal", mylookup(h, "personal")); template_vals_string(tvals, "from", mylookup(h, "from")); template_vals_string(tvals, "reply_to", mylookup(h, "reply_to")); template_vals_string(tvals, "fcc", mylookup(h, "fcc")); template_vals_string(tvals, "signature", mylookup(h, "signature")); } session_seed_template(session, tvals); template_expand("roles_entry", tvals, b); response_html(request, 200); /* Success */ } void cmd_roles_entry(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct options *options = session->options; struct assoc *h = NIL; char *alias; char *personal; char *from; char *reply_to; char *fcc; char *signature; if (request->method != POST) { if (request->get_suffix) { request_decode_form(request); h = request->form; } generate_form(session, h); return; } request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, "roles_list"); return; } if ((alias = assoc_lookup(h, "alias"))) alias = string_trim_whitespace(alias); if (assoc_lookup(h, "sub_delete")) { if (alias && alias[0]) { role_delete(options->role_list, alias); options->save = T; session_message(session, "Deleted role: \"%s\"", alias); } else session_message(session, "No role supplied to delete"); session_redirect(session, request, "roles_list"); return; } if (!assoc_lookup(h, "sub_update")) { session_alert(session, "Invalid submit method for roles_entry"); generate_form(session, h); return; } if ((personal = assoc_lookup(h, "personal"))) personal = string_trim_whitespace(personal); if (config->fix_from_address) { from = ""; } else { if ((from = assoc_lookup(h, "from"))) from = string_trim_whitespace(from); } if ((reply_to = assoc_lookup(h, "reply_to"))) reply_to = string_trim_whitespace(reply_to); if ((fcc = assoc_lookup(h, "fcc"))) fcc = string_trim_whitespace(fcc); signature = assoc_lookup(h, "signature"); if (!(alias && alias[0])) { session_message(session, "No alias supplied"); generate_form(session, h); return; } if (!(personal && from && reply_to && fcc && signature)) { session_alert(session, "Fields missing from form (program error)"); session_log(session, ("[cmd_roles_entry] Fields missing from form " "(program error)")); generate_form(session, h); return; } if (from && from[0]) { ADDRESS *addr = addr_parse(request->pool, from, ""); BOOL error = T; if (!addr) session_message(session, "From Address invalid: %s", ml_errmsg()); else if (addr && addr->next) session_message(session, "From address must be single address"); else if (!(addr->host && addr->host[0])) session_message(session, "From address must be qualified"); else if (addr->personal && addr->personal[0]) session_message(session, "From address should not contain personal name"); else error = NIL; if (addr) mail_free_address(&addr); if (error) { generate_form(session, h); return; } } if (reply_to && reply_to[0]) { ADDRESS *addr = addr_parse(request->pool, reply_to, ""); ADDRESS *a = NIL; BOOL error = NIL; if (!addr) { session_message(session, "Reply-To Address invalid: %s", ml_errmsg()); error = T; } else { for (a = addr; a; a = a->next) { if (!(a->host && a->host[0])) { session_message(session, "Unqualified address in Reply-To list"); error = T; break; } } mail_free_address(&addr); } if (error) { generate_form(session, h); return; } } if (fcc && fcc[0] && !string_filename_valid(fcc)) { session_message(session, "Invalid Fcc name"); generate_form(session, h); return; } role_update(options->role_list, alias, personal, from, reply_to, fcc, signature); session_message(session, "Updated role: \"%s\"", alias); options->save = T; session_redirect(session, request, "roles_list"); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_disp_unmark.c����������������������������������������������������������������0000644�0065130�0065130�00000004454�11063701633�015646� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_disp_unmark.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_disp_unmark(struct session *session) { struct msgmap *zm = session->zm; struct request *request = session->request; struct pool *pool = request->pool; MAILSTREAM *stream = session->stream; unsigned long msgno, msguid; char *s; unsigned long zm_offset; if (request->argc < 2) { session_redirect(session, request, "error"); return; } msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } /* Find next message in msgmap */ if (!msgmap_update(zm)) { session_redirect(session, request, "restart"); return; } zm_offset = msgmap_find(zm, msgno); if (zm_offset < msgmap_size(zm)) { unsigned long next = msgmap_value(zm, zm_offset + 1); if (msgmap_unmark(zm, msgno)) session_message(session, "Unmarked message %lu, displaying %lu out of %lu", msgno, next, zm->nmsgs); else session_message(session, ("Message %lu already unmarked, " "displaying %lu out of %lu"), msgno, next, zm->nmsgs); s = pool_printf(pool, "display/%lu/%lu", next, ml_uid(session, stream, next)); session_redirect(session, request, s); } else { if (msgmap_unmark(zm, msgno)) session_message(session, "Unmarked message %lu, no more messages", msgno); else session_message(session, "Message %lu already unmarked, no more messages", msgno); session->current = msgno; session_redirect(session, request, "list"); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_expunge1.c�������������������������������������������������������������������0000644�0065130�0065130�00000005450�11064236131�015060� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_expunge1.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_expunge1(struct session *session) { struct request *request = session->request; MAILSTREAM *stream = session->stream; struct msgmap *zm = session->zm; unsigned long count; unsigned long offset, msgno; unsigned long msguid_current; MESSAGECACHE *elt; /* Make sure msgmap is up to date before we start */ if (!msgmap_update(zm)) { session_alert(session, "Failed to update msgmap"); session_redirect(session, request, "restart"); return; } /* Count deleted messages in folder */ for (count = 0, msgno = 1; msgno <= stream->nmsgs; msgno++) { if (!(elt = ml_elt(session, stream, msgno))) { session_redirect(session, request, "restart"); return; } if (elt->deleted) count++; } if (session->current > 0) { /* Find "closest" undeleted message to current in map */ offset = msgmap_find_undeleted(session->zm, session->current); session->current = msgmap_value(session->zm, offset); } /* Record UID of this message so that we can find it after expunge */ if (session->current > 0) msguid_current = ml_uid(session, stream, session->current); else msguid_current = 0; if (!ml_expunge(session, stream)) { session_redirect(session, request, "restart"); return; } if (stream == session->inbox_stream) session->inbox_last_ping_time = time(NIL); else if (stream == session->draft_stream) session->draft_last_ping_time = time(NIL); else session->other_last_ping_time = time(NIL); /* Update msgmap (recalculates marked message count) */ if (!msgmap_update(zm)) { session_alert(session, "Failed to update msgmap"); session_redirect(session, request, "restart"); return; } /* Current message has probably moved */ if (msguid_current > 0) session->current = ml_msgno(session, stream, msguid_current); else session->current = zm->nmsgs; session_log(session, "[cmd_expunge1] Expunged %lu message(s) from %s", count, session->foldername); if (count > 1) session_message(session, "Expunged %lu messages", count); else if (count == 1) session_message(session, "Expunged 1 message"); else session_message(session, "No messages to expunge"); session_redirect(session, request, "list"); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_hdrs.c�����������������������������������������������������������������������0000644�0065130�0065130�00000001411�11063701633�014260� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_hdrs.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_hdrs(struct session *session) { struct request *request = session->request; if (session->full_hdrs) { session_message(session, "Disabling full header display"); session->full_hdrs = NIL; } else { session_message(session, "Showing full headers"); session->full_hdrs = T; } session_redirect(session, request, "display"); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_rm1.c������������������������������������������������������������������������0000644�0065130�0065130�00000005302�11064236131�014017� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_rm1.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_rm1(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct favourite_list *fl = options->favourite_list; MAILSTREAM *stream; char *mailbox; if (request->argc < 3) { session_redirect(session, request, "error"); return; } mailbox = string_canon_decode(request->argv[2]); if (!strcasecmp(mailbox, "INBOX")) { session_alert(session, "Unable to delete inbox folder"); session_redirect(session, request, "folders"); return; } if (session->foldername && session->other_foldername && !strcmp(session->foldername, session->other_foldername) && !strcmp(session->foldername, mailbox)) { /* Attempt to delete current mailbox other than INBOX */ /* Switch to inbox, shut down other stream */ session_streams_change(session, "INBOX"); ml_close(session, session->other_stream); session->other_stream = NIL; } stream = session->stream; ml_clear_error(); ml_clear_have_close(); if (!strcmp(request->argv[1], "directory")) { ml_delete(session, stream, session_dir(session, request->pool, mailbox)); if (ml_have_close()) { session_redirect(session, request, "restart"); return; } else if (ml_have_error()) { session_alert(session, "%s", ml_errmsg()); /* Includes name */ } else { session_message(session, "Deleted directory: \"%s\"", mailbox); folderlist_delete(session->folderlist, mailbox); } } else { ml_delete(session, stream, session_mailbox(session, request->pool, mailbox)); if (ml_have_close()) { session_redirect(session, request, "restart"); return; } else if (ml_have_error()) { session_message(session, "%s", ml_errmsg()); /* Includes name */ } else { session_message(session, "Deleted mailbox: \"%s\"", utf8_from_imaputf7(request->pool, mailbox)); folderlist_delete(session->folderlist, mailbox); if (favourite_delete(fl, mailbox)) options->save = T; } } session_redirect(session, request, "folders"); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_favourites.c�����������������������������������������������������������������0000644�0065130�0065130�00000003201�11063701633�015506� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_favourites.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_favourites(struct session *session) { struct template_vals *tvals = session->template_vals; struct folderlist *fl = folderlist_fetch(session); struct prefs *prefs = session->options->prefs; BOOL suppress_dotfiles = prefs->suppress_dotfiles; struct request *request = session->request; struct buffer *b = request->write_buffer; struct folderitem *fi; char *name; if ((request->argc == 3) && !strcmp(request->argv[1], "toggle")) { name = string_canon_decode(request->argv[2]); fi = folderlist_lookup(folderlist_fetch(session), name); if (fi) { if (fi->expanded) { session_message(session, "Collapsed \"%s\"", name); fi->expanded = NIL; } else { folderlist_expand(session, fi); session_message(session, "Expanded \"%s\"", name); fi->expanded = T; } } } folderlist_template_vals_tree(fl, suppress_dotfiles, tvals, "@folder"); folderlist_template_vals_list(fl, suppress_dotfiles, tvals, T, "@dirlist"); session_seed_template(session, tvals); template_expand("favourites", tvals, b); response_html(request, 200); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_filter_mbox.c����������������������������������������������������������������0000644�0065130�0065130�00000004117�11064236131�015635� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_filter_mbox.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_filter_mbox(struct session *session) { struct request *request = session->request; char *mailbox; BOOL copy; if (session->half_filter == NIL) { session_alert(session, "No filter item defined at the current time"); session_redirect(session, request, "error"); return; } if (request->argc != 3) { session_redirect(session, request, "error"); return; } copy = !strcmp(request->argv[1], "copy") ? T : NIL; mailbox = request->argv[2]; string_canon_decode(mailbox); filter_set_mailbox(session->half_filter, mailbox); filter_set_copy(session->half_filter, copy); account_filter_add(session->account, session->half_filter); if (account_mail_update(session->account, request->pool)) { FILTER_TYPE type = session->half_filter->type; if (type == FILTER_SENDER) session_message(session, "Added SENDER filter"); else if (type == FILTER_RECIPIENT) session_message(session, "Added RECIPIENT filter"); else if (type == FILTER_SUBJECT) session_message(session, "Added SUBJECT filter"); else if (type == FILTER_BLOCK) session_message(session, "Added BLOCK filter"); else session_message(session, "Added Unknown filter type?"); } else { char *msg = account_fetch_message(session->account); session_alert(session, "Problem updating filters: %s", msg); session_log(session, "[cmd_filter_mbox()] Problem updating filters: %s", msg); } /* Remove halfway filter */ session->half_filter = NIL; session_redirect(session, request, "filter"); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_aggregate_tmp.c��������������������������������������������������������������0000644�0065130�0065130�00000024341�11064236131�016132� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_aggregate_tmp.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static BOOL make_sequence(struct session *session, char **seqp, unsigned long *countp) { struct request *request = session->request; MAILSTREAM *stream = session->stream; struct buffer *seq = buffer_create(request->pool, 128); unsigned long count = 0; char *key; assoc_scan_reset(request->form); while (assoc_scan_next(request->form, &key, NIL)) { char *s; unsigned long msgno, msguid; if ((!key) || (!Uisdigit(key[0])) || !strcmp(key, "0@0")) continue; if (!(s = strchr(key, '@'))) continue; msgno = atoi(key); msguid = atoi(s + 1); if ((msgno == 0) || (msguid == 0)) continue; if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) return (NIL); bprintf(seq, "%lu,", msgno); count++; } if (count > 0) { *seqp = buffer_fetch(seq, 0, buffer_size(seq) - 1, NIL); *countp = count; } else { *seqp = ""; *countp = 0; } return (T); } /* ====================================================================== */ static BOOL aggregate_delete(struct session *session, char *sequence, unsigned long count) { MAILSTREAM *stream = session->stream; if (!ml_flag(session, stream, sequence, "\\DELETED", ST_SET)) { session_alert(session, "Failed to delete messages: %s", ml_errmsg()); session_log(session, "[cmd_aggregate_tmp] Failed to delete messages: %s", ml_errmsg()); return (NIL); } if (count > 1) { session_message(session, "Deleted %lu messages", count); session_log(session, "[cmd_aggregate_tmp] Deleted %lu messages from %s", count, session->foldername); } else { session_message(session, "Deleted 1 message"); session_log(session, "[cmd_aggregate_tmp] Deleted 1 message from %s", session->foldername); } return (T); } static BOOL aggregate_undelete(struct session *session, char *sequence, unsigned long count) { MAILSTREAM *stream = session->stream; if (!ml_flag(session, stream, sequence, "\\DELETED", 0)) { session_alert(session, "Failed to undelete messages: %s", ml_errmsg()); session_log(session, "[cmd_aggregate_tmp] Failed to undelete messages: %s", ml_errmsg()); return (NIL); } if (count > 1) { session_message(session, "Undeleted %lu messages", count); session_log(session, "[cmd_aggregate_tmp] Undeleted %lu messages from %s", count, session->foldername); } else { session_message(session, "Undeleted 1 message"); session_log(session, "[cmd_aggregate_tmp] Undeleted 1 message from %s", session->foldername); } return (T); } static BOOL aggregate_read(struct session *session, char *sequence, unsigned long count) { MAILSTREAM *stream = session->stream; if (!ml_flag(session, stream, sequence, "\\SEEN", ST_SET)) { session_alert(session, "Failed to flag messages as read: %s", ml_errmsg()); session_log(session, "[cmd_aggregate_tmp] Failed to flag messages as read: %s", ml_errmsg()); return (NIL); } if (count > 1) { session_message(session, "Flagged %lu messages as read", count); session_log(session, "[cmd_aggregate_tmp] Flagged %lu messages as read from %s", count, session->foldername); } else { session_message(session, "Flagged 1 message as read"); session_log(session, "[cmd_aggregate_tmp] Flagged 1 message as read from %s", session->foldername); } return (T); } static BOOL aggregate_unread(struct session *session, char *sequence, unsigned long count) { MAILSTREAM *stream = session->stream; if (!ml_flag(session, stream, sequence, "\\SEEN", 0)) { session_alert(session, "Failed to flag messages as unread: %s", ml_errmsg()); session_log(session, "[cmd_aggregate_tmp] Failed to flag messages as unread: %s", ml_errmsg()); return (NIL); } if (count > 1) { session_message(session, "Flagged %lu messages as unread", count); session_log(session, "[cmd_aggregate_tmp] Flagged %lu messages as unread from %s", count, session->foldername); } else { session_message(session, "Flagged 1 message as unread"); session_log(session, "[cmd_aggregate_tmp] Flagged 1 message as unread from %s", session->foldername); } return (T); } /* ====================================================================== */ static BOOL aggregate_copy(struct session *session) { struct request *request = session->request; MAILSTREAM *stream = session->stream; char *key; char *s; unsigned long msgno, msguid; unsigned long count = 0; msgmap_tmp_unmark_all(session->zm); assoc_scan_reset(request->form); while (assoc_scan_next(request->form, &key, NIL)) { if ((!key) || (!Uisdigit(key[0])) || !strcmp(key, "0@0")) continue; if (!(s = strchr(key, '@'))) continue; msgno = atoi(key); msguid = atoi(s + 1); if ((msgno == 0) || (msguid == 0)) continue; if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) return (NIL); msgmap_tmp_mark(session->zm, msgno); count++; } if (count == 0) { session_message(session, "No messages marked"); session_redirect(session, request, "list"); } else session_redirect(session, request, "copy/aggregate"); return (T); } /* ====================================================================== */ static BOOL aggregate_forward(struct session *session) { struct request *request = session->request; MAILSTREAM *stream = session->stream; char *key; char *s; unsigned long msgno, msguid; unsigned long count = 0; msgmap_tmp_unmark_all(session->zm); assoc_scan_reset(request->form); while (assoc_scan_next(request->form, &key, NIL)) { if ((!key) || (!Uisdigit(key[0])) || !strcmp(key, "0@0")) continue; if (!(s = strchr(key, '@'))) continue; msgno = atoi(key); msguid = atoi(s + 1); if ((msgno == 0) || (msguid == 0)) continue; if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) return (NIL); msgmap_tmp_mark(session->zm, msgno); count++; } if (count == 0) { session_message(session, "No messages marked"); session_redirect(session, request, "list"); } else session_redirect(session, request, "forward/aggregate"); return (T); } /* ====================================================================== */ void cmd_aggregate_tmp(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct prefs *prefs = options->prefs; char *cmd; char *sequence; unsigned long count; BOOL rc; if (request->method != POST) { session_redirect(session, request, "list"); return; } request_decode_form(request); if (assoc_lookup(request->form, "sub_aggregate")) cmd = assoc_lookup(request->form, "aggregate"); else if (assoc_lookup(request->form, "sub_aggregate2")) cmd = assoc_lookup(request->form, "aggregate2"); else { char *pstr = assoc_lookup(request->form, "page"); unsigned long page = pstr ? atoi(pstr) : 0; unsigned long size = msgmap_size(session->zm); unsigned long pages = (size / prefs->msgs_per_page) + 1; if ((page > 0) && (page <= pages)) { session->current = msgmap_value(session->zm, ((page - 1) * prefs->msgs_per_page) + 1); session_message(session, "Switched to page: %lu", page); } else session_alert(session, "Page out of range"); session_redirect(session, request, "list"); return; } if (!(cmd && cmd[0])) { session_alert(session, "Invalid form input"); session_log(session, "[cmd_aggregate_tmp] Invalid form input"); session_redirect(session, request, "list"); return; } if (!strcmp(cmd, "copy")) { if (!aggregate_copy(session)) session_redirect(session, request, "restart"); return; } if (!strcmp(cmd, "forward")) { if (!aggregate_forward(session)) session_redirect(session, request, "restart"); return; } if (!make_sequence(session, &sequence, &count)) { session_redirect(session, request, "restart"); return; } if (count == 0) { session_message(session, "No messages marked"); session_redirect(session, request, "list"); return; } rc = NIL; if (!strcmp(cmd, "delete")) rc = aggregate_delete(session, sequence, count); else if (!strcmp(cmd, "undelete")) rc = aggregate_undelete(session, sequence, count); else if (!strcmp(cmd, "read")) rc = aggregate_read(session, sequence, count); else if (!strcmp(cmd, "unread")) rc = aggregate_unread(session, sequence, count); else { session_alert(session, "Unknown action"); rc = T; } session_redirect(session, request, (rc) ? "list" : "restart"); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_passwd.c���������������������������������������������������������������������0000644�0065130�0065130�00000007063�11773061651�014641� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_passwd.c,v 1.8 2012/06/28 14:01:13 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session, char *old, char *new, char *new2) { struct template_vals *tvals = session->template_vals; struct config *config = session->config; struct request *request = session->request; struct buffer *b = request->write_buffer; char *delay = NIL; if (config->accountd_passwd_delay > (2 * 60 * 60)) delay = pool_printf(tvals->pool, "%lu hours", config->accountd_passwd_delay / (60 * 60)); else if (config->accountd_passwd_delay > 120) delay = pool_printf(tvals->pool, "%lu minutes", config->accountd_passwd_delay / 60); else if (config->accountd_passwd_delay > 1) delay = pool_printf(tvals->pool, "%lu seconds", config->accountd_passwd_delay); if (config->raven_enable) template_vals_ulong(tvals, "raven_enable", 1); template_vals_string(tvals, "old", old); template_vals_string(tvals, "new", new); template_vals_string(tvals, "new2", new2); if (delay) template_vals_string(tvals, "delay", delay); session_seed_template(session, tvals); template_expand("passwd", tvals, b); response_html(request, 200); } static BOOL process_form(struct session *session, char *old, char *new, char *new2) { struct account *account = session->account; struct request *request = session->request; struct pool *pool = request->pool; if (!(old && old[0])) { session_alert(session, "Existing password not supplied"); return (NIL); } if (!(new && new[0])) { session_alert(session, "New password not supplied"); return (NIL); } if (!(new2 && new2[0])) { session_alert(session, "(Confirmed) New password not supplied"); return (NIL); } if (strcmp(new, new2) != NIL) { session_alert(session, "New passwords do not match"); return (NIL); } if (!account_change_password(session->account, pool, old, new)) { char *msg = account_fetch_message(account); session_alert(session, "Failed to change password: %s", msg); session_log(session, "[cmd_passwd] Failed to change password: %s", msg); return (NIL); } session_message(session, "Password update successful"); return (T); } void cmd_passwd(struct session *session) { struct request *request = session->request; char *old, *new, *new2; if (request->method == POST) { struct assoc *h; request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_change")) { if ((old = assoc_lookup(h, "old"))) old = string_trim_whitespace(old); if ((new = assoc_lookup(h, "new"))) new = string_trim_whitespace(new); if ((new2 = assoc_lookup(h, "new2"))) new2 = string_trim_whitespace(new2); if (!process_form(session, old, new, new2)) { generate_form(session, old, new, new2); return; } } session_redirect(session, request, "manage"); return; } generate_form(session, NIL, NIL, NIL); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_redirect.c�������������������������������������������������������������������0000644�0065130�0065130�00000010436�11165435653�015141� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_redirect.c,v 1.5 2009/04/03 16:39:07 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session, BOOL redirect_enabled, char *redirect_address, BOOL redirect_copy) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; if (redirect_enabled) template_vals_ulong(tvals, "use_redirect", 1); if (redirect_address) template_vals_string(tvals, "redirect_addr", redirect_address); if (redirect_copy) template_vals_ulong(tvals, "redirect_copy", 1); session_seed_template(session, tvals); template_expand("redirect", tvals, b); response_html(request, 200); /* Success */ } static void generate_error(struct session *session) { struct template_vals *tvals = session->template_vals; struct account *account = session->account; struct request *request = session->request; char *msg = account_fetch_message(account); struct buffer *b = request->write_buffer; if (!(msg && msg[0])) msg = "Unable to check mail processing status"; template_vals_string(tvals, "msg", msg); session_seed_template(session, tvals); template_expand("redirect_fail", tvals, b); response_html(request, 200); } void cmd_redirect(struct session *session) { struct request *request = session->request; struct assoc *h = NIL; struct account *account = session->account; char *s; BOOL rc = T; ADDRESS *addr = NIL; BOOL redirect_enabled; char *redirect_address = ""; BOOL redirect_copy; if (request->method != POST) { if (!account_mail_check(account, request->pool)) generate_error(session); else generate_form(session, account->redirect_enabled, account->redirect_address, account->redirect_copy); return; } request_decode_form(request); h = request->form; if (!assoc_lookup(h, "sub_apply")) { session_redirect(session, request, "manage"); return; } /* Store state in temporary variables until validated */ redirect_enabled = (assoc_lookup(h, "use_redirect")) ? T : NIL; redirect_copy = (assoc_lookup(h, "save_copy")) ? T : NIL; s = assoc_lookup(h, "redirect_addr"); redirect_address = (s) ? s : ""; if (redirect_enabled) { addr = addr_parse(request->pool, redirect_address, ""); if (!addr) { session_message(session, "Redirection Address invalid: %s", ml_errmsg()); rc = NIL; } else { if ((addr->next) || (addr->personal && addr->personal[0]) || (!(addr->host && addr->host[0]))) { session_message(session, ("Redirection Address must be " "single, simple " "and fully qualified email address")); rc = NIL; } mail_free_address(&addr); } if (rc == NIL) { generate_form(session, redirect_enabled, redirect_address, redirect_copy); return; } } /* Commit and update */ account->redirect_enabled = redirect_enabled; account->redirect_copy = redirect_copy; string_strdup(&account->redirect_address, redirect_address); if (account_mail_update(account, request->pool)) { session_message(session, "Updated redirection"); } else { char *msg = account_fetch_message(account); session_message(session, "Unable to update redirection: %s", msg); session_log(session, "[cmd_redirect] Unable to update redirection: %s", msg); } session_redirect(session, request, "manage"); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_mark.c�����������������������������������������������������������������������0000644�0065130�0065130�00000004546�11064236131�014263� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_mark.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_mark(struct session *session) { struct request *request = session->request; MAILSTREAM *stream = session->stream; if ((request->argc == 2) && (!strcmp(request->argv[1], "all"))) { struct msgmap *zm = session->zm; unsigned long count = zm->nmsgs - zm->marked; msgmap_mark_all(zm); if (count != 1) session_message(session, "Marked %lu messages", count); else session_message(session, "Marked 1 message"); } else if ((request->argc == 4) && (!strcmp(request->argv[1], "read"))) { unsigned long msgno = atoi(request->argv[2]); unsigned long msguid = atoi(request->argv[3]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } session->current = msgno; if (!ml_flag (session, stream, string_itoa_tmp(msgno), "\\SEEN", ST_SET)) { session_alert(session, "Failed to mark message %lu as read: %s", msgno, ml_errmsg()); session_log(session, "[cmd_mark] Failed to mark message number %lu as read: %s", msgno, ml_errmsg()); session_redirect(session, request, "restart"); return; } session_message(session, "Marked message %lu as read", msgno); } else if (request->argc == 3) { unsigned long msgno = atoi(request->argv[1]); unsigned long msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } if (msgmap_mark(session->zm, msgno)) session_message(session, "Marked message %lu", msgno); else session_message(session, "Message %lu already marked", msgno); } session_redirect(session, request, "list"); } ����������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_update.c���������������������������������������������������������������0000644�0065130�0065130�00000010733�11064236131�015761� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_update.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session, struct assoc *h) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; if ((assoc_lookup(h, "original"))) template_vals_string(tvals, "original", assoc_lookup(h, "original")); else template_vals_string(tvals, "original", assoc_lookup(h, "alias")); template_vals_string(tvals, "alias", assoc_lookup(h, "alias")); template_vals_string(tvals, "name", assoc_lookup(h, "name")); template_vals_string(tvals, "comment", assoc_lookup(h, "comment")); template_vals_string(tvals, "email", assoc_lookup(h, "email")); session_seed_template(session, tvals); template_expand("abook_update", tvals, b); response_html(request, 200); /* Success */ } void cmd_abook_update(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct assoc *h = NIL; char *s; if (request->method != POST) { if (request->get_suffix) { request_decode_form(request); h = request->form; } generate_form(session, h); return; } request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, "abook_list"); return; } if (assoc_lookup(h, "sub_delete") && (s = assoc_lookup(h, "alias"))) { abook_remove(options->abook, s); session->options->save = T; session_message(session, "Removed address book entry: \"%s\"", s); } if (assoc_lookup(h, "sub_update")) { char *original = assoc_lookup(h, "original"); char *alias = assoc_lookup(h, "alias"); char *name = assoc_lookup(h, "name"); char *fcc = pool_strdup(request->pool, ""); /* Not yet */ char *comment = assoc_lookup(h, "comment"); char *email = assoc_lookup(h, "email"); if (alias) alias = string_trim_whitespace(alias); else alias = ""; if (!alias[0]) { session_alert(session, "No alias provided"); generate_form(session, h); return; } if (strchr(alias, ' ') || strchr(alias, '\t')) { session_alert(session, "Alias cannot contain spaces"); generate_form(session, h); return; } if (!(name && comment && email)) { session_alert(session, "Missing form entries"); generate_form(session, h); return; } name = string_trim_whitespace(name); fcc = string_trim_whitespace(fcc); comment = string_trim_whitespace(comment); email = string_trim_whitespace(email); if (original && (strcmp(original, alias) != 0) && abook_lookup(options->abook, alias)) { session_alert(session, "An addressbook entry named \"%s\" already exists", alias); generate_form(session, h); return; } if (email[0] == '\0') { session_alert(session, "No email address supplied"); generate_form(session, h); return; } if (!addr_check_valid(request->pool, email)) { session_alert(session, "%s", ml_errmsg()); generate_form(session, h); return; } /* Have to add unchecked entry to addressbook to spot all possible loops */ abook_replace(options->abook, alias, name, fcc, comment, email); if (!abook_check_loop(request->pool, options->abook, alias, T)) { session_alert(session, "Addressbook loop involving alias \"%s\"", assoc_lookup(h, "alias")); generate_form(session, h); return; } session_message(session, "Updated address book entry: \"%s\"", alias); session->options->save = T; } session_redirect(session, request, "abook_list"); } �������������������������������������./prayer-1.3.5/cmd/cmd_reply.c����������������������������������������������������������������������0000644�0065130�0065130�00000007634�11063701633�014470� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_reply.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" #include "cmd.h" void cmd_reply(struct session *session) { struct template_vals *tvals = session->template_vals; struct pool *pool = tvals->pool; struct request *request = session->request; struct draft *draft = session->draft; char *s, *opt_cc = NIL; MAILSTREAM *stream = session->stream; MESSAGECACHE *elt; ENVELOPE *env; ADDRESS *sender; struct buffer *b = request->write_buffer; unsigned long msgno, msguid; BOOL have_reply_flag = NIL; BOOL reply_all = NIL; char *string; if (request->argc >= 4) { msgno = atoi(request->argv[2]); msguid = atoi(request->argv[3]); session->current = msgno; have_reply_flag = T; if (!strcmp(request->argv[1], "all")) reply_all = T; } else if (request->argc == 3) { msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); session->current = msgno; } else if (request->argc == 2) { msgno = session->current; msguid = ml_uid(session, stream, msgno); session->current = msgno; have_reply_flag = T; if (!strcmp(request->argv[1], "all")) reply_all = T; } else { msgno = session->current; msguid = ml_uid(session, stream, msgno); } if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "list"); return; } if (!((elt = ml_elt(session, stream, msgno)) && (env = ml_fetch_structure(session, stream, msgno, NIL, 0)))) { session_redirect(session, request, "restart"); return; } session->reply_all = NIL; /* Clear Reply to all flag */ draft_role_set(draft, NIL); /* Clear Role indication */ sender = (env->reply_to) ? (env->reply_to) : (env->from); /* Calculate possible Cc value from message recipients */ if (env->to) { opt_cc = addr_text_exclude(session, request->pool, env->to, sender); if (env->cc) { s = addr_text_exclude(session, request->pool, env->cc, sender); if (s && s[0]) { if (opt_cc && opt_cc[0]) opt_cc = pool_strcat3(request->pool, opt_cc, ", ", s); else opt_cc = pool_strdup(request->pool, s); } } } else if (env->cc) opt_cc = addr_text_exclude(session, request->pool, env->cc, sender); if (have_reply_flag) { /* Don't need to ask user here */ session->reply_all = reply_all; cmd_reply1(session); return; } if (!(opt_cc && opt_cc[0])) { /* Don't need to ask user here */ cmd_reply1(session); return; } string = addr_text(pool, sender); string = (char *) rfc1522_decode(pool_alloc(pool, strlen(string)), strlen(string), string, NIL); template_vals_string(tvals, "sender", string); string = opt_cc; string = (char *) rfc1522_decode(pool_alloc(pool, strlen(string)), strlen(string), string, NIL); template_vals_string(tvals, "recipients", string); string = env->subject; if (string && string[0]) { string = (char *) rfc1522_decode(pool_alloc(pool, strlen(string)), strlen(string), string, NIL); } else string = "No subject"; template_vals_string(tvals, "subject", string); session_seed_template(session, tvals); template_expand("reply", tvals, b); response_html(request, 200); } ����������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_rm.c�������������������������������������������������������������������������0000644�0065130�0065130�00000002675�11063701633�013753� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_rm.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" #include "cmd.h" void cmd_rm(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct options *options = session->options; struct prefs *prefs = options->prefs; struct buffer *b = request->write_buffer; char *cmd, *s; if (request->argc < 3) { session_redirect(session, request, "folders"); return; } if (!prefs->confirm_rm) { cmd_rm1(session); return; } s = string_canon_decode(pool_strdup(request->pool, request->argv[2])); cmd = pool_printf(request->pool, "rm1/%s/%s", request->argv[1], request->argv[2]); template_vals_string(tvals, "cmd", cmd); template_vals_string(tvals, "name", s); if (!strcmp(request->argv[1], "directory")) { template_vals_string(tvals, "type", "directory"); } else { template_vals_string(tvals, "type", "mailbox"); } session_seed_template(session, tvals); template_expand("rm", tvals, b); response_html(request, 200); } �������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_compose2.c�������������������������������������������������������������0000644�0065130�0065130�00000003125�11064236131�016223� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_compose2.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_abook_compose2(struct session *session) { struct request *request = session->request; struct draft *draft = session->draft; struct options *options = session->options; struct role *role = NIL; char *s; if ((session->abook_compose_name == NIL) || (session->abook_compose_email == NIL)) { session_alert(session, "No compose name defined"); session_log(session, "[cmd_abook_compose2] called without compose name"); session_redirect(session, request, "abook_list"); return; } request_decode_form(request); if ((s = assoc_lookup(request->form, "role"))) role = role_find(options->role_list, s); draft_role_set(draft, role); draft_init(draft); draft_init_rich_headers(draft); /* Set To address */ draft->to = abook_text_to_string(draft->pool, session->abook_compose_name, session->abook_compose_email); free(session->abook_compose_name); session->abook_compose_name = NIL; free(session->abook_compose_email); session->abook_compose_email = NIL; session_redirect(session, request, "compose"); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_forward.c��������������������������������������������������������������������0000644�0065130�0065130�00000005420�11063701633�014770� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_forward.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" #include "cmd.h" void cmd_forward(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct options *options = session->options; struct prefs *prefs = options->prefs; struct buffer *b = request->write_buffer; MAILSTREAM *stream = session->stream; struct list_item *li; unsigned long count, msgno, msguid; if ((request->argc > 1) && !strcmp(request->argv[1], "aggregate")) { if (prefs->use_mark_persist) count = msgmap_marked_count(session->zm); else count = msgmap_tmp_marked_count(session->zm); if (count > 1) session_message(session, "Forwarding %lu marked messages", count); else if (count == 1) session_message(session, "Forwarding single marked message"); else { session_message(session, "No marked messages to forward"); session_redirect(session, request, "list"); return; } session->aggregate = T; } else if (request->argc > 1) { if (request->argc < 3) { session_redirect(session, request, "error"); return; } msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "list"); return; } session->aggregate = NIL; session->current = atoi(request->argv[1]); session_message(session, "Forwarding message %lu", session->current); } if (list_length(options->role_list) == 0L) { cmd_forward1(session); return; } count = 0; template_vals_foreach_init(tvals, "@roles", count); template_vals_foreach_string(tvals, "@roles", count, "name", "default"); count++; for (li = options->role_list->head; li; li = li->next) { struct role *role = (struct role *) li; template_vals_foreach_init(tvals, "@roles", count); template_vals_foreach_string(tvals, "@roles", count, "name", role->name); count++; } template_vals_string(tvals, "next", "forward1"); session_seed_template(session, tvals); template_expand("roles_select", tvals, b); response_html(request, 200); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_dir_check.c������������������������������������������������������������������0000644�0065130�0065130�00000003523�11063701633�015241� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_dir_check.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Unix Date conversion is ghastly. Stole following from c-client */ static char *current_time(void) { static char current[64]; time_t tn = time(0); struct tm *t = gmtime(&tn); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime(&tn); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if ((julian = t->tm_yday - julian) != 0) zone += ((julian < 0) == (abs(julian) == 1)) ? -24 * 60 : 24 * 60; /* output the time */ sprintf(current, "%02d:%02d:%02d %+03d%02d", t->tm_hour, t->tm_min, t->tm_sec, zone / 60, abs(zone) % 60); return (current); } void cmd_dir_check(struct session *session) { struct request *request = session->request; folderlist_invalidate(session->folderlist); session_message(session, "Refreshed mailbox list cache at %s", current_time()); if (request->argc >= 2) session_redirect(session, request, request->argv[1]); else session_redirect(session, request, "folders"); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_dictionary.c�����������������������������������������������������������������0000644�0065130�0065130�00000005637�11063701633�015503� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_dictionary.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session, struct buffer *b) { struct template_vals *tvals = session->template_vals; struct options *options = session->options; struct dictionary *dictionary = options->dictionary; struct list_item *li; unsigned long i, len, max, perline, count; /* Find maximum length of list item */ count = 0; max = 1; for (li = dictionary->list->head; li; li = li->next) { if ((len = strlen(li->name)) > max) max = len; count++; } if ((max > 0) && (max < 38)) perline = 80 / (max + 5); else perline = 1; if (count > 0) { for (i = 0, li = dictionary->list->head; li; li = li->next, i++) { template_vals_foreach_init(tvals, "@words", i); template_vals_foreach_string(tvals, "@words", i, "word", li->name); if ((i % perline) == (perline - 1)) template_vals_foreach_ulong(tvals, "@words", i, "break", 1); } } session_seed_template(session, tvals); template_expand("dictionary", tvals, b); } void cmd_dictionary(struct session *session) { struct request *request = session->request; struct buffer *b = request->write_buffer; struct assoc *h = NIL; struct options *options = session->options; struct dictionary *dictionary = options->dictionary; char *s, *line, *word; if (request->method != POST) { request_decode_form(request); h = request->form; if ((s = assoc_lookup(h, "remove")) && s[0]) { dictionary_remove(dictionary, s); options->save = T; } generate_form(session, b); response_html(request, 200); return; } request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, "manage"); return; } /* Add or remove words from dictionary */ if (assoc_lookup(h, "sub_add")) { line = assoc_lookup(h, "add"); while ((word = string_get_token(&line))) { if (word[0]) { dictionary_add(dictionary, word); options->save = T; } } } else if (assoc_lookup(h, "sub_remove")) { line = assoc_lookup(h, "remove"); while ((word = string_get_token(&line))) { if (word[0]) { dictionary_remove(dictionary, word); options->save = T; } } } generate_form(session, b); response_html(request, 200); } �������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_restart.c��������������������������������������������������������������������0000644�0065130�0065130�00000012400�11513055016�015001� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_restart.c,v 1.5 2011/01/11 13:24:30 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_error_page(struct session *session) { struct request *request = session->request; struct template_vals *tvals = session->template_vals; struct buffer *b = request->write_buffer; struct config *config = session->config; if (config->raven_enable && (strlen(session->password) > 256)) template_vals_ulong(tvals, "raven_token", 1); session_seed_template(session, tvals); template_expand("restart", tvals, b); response_html(request, 200); } void cmd_restart(struct session *session) { struct request *request = session->request; struct msgmap *zm = session->zm; MAILSTREAM *stream; struct assoc *h; char *s; if (request->method != POST) { if (session->inbox_stream) ml_close(session, session->inbox_stream); if (session->other_stream) ml_close(session, session->other_stream); if (session->draft_stream) ml_close(session, session->draft_stream); session->inbox_stream = NIL; session->other_stream = NIL; session->draft_stream = NIL; session->stream = NIL; session_message_clear(session); if (ml_have_error() && (s = ml_errmsg()) && s[0]) session_message(session, "%s", s); else session_message(session, "Lost connection to IMAP server "); generate_error_page(session); return; } request_decode_form(request); h = request->form; if (assoc_lookup(h, "exit")) { session->draft_stream = NIL; session->other_stream = NIL; session->inbox_stream = NIL; session_redirect(session, request, "exit"); return; } if (assoc_lookup(h, "reopen") && session->foldername) { if (!strcasecmp(session->foldername, "inbox")) { s = session_mailbox(session, request->pool, "inbox"); /* Reopen inbox folder */ if ((stream = ml_open(session, NIL, s, 0))) { session->inbox_last_ping_time = time(NIL); session->stream = session->inbox_stream = stream; } } else if (!strcasecmp (session->foldername, session->draft_foldername)) { /* Reopen draft folder */ s = session_mailbox(session, request->pool, session->draft_foldername); if ((stream = ml_open(session, NIL, s, 0))) { session->draft_last_ping_time = time(NIL); session->stream = session->draft_stream = stream; } } else { /* Reopen other folder */ s = session_mailbox(session, request->pool, session->foldername); if ((stream = ml_open(session, NIL, s, 0))) { session->other_last_ping_time = time(NIL); session->stream = session->other_stream = stream; } } if (!stream) { session_alert(session, ("Unable to reestablish connection" " with IMAP server ")); generate_error_page(session); return; } /* initialise the zoommap */ msgmap_associate(zm, session, stream); msgmap_update(zm); /* Set current and last_displayed message to last or first in zoommap * (cmd_welcome may override with this last unread message) */ if (zm->nmsgs > 0) { if (zm->sort_reverse) session->current = msgmap_value(zm, 1); else session->current = msgmap_value(zm, zm->nmsgs); } else session->current = 0; session->last_displayed = session->current; session_redirect(session, request, "list"); return; } /* Shut down other_stream, draft_stream, attempt to reopen INBOX */ string_free((void **) &session->other_foldername); session->other_stream = NIL; session->draft_stream = NIL; s = session_mailbox(session, request->pool, "inbox"); if (!(stream = ml_open(session, NIL, s, 0))) { session_alert(session, ("Unable to reestablish connection" " with IMAP server ")); generate_error_page(session); return; } session->inbox_last_ping_time = time(NIL); session->stream = session->inbox_stream = stream; /* initialise the zoommap */ msgmap_associate(zm, session, stream); msgmap_update(zm); /* Set current and last_displayed message to last or first in zoommap * (cmd_welcome may override with this last unread message) */ if (zm->nmsgs > 0) { if (zm->sort_reverse) session->current = msgmap_value(zm, 1); else session->current = msgmap_value(zm, zm->nmsgs); } else session->current = 0; session->last_displayed = session->current; session_redirect(session, request, "folders"); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_delete.c���������������������������������������������������������������������0000644�0065130�0065130�00000003106�11064236131�014562� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_delete.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_delete(struct session *session) { struct request *request = session->request; MAILSTREAM *stream = session->stream; unsigned long msgno, msguid; if (request->argc < 2) { session_redirect(session, request, "error"); return; } msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } if (!ml_flag (session, stream, string_itoa_tmp(msgno), "\\DELETED", ST_SET)) { session_alert(session, "Failed to delete message number %lu: %s", msgno, ml_errmsg()); session_log(session, "[cmd_delete] Failed to delete message number %lu from %s: %s", msgno, session->foldername, ml_errmsg()); session_redirect(session, request, "restart"); return; } session_message(session, "Deleted message number %lu", msgno); session_log(session, "[cmd_delete] Deleted message number %lu from %s", msgno, session->foldername); session_redirect(session, request, "list"); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_disp_undelete.c��������������������������������������������������������������0000644�0065130�0065130�00000006532�11064236131�016152� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_disp_undelete.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_disp_undelete(struct session *session) { struct request *request = session->request; struct pool *pool = request->pool; MAILSTREAM *stream = session->stream; unsigned long msgno, msguid; char *s; struct msgmap *zm = session->zm; unsigned long zm_offset; if (request->argc < 2) { session_redirect(session, request, "error"); return; } msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } if (!ml_flag(session, stream, string_itoa_tmp(msgno), "\\DELETED", 0)) { session_alert(session, "Failed to undelete message number %lu", msgno); session_log(session, ("[cmd_disp_undelete] " "Failed to undelete message number %lu from %s: %s"), msgno, session->foldername, ml_errmsg()); session_redirect(session, request, "restart"); return; } session_log(session, "[cmd_disp_undelete] Undeleted message number %lu from %s", msgno, session->foldername); /* Find next marked message, then invalidate zoom map */ if (!msgmap_update(zm)) { session_redirect(session, request, "restart"); return; } if (zm->sort_reverse) { zm_offset = msgmap_find(zm, msgno); if (zm_offset > 1) { unsigned long next = msgmap_value(zm, zm_offset - 1); session_message(session, ("Undeleted message number %lu, " "displaying %lu out of %lu"), msgno, next, zm->nmsgs); s = pool_printf(pool, "display/%lu/%lu", next, ml_uid(session, stream, next)); session_redirect(session, request, s); } else { session_message(session, "Undeleted message number %lu, no more messages", msgno); session->current = msgno; session_redirect(session, request, "list"); } } else { zm_offset = msgmap_find(zm, msgno); if (zm_offset < msgmap_size(zm)) { unsigned long next = msgmap_value(zm, zm_offset + 1); session_message(session, ("Undeleted message number %lu, " "displaying %lu out of %lu"), msgno, next, zm->nmsgs); s = pool_printf(pool, "display/%lu/%lu", next, ml_uid(session, stream, next)); session_redirect(session, request, s); } else { session_message(session, "Undeleted message number %lu, no more messages", msgno); session->current = msgno; session_redirect(session, request, "list"); } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_spam.c�����������������������������������������������������������������������0000644�0065130�0065130�00000014734�11064236131�014271� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_spam.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct account *account = session->account; struct buffer *b = request->write_buffer; unsigned long threshold = (account->spam_threshold_valid) ? account->spam_threshold : 10; template_vals_ulong(tvals, "spam_threshold", threshold); if (account->spam_enabled) template_vals_ulong(tvals, "spam_enabled", 1); if (session->sieved_server) template_vals_ulong(tvals, "using_sieve", 1); if (account->spam_purge_enabled) template_vals_ulong(tvals, "spam_purge_enabled", 1); template_vals_ulong(tvals, "spam_purge_timeout", account->spam_purge_timeout); if (account->spam_whitelist && account->spam_whitelist[0]) template_vals_string(tvals, "spam_whitelist", account->spam_whitelist); session_seed_template(session, tvals); template_expand("spam", tvals, b); response_html(request, 200); /* Success */ } static void generate_error(struct session *session) { struct template_vals *tvals = session->template_vals; struct account *account = session->account; struct request *request = session->request; char *msg = account_fetch_message(account); struct buffer *b = request->write_buffer; if (!(msg && msg[0])) msg = "Unable to check mail processing status"; template_vals_string(tvals, "msg", msg); session_seed_template(session, tvals); template_expand("spam_fail", tvals, b); response_html(request, 200); } /* Remove extraneous whitespace from each line in whitelist */ static char * normalise_whitelist(char *list, struct pool *pool) { struct buffer *b = buffer_create(pool, 64); char *tmp = pool_strdup(pool, list); /* Scratch copy */ char *s; while ((s=string_get_line(&tmp))) { if ((s=string_trim_whitespace(s)) && s[0]) { bputs(b, s); bputs(b, ""CRLF); } } return(buffer_fetch(b, 0, buffer_size(b), NIL)); } /* Check that addresslist consists of one valid address per line (wildcard characters are allowed in addresses) */ static BOOL validate_whitelist(struct session *session, char *list, struct pool *pool) { char *tmp = pool_strdup(pool, list); /* Scratch copy */ char *s; ADDRESS *addr; while ((s=string_get_line(&tmp))) { if ((s=string_trim_whitespace(s)) && s[0]) { addr = addr_parse(pool, s, ""); if (!addr) { session_message(session, "Invalid address: %s", s); return(NIL); } if (addr->next) { session_message(session, "Single address on each line please: %s", s); mail_free_address(&addr); return(NIL); } mail_free_address(&addr); } } return(T); } void cmd_spam(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct assoc *h = NIL; struct account *account = session->account; char *s, *t; if (request->method != POST) { if (!account_mail_check(account, request->pool)) generate_error(session); else generate_form(session); return; } /* Form post */ request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, "manage"); return; } s = assoc_lookup(h, "spam_threshold"); if (!(s && string_isnumber(s) && (atoi(s) > 0))) { session_message(session, "Threshold must be a number greater than zero"); generate_form(session); return; } account->spam_enabled = assoc_lookup(h, "sub_enable") ? T : NIL; account->spam_threshold = atoi(s); account->spam_threshold_valid = T; /* Spam whitelist and purge currently only available to sieve users */ if (session->sieved_server) { if ((t = assoc_lookup(h, "spam_whitelist"))) { string_strdup(&account->spam_whitelist, normalise_whitelist(t, request->pool)); if (!validate_whitelist(session, account->spam_whitelist, request->pool)) { generate_form(session); return; } } else string_strdup(&account->spam_whitelist, ""); t = assoc_lookup(h, "spam_purge_timeout"); if (!(t && string_isnumber(t) && (atoi(t) >= 0))) { session_message(session, "Purge time must be a non-negative integer"); generate_form(session); return; } account->spam_purge_timeout = atoi(t); account->spam_purge_enabled = assoc_lookup(h, "spam_purge") ? T : NIL; if (account->spam_purge_enabled) { session_log(session, "[cmd_spam] spam_purge enabled: %d days", account->spam_purge_timeout); } else { session_log(session, "[cmd_spam] spam_purge disabled"); } } if (!account_mail_update(account, request->pool)) { char *msg = account_fetch_message(account); session_alert(session, "Failed to update spam filter: %s", msg); session_log(session, "[cmd_spam] Failed to update spam filter: %s", msg); generate_form(session); return; } if (account->spam_enabled && !folderlist_lookup(session->folderlist, "spam")) { if (ml_create(session, session->stream, session_mailbox(session, request->pool, "spam"))) { if (config->dualuse) folderlist_add(session->folderlist, "spam", NIL, NIL); else folderlist_add(session->folderlist, "spam", NIL, T); } else session_alert(session, "Failed to create spam folder"); } session_message(session, "Updated junk email filtering"); session_redirect(session, request, "manage"); } ������������������������������������./prayer-1.3.5/cmd/cmd_detach.c���������������������������������������������������������������������0000644�0065130�0065130�00000001360�11063701633�014553� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_detach.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_detach(struct session *session) { struct request *request = session->request; struct draft *draft = session->draft; if (request->argc < 2) { session_redirect(session, request, "error"); return; } draft_delete_attachment(draft, atoi(request->argv[1])); session_redirect(session, request, "attachments"); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_error.c����������������������������������������������������������������������0000644�0065130�0065130�00000001330�11063701633�014451� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_error.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_error(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; session_seed_template(session, tvals); template_expand("error", tvals, b); response_html(request, 200); /* Success */ } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_unmark.c���������������������������������������������������������������������0000644�0065130�0065130�00000004630�11064236131�014620� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_unmark.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_unmark(struct session *session) { struct request *request = session->request; MAILSTREAM *stream = session->stream; if ((request->argc == 2) && (!strcmp(request->argv[1], "all"))) { struct msgmap *zm = session->zm; unsigned long count = zm->marked; msgmap_unmark_all(zm); if (count != 1) session_message(session, "Unmarked %lu messages", count); else session_message(session, "Unmarked 1 message"); } else if ((request->argc == 4) && (!strcmp(request->argv[1], "read"))) { unsigned long msgno = atoi(request->argv[2]); unsigned long msguid = atoi(request->argv[3]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } session->current = msgno; if (!ml_flag(session, stream, string_itoa_tmp(msgno), "\\SEEN", 0)) { session_alert(session, "Failed to mark message %lu as unread: %s", msgno, ml_errmsg()); session_log(session, ("[cmd_unmark] " "Failed to mark message number %lu as unread: %s"), msgno, ml_errmsg()); session_redirect(session, request, "restart"); return; } session_message(session, "Marked message %lu as read", msgno); } else if (request->argc == 3) { unsigned long msgno = atoi(request->argv[1]); unsigned long msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } if (msgmap_unmark(session->zm, msgno)) session_message(session, "Unmarked message %lu", msgno); else session_message(session, "Message %lu already unmarked", msgno); } session_redirect(session, request, "list"); } ��������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_include.c��������������������������������������������������������������������0000644�0065130�0065130�00000003342�11064236131�014745� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_include.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; session_seed_template(session, tvals); template_expand("include", tvals, b); response_html(request, 200); } void cmd_include(struct session *session) { struct request *request = session->request; struct draft *draft = session->draft; char *start, *end; unsigned long len; if ((request->argc >= 2) && (!strcmp(request->argv[1], "cancel"))) { session_redirect(session, request, "compose"); return; } if (request->method != POST) { generate_form(session); return; } request_decode_post_multipart(request, NIL, &start, &end); *end = '\0'; if (end > start) len = (char *) end - (char *) start; else len = 0; if (len < 1) { session_alert(session, "Please choose a file to include"); generate_form(session); return; } session_log(session, "[cmd_include] Included %lu bytes", end - start); if (draft->body && draft->body[0]) draft->body = pool_strcat3(draft->pool, draft->body, CRLF, start); else draft->body = pool_strdup(draft->pool, start); session_redirect(session, request, "compose"); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_disp_mark.c������������������������������������������������������������������0000644�0065130�0065130�00000004337�11063701633�015303� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_disp_mark.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_disp_mark(struct session *session) { struct msgmap *zm = session->zm; struct request *request = session->request; struct pool *pool = request->pool; MAILSTREAM *stream = session->stream; unsigned long msgno, msguid; char *s; unsigned long zm_offset; if (request->argc < 2) { session_redirect(session, request, "error"); return; } msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } /* Find next message in msgmap */ if (!msgmap_update(zm)) { session_redirect(session, request, "restart"); return; } zm_offset = msgmap_find(zm, msgno); if (zm_offset < msgmap_size(zm)) { unsigned long next = msgmap_value(zm, zm_offset + 1); if (msgmap_mark(zm, msgno)) session_message(session, "Marked message %lu, displaying %lu out of %lu", msgno, next, zm->nmsgs); else session_message(session, "Message %lu already marked, displaying %lu out of %lu", msgno, next, zm->nmsgs); s = pool_printf(pool, "display/%lu/%lu", next, ml_uid(session, stream, next)); session_redirect(session, request, s); } else { if (msgmap_mark(zm, msgno)) session_message(session, "Marked message %lu, no more messages", msgno); else session_message(session, "Message %lu already marked, no more messages", msgno); session->current = msgno; session_redirect(session, request, "list"); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_disp_delete.c����������������������������������������������������������������0000644�0065130�0065130�00000006423�11064236131�015606� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_disp_delete.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_disp_delete(struct session *session) { struct request *request = session->request; struct pool *pool = request->pool; MAILSTREAM *stream = session->stream; unsigned long msgno, msguid; char *s; struct msgmap *zm = session->zm; unsigned long zm_offset; if (request->argc < 2) { session_redirect(session, request, "error"); return; } msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } if (!ml_flag (session, stream, string_itoa_tmp(msgno), "\\DELETED", ST_SET)) { session_alert(session, "Failed to delete message number %lu", msgno); session_log(session, ("[cmd_disp_delete] " "Failed to delete message number %lu from %s: %s"), msgno, session->foldername, ml_errmsg()); session_redirect(session, request, "restart"); return; } session_log(session, "[cmd_disp_delete] Deleted message number %lu from %s", msgno, session->foldername); /* Find next message */ if (!msgmap_update(zm)) { session_redirect(session, request, "restart"); return; } if (zm->sort_reverse) { zm_offset = msgmap_find(zm, msgno); if (zm_offset > 1) { unsigned long next = msgmap_value(zm, zm_offset - 1); session_message(session, "Deleted message number %lu, displaying %lu out of %lu", msgno, next, zm->nmsgs); s = pool_printf(pool, "display/%lu/%lu", next, ml_uid(session, stream, next)); session_redirect(session, request, s); } else { session_message(session, "Deleted message number %lu, no more messages", msgno); session->current = msgno; session_redirect(session, request, "list"); } } else { zm_offset = msgmap_find(zm, msgno); if (zm_offset < msgmap_size(zm)) { unsigned long next = msgmap_value(zm, zm_offset + 1); session_message(session, "Deleted message number %lu, displaying %lu out of %lu", msgno, next, zm->nmsgs); s = pool_printf(pool, "display/%lu/%lu", next, ml_uid(session, stream, next)); session_redirect(session, request, s); } else { session_message(session, "Deleted message number %lu, no more messages", msgno); session->current = msgno; session_redirect(session, request, "list"); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_subscribe.c������������������������������������������������������������������0000644�0065130�0065130�00000002506�11063701633�015307� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_subscribe.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_subscribe(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct favourite_list *fl = options->favourite_list; char *name; if (request->argc == 2) { name = string_canon_decode(pool_strdup (request->pool, request->argv[1])); if (string_filename_valid(name)) { if (favourite_add(fl, name)) { options->save = T; session_message(session, "Added %s to favourites list", utf8_from_imaputf7(request->pool, name)); } else session_message(session, "Already on favourites list", name); } else session_message(session, "String contained illegal characters"); } session_redirect(session, request, "favourites"); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_manage.c���������������������������������������������������������������������0000644�0065130�0065130�00000006321�11243457414�014562� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_manage.c,v 1.4 2009/08/21 08:47:08 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_manage(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct assoc *h = NIL; char *s; struct buffer *b = request->write_buffer; struct template_vals *tvals = session->template_vals; /* Record last command for compose/cancel and friends */ if (!session->draft->have_draft) session->compose_parent_cmd = "manage"; if (request->method != POST) { /* Save options if anything changed */ if (session->options->save) session_streams_save_options(session); if (session->sieved_server) template_vals_ulong(tvals, "using_sieve", 1); session_seed_template(session, tvals); if (config->accountd_server && config->accountd_server[0]) { template_vals_string(tvals, "accountd_server", config->accountd_server); } template_expand("manage", tvals, b); response_html(request, 200); return; } request_decode_form(request); h = request->form; if ((s = assoc_lookup(h, "sub_cancel"))) { /* Free up working preferences and return to list screen */ session_redirect(session, request, "list"); return; } if (assoc_lookup(h, "sub_prefs")) { session_redirect(session, request, "prefs"); return; } if (assoc_lookup(h, "sub_passwd")) { session_redirect(session, request, "passwd"); return; } if (assoc_lookup(h, "sub_fullname")) { session_redirect(session, request, "fullname"); return; } if (assoc_lookup(h, "sub_quota")) { session_redirect(session, request, "quota"); return; } if (assoc_lookup(h, "sub_redirect")) { session_redirect(session, request, "redirect"); return; } if (assoc_lookup(h, "sub_vacation")) { session_redirect(session, request, "vacation"); return; } if (assoc_lookup(h, "sub_vaclog")) { session_redirect(session, request, "vaclog"); return; } if (assoc_lookup(h, "sub_filter")) { session_redirect(session, request, "filter"); return; } if (assoc_lookup(h, "sub_block")) { session_redirect(session, request, "block"); return; } if (assoc_lookup(h, "sub_spam")) { session_redirect(session, request, "spam"); return; } if (assoc_lookup(h, "sub_sieve")) { session_redirect(session, request, "sieve"); return; } if (assoc_lookup(h, "sub_roles")) { session_redirect(session, request, "roles_list"); return; } if (assoc_lookup(h, "sub_dictionary")) { session_redirect(session, request, "dictionary"); return; } session_redirect(session, request, "list"); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_compose1.c�������������������������������������������������������������������0000644�0065130�0065130�00000001704�11063701633�015053� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_compose1.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_compose1(struct session *session) { struct request *request = session->request; struct draft *draft = session->draft; struct options *options = session->options; struct role *role = NIL; char *s; request_decode_form(request); if ((s = assoc_lookup(request->form, "role"))) role = role_find(options->role_list, s); /* Set up draft and role */ draft_role_set(draft, role); draft_init(draft); draft_init_rich_headers(draft); /* Redirect to draft */ session_redirect(session, request, "compose"); } ������������������������������������������������������������./prayer-1.3.5/cmd/cmd_copy_msg.c�������������������������������������������������������������������0000644�0065130�0065130�00000014163�11064236131�015145� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_copy_msg.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_copy_msg(struct session *session) { struct request *request = session->request; MAILSTREAM *stream = session->stream; struct prefs *prefs = session->options->prefs; char *mailbox; unsigned long count = 0; unsigned long next; struct pool *pool = request->pool; unsigned long msgno; char *s; struct msgmap *zm = session->zm; unsigned long zm_offset; if (request->argc < 2) { session_redirect(session, request, "error"); return; } mailbox = pool_strdup(request->pool, request->argv[1]); string_canon_decode(mailbox); if (!string_filename_valid(mailbox)) { session_alert(session, "Path contained illegal characters"); session_redirect(session, request, "display"); return; } ml_clear_error(); ml_clear_try_create(); if (session->aggregate) { char *seq; if (prefs->use_mark_persist) seq = msgmap_mark_sequence(session->zm); else seq = msgmap_tmp_mark_sequence(session->zm); if (seq && seq[0] && !ml_copy(session, stream, seq, mailbox, CP_MOVE)) { if (ml_have_close()) { session_redirect(session, request, "restart"); return; } if (ml_have_error()) { session_alert(session, "Copy failed: %s", ml_errmsg()); session_log(session, "[cmd_copy_msg] Copy failed to %s: %s", mailbox, ml_errmsg()); session_redirect(session, request, session->copy_parent_cmd); return; } } if (prefs->use_mark_persist) { count = msgmap_marked_count(session->zm); /* Unmark messages unless error occurred */ if (!ml_have_error() && prefs->use_agg_unmark) { msgmap_unmark_all(session->zm); msgmap_disable_zoom(session->zm); } } else { count = msgmap_tmp_marked_count(session->zm); msgmap_tmp_unmark_all(session->zm); } } else { if (!ml_copy(session, stream, string_itoa_tmp(session->current), mailbox, CP_MOVE)) { if (ml_have_close()) { session_redirect(session, request, "restart"); return; } if (ml_have_error()) { session_alert(session, "Copy failed: %s", ml_errmsg()); session_log(session, "[cmd_copy_msg] Copy failed to %s: %s", mailbox, ml_errmsg()); session_redirect(session, request, session->copy_parent_cmd); return; } } count = 1; } /* Need to ping target stream if we are saving to an active folder */ if (!session_streams_ping(session, mailbox)) { session_redirect(session, request, "restart"); return; } if (ml_have_try_create()) { session_alert(session, "Copy failed (need to create folder first)"); session_log(session, "[cmd_copy_msg] Copy failed [TRYCREATE]"); session_redirect(session, request, session->copy_parent_cmd); return; } if (ml_have_error()) { session_alert(session, "Copy operation failed: %s", ml_errmsg()); session_log(session, "[cmd_copy_msg] Copy operation failed: %s", ml_errmsg()); session_redirect(session, request, session->copy_parent_cmd); return; } if (!(!strcmp(session->copy_parent_cmd, "display") && !session->aggregate)) { /* Keep current message */ if (count > 1) { session_message(session, "Copied %lu messages to %s", count, utf8_from_imaputf7(request->pool, mailbox)); session_log(session, "[cmd_copy_msg] Copied %lu messages to %s", count, mailbox); } else if (count == 1) { session_message(session, "Copied 1 message to %s", utf8_from_imaputf7(request->pool, mailbox)); session_log(session, "[cmd_copy_msg] Copied 1 message to %s", mailbox); } else { session_message(session, "No messages marked to copy"); session_log(session, "[cmd_copy_msg] No messages marked to copy"); } session_redirect(session, request, session->copy_parent_cmd); return; } /* Locate next message */ msgno = session->current; zm_offset = msgmap_find(zm, msgno); if (zm->sort_reverse && (zm_offset > 1)) next = msgmap_value(zm, zm_offset - 1); else if (!zm->sort_reverse && (zm_offset < msgmap_size(zm))) next = msgmap_value(zm, zm_offset + 1); else { /* No next message */ session_message(session, "Copied message %lu to \"%s\", no more messages", msgno, utf8_from_imaputf7(request->pool, mailbox)); session_log(session, "[cmd_copy_msg] Copied message %lu to %s", msgno, mailbox); session->current = msgno; session_redirect(session, request, "list"); return; } session_message(session, "Copied message %lu to \"%s\", displaying %lu out of %lu", msgno, utf8_from_imaputf7(request->pool, mailbox), next, zm->nmsgs); session_log(session, "[cmd_copy_msg] Copied message %lu to %s", msgno, mailbox); s = pool_printf(pool, "display/%lu/%lu", next, ml_uid(session, stream, next)); session_redirect(session, request, s); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_add.c������������������������������������������������������������������0000644�0065130�0065130�00000010414�11064236131�015223� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_add.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session, struct assoc *h) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; template_vals_string(tvals, "alias", assoc_lookup(h, "alias")); template_vals_string(tvals, "name", assoc_lookup(h, "name")); template_vals_string(tvals, "comment", assoc_lookup(h, "comment")); template_vals_string(tvals, "email", assoc_lookup(h, "email")); session_seed_template(session, tvals); template_expand("abook_add", tvals, b); response_html(request, 200); /* Success */ } void cmd_abook_add(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct assoc *h = NIL; char *s; if (request->method != POST) { if (request->get_suffix) { request_decode_form(request); h = request->form; } generate_form(session, h); return; } request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, "abook_list"); return; } if (assoc_lookup(h, "delete_entry") && (s = assoc_lookup(h, "alias"))) { abook_remove(options->abook, s); session->options->save = T; session_message(session, "Removed address book entry: \"%s\"", s); } if (assoc_lookup(h, "sub_add")) { char *alias = assoc_lookup(h, "alias"); char *name = assoc_lookup(h, "name"); char *fcc = pool_strdup(request->pool, ""); /* Not yet */ char *comment = assoc_lookup(h, "comment"); char *email = assoc_lookup(h, "email"); if (alias) alias = string_trim_whitespace(alias); else alias = ""; if (!alias[0]) { session_alert(session, "No alias provided"); generate_form(session, h); return; } if (strchr(alias, ' ') || strchr(alias, '\t')) { session_alert(session, "Alias cannot contain spaces"); generate_form(session, h); return; } if (!(name && comment && email)) { session_alert(session, "Missing form entries"); generate_form(session, h); return; } name = string_trim_whitespace(name); fcc = string_trim_whitespace(fcc); comment = string_trim_whitespace(comment); email = string_trim_whitespace(email); if (abook_lookup(options->abook, alias)) { session_alert(session, "An addressbook entry named \"%s\" already exists", alias); generate_form(session, h); return; } if (email[0] == '\0') { session_alert(session, "No email address supplied"); generate_form(session, h); return; } if (!addr_check_valid(request->pool, email)) { session_alert(session, "%s", ml_errmsg()); generate_form(session, h); return; } /* Have to add unchecked entry to addressbook to spot all possible loops */ abook_replace(options->abook, alias, name, fcc, comment, email); if (!abook_check_loop(request->pool, options->abook, alias, T)) { /* Easy to revert to old addressbook in this case... */ abook_remove(options->abook, alias); session_alert(session, "Addressbook loop involving alias \"%s\"", assoc_lookup(h, "alias")); generate_form(session, h); return; } session_message(session, "Updated address book entry: \"%s\"", alias); session->options->save = T; } session_redirect(session, request, "abook_list"); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_list.c�����������������������������������������������������������������������0000644�0065130�0065130�00000040026�11555510532�014302� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_list.c,v 1.6 2011/04/26 09:33:14 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Add template_vals used to navigate to other pages */ static BOOL cmd_list_addsort(struct session *session) { struct template_vals *tvals = session->template_vals; struct msgmap *zm = session->zm; switch (zm->sort_mode) { case ARRIVAL: template_vals_string(tvals, "$sort_mode", "arrival"); break; case DATE: template_vals_string(tvals, "$sort_mode", "date"); break; case FROM: template_vals_string(tvals, "$sort_mode", "from"); break; case SUBJECT: template_vals_string(tvals, "$sort_mode", "subject"); break; case TO: template_vals_string(tvals, "$sort_mode", "to"); break; case CC: template_vals_string(tvals, "$sort_mode", "cc"); break; case SIZE: template_vals_string(tvals, "$sort_mode", "size"); break; case REFERENCES: template_vals_string(tvals, "$sort_mode", "references"); break; case ORDEREDSUBJECT: template_vals_string(tvals, "$sort_mode", "orderedsubject"); break; } if (zm->sort_reverse) template_vals_ulong(tvals, "$sort_reverse", 1); return(T); } static BOOL cmd_list_addnav(struct session *session, unsigned long zm_offset) { struct template_vals *tvals = session->template_vals; struct prefs *prefs = session->options->prefs; struct msgmap *zm = session->zm; MAILSTREAM *stream = session->stream; unsigned long count = msgmap_size(session->zm); unsigned long per_page = prefs->msgs_per_page; unsigned long page = 0; unsigned long pages = 0; unsigned msgno; unsigned uid; if (count > 0) { page = ((zm_offset - 1) / prefs->msgs_per_page) + 1; pages = ((count - 1) / prefs->msgs_per_page) + 1; } template_vals_hash_ulong(tvals, "$nav", "msg_count", count); template_vals_hash_ulong(tvals, "$nav", "page_current", page); template_vals_hash_ulong(tvals, "$nav", "page_count", pages); if (page > 1) { msgno = msgmap_value(zm, 1); uid = ml_uid(session, stream, msgno); template_vals_hash_ulong(tvals, "$nav", "first_msg", msgno); template_vals_hash_ulong(tvals, "$nav", "first_uid", uid); msgno = msgmap_value(zm, zm_offset - per_page); uid = ml_uid(session, stream, msgno); template_vals_hash_ulong(tvals, "$nav", "prev_msg", msgno); template_vals_hash_ulong(tvals, "$nav", "prev_uid", uid); } if (page < pages) { if ((msgno = (zm_offset + per_page)) > count) msgno = count; msgno = msgmap_value(zm, msgno); uid = ml_uid(session, stream, msgno); template_vals_hash_ulong(tvals, "$nav", "next_msg", msgno); template_vals_hash_ulong(tvals, "$nav", "next_uid", uid); msgno = msgmap_value(zm, count); uid = ml_uid(session, stream, msgno); template_vals_hash_ulong(tvals, "$nav", "last_msg", msgno); template_vals_hash_ulong(tvals, "$nav", "last_uid", uid); } return(T); } /* Add template_vals for a single message */ /* Look for non-text leaf */ static BOOL body_has_attachments(BODY *body) { PART *part; int i; switch (body->type) { case TYPEMULTIPART: for (i = 1, part = body->nested.part; part != NIL; part = part->next, i++) { if (body_has_attachments(&part->body)) return(T); } break; case TYPEMESSAGE: if (body->type != TYPEMULTIPART) return(NIL); /* Nested multipart message */ for (i = 1, part = body->nested.part; part != NIL; part = part->next, i++) { if (body_has_attachments(&part->body)) return(T); } break; case TYPETEXT: return(NIL); default: return(T); } return(NIL); } static BOOL cmd_list_msg(struct session *session, MAILSTREAM * stream, unsigned long msgno, ADDRESS * alt_addr, int offset) { struct template_vals *tvals = session->template_vals; struct config *config = session->config; struct prefs *prefs = session->options->prefs; struct request *request = session->request; struct pool *pool = request->pool; MESSAGECACHE *elt; ENVELOPE *env; BODY *body = NIL; ADDRESS *addr; BOOL use_to; char *string; char *pstring; if (!((elt = ml_elt(session, stream, msgno)) && (env = ml_fetch_structure(session, stream, msgno, &body, 0)))) return (NIL); template_vals_foreach_init(tvals, "@list_msg", offset); template_vals_foreach_ulong(tvals, "@list_msg", offset, "num", msgno); template_vals_foreach_ulong(tvals, "@list_msg", offset, "uid", ml_uid(session, stream, msgno)); if (elt->deleted) template_vals_foreach_ulong(tvals, "@list_msg", offset, "is_deleted", 1); if (elt->answered) template_vals_foreach_ulong(tvals, "@list_msg", offset, "is_answered", 1); if (elt->seen) template_vals_foreach_ulong(tvals, "@list_msg", offset, "is_seen", 1); if (prefs->use_mark_persist && msgmap_has_mark(session->zm, msgno)) template_vals_foreach_ulong(tvals, "@list_msg", offset, "is_marked", 1); if (offset % 2 == 0) template_vals_foreach_ulong(tvals, "@list_msg", offset, "even_row", 1); if (body && body_has_attachments(body)) template_vals_foreach_ulong(tvals, "@list_msg", offset, "has_attach", 1); /* Message Date */ if (env->date) { MESSAGECACHE tmp; mail_parse_date(&tmp, env->date); string = mc_date_to_string_full(&tmp); } else string = "(No date)"; if (string && string[0]) template_vals_foreach_string(tvals, "@list_msg", offset, "date", string); /* Try and work out if user sent this message * Yes => show "To:" rather than from address in header. */ use_to = NIL; if ((addr = env->from) && addr->host) { while (alt_addr) { if (!strcasecmp(addr->mailbox, alt_addr->mailbox) && !strcasecmp(addr->host, alt_addr->host)) { use_to = T; break; } alt_addr = alt_addr->next; } if (!use_to && !strcasecmp(addr->mailbox, session->username) && config->local_domain_list) { /* Find out if address is local use of CRSid * e.g: dpc22@cam.ac.uk, dpc22@hermes.cam.ac.uk */ struct list_item *li; /* Check for username@[username_domain]. */ for (li = config->local_domain_list->head; li; li = li->next) { if (!strcasecmp(li->name, addr->host)) { use_to = T; break; } } } } /* From or To address depending on context */ addr = (use_to) ? env->to : env->from; if (addr && addr->personal) string = addr->personal; else if (addr && addr->mailbox && addr->host) string = pool_printf(pool, "%s@%s", addr->mailbox, addr->host); else string = "(unknown)"; string = (char *) rfc1522_decode(pool_alloc(pool, strlen(string)), strlen(string), string, NIL); pstring = utf8_prune(pool, string, config->list_addr_maxlen); if (use_to) { string = pool_strcat(pool, "To: ", string); pstring = pool_strcat(pool, "To: ", pstring); } template_vals_foreach_string(tvals, "@list_msg", offset, "full_dname", string); template_vals_foreach_string(tvals, "@list_msg", offset, "dname", pstring); /* Message size */ if (elt->rfc822_size > 1024) string = pool_printf(pool, "%luK", elt->rfc822_size / 1024); else string = pool_printf(pool, "%lu", elt->rfc822_size); template_vals_foreach_string(tvals, "@list_msg", offset, "size", string); /* Message subject */ if (env->subject && env->subject[0]) { string = env->subject; string = (char *) rfc1522_decode(pool_alloc(pool, strlen(string)), strlen(string), string, NIL); pstring = utf8_prune(pool, string, config->list_subject_maxlen); } else pstring = string = "(No subject)"; template_vals_foreach_string(tvals, "@list_msg", offset, "full_subject", string); template_vals_foreach_string(tvals, "@list_msg", offset, "subject", pstring); return (T); } /* ====================================================================== */ /* Couple of small support routines for alt_addr stuff */ static ADDRESS *cmd_list_alt_addr_generate(struct session *session, struct pool *pool, struct prefs *prefs) { ADDRESS *alt_addr = NIL; char *text; if (prefs->from_address && prefs->from_address[0]) { if (prefs->alt_addr && prefs->alt_addr[0]) text = pool_printf(pool, "%s, %s", prefs->from_address, prefs->alt_addr); else text = pool_strdup(pool, prefs->from_address); } else text = pool_strdup(pool, prefs->alt_addr); if (text && text[0] && !(alt_addr=addr_parse_destructive(text, ""))) { session_alert(session, "Alt-address invalid - %s", ml_errmsg()); return(NIL); } return (alt_addr); } static void cmd_list_alt_addr_free(ADDRESS * alt_addr) { mail_free_address(&alt_addr); } /* cmd_list_work() ******************************************************* * * Generate list screen. Parent routine will clean up after error. ************************************************************************/ static BOOL cmd_list_work(struct session *session) { struct request *request = session->request; struct prefs *prefs = session->options->prefs; unsigned long first, current, last; MAILSTREAM *stream = session->stream; struct buffer *b = request->write_buffer; struct msgmap *zm = session->zm; unsigned long zm_offset; ADDRESS *alt_addr; unsigned long count; struct template_vals *tvals = session->template_vals; int offset = 0; BOOL mark_page = NIL; BOOL unmark_page = NIL; if (!msgmap_update(zm)) return (NIL); if (request->argc == 3) { unsigned long msgno = atoi(request->argv[1]); unsigned long msguid = atoi(request->argv[2]); if ((msgno == 0) || (msgno > zm->nmsgs) || (!(msgno = stream_check_uid(session, stream, msgno, msguid)))) msgno = zm->nmsgs; session->current = msgno; } else if (request->argc == 2) { if (!strcmp(request->argv[1], "mark")) { mark_page = T; } else if (!strcmp(request->argv[1], "unmark")) { unmark_page = T; } } /* Expunge event => session->current may no longer be valid? */ if ((session->current == 0) || (session->current > zm->nmsgs)) session->current = zm->nmsgs; zm_offset = msgmap_find(zm, session->current); count = msgmap_size(session->zm); if (zm_offset > prefs->msgs_per_page) first = zm_offset - ((zm_offset - 1) % prefs->msgs_per_page); else first = 1; last = (((first + prefs->msgs_per_page - 1) < count) ? (first + prefs->msgs_per_page - 1) : count); if (prefs->use_mark_persist) template_vals_ulong(tvals, "use_persist", 1); if (msgmap_marked_count(session->zm) > 0) template_vals_ulong(tvals, "have_marked", 1); if (msgmap_have_zoom(session->zm)) template_vals_ulong(tvals, "have_zoom", 1); cmd_list_addsort(session); cmd_list_addnav(session, zm_offset); alt_addr = cmd_list_alt_addr_generate(session, request->pool, prefs); if (prefs->use_mark_persist) { int msgs_on_page = 0; int marked_on_page = 0; int change_count = 0; if (mark_page || unmark_page) { /* Mark or unmark all message on the page */ for (current = first; current <= last; current++) { if (mark_page && !msgmap_has_mark(zm, current)) { msgmap_mark(session->zm, current); change_count++; } else if (unmark_page && msgmap_has_mark(zm, current)) { msgmap_unmark(session->zm, current); change_count++; } } session_message(session, "%s %lu %s", (mark_page) ? "Marked" : "Unmarked", (change_count), ((change_count) != 1) ? "messages" : "message"); } /* Work out sensible state for top link */ for (current = first; current <= last; current++) { msgs_on_page++; if (msgmap_has_mark(zm, current)) marked_on_page++; } if (marked_on_page == msgs_on_page) template_vals_ulong(tvals, "page_all_marked", 1); } else { /* !prefs->use_mark_persist */ if (mark_page) template_vals_ulong(tvals, "page_all_marked", 1); } offset = 0; for (current = first; current <= last; current++) { if (!cmd_list_msg(session, stream, msgmap_value(zm, current), alt_addr, offset)) return (NIL); offset++; } cmd_list_alt_addr_free(alt_addr); template_vals_string(tvals, "foldername", session->foldername); session_seed_template(session, tvals); template_expand("list", tvals, b); return (T); } /* ====================================================================== */ void cmd_list(struct session *session) { struct options *options = session->options; struct msgmap *zm = session->zm; struct request *request = session->request; char *cmd, *folder; /* Handle POST requests: folder change requests */ if (request->method == POST) { request_decode_form(request); if (assoc_lookup(request->form, "sub_folder_dialogue") && (folder = assoc_lookup(request->form, "folder")) && folder[0]) { if ((cmd = assoc_lookup(request->form, "command")) && !strcmp(cmd, "copy")) { session->aggregate = T; session_redirect(session, request, pool_strcat(request->pool, "copy_msg/", folder)); } else session_redirect(session, request, pool_strcat(request->pool, "change/", folder)); return; } } /* Save options if anything changed */ if (options->save) session_streams_save_options(session); /* Record last command for compose/cancel and friends */ if (!session->draft->have_draft) session->compose_parent_cmd = "list"; /* Record last command for copy/cancel */ session->copy_parent_cmd = "list"; if (msgmap_have_zoom(zm) && (msgmap_marked_count(zm) == 0)) { msgmap_unmark_all(zm); msgmap_disable_zoom(zm); session_message(session, "No messages marked: disabling zoom mode"); } if (!cmd_list_work(session)) { session_redirect(session, request, "restart"); return; } /* Send out HTML */ response_html(request, 200); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_welcome.c��������������������������������������������������������������������0000644�0065130�0065130�00000004566�11102562027�014765� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_welcome.c,v 1.5 2008/10/31 10:55:19 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_welcome_page(struct session *session) { struct template_vals *tvals = session->template_vals; struct pool *pool = tvals->pool; struct config *config = session->config; struct request *request = session->request; struct buffer *b = request->write_buffer; char *s; unsigned long hours = config->session_timeout / (60 * 60); unsigned long mins = (config->session_timeout / 60) % 60; if ((hours > 1) && (mins > 1)) s = pool_printf(pool, "%lu hours and %lu minutes", hours, mins); else if ((hours > 1) && (mins == 1)) s = pool_printf(pool, "%lu hours and 1 minutes", hours); else if (hours > 1) s = pool_printf(pool, "%lu hours", hours); else if (hours == 1) s = "1 hour"; else s = pool_printf(pool, "%lu minutes", mins); template_vals_string(tvals, "timeout", s); session_seed_template(session, tvals); template_expand("welcome", tvals, b); response_html(request, 200); } void cmd_welcome(struct session *session) { struct options *options = session->options; struct prefs *prefs = options->prefs; struct request *request = session->request; unsigned long msgno; if ((request->method != POST) && (prefs->use_welcome)) { generate_welcome_page(session); return; } if (request->method == POST) { request_decode_form(request); if (!assoc_lookup(request->form, "enable_welcome")) { options->prefs->use_welcome = NIL; options->prefs_save->use_welcome = NIL; session->options->save = T; } } msgno = stream_find_unread(session, session->stream); if (msgno > 0) { if (prefs->use_unread) { session->current = msgno; session->last_displayed = msgno; } session_message(session, "First unread message: %lu", msgno); } else session_message(session, "No unread messages in inbox"); session_redirect(session, request, "list"); } ������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_spell.c����������������������������������������������������������������������0000644�0065130�0065130�00000022757�11064236131�014454� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_spell.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static char * generate_text(struct speller *speller, struct pool *pool, char *word) { struct buffer *b = buffer_create(pool, 128); char *t, c; unsigned long len = utf8_len(word); speller_print_lastline(speller, b); /* Print word (need to highlight) */ bputs(b, "<b>"); t = word; while ((c = *t++) && (c != '\015') && (c != '\012')) html_quote_char(b, c); bputs(b, "</b>"); /* Print remainder of line */ t = speller->line; utf8_find_offset(&t, speller->offset + len); while ((c = *t) && (c != '\015') && (c != '\012')) { html_quote_char(b, c); t++; } /* And next line if that exists */ if (c) { t += ((t[0] == '\015') && (t[1] == '\012')) ? 2 : 1; bputs(b, "" CRLF); while ((c = *t++) && (c != '\015') && (c != '\012')) html_quote_char(b, c); } /* Plus third line if we are at start of text */ if (c && (speller->last_line == 0)) { t += ((t[0] == '\015') && (t[1] == '\012')) ? 2 : 1; bputs(b, "" CRLF); while ((c = *t++) && (c != '\015') && (c != '\012')) html_quote_char(b, c); } return(buffer_fetch(b, 0, buffer_size(b), NIL)); } /* ====================================================================== */ static BOOL process_line(struct session *session, struct request *request, struct speller *speller, char *s, BOOL is_alt_line) { struct template_vals *tvals = session->template_vals; struct buffer *b = request->write_buffer; char *t, *word, c; unsigned long count, offset, len, maxlen, i, perline; char **alts; char *text; /* Format: word count offset: word1 word2 word3 */ word = string_get_token(&s); if (is_alt_line) count = atoi(string_get_token(&s)); else count = 0; offset = atoi(string_get_token(&s)); /* Snarfs trailing ':' as well */ /* Adjust for "^" sent at start of each line */ if (offset > 0) offset--; /* Copy line up to designated offset */ speller_copy_to_offset(speller, offset); speller_record_cursize(speller, utf8_len(word)); /* Check word against permanent dictionary */ if (dictionary_lookup(session->options->dictionary, word)) return (NIL); /* Check word against current ignore list */ if (speller_check_ignore_list(speller, word)) return (NIL); text = generate_text(speller, tvals->pool, word); template_vals_string(tvals, "$text", text); template_vals_string(tvals, "$word", word); template_vals_ulong(tvals, "$close_count", count); if (speller->no_changes > 0) template_vals_ulong(tvals, "$have_changes", 1); alts = pool_alloc(request->pool, (count + 1) * sizeof(char *)); maxlen = 0; for (i = 0; i < count; i++) { while (*s == ' ') /* Skip leading whitespace */ s++; if (*s == '\0') /* Reached end of line? */ break; alts[i] = t = s; /* Record start of token */ while ((c = *s) && (c != ',')) /* Scan for end of line or ',' separator */ s++; len = s - t; /* Calculate length of string */ if (len > maxlen) maxlen = len; if (*s) /* Make sure that string is tied off */ *s++ = '\0'; } alts[i] = NIL; if ((maxlen > 0) && (maxlen < 38)) perline = 80 / (maxlen + 5); else perline = 1; for (i = 0; alts[i]; i++) { template_vals_foreach_init(tvals, "@close", i); template_vals_foreach_string(tvals, "@close", i, "word", alts[i]); if ((i % perline) == (perline - 1)) template_vals_foreach_ulong(tvals, "@close", i, "break", 1); } session_seed_template(session, tvals); template_expand("spell", tvals, b); return (T); } /* ====================================================================== */ void cmd_spell(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct prefs *prefs = options->prefs; struct draft *draft = session->draft; struct speller *speller = session->speller; char *line, *s; struct assoc *h; if (!draft->body) { session_message(session, "No draft message currently active"); session_redirect(session, request, "list"); return; } if (!session->sequence_okay) { if (speller_active(speller)) speller_stop(speller); session_alert(session, "Aborting Spell Check: Browser history in use"); session_redirect(session, request, "compose"); return; } request_decode_form(request); if (!(h = request->form)) { /* No arguments to URL: Start or restart speller */ if (speller_active(speller)) speller_stop(speller); if (prefs->line_wrap_on_spell) draft_line_wrap_body(draft); if (!speller_start(speller, session, draft->body, prefs->ispell_language, prefs->spell_skip_quoted)) { session_alert(session, "Couldn't start spell checker!"); session_redirect(session, request, "compose"); return; } speller_feedline(speller); } else { if (!speller_active(speller)) { session_message(session, "Spell checker not currently active"); session_redirect(session, request, "compose"); return; } /* Process GET form arguments */ if (assoc_lookup(h, "cancel")) { speller_stop(speller); session_message(session, "Spell Check cancelled"); session_redirect(session, request, "compose"); return; } if (assoc_lookup(h, "apply")) { speller_copy_remainder(speller); draft->body = pool_strdup(draft->pool, speller_output(speller)); speller_stop(speller); if (speller->no_changes != 1) session_message(session, "Spell Check finished (%lu changes made)", speller->no_changes); else session_message(session, "Spell Check finished (1 change made)"); session_redirect(session, request, "compose"); return; } if ((s = assoc_lookup(h, "add"))) { dictionary_add(options->dictionary, s); options->save = T; } else if ((s = assoc_lookup(h, "accept"))) { speller_add_ignore_list(speller, s); } else if ((s = assoc_lookup(h, "replace"))) { speller->no_changes++; } else if (!(s = assoc_lookup(h, "leave"))) { speller_stop(speller); session_alert(session, "Unexpected input from user"); session_log(session, "[cmd_spell] Unexpected input from user"); session_redirect(session, request, "compose"); return; } /* Replace word with substitute version */ speller_copy_string(speller, s); speller_skip_input(speller, speller_fetch_cursize(speller)); } while (1) { if (!(line = speller_getline(speller, request->pool))) { speller_stop(speller); session_alert(session, "Spell check process shut down unexpectedly"); session_log(session, "[cmd_spell] Spell check process shut down unexpectedly"); session_redirect(session, request, "compose"); return; } if (line[0] == '\0') { if (!speller_copy_from_offset(speller)) /* Rest of line okay */ break; speller_feedline(speller); continue; } switch (line[0]) { case '*': /* Word correct */ break; case '-': /* Compound word (should not happen w/o -C option on ispell) */ break; case '+': /* Derivative word (insufficient context?) */ break; case '&': /* Word incorrect: have options */ case '?': /* Word incorrect: no options */ if (!process_line(session, request, speller, line + 2, T)) break; response_html(request, 200); /* OK */ return; case '#': /* Word incorrect: no options */ if (!process_line(session, request, speller, line + 2, NIL)) break; response_html(request, 200); /* OK */ return; default: /* Ignore all other responses for the time being */ break; } } draft->body = pool_strdup(draft->pool, speller_output(speller)); speller_stop(speller); if (speller->no_changes != 1) session_message(session, "Spell Check finished (%lu changes made)", speller->no_changes); else session_message(session, "Spell Check finished (1 change made)"); session_redirect(session, request, "compose"); } �����������������./prayer-1.3.5/cmd/cmd_vacation.c�������������������������������������������������������������������0000644�0065130�0065130�00000011311�11413321714�015121� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_vacation.c,v 1.5 2010/07/02 08:31:08 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; struct account *account = session->account; char *aliases = account->vacation_aliases; char *subject = account->vacation_subject; if (!(subject && subject[0])) subject = "Auto-Response: Vacation Message"; if (account->vacation_enabled) template_vals_ulong(tvals, "use_vacation", 1); template_vals_string(tvals, "aliases", aliases); template_vals_string(tvals, "subject", subject); template_vals_ulong(tvals, "days", account->vacation_days); if (session->sieved_server) template_vals_ulong(tvals, "using_sieve", 1); if (account->vacation_msg && account->vacation_msg[0]) template_vals_string(tvals, "vacation_msg", account->vacation_msg); session_seed_template(session, tvals); template_expand("vacation", tvals, b); response_html(request, 200); /* Success */ } static void generate_error(struct session *session) { struct template_vals *tvals = session->template_vals; struct account *account = session->account; struct request *request = session->request; char *msg = account_fetch_message(account); struct buffer *b = request->write_buffer; if (!(msg && msg[0])) msg = "Unable to check mail processing status"; template_vals_string(tvals, "msg", msg); session_seed_template(session, tvals); template_expand("vacation_fail", tvals, b); response_html(request, 200); } void cmd_vacation(struct session *session) { struct request *request = session->request; struct assoc *h = NIL; struct account *account = session->account; ADDRESS *addr = NIL; ADDRESS *a = NIL; char *s; BOOL rc = T; if (request->method != POST) { if (!account_mail_check(account, request->pool)) generate_error(session); else generate_form(session); return; } /* Form post */ request_decode_form(request); h = request->form; if (!(s = assoc_lookup(h, "sub_apply"))) { session_redirect(session, request, "manage"); /* parent screen */ return; } account->vacation_enabled = (assoc_lookup(h, "use_vacation")) ? T : NIL; if ((s = assoc_lookup(h, "vacation_msg"))) string_strdup(&account->vacation_msg, s); else string_strdup(&account->vacation_msg, ""); if ((s = assoc_lookup(h, "days")) && s[0]) { if (!(string_isnumber(s) && (atoi(s) >= 0))) { session_message(session, "Days option must be non-negative integer"); generate_form(session); return; } account->vacation_days = atoi(s); } if ((s = assoc_lookup(h, "aliases")) && s[0]) { string_strdup(&account->vacation_aliases, s); if (!(addr=addr_parse_destructive(s, ""))) { session_message(session, "Alias list invalid: %s", ml_errmsg()); rc = NIL; } else { for (a = addr; a; a = a->next) { if (!(a->host && a->host[0])) { session_message(session, "Unqualified address in alias list"); rc = NIL; break; } } mail_free_address(&addr); } } else string_strdup(&account->vacation_aliases, ""); if ((s = assoc_lookup(h, "subject"))) string_strdup(&account->vacation_subject, s); else string_strdup(&account->vacation_subject, ""); if (rc) { if (account_vacation_update(account, request->pool) && account_mail_update(account, request->pool)) { session_message(session, "Updated vacation message"); session_redirect(session, request, "manage"); return; } else { char *msg = account_fetch_message(account); session_alert(session, "Failed to update vacation message: %s", msg); session_log(session, "[cmd_vacation] Failed to update vacation message: %s", msg); } } /* Report some kind of error */ generate_form(session); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_export.c���������������������������������������������������������������0000644�0065130�0065130�00000002105�11064236131�016012� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_export.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Export Pine format addressbook to accountd system */ void cmd_abook_export(struct session *session) { struct account *account = session->account; struct request *request = session->request; struct options *options = session->options; struct abook *abook = options->abook; char *abook_text = abook_export_text(abook, request->pool); if (!account_abook_put(account, request->pool, abook_text)) { session_alert(session, "Failed to export addressbook"); session_redirect(session, request, "abook_xfer"); } else { session_message(session, "Addressbook exported to Hermes"); session_redirect(session, request, "abook_list"); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_compose.c��������������������������������������������������������������0000644�0065130�0065130�00000003370�11063701633�016146� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_compose.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_abook_compose(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct options *options = session->options; struct buffer *b = request->write_buffer; struct list_item *li; unsigned long count = 0; if (request->argc == 3) { string_strdup(&session->abook_compose_name, request->argv[1]); string_strdup(&session->abook_compose_email, request->argv[2]); string_canon_decode(session->abook_compose_name); string_canon_decode(session->abook_compose_email); } if (list_length(options->role_list) == 0L) { session_redirect(session, request, "abook_compose2"); return; } template_vals_foreach_init(tvals, "@roles", count); template_vals_foreach_string(tvals, "@roles", count, "name", "default"); count++; for (li = options->role_list->head; li; li = li->next) { struct role *role = (struct role *) li; template_vals_foreach_init(tvals, "@roles", count); template_vals_foreach_string(tvals, "@roles", count, "name", role->name); count++; } template_vals_string(tvals, "next", "abook_compose2"); session_seed_template(session, tvals); template_expand("roles_select", tvals, b); response_html(request, 200); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_transfer.c�������������������������������������������������������������������0000644�0065130�0065130�00000003172�11063701633�015152� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_transfer.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_transfer(struct session *session) { struct template_vals *tvals = session->template_vals; struct folderlist *fl = folderlist_fetch(session); struct prefs *prefs = session->options->prefs; BOOL suppress_dotfiles = prefs->suppress_dotfiles; struct request *request = session->request; struct buffer *b = request->write_buffer; struct folderitem *fi; char *name; if ((request->argc == 3) && !strcmp(request->argv[1], "toggle")) { name = string_canon_decode(request->argv[2]); fi = folderlist_lookup(folderlist_fetch(session), name); if (fi) { if (fi->expanded) { session_message(session, "Collapsed \"%s\"", name); fi->expanded = NIL; } else { folderlist_expand(session, fi); session_message(session, "Expanded \"%s\"", name); fi->expanded = T; } } } folderlist_template_vals_tree(fl, suppress_dotfiles, tvals, "@folder"); folderlist_template_vals_list(fl, suppress_dotfiles, tvals, T, "@dirlist"); session_seed_template(session, tvals); template_expand("transfer", tvals, b); response_html(request, 200); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_list.c�����������������������������������������������������������������0000644�0065130�0065130�00000020435�11656510704�015462� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_list.c,v 1.4 2011/11/09 14:44:20 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void process_remove(struct session *session) { struct options *options = session->options; struct abook *abook = options->abook; struct request *request = session->request; struct pool *pool = request->pool; unsigned long count; char *key, *tmp; assoc_scan_reset(request->form); count = 0; while (assoc_scan_next(request->form, &key, NIL)) { if (strncmp(key, "remove_", strlen("remove_")) != 0) continue; tmp = pool_strdup(pool, key + strlen("remove_")); string_canon_decode(tmp); abook_remove(abook, tmp); count++; } if (count > 0) session->options->save = T; if (count != 1) session_message(session, "Removed %lu entries from addressbook", count); else session_message(session, "Added 1 entry from addressbook"); } static void process_add_address(struct session *session) { struct options *options = session->options; struct abook *abook = options->abook; struct request *request = session->request; struct draft *draft = session->draft; unsigned long num; unsigned long count; struct abook_entry *abe; char *key; assoc_scan_reset(request->form); count = 0; while (assoc_scan_next(request->form, &key, NIL)) { if (!strncmp(key, "to_", strlen("to_"))) { num = atoi(key + strlen("to_")) - 1; if ((abe = abook_lookup_byoffset(abook, num))) { draft_add_to(draft, abook_entry_to_string(request->pool, abe)); count++; } } else if (!strncmp(key, "cc_", strlen("cc_"))) { num = atoi(key + strlen("cc_")) - 1; if ((abe = abook_lookup_byoffset(abook, num))) { draft_add_cc(draft, abook_entry_to_string(request->pool, abe)); count++; } } else if (!strncmp(key, "bcc_", strlen("bcc_"))) { num = atoi(key + strlen("bcc_")) - 1; if ((abe = abook_lookup_byoffset(abook, num))) { draft_add_bcc(draft, abook_entry_to_string(request->pool, abe)); count++; } } } if (count != 1) session_message(session, "Added %lu addresses to draft", count); else session_message(session, "Added 1 address to draft"); } static BOOL cmd_abook_list_addsort(struct template_vals *tvals, abook_sort_mode sort_mode, BOOL sort_reverse) { switch (sort_mode) { case ABOOK_SORT_ORDER: template_vals_string(tvals, "$sort_mode", "order"); break; case ABOOK_SORT_ALIAS: template_vals_string(tvals, "$sort_mode", "alias"); break; case ABOOK_SORT_NAME: template_vals_string(tvals, "$sort_mode", "name"); break; case ABOOK_SORT_COMMENT: template_vals_string(tvals, "$sort_mode", "comment"); break; case ABOOK_SORT_EMAIL: template_vals_string(tvals, "$sort_mode", "email"); break; } if (sort_reverse) template_vals_ulong(tvals, "$sort_reverse", 1); return (T); } static BOOL cmd_abook_list_addnav(struct template_vals *tvals, unsigned long offset, unsigned long count, unsigned long per_page) { unsigned long page; unsigned long pages; if (count > 0) { page = ((offset - 1) / per_page) + 1; pages = ((count - 1) / per_page) + 1; } else { page = 0; pages = 0; } template_vals_ulong(tvals, "entries", count); template_vals_ulong(tvals, "page_current", page); template_vals_ulong(tvals, "page_total", pages); if (page > 1) { template_vals_hash_ulong(tvals, "$nav", "first_page", 1); template_vals_hash_ulong(tvals, "$nav", "prev_page", offset-per_page); } if (page < pages) { template_vals_hash_ulong(tvals, "$nav", "next_page", offset+per_page); template_vals_hash_ulong(tvals, "$nav", "last_page", count); } return(T); } static void cmd_abook_list_single(struct template_vals *tvals, struct abook_entry *abe, unsigned long i) { template_vals_foreach_init(tvals, "@abook", i); template_vals_foreach_ulong(tvals, "@abook", i, "num", abe->position); template_vals_foreach_string(tvals, "@abook", i, "alias", abe->alias); template_vals_foreach_string(tvals, "@abook", i, "name", abe->name); template_vals_foreach_string(tvals, "@abook", i, "comment", abe->comment); template_vals_foreach_string(tvals, "@abook", i, "email", string_email_split(tvals->pool, abe->email)); if (i % 2 == 0) template_vals_foreach_ulong(tvals, "@abook", i, "even_row", 1); } void cmd_abook_list(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; struct options *options = session->options; struct abook *abook = options->abook; struct prefs *prefs = options->prefs; struct lookup *lookup = session->lookup; struct abook_entry *abe; unsigned long offset; unsigned long first, last, count, i; BOOL have_lookup = NIL; /* Save options if anything changed */ if (options->save) session_streams_save_options(session); if (request->method == POST) { request_decode_form(request); if (assoc_lookup(request->form, "sub_remove")) { process_remove(session); } else if (assoc_lookup(request->form, "sub_add_address")) { process_add_address(session); } else { char *pstr = assoc_lookup(request->form, "page"); unsigned long page = pstr ? atoi(pstr) : 0; unsigned long size = list_length(abook->list); unsigned long pages = (size / prefs->abook_per_page) + 1; if ((page > 0) && (page <= pages)) abook->current = (page - 1) * prefs->abook_per_page + 1; if (abook->current > size) abook->current = size; } } else if (request->argc == 2) abook->current = atoi(request->argv[1]); /* Move to page */ /* Record last command for compose/cancel and friends */ if (!session->draft->have_draft) session->compose_parent_cmd = "abook_list"; /* Work out if "current" entry still exists. If not, make the last * address on the list current. */ if ((count = list_length(abook->list)) > 0) { if (abook->current > count) abook->current = count; else if (abook->current == 0) abook->current = 1; } else abook->current = 0; /* Calculate first and last entry on page. */ offset = abook->current; if (offset >= prefs->abook_per_page) first = (offset - ((offset - 1) % prefs->abook_per_page)); else first = 1; last = (((first + (prefs->abook_per_page - 1)) <= count) ? (first + (prefs->abook_per_page - 1)) : count); cmd_abook_list_addsort(tvals, abook->sort_mode, abook->sort_reverse); cmd_abook_list_addnav(tvals, first, count, prefs->abook_per_page); abook_sort(abook); i = 0; offset = first; while (offset <= last) { if (!(abe = abook_lookup_sorted_byoffset(abook, offset - 1))) break; cmd_abook_list_single(tvals, abe, i); offset++; i++; } have_lookup = NIL; if (lookup_local_available(lookup)) { template_vals_ulong(tvals, "$have_local_lookup", 1); have_lookup = T; } if (lookup_ldap_available(lookup)) { template_vals_ulong(tvals, "$have_ldap_lookup", 1); have_lookup = T; } if (have_lookup) template_vals_ulong(tvals, "$have_lookup", 1); session_seed_template(session, tvals); template_expand("abook_list", tvals, b); response_html(request, 200); /* Success */ } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_send.c�����������������������������������������������������������������������0000644�0065130�0065130�00000024352�11240760256�014265� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_send.c,v 1.14 2009/08/13 09:45:18 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" struct channel { struct iostream *output; pid_t child; }; static struct channel *channel_open(struct session *session, struct pool *p, char *cmd) { struct request *request = session->request; pid_t childpid; int pipefd[2]; struct channel *channel = pool_alloc(p, sizeof(struct channel)); char **argv; char *path; int argc; char *s, *t; /* Local scratch copy of cmd */ cmd = pool_strdup(p, cmd); /* Count number of tokens in cmd */ argc = 0; s = cmd; while ((string_skip_token(&s))) argc++; /* Allocate (temporary) argv array based on this count */ argv = pool_alloc(p, (argc + 1) * sizeof(char *)); /* Split up cmd (destructive) */ argc = 0; while ((t = string_get_token(&cmd))) argv[argc++] = t; argv[argc] = NIL; /* Set up child process */ if (pipe(pipefd) < 0) { session_log(session, "[cmd_send] pipe(): %s", strerror(errno)); return (NIL); } if ((childpid = fork()) < 0) { session_log(session, "[cmd_send] fork(): %s", strerror(errno)); return (NIL); } if (childpid == 0) { /* Redirect stdin for child process */ close(pipefd[1]); dup2(pipefd[0], 0); close(pipefd[0]); /* Redirect stdout and stderr child to /dev/null */ close(1); open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, 0666); dup2(1, 2); path = argv[0]; if ((s = strrchr(path, '/'))) /* Should be leave path intact? */ argv[0] = s + 1; execv(path, argv); session_fatal(session, "[cmd_send] exec(sendmail): %s", strerror(errno)); } /* Parent */ close(pipefd[0]); channel->child = childpid; channel->output = iostream_create(request->pool, pipefd[1], 0); return (channel); } static int channel_close(struct channel *channel) { int status = 0; int rc = 0; iostream_close(channel->output); do { rc = waitpid(channel->child, &status, 0); } while ((rc < 0) && (errno == EINTR)); if ((rc >= 0) && WIFEXITED(status) && (WEXITSTATUS(status) == 0)) return(T); return(NIL); } static void touch_file(char *path) { FILE *file; if (path && path[0]) { if ((file = fopen(path, "a+"))) fclose(file); } } /* ====================================================================== */ void cmd_send(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct draft *draft = session->draft; MAILSTREAM *stream = session->stream; struct options *options = session->options; struct prefs *prefs = options->prefs; struct pool *pool = request->pool; struct buffer *cb = buffer_create(pool, 1024); char *s; int c; unsigned long offset; char *recips, *msg; STRING ms; char *command; struct channel *channel; struct iostream *output; unsigned long msg_len = 0L; char *sendmail; unsigned long recips_count = 0; if (config->sendmail_path && config->sendmail_path[0]) sendmail = config->sendmail_path; else sendmail = "/usr/lib/sendmail"; if (!(recips = draft_make_recipients(draft, NIL, &recips_count))) { session_redirect(session, request, "compose"); return; } if ((config->recips_max_msg > 0) && (recips_count > config->recips_max_msg)) { session_message(session, "Too many recipients"); session_log(session, "Too many recipients"); session_redirect(session, request, "compose"); return; } /* Block sending altogether if per session limit reached */ session->recips_count_session += recips_count; if (!session->sending_allow && (config->recips_max_session > 0) && (session->recips_count_session > config->recips_max_session)) { struct stat sbuf; char *allow_path = NIL; if (config->sending_allow_dir && session->username) { allow_path = pool_strcat3(request->pool, config->sending_allow_dir, "/", session->username); } if (allow_path && (stat(allow_path, &sbuf) == 0)) { session->sending_allow = T; } else { session->sending_block = T; /* Stop subsequent logins from sending either */ if (config->sending_block_dir && session->username) { touch_file(pool_strcat3(request->pool, config->sending_block_dir, "/", session->username)); } } } else if (config->sending_block_dir) { struct stat sbuf; char *path = pool_strcat3(request->pool, config->sending_block_dir, "/", session->username); if (stat(path, &sbuf) == 0) { session->sending_block = T; } } if (session->sending_block) { session_message(session, "Outgoing email disabled (compromised account?)"); session_log(session, "Outgoing email disabled (compromised account?)"); session_redirect(session, request, "compose"); return; } if (!(recips && recips[0])) { session_message(session, "No recipients for message"); session_redirect(session, request, "compose"); return; } if (prefs->line_wrap_advanced) { if (draft->line_wrap) draft_line_wrap_body(draft); } else if (prefs->line_wrap_on_send) draft_line_wrap_body(draft); if (!(msg = draft_make_msg(draft, NIL, &msg_len))) { session_redirect(session, request, "compose"); return; } if (draft->save_copy && draft->fcc && draft->fcc[0]) { char *fcc_name; if (prefs->maildir && prefs->maildir[0]) fcc_name = pool_strcat3(request->pool, prefs->maildir, session->hiersep, draft->fcc); else fcc_name = draft->fcc; /* Convert simple "char *" string into c-client "STRING *" string */ INIT(&ms, mail_string, msg, msg_len); ml_clear_error(); ml_clear_have_close(); /* Append message to end of sent-mail folder */ ml_append(session, stream, session_mailbox(session, request->pool, fcc_name), &ms); if (ml_have_close()) { session_redirect(session, request, "restart"); return; } else if (ml_have_error()) { session_alert(session, "Unable to append message to %s folder: %s", draft->fcc, ml_errmsg()); session_log(session, "[cmd_send] Unable to write to %s folder: %s", draft->fcc, ml_errmsg()); session_redirect(session, request, "compose"); return; } } /* -oi important: allows lines with single '.' in message body */ if (strchr(session->username, '@')) { bprintf(cb, "%s -oi -f %s %s", sendmail, session->username, recips); } else { bprintf(cb, "%s -oi -f %s@%s %s", sendmail, session->username, config->return_path_domain, recips); } command = buffer_fetch(cb, 0, buffer_size(cb), NIL); if ((channel = channel_open(session, request->pool, command)) == NIL) { session_alert(session, "Failed to send message (system problem?)"); session_log(session, "[cmd_send] Failed to send message: failed to start %s", command); session_redirect(session, request, "compose"); return; } output = channel->output; s = msg; offset = 0; /* Copy hdr replacing CRLF, CR or LF with LF. Remove Bcc headers */ while ((c = *s)) { if ((offset == 0) && !strncasecmp(s, "Bcc:", strlen("Bcc:"))) { /* Skip over Bcc header (may be folded over several lines) */ while ((c = *s++)) { if ((c == '\015') || (c == '\012')) { if ((c == '\015') && (*s == '\012')) s++; if (((c = *s) != ' ') && (c != '\t')) break; } } continue; } if ((c == '\015') || (c == '\012')) { /* Replace CRLF with single LF */ s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; ioputc('\n', output); if (offset == 0) break; offset = 0; continue; } ioputc(c, output); s++; offset++; } /* Copy body replacing CRLF, CR or LF with LF */ while ((c = *s)) { if ((c == '\015') || (c == '\012')) { /* Replace CRLF with single LF */ s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; ioputc('\n', output); continue; } ioputc(c, output); s++; offset++; } if (!channel_close(channel)) { session_alert(session, "Failure sending message (system problem)"); session_log(session, "[cmd_send] Failed to send message: failure reported by %s", command); session_redirect(session, request, "compose"); return; } session_message(session, "Message sent"); session_log(session, "[cmd_send] Message sent (%lu recipients)", recips_count); if (draft_is_reply(draft)) draft_flag_answered(draft); /* Finished with this draft */ draft_clear_atts(session->draft); draft_free(session->draft); draft_free(session->draft0); session_redirect(session, request, session->compose_parent_cmd); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_change.c���������������������������������������������������������������������0000644�0065130�0065130�00000003751�11064236131�014553� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_change.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_change(struct session *session) { struct request *request = session->request; char *name; if (request->method == POST) { request_decode_form(request); if (!(name = utf8_to_imaputf7(request->pool, assoc_lookup(request->form, "folder")))) { session_redirect(session, request, "error"); return; } string_canon_decode(name); } else if (request->argc < 2) { session_redirect(session, request, "error"); return; } else { name = pool_strdup(session->pool, request->argv[1]); string_canon_decode(name); } if (!session_streams_change(session, name)) { session_alert(session, "Unable to switch to folder: %s", utf8_from_imaputf7(request->pool, name)); session_redirect(session, request, "restart"); return; } if (!strcasecmp(name, "inbox")) { unsigned long msgno = stream_find_unread(session, session->stream); if (msgno > 0) { if (session->options->prefs->use_unread) { session->current = msgno; session->last_displayed = msgno; } session_message(session, "First unread message: %lu", msgno); } else session_message(session, "No unread messages in inbox"); } session_message(session, "Switched to mailbox: %s", utf8_from_imaputf7(request->pool, session->foldername)); session_log(session, "[cmd_change] Switched to mailbox: %s", session->foldername); session_redirect(session, request, "list"); } �����������������������./prayer-1.3.5/cmd/cmd_help.c�����������������������������������������������������������������������0000644�0065130�0065130�00000001463�11063701633�014257� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_help.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_help(struct session *session) { struct request *request = session->request; if (request->argc < 2) { session_redirect(session, request, "error"); return; } if (request->argc == 3) session->help_toolbar = (session->help_toolbar) ? NIL : T; else session->help_enabled = (session->help_enabled) ? NIL : T; session_redirect(session, request, request->argv[1]); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_upload_xfer.c����������������������������������������������������������������0000644�0065130�0065130�00000013624�11064236131�015636� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_upload_xfer.c,v 1.5 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" typedef struct append_package { struct pool *pool; /* Scratch pool for this interation */ MAILSTREAM *src; /* Source stream */ unsigned long last; /* Last message appended (0 => none) */ } APPENDPACKAGE; /* Append all marked messages to target stream */ static long upload_append_next(MAILSTREAM * target, void *data, char **flags, char **date, STRING ** message) { APPENDPACKAGE *ap = (APPENDPACKAGE *) data; MAILSTREAM *src = ap->src; MESSAGECACHE *elt; unsigned long msgno; struct buffer *b, *f; char *text, *s; unsigned long len; static STRING msg; int flag; if (ap->pool) pool_free(ap->pool); /* Generate new pool */ if (ap->last == src->nmsgs) { *message = NIL; return (LONGT); } msgno = ++ap->last; /* Generate scratch space for this interation */ ap->pool = pool_create(0); b = buffer_create(ap->pool, 4096); f = buffer_create(ap->pool, 1024); /* Generate message flags. */ if ((elt = mail_elt(src, msgno)) != NIL) { if (elt->seen) bputs(f, "\\Seen "); if (elt->deleted) bputs(f, "\\Deleted "); if (elt->flagged) bputs(f, "\\Flagged "); if (elt->answered) bputs(f, "\\Answered "); if (elt->draft) bputs(f, "\\Draft "); for (flag = 0 ; flag < NUSERFLAGS ; flag++) { if ((elt->user_flags & (1<<flag)) && src->user_flags[flag]) { bprintf(f, "%s ", src->user_flags[flag]); } } } /* Generate copy of full message in string */ text = mail_fetch_header(src, msgno, NIL, NIL, &len, FT_PEEK); for (s = text; *s; s++) bputc(b, *s); text = mail_fetch_text(src, msgno, NIL, &len, FT_PEEK); for (s = text; *s; s++) bputc(b, *s); /* Initialise msg STRING */ s = buffer_fetch(b, 0, len = buffer_size(b), NIL); INIT(&msg, mail_string, (void *) s, len); if (buffer_size(f) > 0) *flags = buffer_fetch(f, 0, buffer_size(f)-1, NIL); else *flags = NIL; *date = NIL; *message = &msg; return LONGT; /* always return success */ } /* ====================================================================== */ static BOOL upload(struct session *session, char *name, BOOL append) { struct request *request = session->request; MAILSTREAM *tin; MAILSTREAM *tout; APPENDPACKAGE ap; /* Calculate remote folder name */ name = session_mailbox(session, request->pool, name); if (!(tin = ml_open(session, NIL, session->upload_file, OP_READONLY))) { session_alert(session, "Failed to open temporary mail folder"); session_log(session, "[cmd_upload_xfer] Failed to open temporary mail folder"); return (NIL); } tout = session->inbox_stream; if (!append && !ml_create(session, tout, name)) { session_alert(session, "Failed to create target folder: %s", ml_errmsg()); session_log(session, "[cmd_upload_xfer] Failed to create target folder: %s", ml_errmsg()); return (NIL); } /* Transfer all messages from tin to tout using multiappend system */ /* Prime append package */ ap.pool = NIL; ap.last = 0; ap.src = tin; if (!ml_append_multiple(session, tout, name, upload_append_next, (void *) &ap)) { session_alert(session, "Failed to append message to target folder: %s", ml_errmsg()); session_log(session, ("[cmd_upload_xfer] Failed to append message" " to target folder (%s): %s"), name, ml_errmsg()); } ml_close(session, tin); unlink(session->upload_file); string_free((void **) &session->upload_file); return (T); } /* ====================================================================== */ void cmd_upload_xfer(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct assoc *h = NIL; char *name = NIL; char *parent = NIL; BOOL append; if (!session->upload_file) { session_alert(session, "Transit File missing (playing with browser history?)"); session_redirect(session, request, "transfer"); return; } if (request->argc < 2) { request_decode_form(request); h = request->form; if (assoc_lookup(h, "cancel")) { session_redirect(session, request, "upload_exit"); return; } if (!(name = assoc_lookup(h, "name"))) { response_error(request, 404); return; } parent = assoc_lookup(h, "parent"); append = (assoc_lookup(h, "append")) ? T : NIL; } else { name = request->argv[1]; string_canon_decode(name); append = T; } if (parent && parent[0]) { string_canon_decode(parent); name = pool_strcat3(request->pool, parent, session->hiersep, name); } string_strdup(&session->upload_name, name); if (upload(session, name, append) && !append) { if (config->dualuse) folderlist_add(session->folderlist, name, NIL, NIL); else folderlist_add(session->folderlist, name, NIL, T); } string_free((void **) &session->upload_name); session_message(session, "Folder Upload Complete"); session_redirect(session, request, "transfer"); } ������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_copy.c�����������������������������������������������������������������������0000644�0065130�0065130�00000006224�11067640026�014303� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_copy.c,v 1.4 2008/09/28 08:28:06 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_copy(struct session *session) { struct template_vals *tvals = session->template_vals; struct folderlist *fl = folderlist_fetch(session); struct prefs *prefs = session->options->prefs; BOOL suppress_dotfiles = prefs->suppress_dotfiles; struct request *request = session->request; struct buffer *b = request->write_buffer; MAILSTREAM *stream = session->stream; unsigned long msgno, msgno_uid; unsigned long count = 1; struct folderitem *fi; char *name; if ((request->argc == 3) && !strcmp(request->argv[1], "toggle")) { name = string_canon_decode(request->argv[2]); fi = folderlist_lookup(folderlist_fetch(session), name); if (fi) { if (fi->expanded) { session_message(session, "Collapsed \"%s\"", name); fi->expanded = NIL; } else { folderlist_expand(session, fi); session_message(session, "Expanded \"%s\"", name); fi->expanded = T; } } } else if ((request->argc > 1) && !strcmp(request->argv[1], "aggregate")) { if (prefs->use_mark_persist) count = msgmap_marked_count(session->zm); else count = msgmap_tmp_marked_count(session->zm); if (count > 1) session_message(session, "Copying %lu marked messages", count); else if (count == 1) session_message(session, "Copying single marked message"); else { session_message(session, "No marked messages to copy"); session_redirect(session, request, "list"); return; } session->aggregate = T; } else if (request->argc > 2) { msgno = atoi(request->argv[1]); msgno_uid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msgno_uid))) { session_redirect(session, request, "restart"); return; } session->current = msgno; session->aggregate = NIL; session_message(session, "Copying message %lu", msgno); } else if (session->aggregate) { if (prefs->use_mark_persist) count = msgmap_marked_count(session->zm); else count = msgmap_tmp_marked_count(session->zm); } else count = 1; folderlist_template_vals_tree(fl, suppress_dotfiles, tvals, "@folder"); folderlist_template_vals_list(fl, suppress_dotfiles, tvals, T, "@dirlist"); template_vals_string(tvals, "fcmd", "copy_msg"); template_vals_string(tvals, "copy_parent_cmd", session->copy_parent_cmd); template_vals_ulong(tvals, "count", count); session_seed_template(session, tvals); template_expand("copy", tvals, b); response_html(request, 200); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_upload_select.c��������������������������������������������������������������0000644�0065130�0065130�00000010220�11064236131�016136� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_upload_select.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static BOOL upload(struct session *session, char *name, char *data, unsigned long len) { struct config *config = session->config; struct request *request = session->request; char *tmpfname; FILE *tmpfile; int fd; tmpfname = pool_printf(request->pool, "%s/%s:%lu:XXXXXX", config->tmp_dir, session->username, (unsigned long) getpid()); if ((fd = mkstemp(tmpfname)) < 0) return (NIL); /* Transfer data to temporary file */ if ((tmpfile = fdopen(fd, "w")) == NIL) { session_alert(session, "Failed to open temporary file"); return (NIL); } while (len > 0) { fputc((*data) ? (*data) : ' ', tmpfile); data++; len--; } fclose(tmpfile); if (session->upload_file) { unlink(session->upload_file); string_free((void **) &session->upload_file); } session->upload_file = pool_strdup(NIL, tmpfname); return (T); } static BOOL process_upload_request(struct session * session, struct request * request) { char *s, *disp; char *start, *end; struct assoc *hdrs = assoc_create(request->pool, 16, T); char *name = NIL; unsigned long len; request_decode_post_multipart(request, hdrs, &start, &end); *end = '\0'; if (end > start) len = (char *) end - (char *) start; else len = 0; if ((disp = assoc_lookup(hdrs, "content-disposition"))) { for (s = disp; *s; s++) { if (!strncasecmp(s, "filename=\"", strlen("filename=\""))) { name = s = s + strlen("filename=\""); while (*s && (*s != '"')) s++; *s = '\0'; break; } } } if (name && name[0]) { if ((s = strrchr(name, '/'))) name = s + 1; else if ((s = strrchr(name, '\\'))) name = s + 1; } else name = "Upload"; if (!upload(session, name, start, len)) return (NIL); session_message(session, "Copied mailbox to halfway point"); session->upload_name = pool_strdup(NIL, name); return (T); } /* ====================================================================== */ void cmd_upload_select(struct session *session) { struct template_vals *tvals = session->template_vals; struct folderlist *fl = folderlist_fetch(session); struct prefs *prefs = session->options->prefs; BOOL suppress_dotfiles = prefs->suppress_dotfiles; struct request *request = session->request; struct buffer *b = request->write_buffer; struct folderitem *fi; char *name; if (request->method == POST) { if (!process_upload_request(session, request)) { session_redirect(session, request, "restart"); return; } } if ((request->argc == 3) && !strcmp(request->argv[1], "toggle")) { name = string_canon_decode(request->argv[2]); fi = folderlist_lookup(folderlist_fetch(session), name); if (fi) { if (fi->expanded) { session_message(session, "Collapsed \"%s\"", name); fi->expanded = NIL; } else { folderlist_expand(session, fi); session_message(session, "Expanded \"%s\"", name); fi->expanded = T; } } } folderlist_template_vals_tree(fl, suppress_dotfiles, tvals, "@folder"); folderlist_template_vals_list(fl, suppress_dotfiles, tvals, T, "@dirlist"); if (session->upload_name) template_vals_string(tvals, "$upload_name", session->upload_name); session_seed_template(session, tvals); template_expand("upload_select", tvals, b); response_html(request, 200); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_sizes.c����������������������������������������������������������������������0000644�0065130�0065130�00000003633�11064236131�014462� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_sizes.c,v 1.3 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_sizes(struct session *session) { struct template_vals *tvals = session->template_vals; struct folderlist *fl = folderlist_fetch(session); struct prefs *prefs = session->options->prefs; BOOL suppress_dotfiles = prefs->suppress_dotfiles; struct request *request = session->request; struct buffer *b = request->write_buffer; struct folderitem *fi; char *name; /* Record last command for compose/cancel and friends */ if ((request->argc == 3) && !strcmp(request->argv[1], "toggle")) { name = string_canon_decode(request->argv[2]); fi = folderlist_lookup(fl, name); if (fi) { if (fi->expanded) { session_message(session, "Collapsed \"%s\"", name); fi->expanded = NIL; } else { folderlist_expand(session, fi); session_message(session, "Expanded \"%s\"", name); fi->expanded = T; } } } /* Save options if anything changed */ if (session->options->save) session_streams_save_options(session); if (!folderlist_update_sizes(folderlist_fetch(session), session)) session_alert(session, "Failed to update folder sizes"); folderlist_template_vals_tree(fl, suppress_dotfiles, tvals, "@folder"); folderlist_template_vals_list(fl, suppress_dotfiles, tvals, T, "@dirlist"); session_seed_template(session, tvals); template_expand("sizes", tvals, b); response_html(request, 200); } �����������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_unsubscribe.c����������������������������������������������������������������0000644�0065130�0065130�00000002632�11063701633�015652� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_unsubscribe.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_unsubscribe(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct favourite_list *fl = options->favourite_list; char *name; if (request->argc == 2) { name = string_canon_decode(pool_strdup (request->pool, request->argv[1])); if (string_filename_valid(name)) { if (favourite_delete(fl, name)) { options->save = T; session_message(session, "Removed %s from favourites list", utf8_from_imaputf7(request->pool, name)); } else session_message(session, "Folder %s not on favourites list", utf8_from_imaputf7(request->pool, name)); } else session_message(session, "String contained illegal characters"); } session_redirect(session, request, "favourites"); } ������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_display.c��������������������������������������������������������������������0000644�0065130�0065130�00000011225�11415401425�014766� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_display.c,v 1.18 2010/07/08 16:55:49 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_display(struct session *session) { struct template_vals *tvals = session->template_vals; struct options *options = session->options; struct prefs *prefs = options->prefs; struct request *request = session->request; struct msgmap *zm = session->zm; unsigned long msgno, msguid; char *section; struct buffer *b = request->write_buffer; MAILSTREAM *stream = session->stream; BOOL html_show_images = prefs->html_remote_images; if (request->method == POST) { char *cmd, *folder; request_decode_form(request); if (assoc_lookup(request->form, "sub_folder_dialogue") && (folder = assoc_lookup(request->form, "folder")) && folder[0]) { if ((cmd = assoc_lookup(request->form, "command")) && !strcmp(cmd, "copy")) { session->aggregate = T; session_redirect(session, request, pool_strcat(request->pool, "copy_msg/", folder)); } else session_redirect(session, request, pool_strcat(request->pool, "change/", folder)); return; } } if (!msgmap_update(zm)) { session_alert(session, "Failed to update msgmap"); session_redirect(session, request, "restart"); return; } if (msgmap_size(zm) == 0) { session_message(session, "Folder is empty"); session_redirect(session, request, "list"); return; } /* Save options if anything changed */ if (options->save) session_streams_save_options(session); /* Record last command for compose/cancel and friends */ if (!session->draft->have_draft) session->compose_parent_cmd = "display"; /* Record last command for save/cancel */ session->copy_parent_cmd = "display"; /* Record last command for addressbook take */ session->take_parent_cmd = "display"; if ((request->argc == 5) && !strcmp(request->argv[4], "show_images")) html_show_images = T; section = NIL; if (request->argc >= 4) section = request->argv[3]; if (request->argc >= 3) { msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "list"); return; } } else { msgno = session->last_displayed; if ((msgno == 0) || (msgno > msgmap_size(zm))) msgno = msgmap_value(zm, msgmap_size(zm)); msguid = ml_uid(session, stream, msgno); } session->current = msgno; session->last_displayed = msgno; if (session->stream == session->draft_stream) template_vals_ulong(tvals, "$is_postponed_folder", 1); if (prefs->use_mark_persist) template_vals_ulong(tvals, "$use_persist", 1); if (prefs->use_tail_banner) template_vals_ulong(tvals, "$use_tail_banner", 1); if (prefs->html_inline) template_vals_ulong(tvals, "$html_inline", 1); if (prefs->html_remote_images) template_vals_ulong(tvals, "$html_remote_images", 1); /* Need different name to avoid collision below */ if (section) template_vals_string(tvals, "$section_url", section); display_addnav(session, stream, msgno); if (session->full_hdrs) { char *hdr; unsigned long len; template_vals_ulong(tvals, "$full_hdrs", 1); session_seed_template(session, tvals); template_expand("display", tvals, b); bprintf(b, "<pre>" CRLF); if ((hdr = ml_fetch_header(session, stream, msgno, NIL, NIL, &len, 0))) wrap_text_html_quotes(b, hdr, 80, T); bprintf(b, "</pre>" CRLF); } else { display_addhdrs(session, stream, msgno); session_seed_template(session, tvals); template_expand("display", tvals, b); } if (!display_body(session, request, stream, msgno, section, "display", html_show_images)) { session_redirect(session, request, "restart"); return; } template_expand("display_tail", tvals, b); /* Send out the response */ response_html(request, 200); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_aggregate.c������������������������������������������������������������������0000644�0065130�0065130�00000015243�11064236131�015253� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_aggregate.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static BOOL aggregate_delete(struct session *session, char *sequence, unsigned long count) { MAILSTREAM *stream = session->stream; if (!ml_flag(session, stream, sequence, "\\DELETED", ST_SET)) { session_alert(session, "Failed to delete messages: %s", ml_errmsg()); session_log(session, "[cmd_aggregate] Failed to delete messages: %s", ml_errmsg()); return (NIL); } if (count > 1) { session_message(session, "Deleted %lu messages", count); session_log(session, "[cmd_aggregate] Deleted %lu messages from %s", count, session->foldername); } else { session_message(session, "Deleted 1 message"); session_log(session, "[cmd_aggregate] Deleted 1 message from %s", session->foldername); } return (T); } static BOOL aggregate_undelete(struct session *session, char *sequence, unsigned long count) { MAILSTREAM *stream = session->stream; if (!ml_flag(session, stream, sequence, "\\DELETED", 0)) { session_alert(session, "Failed to undelete messages: %s", ml_errmsg()); session_log(session, "[cmd_aggregate] Failed to undelete messages: %s", ml_errmsg()); return (NIL); } if (count > 1) { session_message(session, "Undeleted %lu messages", count); session_log(session, "[cmd_aggregate] Undeleted %lu messages from %s", count, session->foldername); } else { session_message(session, "Undeleted 1 message"); session_log(session, "[cmd_aggregate] Undeleted 1 message from %s", session->foldername); } return (T); } static BOOL aggregate_read(struct session *session, char *sequence, unsigned long count) { MAILSTREAM *stream = session->stream; if (!ml_flag(session, stream, sequence, "\\SEEN", ST_SET)) { session_alert(session, "Failed to flag messages as read: %s", ml_errmsg()); session_log(session, "[cmd_aggregate] Failed to flag messages as read: %s", ml_errmsg()); return (NIL); } if (count > 1) { session_message(session, "Flagged %lu messages as read", count); session_log(session, "[cmd_aggregate] Flagged %lu messages as read from %s", count, session->foldername); } else { session_message(session, "Flagged 1 message as read"); session_log(session, "[cmd_aggregate] Flagged 1 message as read from %s", session->foldername); } return (T); } static BOOL aggregate_unread(struct session *session, char *sequence, unsigned long count) { MAILSTREAM *stream = session->stream; if (!ml_flag(session, stream, sequence, "\\SEEN", 0)) { session_alert(session, "Failed to flag messages as unread: %s", ml_errmsg()); session_log(session, "[cmd_aggregate] Failed to flag messages as unread: %s", ml_errmsg()); return (NIL); } if (count > 1) { session_message(session, "Flagged %lu messages as unread", count); session_log(session, "[cmd_aggregate] Flagged %lu messages as unread from %s", count, session->foldername); } else { session_message(session, "Flagged 1 message as unread"); session_log(session, "[cmd_aggregate] Flagged 1 message as unread from %s", session->foldername); } return (T); } void cmd_aggregate(struct session *session) { struct options *options = session->options; struct prefs *prefs = options->prefs; struct request *request = session->request; char *cmd; char *sequence; BOOL rc; unsigned long count; request_decode_form(request); if (assoc_lookup(request->form, "sub_aggregate")) cmd = assoc_lookup(request->form, "aggregate"); else if (assoc_lookup(request->form, "sub_aggregate2")) cmd = assoc_lookup(request->form, "aggregate2"); else { char *pstr = assoc_lookup(request->form, "page"); unsigned long page = pstr ? atoi(pstr) : 0; unsigned long size = msgmap_size(session->zm); unsigned long pages = (size / prefs->msgs_per_page) + 1; if ((page > 0) && (page <= pages)) { session->current = msgmap_value(session->zm, ((page - 1) * prefs->msgs_per_page) + 1); session_message(session, "Switched to page: %lu", page); } else session_message(session, "Page out of range"); session_redirect(session, request, "list"); return; } if (!(cmd && cmd[0])) { session_alert(session, "Invalid form input"); session_log(session, "[cmd_aggregate] Invalid form input"); session_redirect(session, request, "list"); return; } if (msgmap_marked_count(session->zm) == 0) { session_message(session, "No messages marked"); session_redirect(session, request, "list"); return; } if (!strcmp(cmd, "copy")) { session_redirect(session, request, "copy/aggregate"); return; } else if (!strcmp(cmd, "forward")) { session_redirect(session, request, "forward/aggregate"); return; } sequence = msgmap_mark_sequence(session->zm); count = msgmap_marked_count(session->zm); if (!strcmp(cmd, "delete")) rc = aggregate_delete(session, sequence, count); else if (!strcmp(cmd, "undelete")) rc = aggregate_undelete(session, sequence, count); else if (!strcmp(cmd, "read")) rc = aggregate_read(session, sequence, count); else if (!strcmp(cmd, "unread")) rc = aggregate_unread(session, sequence, count); else { session_alert(session, "Unknown action"); rc = T; } if (rc && prefs->use_agg_unmark) msgmap_unmark_all(session->zm); session_redirect(session, request, (rc) ? "list" : "restart"); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_search.c���������������������������������������������������������������������0000644�0065130�0065130�00000041135�11064236131�014571� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_search.c,v 1.5 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static BOOL search_clear_all(struct session *session) { return (msgmap_unmark_all(session->zm)); } /* ====================================================================== */ static void template_dates(struct template_vals *tvals) { static char *date_month[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; unsigned long i; time_t now = time(0); struct tm *date = localtime(&now); unsigned long count = 0; count = 0; for (i = 1; i <= 31; i++) { template_vals_foreach_init(tvals, "@day", count); template_vals_foreach_ulong(tvals, "@day", count, "day", i); if (i == date->tm_mday) template_vals_foreach_ulong(tvals, "@day", count, "selected", 1); count++; } count = 0; for (i = 1; i <= 12; i++) { template_vals_foreach_init(tvals, "@month", count); template_vals_foreach_ulong(tvals, "@month", count, "value", i); template_vals_foreach_string(tvals, "@month", count, "name", date_month[i - 1]); if (i == (1 + date->tm_mon)) template_vals_foreach_ulong(tvals, "@month", count, "selected", 1); count++; } template_vals_ulong(tvals, "year", 1900 + date->tm_year); } /* ====================================================================== */ /* Various fields that we can search */ #define SEARCH_FIELD_NONE (0) #define SEARCH_FIELD_FROM (1) #define SEARCH_FIELD_TO (2) #define SEARCH_FIELD_CC (3) #define SEARCH_FIELD_RECIPIENT (4) #define SEARCH_FIELD_PARTICIPANT (5) #define SEARCH_FIELD_SUBJECT (6) #define SEARCH_FIELD_TEXT (7) static BOOL search_text_apply(struct session *session, BOOL narrow, int field, BOOL match, char *value) { MAILSTREAM *stream = session->stream; char *charset = "UTF-8"; SEARCHPGM *pgm, *pgm2; pgm = mail_newsearchpgm(); switch (field) { case SEARCH_FIELD_FROM: pgm->from = mail_newstringlist(); pgm->from->text.data = (unsigned char *) cpystr(value); pgm->from->text.size = strlen(value); break; case SEARCH_FIELD_CC: pgm->cc = mail_newstringlist(); pgm->cc->text.data = (unsigned char *) cpystr(value); pgm->cc->text.size = strlen(value); break; case SEARCH_FIELD_TO: pgm->to = mail_newstringlist(); pgm->to->text.data = (unsigned char *) cpystr(value); pgm->to->text.size = strlen(value); break; case SEARCH_FIELD_SUBJECT: pgm->subject = mail_newstringlist(); pgm->subject->text.data = (unsigned char *) cpystr(value); pgm->subject->text.size = strlen(value); break; case SEARCH_FIELD_TEXT: pgm->text = mail_newstringlist(); pgm->text->text.data = (unsigned char *) cpystr(value); pgm->text->text.size = strlen(value); break; case SEARCH_FIELD_RECIPIENT: pgm->or = mail_newsearchor(); pgm->or->first->to = mail_newstringlist(); pgm->or->first->to->text.data = (unsigned char *) cpystr(value); pgm->or->first->to->text.size = strlen(value); pgm->or->second->cc = mail_newstringlist(); pgm->or->second->cc->text.data = (unsigned char *) cpystr(value); pgm->or->second->cc->text.size = strlen(value); break; case SEARCH_FIELD_PARTICIPANT: /* Participant match */ pgm->or = mail_newsearchor(); pgm->or->first->to = mail_newstringlist(); pgm->or->first->to->text.data = (unsigned char *) cpystr(value); pgm->or->first->to->text.size = strlen(value); pgm->or->second->or = mail_newsearchor(); pgm->or->second->or->first->cc = mail_newstringlist(); pgm->or->second->or->first->cc->text.data = (unsigned char *) cpystr(value); pgm->or->second->or->first->cc->text.size = strlen(value); pgm->or->second->or->second->from = mail_newstringlist(); pgm->or->second->or->second->from->text.data = (unsigned char *) cpystr(value); pgm->or->second->or->second->from->text.size = strlen(value); break; } if (!match) { /* Negate test */ pgm2 = mail_newsearchpgm(); pgm2->not = mail_newsearchpgmlist(); pgm2->not->pgm = pgm; pgm2->not->next = NIL; pgm = pgm2; } /* Apply this search pattern */ if (!ml_search_full(session, stream, charset, pgm, (SE_NOPREFETCH | SE_FREE))) return (NIL); return (msgmap_mark_searched(session->zm, narrow)); } static BOOL process_text_form(struct session *session) { struct request *request = session->request; struct assoc *h = request->form; /* Already processed */ char *key, *value, *s; BOOL match, narrow; static struct { char *text; int value; } *l, lookup_table[] = { { "from", SEARCH_FIELD_FROM} , { "to", SEARCH_FIELD_TO} , { "cc", SEARCH_FIELD_CC} , { "recipient", SEARCH_FIELD_RECIPIENT} , { "participant", SEARCH_FIELD_PARTICIPANT} , { "subject", SEARCH_FIELD_SUBJECT} , { "text", SEARCH_FIELD_TEXT} , { NIL, SEARCH_FIELD_NONE} }; if (!((key = assoc_lookup(h, "text_key")) && (value = assoc_lookup(h, "text_value")) && key[0] && value[0])) { session_message(session, "No search criteria provided"); session_redirect(session, request, "list"); return (NIL); } match = ((s = assoc_lookup(h, "text_op")) && !strcmp(s, "match")); /* Find field value in table */ for (l = lookup_table; l->text; l++) if (!strcmp(l->text, key)) break; narrow = NIL; if (assoc_lookup(h, "sub_fresh")) { if (!search_clear_all(session)) { session_redirect(session, request, "restart"); return (NIL); } } else if (assoc_lookup(h, "sub_narrow")) narrow = T; if (!search_text_apply(session, narrow, l->value, match, value)) { session_redirect(session, request, "restart"); return (NIL);; } if (msgmap_marked_count(session->zm) != 1) session_message(session, "Search criteria applied: %lu messages match", msgmap_marked_count(session->zm)); else session_message(session, "Search criteria applied: 1 message matches"); return (T); } /* ====================================================================== */ /* Various fields that we can search */ static BOOL search_date_apply(struct session *session, BOOL narrow, char *op, unsigned long day, unsigned long month, unsigned long year) { MAILSTREAM *stream = session->stream; SEARCHPGM *pgm; unsigned short date = ((year - BASEYEAR) << 9) + (month << 5) + day; pgm = mail_newsearchpgm(); if (!strcmp(op, "before_exc")) pgm->sentbefore = date; else if (!strcmp(op, "before_inc")) pgm->sentbefore = date + 1; else if (!strcmp(op, "on")) pgm->senton = date; else if (!strcmp(op, "since_inc")) pgm->sentsince = date; else if (!strcmp(op, "since_exc")) pgm->sentsince = date + 1; /* Apply this search pattern */ if (!ml_search_full (session, stream, NIL, pgm, (SE_NOPREFETCH | SE_FREE))) return (NIL); return (msgmap_mark_searched(session->zm, narrow)); } static BOOL process_date_form(struct session *session) { struct request *request = session->request; struct assoc *h = request->form; /* Already processed */ char *op, *tmp; unsigned long day, month, year; BOOL narrow; if (!((op = assoc_lookup(h, "date_op")) && op[0] && (tmp = assoc_lookup(h, "date_day")) && tmp[0] && (tmp = assoc_lookup(h, "date_month")) && tmp[0] && (tmp = assoc_lookup(h, "date_year")) && tmp[0])) { session_message(session, "No search criteria provided"); session_redirect(session, request, "list"); return (NIL); } day = atoi(assoc_lookup(h, "date_day")); month = atoi(assoc_lookup(h, "date_month")); year = atoi(assoc_lookup(h, "date_year")); if (!((day >= 1) && (month <= 31) && (month >= 1) && (month <= 12) && (year >= 1970) && (year <= 2098))) { session_alert(session, "Invalid search criteria provided"); session_redirect(session, request, "list"); return (NIL); } narrow = NIL; if (assoc_lookup(h, "sub_fresh")) { if (!search_clear_all(session)) { session_redirect(session, request, "restart"); return (NIL); } } else if (assoc_lookup(h, "sub_narrow")) narrow = T; if (!search_date_apply(session, narrow, op, day, month, year)) { session_redirect(session, request, "restart"); return (NIL); } if (msgmap_marked_count(session->zm) != 1) session_message(session, "Search criteria applied: %lu messages match", msgmap_marked_count(session->zm)); else session_message(session, "Search criteria applied: 1 message matches"); return (T); } /* ====================================================================== */ static BOOL search_status_apply(struct session *session, BOOL narrow, char *op) { MAILSTREAM *stream = session->stream; SEARCHPGM *pgm; pgm = mail_newsearchpgm(); if (!strcmp(op, "seen")) pgm->seen = T; else if (!strcmp(op, "unseen")) pgm->unseen = T; else if (!strcmp(op, "deleted")) pgm->deleted = T; else if (!strcmp(op, "undeleted")) pgm->undeleted = T; else if (!strcmp(op, "answered")) pgm->answered = T; else if (!strcmp(op, "unanswered")) pgm->unanswered = T; /* Apply this search pattern */ if (!ml_search_full (session, stream, NIL, pgm, (SE_NOPREFETCH | SE_FREE))) return (NIL); return (msgmap_mark_searched(session->zm, narrow)); } static BOOL process_status_form(struct session *session) { struct request *request = session->request; struct assoc *h = request->form; /* Already processed */ char *op; BOOL narrow; if (!((op = assoc_lookup(h, "status_op")) && op[0])) { session_alert(session, "No search criteria provided"); session_redirect(session, request, "list"); return (NIL); } narrow = NIL; if (assoc_lookup(h, "sub_fresh")) { if (!search_clear_all(session)) { session_redirect(session, request, "restart"); return (NIL); } } else if (assoc_lookup(h, "sub_narrow")) narrow = T; if (!search_status_apply(session, narrow, op)) { session_redirect(session, request, "restart"); return (NIL); } if (msgmap_marked_count(session->zm) != 1) session_message(session, "Search criteria applied: %lu messages match", msgmap_marked_count(session->zm)); else session_message(session, "Search criteria applied: 1 message matches"); return (T); } /* ====================================================================== */ static BOOL search_size_apply(struct session *session, BOOL narrow, char *op, unsigned long size) { MAILSTREAM *stream = session->stream; SEARCHPGM *pgm; pgm = mail_newsearchpgm(); if (!strcmp(op, "larger")) pgm->larger = size * 1024; else if (!strcmp(op, "smaller")) pgm->smaller = size * 1024; /* Apply this search pattern */ if (!ml_search_full (session, stream, NIL, pgm, (SE_NOPREFETCH | SE_FREE))) return (NIL); return (msgmap_mark_searched(session->zm, narrow)); } static BOOL process_size_form(struct session *session) { struct request *request = session->request; struct assoc *h = request->form; /* Already processed */ char *op, *value; BOOL narrow; unsigned long size; if (!((op = assoc_lookup(h, "size_op")) && op[0] && (value = (assoc_lookup(h, "value"))) && value[0])) { session_alert(session, "No search criteria provided"); session_redirect(session, request, "list"); return (NIL); } size = atoi(value); narrow = NIL; if (assoc_lookup(h, "sub_fresh")) { if (!search_clear_all(session)) { session_redirect(session, request, "restart"); return (NIL); } } else if (assoc_lookup(h, "sub_narrow")) narrow = T; if (!search_size_apply(session, narrow, op, size)) { session_redirect(session, request, "restart"); return (NIL); } if (msgmap_marked_count(session->zm) != 1) session_message(session, "Search criteria applied: %lu messages match", msgmap_marked_count(session->zm)); else session_message(session, "Search criteria applied: 1 message matches"); return (T); } /* ====================================================================== */ void cmd_search(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; struct options *options = session->options; struct prefs *prefs = options->prefs; struct assoc *h = NIL; unsigned long selected = msgmap_marked_count(session->zm); unsigned long count = session->zm->nmsgs; char *page; char *sent_mail_name; if (request->method != POST) { template_vals_ulong(tvals, "selected", selected); template_vals_ulong(tvals, "count", count); if (prefs->maildir && prefs->maildir[0]) sent_mail_name = pool_strcat3(request->pool, prefs->maildir, session->hiersep, prefs->sent_mail_folder); else sent_mail_name = prefs->sent_mail_folder; if (!strcmp(session->foldername, sent_mail_name)) template_vals_ulong(tvals, "is_sent_mail", 1); if ((request->argc > 1) && (!strcmp(request->argv[1], "date"))) { template_dates(tvals); page = "search_date"; } else if ((request->argc > 1) && (!strcmp(request->argv[1], "status"))) { page = "search_status"; } else if ((request->argc > 1) && (!strcmp(request->argv[1], "size"))) { page = "search_size"; } else { page = "search_text"; } session_seed_template(session, tvals); template_expand(page, tvals, b); response_html(request, 200); return; } /* POST request */ request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_message(session, "Search operation cancelled"); session_redirect(session, request, "list"); return; } if (assoc_lookup(h, "sub_text")) { session_redirect(session, request, "search/text"); return; } if (assoc_lookup(h, "sub_date")) { session_redirect(session, request, "search/date"); return; } if (assoc_lookup(h, "sub_status")) { session_redirect(session, request, "search/status"); return; } if (assoc_lookup(h, "sub_size")) { session_redirect(session, request, "search/size"); return; } if (assoc_lookup(h, "text_op")) { if (!process_text_form(session)) return; } else if (assoc_lookup(h, "date_op")) { if (!process_date_form(session)) return; } else if (assoc_lookup(h, "status_op")) { if (!process_status_form(session)) return; } else if (assoc_lookup(h, "size_op")) { if (!process_size_form(session)) return; } count = msgmap_marked_count(session->zm); if (prefs->use_search_zoom && (count > 0) && (count < session->zm->nmsgs)) msgmap_enable_zoom(session->zm); session_redirect(session, request, "list"); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_xfer.c�����������������������������������������������������������������0000644�0065130�0065130�00000007555�11064236131�015453� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_xfer.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Transfer addressbook to/from local system */ static void generate_form(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; /* Miscelleneous Actions 2 */ if (session->accountd_server && session->accountd_server[0]) template_vals_ulong(tvals, "local_pine_abook", 1); session_seed_template(session, tvals); template_expand("abook_transfer", tvals, b); response_html(request, 200); /* Success */ } /* ====================================================================== */ /* Export Pine format addressbook */ static BOOL export_pine(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct abook *abook = options->abook; struct buffer *b = request->write_buffer; char *name = "addressbook"; bprintf(b, "# Prayer addressbook for %s\n", session->username); abook_export_pine(abook, b); response_raw(request, name, "application/octet-stream", 200); return (T); } /* ====================================================================== */ /* Export CSV (Outlook format) addressbook */ static BOOL export_csv(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct abook *abook = options->abook; struct buffer *b = request->write_buffer; char *name = "addressbook"; abook_export_csv(abook, b); response_raw(request, name, "application/octet-stream", 200); return (T); } /* ====================================================================== */ void cmd_abook_xfer(struct session *session) { struct request *request = session->request; char *start, *end; if (request->method != POST) { if ((request->argc >= 2) && !strcmp(request->argv[1], "export")) { export_pine(session); return; } if ((request->argc >= 2) && !strcmp(request->argv[1], "export_csv")) { export_csv(session); return; } generate_form(session); return; } if (request->argc < 2) { session_redirect(session, request, "error"); return; } request_decode_post_multipart(request, NIL, &start, &end); *end = '\0'; if (abook_import_csv_valid(start)) { struct abook *abook = session->options->abook; unsigned long count = abook_import_csv(abook, start); if (count != 1) session_message(session, "Imported %lu aliases", count); else session_message(session, "Imported 1 alias"); if (count > 0) session->options->save = T; } else if (!strncmp(start, "First Name\tLast Name\t", strlen("First Name\tLast Name\t"))) { session_alert(session, "Old format Outlook addressbooks not supported"); } else if (abook_import_pine_valid(start)) { struct abook *abook = session->options->abook; unsigned long count = abook_import_pine(abook, start); if (count != 1) session_message(session, "Imported %lu aliases", count); else session_message(session, "Imported 1 alias"); if (count > 0) session->options->save = T; } else session_alert(session, "Invalid/Unsupported addressbook format"); session_redirect(session, request, "abook_list"); } ���������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_preferred.c������������������������������������������������������������������0000644�0065130�0065130�00000002270�11063701633�015302� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_preferred.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_preferred(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct favourite_list *fl = options->favourite_list; char *name; if (request->argc >= 2) { name = string_canon_decode(pool_strdup (request->pool, request->argv[1])); if (string_filename_valid(name)) { favourite_preferred(fl, name); options->save = T; session_message(session, "Making %s preferred folder", utf8_from_imaputf7(request->pool, name)); } else session_message(session, "String contained illegal characters"); } session_redirect(session, request, "favourites"); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_lookup.c���������������������������������������������������������������0000644�0065130�0065130�00000024174�11064236131�016014� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_lookup.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static BOOL cmd_abook_lookup_addnav(struct template_vals *tvals, unsigned long offset, unsigned long count, unsigned long per_page) { unsigned long page; unsigned long pages; if (count > 0) { page = ((offset - 1) / per_page) + 1; pages = ((count - 1) / per_page) + 1; } else { page = 0; pages = 0; } template_vals_ulong(tvals, "entries", count); template_vals_ulong(tvals, "page_current", page); template_vals_ulong(tvals, "page_total", pages); if (page > 1) { template_vals_hash_ulong(tvals, "$nav", "first_page", 1); template_vals_hash_ulong(tvals, "$nav", "prev_page", offset-per_page); } if (page < pages) { template_vals_hash_ulong(tvals, "$nav", "next_page", offset+per_page); template_vals_hash_ulong(tvals, "$nav", "last_page", count); } return(T); } /* Is display_name sufficiently different from registered_name to warant showing both? Ignore case, spaces and punctuation */ static BOOL compare_display_ignore_char(char c) { return ((c == ' ') || (c == '\t') || (c == ',') || (c == '.')); } static BOOL compare_display_name(char *display, char *registered) { while (1) { while (*display && compare_display_ignore_char(*display)) display++; while (*registered && compare_display_ignore_char(*registered)) registered++; if ((*display == '\0') || (*registered == '\0')) break; if (Utolower(*display) != Utolower(*registered)) break; display++; registered++; } return (((*display == '\0') && (*registered == '\0')) ? T : NIL); } static void cmd_abook_lookup_single(struct template_vals *tvals, struct lookup_item *entry, unsigned long offset, BOOL have_draft, unsigned long count) { template_vals_foreach_init(tvals, "@list", count); template_vals_foreach_ulong(tvals, "@list", count, "offset", offset); if (count % 2 == 0) template_vals_foreach_ulong(tvals, "@list", count, "even_row", 1); template_vals_foreach_string(tvals, "@list", count, "userid", entry->userid); template_vals_foreach_string(tvals, "@list", count, "display_name", entry->display_name); if (!compare_display_name(entry->display_name, entry->registered_name)) { template_vals_foreach_string(tvals, "@list", count, "registered_name", entry->registered_name); } template_vals_foreach_string(tvals, "@list", count, "affiliation", entry->affiliation); if (entry->cancelled) template_vals_foreach_ulong(tvals, "@list", count, "cancelled", 1); template_vals_foreach_string(tvals, "@list", count, "phone", entry->phone); template_vals_foreach_string(tvals, "@list", count, "email", entry->email); } void my_generate_page(struct session *session) { struct template_vals *tvals = session->template_vals; struct prefs *prefs = session->options->prefs; struct lookup *lookup = session->lookup; struct request *request = session->request; struct buffer *b = request->write_buffer; BOOL have_draft = session->draft->have_draft; unsigned long i, offset, first, last; unsigned long count; /* Calculate first and last entry on page. */ offset = lookup->current; if (offset >= prefs->abook_per_page) first = (offset - ((offset - 1) % prefs->abook_per_page)); else first = 1; last = (((first + (prefs->abook_per_page - 1)) <= lookup->count) ? (first + (prefs->abook_per_page - 1)) : lookup->count); count = 0; for (i = first ; i <= last ; i++) { cmd_abook_lookup_single(tvals, lookup->entries[i-1], i, have_draft, count); count++; } cmd_abook_lookup_addnav(tvals, first, lookup->count, prefs->abook_per_page); template_vals_string(tvals, "$query", lookup->query); template_vals_ulong(tvals, "$count", lookup->count); if (lookup->have_phone) template_vals_ulong(tvals, "$have_phone", 1); if (lookup->have_cancelled) template_vals_ulong(tvals, "$have_cancelled", 1); session_seed_template(session, tvals); template_expand("abook_lookup", tvals, b); response_html(request, 200); } static void my_add_addresses(struct session *session) { struct request *request = session->request; struct pool *pool = request->pool; struct draft *draft = session->draft; unsigned long offset; unsigned long count; struct lookup *lookup = session->lookup; struct lookup_item **entries = lookup->entries, *entry; unsigned long max = lookup->count; void (*fn)(struct draft *draft, char *text) = NIL; char *key, *name; if (!entries) return; assoc_scan_reset(request->form); count = 0; while (assoc_scan_next(request->form, &key, NIL)) { if (!strncmp(key, "to_", strlen("to_"))) { key += strlen("to_"); fn = draft_add_to; } else if (!strncmp(key, "cc_", strlen("cc_"))) { key += strlen("cc_"); fn = draft_add_cc; } else if (!strncmp(key, "bcc_", strlen("bcc_"))) { key += strlen("bcc_"); fn = draft_add_bcc; } else continue; if ((offset = atoi(key)) > max) continue; entry = entries[offset-1]; if (!(entry->email && entry->email[0])) continue; if (entry->display_name && entry->display_name[0]) name = entry->display_name; else if (entry->registered_name && entry->registered_name[0]) name = entry->registered_name; else name = ""; (*fn)(draft, abook_text_to_string(pool, name, entry->email)); count++; } if (count != 1) session_message(session, "Added %lu addresses to draft", count); else session_message(session, "Added 1 address to draft"); } static BOOL validate_query(char *s) { char c; if (!s) return(NIL); while ((c=*s++)) { if (strchr("()|&=", c) != NIL) return(NIL); } return(T); } void cmd_abook_lookup(struct session *session) { struct lookup *lookup = session->lookup; struct prefs *prefs = session->options->prefs; struct request *request = session->request; struct assoc *h = NIL; char *query; BOOL do_ldap = NIL; if (request->method != POST) { if (request->argc == 2) lookup->current = atoi(request->argv[1]); /* Move to page */ my_generate_page(session); return; } request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { lookup_clear(lookup); session_redirect(session, request, "abook_list"); return; } /* Record last command for addressbook take */ session->take_parent_cmd = "abook_lookup"; /* Record last command for compose/cancel and friends */ if (!session->draft->have_draft) session->compose_parent_cmd = "abook_lookup"; if (assoc_lookup(h, "sub_page")) { char *pstr = assoc_lookup(request->form, "page"); unsigned long page = pstr ? atoi(pstr) : 0; unsigned long pages = (lookup->count / prefs->abook_per_page) + 1; if ((page > 0) && (page <= pages)) lookup->current = (page - 1) * prefs->abook_per_page + 1; if (lookup->current > lookup->count) lookup->current = lookup->count; my_generate_page(session); return; } if (assoc_lookup(h, "sub_add_address")) { my_add_addresses(session); my_generate_page(session); return; } /* If we get this far then there is a fresh query */ if ((query=assoc_lookup(h, "query"))) query = string_trim_whitespace(query); if (!(query && query[0])) { session_alert(session, "No search term provided"); session_redirect(session, request, "abook_list"); return; } if (!validate_query(query)) { session_alert(session, "Query contained illegal characters"); session_redirect(session, request, "abook_list"); return; } if (assoc_lookup(h, "sub_ldap")) { do_ldap = T; } else if (assoc_lookup(h, "sub_local")) { do_ldap = NIL; } else if (lookup_ldap_available(lookup)) { do_ldap = T; } else do_ldap = NIL; if (do_ldap) { session_log(session, "[cmd_abook_lookup] LDAP lookup for \"%s\"", query); if (!lookup_ldap(lookup, query)) { session_redirect(session, request, "abook_list"); return; } } else { session_log(session, "[cmd_abook_lookup] Local lookup for \"%s\"", query); if (!lookup_local(lookup, query, prefs->default_domain)) { session_redirect(session, request, "abook_list"); return; } } if (lookup->count == 0) { session_message(session, ("0 matches for \"%s\" (may indicate too" " many possible matches)"), query); } else if (lookup->count == 1) { session_message(session, "1 match for \"%s\"", query); } else { session_message(session, "%lu matches for \"%s\"", lookup->count, query); } if (!lookup->entries) { session_redirect(session, request, "abook_list"); return; } my_generate_page(session); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_reply1.c���������������������������������������������������������������������0000644�0065130�0065130�00000003440�11063701633�014540� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_reply1.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" #include "cmd.h" void cmd_reply1(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct options *options = session->options; struct assoc *h; struct list_item *li; struct buffer *b = request->write_buffer; unsigned long count = 0; if (request->method == POST) { request_decode_form(request); if (assoc_lookup((h = request->form), "cancel")) { session_redirect(session, request, session->compose_parent_cmd); return; } session->reply_all = (assoc_lookup(h, "all")) ? T : NIL; } if (list_length(options->role_list) == 0L) { cmd_reply2(session); return; } count = 0; template_vals_foreach_init(tvals, "@roles", count); template_vals_foreach_string(tvals, "@roles", count, "name", "default"); count++; for (li = options->role_list->head; li; li = li->next) { struct role *role = (struct role *) li; template_vals_foreach_init(tvals, "@roles", count); template_vals_foreach_string(tvals, "@roles", count, "name", role->name); count++; } template_vals_string(tvals, "next", "reply2"); session_seed_template(session, tvals); template_expand("roles_select", tvals, b); response_html(request, 200); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_upload_exit.c����������������������������������������������������������������0000644�0065130�0065130�00000001470�11063701633�015642� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_upload_exit.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_upload_exit(struct session *session) { struct request *request = session->request; if (session->upload_file) { unlink(session->upload_file); string_free((void **) &session->upload_file); } if (session->upload_name) string_free((void **) &session->upload_name); session_message(session, "Folder Upload Cancelled"); session_redirect(session, request, "transfer"); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_sieve.c����������������������������������������������������������������������0000644�0065130�0065130�00000021252�11716463742�014453� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_sieve.c,v 1.5 2012/02/14 13:55:46 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Check whether string empty */ static BOOL cmd_sieve_has_content(char *s) { char c; while ((c=*s++)) { if ((c != ' ') && (c != '\t') && (c != '\015') && (c != '\012')) return(T); } return(NIL); } /* Replace a few daft error messages from Sieve */ static char * cmd_sieve_substitute(char *s) { if (!strcmp(s, "parse error, unexpected $undefined.")) s = "syntax error"; return(s); } static void cmd_sieve_print_error_line(struct session *session, struct buffer *b, char *s) { struct config_theme *theme = session->theme_main; unsigned long lineno; if ((strncmp(s, "line ", strlen("line ")) != 0) || ((lineno=atoi(s+strlen("line "))) == 0)) { while (string_isspace(*s)) s++; bprintf(b, CRLF"%s"CRLF, cmd_sieve_substitute(s)); return; } s += strlen("line "); while (*s && Uisdigit(*s)) s++; if ((s[0] == ':') && (s[1] == ' ')) s += 2; while (string_isspace(*s)) s++; bprintf(b, "<font color=\"%s\"> Line %lu:</font> %s"CRLF, theme->fgcolor_quote2, lineno, cmd_sieve_substitute(s)); } static void cmd_sieve_merge_text(struct session *session, struct buffer *b, char *script, char *error) { struct config_theme *theme = session->theme_main; unsigned long lineno = 0; unsigned long tmp_lineno = 0; unsigned long err_lineno = 0; char *line, *errline, tmp[64]; tmp_lineno = 0; while ((errline = string_get_line(&error))) { tmp_lineno++; if (!strncmp(errline, "line ", strlen("line ")) && ((err_lineno = atoi(errline + strlen("line "))) > 0)) break; /* Got a numbered line */ if ((tmp_lineno == 1) && !strcmp(errline, "script errors:")) continue; /* Print unmatched lines at the start */ cmd_sieve_print_error_line(session, b, errline); } lineno = 0; while ((line=string_get_line(&script))) { lineno++; sprintf(tmp, "%5lu", lineno); bprintf(b, "<font color=\"%s\">%s:</font> %s"CRLF, theme->fgcolor_quote1, tmp, line); if (errline && (lineno == err_lineno)) { bputs(b, ""CRLF); cmd_sieve_print_error_line(session, b, errline); /* Check for possible continuation lines (no linenumber given) or further errors on the same line */ while ((errline = string_get_line(&error))) { if (!strncmp(errline, "line ", strlen("line ")) && ((err_lineno = atoi(errline + strlen("line "))) > lineno)) break; cmd_sieve_print_error_line(session, b, errline); } bputs(b, ""CRLF); } } /* Anything left at the end? */ while (errline) { cmd_sieve_print_error_line(session, b, errline); errline = string_get_line(&error); } } static void generate_sieve_error(struct session *session, char *script, char *error) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; session_seed_template(session, tvals); template_expand("sieve_error", tvals, b); bputs(b, "<pre>"CRLF); cmd_sieve_merge_text(session, b, script, error); bputs(b, "</pre>"CRLF); template_expand("sieve_error_tail", tvals, b); response_html(request, 200); /* Success */ } static void generate_connect_error(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; char *msg = sieve_fetch_message(session->sieve); struct buffer *b = request->write_buffer; if (!(msg && msg[0])) msg = "Unable to check mail processing status with server"; template_vals_string(tvals, "msg", msg); session_seed_template(session, tvals); template_expand("sieve_fail", tvals, b); response_html(request, 200); } static void generate_form(struct session *session) { struct template_vals *tvals = session->template_vals; struct prefs *prefs = session->options->prefs; struct request *request = session->request; struct buffer *b = request->write_buffer; struct sieve *sieve = session->sieve; char *script = sieve_current(sieve); template_vals_ulong(tvals, "rows", prefs->large_rows); template_vals_ulong(tvals, "cols", prefs->large_cols); template_vals_string(tvals, "script", script); session_seed_template(session, tvals); template_expand("sieve", tvals, b); response_html(request, 200); /* Success */ } BOOL my_sieve_check(struct sieve *sieve, struct session *session) { char *script; if (sieve->checked) return(T); if (!sieve_fetch(sieve, session, "sieve", &script)) return(NIL); sieve_current_record(sieve, script); sieve_live_record(sieve, script); sieve->checked = T; return(T); } void cmd_sieve(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct buffer *b = request->write_buffer; struct sieve *sieve = session->sieve; struct account *account = session->account; struct assoc *h = NIL; char *script; char *end; unsigned long len; if (!my_sieve_check(sieve, session)) { generate_connect_error(session); return; } if (request->argc == 2) { if (!strcmp(request->argv[1], "download")) { bputs(b, sieve_current(session->sieve)); response_raw(request, "sieve.script", "text/plain", 200); return; } if ((strcmp(request->argv[1], "upload") != 0) || (request->method != POST)) { generate_form(session); return; } request_decode_post_multipart(request, NIL, &script, &end); *end = '\0'; if (end > script) len = (char *) end - (char *) script; else len = 0; if (len < 1) { session_alert(session, "Please choose a file to attach"); generate_form(session); return; } if ((config->sieve_maxsize > 0) && (len > config->sieve_maxsize)) { session_alert(session, "Sieve file too large"); generate_form(session); return; } script = string_expand_crlf(request->pool, script); } else { if (request->method != POST) { generate_form(session); return; } /* Form post */ request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_sieve")) { generate_form(session); return; } if (!assoc_lookup(h, "sub_apply")) { session_redirect(session, request, "manage"); /* parent screen */ return; } if (!(script = assoc_lookup(h, "script"))) { session_alert(session, "Invalid form input"); session_redirect(session, request, "manage"); /* parent screen */ return; } } /* Process Sieve file uploaded by one means or another */ /* Useful subset of ISO-8859-1 and UTF-8 is ASCII */ string_strip8bit(script); if (script && cmd_sieve_has_content(script)) { sieve_current_record(sieve, script); if (!(sieve_upload(sieve, session, "sieve", script) && sieve_activate(sieve, session, "sieve"))) { char *error = sieve_fetch_message(sieve); generate_sieve_error(session, script, error); return; } sieve_live_record(sieve, script); session_message(session, "Sieve script sucessfully installed"); account->mail_checked = NIL; /* Blat existing automatic filtering */ } else { sieve_current_record(sieve, NIL); if (sieve_live(sieve)) { /* Need to deactivate sieve file before deleting with Cyrus 2.4 */ if (sieve_activate(sieve, session, "") && sieve_delete(sieve, session, "sieve")) { session_message(session, "Removed sieve filter"); sieve_live_record(sieve, NIL); } else session_alert(session, "Problem removing sieve filter"); } } session_redirect(session, request, "manage"); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_zoom.c�����������������������������������������������������������������������0000644�0065130�0065130�00000001717�11063701633�014315� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_zoom.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_zoom(struct session *session) { struct request *request = session->request; if (msgmap_have_zoom(session->zm)) { session_message(session, "Zoom mode disabled"); msgmap_disable_zoom(session->zm); } else { if (msgmap_marked_count(session->zm) > 0) { msgmap_enable_zoom(session->zm); session_message(session, "Zoom mode enabled"); } else session_message(session, "Zoom mode not enabled (no messages marked)"); } session_redirect(session, request, "list"); } �������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_sort.c�����������������������������������������������������������������0000644�0065130�0065130�00000004705�11063701633�015473� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_sort.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_abook_sort(struct session *session) { struct abook *abook = session->options->abook; struct request *request = session->request; char *type, *text = ""; BOOL reverse; if (request->argc < 2) { session_redirect(session, request, "abook_list"); return; } type = request->argv[1]; reverse = abook->sort_reverse; if (!strcmp(type, "order")) { if (abook->sort_mode == ABOOK_SORT_ORDER) { reverse = (reverse) ? NIL : T; abook_set_sort(abook, ABOOK_SORT_ORDER, reverse); } else abook_set_sort(abook, ABOOK_SORT_ORDER, reverse=NIL); text = "order"; } else if (!strcmp(type, "alias")) { if (abook->sort_mode == ABOOK_SORT_ALIAS) { reverse = (reverse) ? NIL : T; abook_set_sort(abook, ABOOK_SORT_ALIAS, reverse); } else abook_set_sort(abook, ABOOK_SORT_ALIAS, reverse=NIL); text = "alias"; } else if (!strcmp(type, "name")) { if (abook->sort_mode == ABOOK_SORT_NAME) { reverse = (reverse) ? NIL : T; abook_set_sort(abook, ABOOK_SORT_NAME, reverse); } else abook_set_sort(abook, ABOOK_SORT_NAME, NIL); text = "name"; } else if (!strcmp(type, "comment")) { if (abook->sort_mode == ABOOK_SORT_COMMENT) { reverse = (reverse) ? NIL : T; abook_set_sort(abook, ABOOK_SORT_COMMENT, reverse); } else abook_set_sort(abook, ABOOK_SORT_COMMENT, reverse=NIL); text = "comment"; } else if (!strcmp(type, "email")) { if (abook->sort_mode == ABOOK_SORT_EMAIL) { reverse = (reverse) ? NIL : T; abook_set_sort(abook, ABOOK_SORT_EMAIL, reverse); } else abook_set_sort(abook, ABOOK_SORT_EMAIL, reverse=NIL); text = "address(es)"; } if (reverse) session_message(session, "Sorting on reverse %s", text); else session_message(session, "Sorting on %s", text); session_redirect(session, request, "abook_list"); } �����������������������������������������������������������./prayer-1.3.5/cmd/cmd_logout.c���������������������������������������������������������������������0000644�0065130�0065130�00000001732�11063701633�014637� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_logout.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_logout(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct prefs *prefs = session->options->prefs; struct buffer *b = request->write_buffer; char *back = pool_join(request->pool, '/', &request->argv[1]); if (!prefs->confirm_logout) { session_redirect(session, request, "exit"); return; } template_vals_string(tvals, "cancel", back); session_seed_template(session, tvals); template_expand("logout", tvals, b); response_html(request, 200); } ��������������������������������������./prayer-1.3.5/cmd/cmd_rename.c���������������������������������������������������������������������0000644�0065130�0065130�00000003603�11063701633�014574� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_rename.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_rename(struct session *session) { struct template_vals *tvals = session->template_vals; struct folderlist *fl = folderlist_fetch(session); struct prefs *prefs = session->options->prefs; BOOL suppress_dotfiles = prefs->suppress_dotfiles; struct request *request = session->request; struct buffer *b = request->write_buffer; struct folderitem *fi; char *name; if ((request->argc == 3) && !strcmp(request->argv[1], "toggle")) { name = string_canon_decode(request->argv[2]); fi = folderlist_lookup(folderlist_fetch(session), name); if (fi) { if (fi->expanded) { session_message(session, "Collapsed \"%s\"", name); fi->expanded = NIL; } else { folderlist_expand(session, fi); session_message(session, "Expanded \"%s\"", name); fi->expanded = T; } } } else if (request->argc == 2) { string_strdup(&session->rename_foldername, request->argv[1]); string_canon_decode(session->rename_foldername); } folderlist_template_vals_tree(fl, suppress_dotfiles, tvals, "@folder"); folderlist_template_vals_list(fl, suppress_dotfiles, tvals, T, "@dirlist"); template_vals_string(tvals, "rename_foldername", session->rename_foldername); session_seed_template(session, tvals); template_expand("rename", tvals, b); response_html(request, 200); } �����������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_forward1.c�������������������������������������������������������������������0000644�0065130�0065130�00000041520�11747523621�015062� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_forward1.c,v 1.12 2012/04/30 14:54:09 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void buffer_puts_mime(struct buffer *b, char *s) { unsigned long len = strlen(s) + 20; char *buffer = pool_alloc(b->pool, len); /* Decoded form smaller */ char *d; d = (char *) rfc1522_decode((unsigned char *) buffer, len, s, NIL); bputs(b, d); } static char *string_decode_mime(struct pool *tpool, char *s) { unsigned long len = strlen(s) + 20; char *buffer = pool_alloc(tpool, len); char *d; d = (char *) rfc1522_decode((unsigned char *) buffer, len, s, NIL); return (d); } /* ====================================================================== */ static BOOL add_attachments(struct session *session, struct draft *draft, struct pool *pool, MAILSTREAM * stream, unsigned long msgno, BOOL attach_first) { BODY *body; PART *part; unsigned long section; char *hdr, *msg; unsigned long hdr_len, msg_len; char *name, *type, *encoding; PARAMETER *parameter; if (!ml_fetch_structure(session, stream, msgno, &body, NIL)) return (NIL); /* Deal with nested message as special case */ if (body->type == TYPEMESSAGE) { type = pool_strcat3(pool, body_types[body->type], "/", body->subtype); encoding = pool_strdup(pool, body_encodings[body->encoding]); string_lcase(type); string_lcase(encoding); if ((hdr = ml_fetch_mime(session, stream, msgno, "1", &hdr_len, FT_PEEK)) && (msg = ml_fetchbody(session, stream, msgno, "1", &msg_len))) { draft_add_attachment(draft, "", type, encoding, hdr, hdr_len, msg, msg_len); return (T); } return (NIL); } /* Process top level multipart message */ if (body->type != TYPEMULTIPART) return (T); if (body->subtype && !strcasecmp(body->subtype, "alternative")) return (T); if (!(part = body->nested.part)) return (T); /* First part is typically text part displayed to user. Skip it unless we were unable to extract text part to display inline (add_text) */ if (attach_first) { section = 1; } else { section = 2; part = part->next; } while (part) { char *stext = string_itoa(pool, section); body = &part->body; name = NIL; for (parameter = body->parameter; parameter; parameter = parameter->next) { if (!strcasecmp(parameter->attribute, "NAME")) name = parameter->value; } if (!name && body->description) name = body->description; if (!name) name = ""; type = pool_strcat3(pool, body_types[body->type], "/", body->subtype); encoding = pool_strdup(pool, body_encodings[body->encoding]); string_lcase(type); string_lcase(encoding); if ((hdr = ml_fetch_mime(session, stream, msgno, stext, &hdr_len, FT_PEEK)) && (msg = ml_fetchbody(session, stream, msgno, stext, &msg_len))) { draft_add_attachment(draft, name, type, encoding, hdr, hdr_len, msg, msg_len); } else return (NIL); part = part->next; section++; } return (T); } /* ====================================================================== */ /* Small utility routine stolen from PINE */ static STRINGLIST *new_strlst(char **l) { STRINGLIST *sl = mail_newstringlist(); sl->text.data = (unsigned char *) (*l); sl->text.size = strlen(*l); sl->next = (*++l) ? new_strlst(l) : NULL; return (sl); } static void add_text_single(struct buffer *b, char *s) { if (!s) return; while (*s) { if ((*s == '\015') || (*s == '\012')) { s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; bputc(b, '\015'); bputc(b, '\012'); } else { bputc(b, *s); s++; } } } static BOOL add_text(struct session *session, struct buffer *b, STRINGLIST * hdrslist, struct pool *pool, MAILSTREAM * stream, unsigned long msgno, BOOL *attach_first) { struct options *options = session->options; struct prefs *prefs = options->prefs; unsigned long len; char *text; char *init_msg, *decode_msg, *type; BODY *body = NIL; char *section = "1"; PARAMETER *parameter; char *charset = "ISO-8859-1"; *attach_first = NIL; if (!(text = ml_fetch_header(session, stream, msgno, NIL, hdrslist, &len, 0))) return (NIL); buffer_puts_mime(b, text); /* Only include text of first part in body */ if ((body = ml_body(session, stream, msgno, "1")) == NIL) return (NIL); if (body->type == TYPEMESSAGE) return (T); if (body->type == TYPEMULTIPART) { PART *part = body->nested.part; int i = 1, body_plain = 0, body_html = 0, subsection; for (i = 1; part != NIL; part = part->next, i++) { if (!(body = &part->body)) continue; if ((body->type != TYPETEXT) || !body->subtype) continue; if (!strcasecmp(body->subtype, "plain")) { if (!body_plain) body_plain = i; } else if (!strcasecmp(body->subtype, "html")) { if (!body_html) body_html = i; } } subsection = (body_plain) ? body_plain : body_html; if (!subsection) { bputs(b, "(Message body included as attachment)" CRLF); *attach_first = T; return(T); } section = pool_printf(pool, "1.%lu", subsection); if ((body = ml_body(session, stream, msgno, section)) == NIL) return (NIL); } else if (body->type != TYPETEXT) { bputs(b, "(Message body included as attachment)" CRLF); *attach_first = T; return (T); } else section = "1"; for (parameter = body->parameter; parameter; parameter = parameter->next) { if (strcasecmp(parameter->attribute, "charset") == 0) { charset = parameter->value; break; } } if (!(init_msg = ml_fetchbody(session, stream, msgno, section, &len))) return (NIL); /* Strip off encoding */ switch (body->encoding) { case ENCBASE64: if (! (decode_msg = (char *) rfc822_base64((unsigned char *) init_msg, body->size.bytes, &len))) { /* Decode failed */ decode_msg = init_msg; len = body->size.bytes; } break; case ENCQUOTEDPRINTABLE: if (! (decode_msg = (char *) rfc822_qprint((unsigned char *) init_msg, body->size.bytes, &len))) { /* Decode failed */ decode_msg = init_msg; len = body->size.bytes; } break; case ENC7BIT: case ENC8BIT: case ENCBINARY: case ENCOTHER: default: decode_msg = init_msg; len = body->size.bytes; } type = pool_strcat3(pool, body_types[body->type], "/", body->subtype); string_lcase(type); if ((!strcasecmp(type, "text/html") && prefs->html_inline) || (!strncasecmp(decode_msg, "<html>", strlen("<html>")) && prefs->html_inline_auto)) { if (decode_msg == init_msg) decode_msg = strdup(init_msg); html_secure_strip_all(b, utf8_from_string(pool, charset, decode_msg, len)); } else { add_text_single(b, utf8_from_string(pool, charset, decode_msg, len)); } if (decode_msg != init_msg) fs_give((void **) &decode_msg); return (T); } /* ====================================================================== */ void cmd_forward1(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct draft *draft = session->draft; struct options *options = session->options; struct prefs *prefs = options->prefs; unsigned long offset; char *s; MAILSTREAM *stream = session->stream; struct buffer *b; MESSAGECACHE *elt; ENVELOPE *env; unsigned long count, count2, bytes; unsigned long att_count; struct role *role = NIL; char *postponed_text = ""; struct msgmap *zm = session->zm; STRINGLIST *hdrslist; static STRINGLIST *myhdrslist = NIL; static char *short_hdrs[] = { "from", "to", "cc", "date", "subject", NIL }; /* Set up hdrlist on first call only */ if (!myhdrslist) myhdrslist = new_strlst(short_hdrs); hdrslist = (session->full_hdrs) ? NIL : myhdrslist; /* Clear session_message generated by cmd_forward() if we are redirected * here automatically */ session_message_clear(session); request_decode_form(request); if ((s = assoc_lookup(request->form, "role"))) role = role_find(options->role_list, s); /* Write out exiting draft */ if (draft->have_draft) { if (!draft_write(draft)) { session_message_clear(session); session_alert(session, "Failed to postpone existing draft before forward"); session_log(session, "[cmd_forward1] Failed to postponed draft message: %s", ml_errmsg()); session_redirect(session, session->request, "compose"); return; } draft_free(draft); postponed_text = " Postponed existing draft."; } draft_role_set(draft, role); draft_init(draft); draft_init_rich_headers(draft); /* Create temporary scratch buffer */ b = buffer_create(draft->pool, 0); /* Install existing body (includes signature) */ if (draft->body && draft->body[0]) bputs(b, draft->body); if (!session->aggregate) { /* Simple forward */ BOOL attach_first = NIL; bprintf(b, CRLF "---------- Forwarded message ----------" CRLF); /* Add message text */ if (!add_text(session, b, hdrslist, request->pool, stream, session->current, &attach_first)) { session_redirect(session, request, "restart"); return; } /* Add attachments if multipart message */ if (!add_attachments(session, draft, request->pool, stream, session->current, attach_first)) { session_redirect(session, request, "restart"); return; } draft->body = buffer_fetch(b, 0, buffer_size(b), NIL); att_count = draft_att_count(draft); if (att_count > 1) session_message(session, "Forwarding message %lu (%lu attachments).%s", session->current, att_count, postponed_text); else if (att_count == 1) session_message(session, "Forwarding message %lu (1 attachment).%s", session->current, postponed_text); else session_message(session, "Forwarding message %lu (no attachments).%s", session->current, postponed_text); if (! (env = ml_fetch_structure(session, stream, session->current, NIL, 0))) { session_redirect(session, request, "restart"); return; } if (env->subject && env->subject) { char *s = string_decode_mime(request->pool, env->subject); if (!strncasecmp(s, "Fwd: ", strlen("Fwd: "))) draft->subject = pool_strdup(draft->pool, s); else draft->subject = pool_strcat(draft->pool, "Fwd: ", s); } session_redirect(session, request, "compose"); return; } /* Aggregate forward */ /* Fetch overview for all messages in folder */ if (!ml_fetch_overview(session, stream, "1:*", NIL)) { session_alert(session, "Failed to fetch folder overview: %s", ml_errmsg()); session_redirect(session, request, "list"); return; } /* Work out number of messages involved, and approx size */ count = 0L; bytes = 0L; for (offset = 1L; offset <= msgmap_size(zm); offset++) { unsigned long msgno = msgmap_value(zm, offset); if (prefs->use_mark_persist) { if (msgmap_has_mark(zm, msgno)) { count++; if ((elt = ml_elt(session, stream, msgno))) bytes += elt->rfc822_size; } } else { if (msgmap_has_tmp_mark(zm, msgno)) { count++; if ((elt = ml_elt(session, stream, msgno))) bytes += elt->rfc822_size; } } } /* Block godzillagrams created by "Mark All" and GByte sized mboxes */ if ((config->draft_att_total_max > 0) && (bytes > config->draft_att_total_max)) { session_message(session, "Forwarded message (%lu MBytes) would be larger than" " maximum allowed (%lu MBytes)", bytes/(1024*1024), config->draft_att_total_max/(1024*1024)); session_redirect(session, request, "list"); return; } if (count != 1) bputs(b, CRLF "---------- Forwarded messages ----------" CRLF); else bputs(b, CRLF "---------- Forwarded message ----------" CRLF); if (!msgmap_update(zm)) { session_redirect(session, request, "restart"); return; } count2 = 0; for (offset = 1L; offset <= msgmap_size(zm); offset++) { unsigned long msgno = msgmap_value(zm, offset); BOOL forward_this; BOOL attach_first = NIL; if (prefs->use_mark_persist && msgmap_has_mark(zm, msgno)) forward_this = T; else if (!prefs->use_mark_persist && msgmap_has_tmp_mark(zm, msgno)) forward_this = T; else forward_this = NIL; if (forward_this) { /* Add message text */ if (count != 1) bprintf(b, CRLF "---------- Message %lu ----------" CRLF, ++count2); if (!add_text (session, b, hdrslist, request->pool, stream, msgno, &attach_first)) { session_redirect(session, request, "restart"); return; } if (count != 1) bputs(b, "" CRLF); /* Add attachments if multipart message */ if (!add_attachments (session, draft, request->pool, stream, msgno, attach_first)) { session_redirect(session, request, "restart"); return; } } } draft->body = buffer_fetch(b, 0, buffer_size(b), NIL); att_count = draft_att_count(draft); if (count != 1) { draft->subject = pool_printf(draft->pool, "Fwd: %lu separate messages", count); if (att_count > 1) session_message(session, "Forwarding %lu messages (%lu attachments).%s", count, att_count, postponed_text); else if (att_count == 1) session_message(session, "Forwarding %lu messages (1 attachment).%s", count, postponed_text); else session_message(session, "Forwarding %lu messages (no attachments).%s", count, postponed_text); } else { draft->subject = pool_strdup(draft->pool, "Fwd: Single message"); if (att_count > 1) session_message(session, "Forwarding single message (%lu attachments).%s", att_count, postponed_text); else if (att_count == 1) session_message(session, "Forwarding single message (1 attachment).%s", postponed_text); else session_message(session, "Forwarding single message (no attachments).%s", postponed_text); } if (prefs->use_agg_unmark) { msgmap_unmark_all(session->zm); msgmap_disable_zoom(session->zm); } session_redirect(session, request, "compose"); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_download_xfer.c��������������������������������������������������������������0000644�0065130�0065130�00000015543�11305245733�016171� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_download_xfer.c,v 1.5 2009/12/01 17:01:15 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* ====================================================================== */ /* unix_pseudo stolen from c-client */ extern unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr); static BOOL download(struct session *session, char *name) { struct config *config = session->config; struct request *request = session->request; struct buffer *b = request->write_buffer; MAILSTREAM *tstream; unsigned long msgno, len; char *text, *s, c; char lastc = '\n'; MESSAGECACHE *elt; ENVELOPE *env; ADDRESS *addr; int flag; char tmp[MAILTMPLEN]; unsigned long uid; unsigned long total; session->xfer_stream = ml_open(session, session->xfer_stream, session_mailbox(session, request->pool, name), OP_READONLY); if (!session->xfer_stream) { session_alert(session, "Failed to open mail folder: %s", utf8_from_imaputf7(request->pool, name)); session_log(session, "[cmd_transfer] Failed to open mail folder: %s", name); return (NIL); } tstream = session->xfer_stream; /* Fetch overview for all messages in folder */ if (!ml_fetch_fast(session, tstream, "1:*", 0)) { session_alert(session, "Failed to fetch folder overview: %s", utf8_from_imaputf7(request->pool, name)); session_log(session, "[cmd_transfer]] Failed to fetch overview: %s", name); return (NIL); } /* Test size of download */ if (config->http_max_body_size > 0) { total = 0; for (msgno = 1; msgno <= tstream->nmsgs; msgno++) { if (!(elt = ml_elt(session, tstream, msgno))) return (NIL); total += elt->rfc822_size; } if (total > config->http_max_body_size) { struct template_vals *tvals = session->template_vals; template_vals_ulong(tvals, "size", total / (1024*1024)); template_vals_ulong(tvals, "limit", config->http_max_body_size / (1024*1024)); session_seed_template(session, tvals); template_expand("download_xfer_error", tvals, b); response_html(request, 200); return(T); } } /* Fudge up unix pseudo message for Keywords etc */ unix_pseudo(tstream, tmp); bputs(b, tmp); for (msgno = 1; msgno <= tstream->nmsgs; msgno++) { if (!((uid = ml_uid(session, tstream, msgno)) && (elt = ml_elt(session, tstream, msgno)) && (env = ml_fetch_structure(session, tstream, msgno, NIL, 0)))) return (NIL); mail_cdate (tmp, elt); if ((addr = env->sender) && addr->mailbox && addr->host) bprintf(b, "From %s@%s %s", addr->mailbox, addr->host, tmp); else bprintf(b, "From unknown@nowhere.com %s", tmp); if (! (text = ml_fetch_header(session, tstream, msgno, NIL, NIL, &len, 0))) { session_alert(session, "Couldn't fetch header for message %lu", msgno); session_log(session, ("[cmd_transfer] Couldn't fetch header for message %lu" "in folder: %s"), msgno, name); return (NIL); } /* Copy header replacing CRLF, CR or LF with LF */ s = text; while ((c = *s)) { /* Chomp final CRLF sequence */ if ((s[0] == '\015') && (s[1] == '\012') && (s[2] == '\0')) break; if (((s[0] == '\015') || (s[0] == '\012')) && (s[1] == '\0')) break; if ((c == '\015') || (c == '\012')) { /* Replace CRLF with single LF */ s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; bputc(b, '\n'); /* Quote "From" on following line */ if (!strncmp(s, "From ", strlen("From "))) bputc(b, '>'); continue; } bputc(b, c); s++; } bputs(b, "Status: "); if (elt->seen) bputc(b, 'R'); if (!elt->recent) bputc(b, 'O'); bputs(b, "\nX-Status: "); if (elt->deleted) bputc(b, 'D'); if (elt->flagged) bputc(b, 'F'); if (elt->answered) bputc(b, 'A'); if (elt->draft) bputc(b, 'T'); bputs(b, "\nX-Keywords:"); for (flag = 0 ; flag < NUSERFLAGS ; flag++) { if ((elt->user_flags & (1<<flag)) && tstream->user_flags[flag]) { bprintf(b, " %s", tstream->user_flags[flag]); } } bprintf(b, "\nX-UID: %lu\n\n", uid); if (!(text = ml_fetch_text(session, tstream, msgno, NIL, &len, 0))) { session_alert(session, "Couldn't fetch body for message %lu", msgno); session_log(session, ("[cmd_transfer] Couldn't fetch body for message %lu" "in folder: %s"), msgno, name); return (NIL); } /* Copy body replacing CRLF, CR or LF with LF */ s = text; while ((c = *s)) { if ((c == '\015') || (c == '\012')) { /* Replace CRLF with single LF */ s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; bputc(b, '\n'); lastc = '\n'; /* Quote "From" on following line */ if (!strncmp(s, "From ", strlen("From "))) bputc(b, '>'); continue; } lastc = c; bputc(b, c); s++; } if (lastc != '\n') bputc(b, '\n'); bputc(b, '\n'); if (elt->rfc822_size > (1024*1024)) /* Large attachment */ mail_gc(tstream, GC_ENV | GC_TEXTS); /* Discard cache */ } mail_gc(tstream, GC_ENV | GC_TEXTS); /* Discard cache immediately */ response_raw(request, name, "application/octet-stream", 200); return (T); } /* ====================================================================== */ void cmd_download_xfer(struct session *session) { struct request *request = session->request; if (request->argc < 2) { session_redirect(session, request, "error"); return; } if (!download(session, string_canon_decode(request->argv[1]))) session_redirect(session, request, "restart"); return; } �������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_reply2.c���������������������������������������������������������������������0000644�0065130�0065130�00000024726�11064236131�014550� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_reply2.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static BOOL string_check_sigdash(char *sig) { char *s; /* Check whether signature already contains sigdash line */ for (s = sig; *s; s++) { if ((s[0] == '-') && (s[1] == '-') && (s[2] == ' ') && ((s[3] == '\015') || (s[3] == '\012'))) { return (NIL); } } return (T); } static char *string_decode_mime(struct pool *tpool, char *s) { unsigned long len = strlen(s) + 20; char *buffer = pool_alloc(tpool, len); char *d; d = (char *) rfc1522_decode((unsigned char *) buffer, len, s, NIL); return (d); } /* ====================================================================== */ /* Extract text from relevant message (go fishing around inside multipart * messages) and put in into the specified buffer as quoted (and possibly * line wrapped) text */ static BOOL add_text(struct session *session, struct buffer *b, struct pool *pool, MAILSTREAM *stream, unsigned long msgno) { struct prefs *prefs = session->options->prefs; BODY *body = NIL; char *section = NIL; char *init_msg, *decode_msg, *type; unsigned long len; char *text, *s; PARAMETER *parameter; char *charset = "ISO-8859-1"; if ((body = ml_body(session, stream, msgno, "1")) == NIL) return(NIL); if (body->type == TYPEMULTIPART) { PART *part = body->nested.part; int i = 1, body_plain = 0, body_html = 0, subsection; for (i = 1; part != NIL; part = part->next, i++) { if (!(body = &part->body)) continue; if ((body->type != TYPETEXT) || !body->subtype) continue; if (!strcasecmp(body->subtype, "plain")) { if (!body_plain) body_plain = i; } else if (!strcasecmp(body->subtype, "html")) { if (!body_html) body_html = i; } } subsection = (body_plain) ? body_plain : body_html; if (subsection) { section = pool_printf(pool, "1.%lu", subsection); if ((body = ml_body(session, stream, msgno, section)) == NIL) return (NIL); } else section = NIL; } else if (body->type == TYPETEXT) { section = "1"; } else section = NIL; if (!section) { bputs(b, "> (Message body was not text: suppressed)" CRLF); return(T); } for (parameter = body->parameter; parameter; parameter = parameter->next) { if (strcasecmp(parameter->attribute, "charset") == 0) { charset = parameter->value; break; } } /* Got a valid text section to display */ if (!(init_msg=ml_fetchbody(session, stream, msgno, section, &len))) return(NIL); /* Strip off encoding */ switch (body->encoding) { case ENCBASE64: if (!(decode_msg = (char *) rfc822_base64((unsigned char *) init_msg, body->size.bytes, &len))) { /* Decode failed */ decode_msg = init_msg; len = body->size.bytes; } break; case ENCQUOTEDPRINTABLE: if (!(decode_msg = (char *) rfc822_qprint((unsigned char *) init_msg, body->size.bytes, &len))) { /* Decode failed */ decode_msg = init_msg; len = body->size.bytes; } break; case ENC7BIT: case ENC8BIT: case ENCBINARY: case ENCOTHER: default: decode_msg = init_msg; len = body->size.bytes; } type = pool_strcat3(pool, body_types[body->type], "/", body->subtype); string_lcase(type); if ((!strcasecmp(type, "text/html") && prefs->html_inline) || (!strncasecmp(decode_msg, "<html>", strlen("<html>")) && prefs->html_inline_auto)) { struct buffer *b = buffer_create(pool, 8192); if (decode_msg == init_msg) decode_msg = strdup(init_msg); html_secure_strip_all(b, utf8_from_string(pool, charset, decode_msg, len)); text = buffer_fetch(b, 0, buffer_size(b), NIL); } else text = utf8_from_string(pool, charset, decode_msg, len); bputs(b, ">"); for (s = text; *s;) { if ((s[0] == '\015') || (s[0] == '\012')) { if ((s[0] == '\015') && (s[1] == '\012')) s += 2; /* CRLF */ else s++; /* CR or LF */ bputs(b, CRLF ">"); /* Check for sigdash at start of line */ if ((s[0] == '-') && (s[1] == '-') && (s[2] == ' ') && ((s[3] == '\015') || (s[3] == '\012'))) break; } else bputc(b, *s++); } if (decode_msg != init_msg) fs_give((void **) &decode_msg); return(T); } /* ====================================================================== */ void cmd_reply2(struct session *session) { struct request *request = session->request; struct draft *draft = session->draft; struct options *options = session->options; struct prefs *prefs = options->prefs; unsigned long msgno; unsigned long msgno_uid; char *s, *opt_cc; MAILSTREAM *stream = session->stream; MESSAGECACHE *elt; ENVELOPE *env; ADDRESS *sender; struct buffer *b = request->write_buffer; char *postponed_text = ""; request_decode_form(request); if ((s = assoc_lookup(request->form, "role"))) draft_role_set(draft, role_find(options->role_list, s)); msgno = session->current; msgno_uid = ml_uid(session, stream, msgno); if (!(msgno = stream_check_uid(session, stream, msgno, msgno_uid))) { session_redirect(session, request, "list"); return; } if (!((elt = ml_elt(session, stream, msgno)) && (env = ml_fetch_structure(session, stream, msgno, NIL, 0)))) { session_redirect(session, request, "restart"); return; } sender = (env->reply_to) ? (env->reply_to) : (env->from); /* Calculate possible Cc value from message recipients */ if (env->to) { opt_cc = pool_strdup(request->pool, addr_text_exclude(session, request->pool, env->to, sender)); if (env->cc) { s = addr_text_exclude(session, request->pool, env->cc, sender); if (s && s[0]) { if (opt_cc && opt_cc[0]) opt_cc = pool_strcat3(request->pool, opt_cc, ", ", s); else opt_cc = pool_strdup(request->pool, s); } } } else if (env->cc) { opt_cc = pool_strdup(request->pool, addr_text_exclude(session, request->pool, env->cc, sender)); } else opt_cc = NIL; /* Write out exiting draft */ if (draft->have_draft) { if (!draft_write(draft)) { session_message_clear(session); session_alert(session, "Failed to postpone existing draft before reply"); session_log(session, "[cmd_reply2] Failed to postponed draft message: %s", ml_errmsg()); session_redirect(session, session->request, "compose"); return; } draft_free(draft); postponed_text = " Postponed existing draft."; } draft_init(draft); draft_init_rich_headers(draft); /* Record message that we are responding to here */ draft_set_reply(draft, stream, session->foldername, msgno); /* Set To address */ if (sender && sender->mailbox && sender->host) { char *s = string_decode_mime(request->pool, addr_text(request->pool, sender)); draft->to = pool_strdup(draft->pool, s); } /* Set Cc address */ if (opt_cc && opt_cc[0] && (session->reply_all)) { char *s = string_decode_mime(request->pool, opt_cc); draft->cc = pool_strdup(draft->pool, s); } /* Create temporary scratch buffer */ b = buffer_create(draft->pool, 0); if ((sender = env->from)) { bprintf(b, "On %s, ", mc_date_to_string(elt)); /* XXX Factor out rfc1522_decode calls */ if (sender->personal) { unsigned long len = strlen(sender->personal) + 20; char *buffer = pool_alloc(b->pool, len); /* Decoded form smaller */ char *d = (char *) rfc1522_decode((unsigned char *) buffer, len, sender->personal, NIL); bprintf(b, "%s wrote:" CRLF "" CRLF, d); } else if (sender->mailbox && sender->host) bprintf(b, "%s@%s wrote:" CRLF "" CRLF, sender->mailbox, sender->host); } if (!add_text(session, b, request->pool, stream, msgno)) { session_redirect(session, request, "restart"); return; } if (draft->role && draft->role->signature && draft->role->signature[0]) { bputs(b, "" CRLF "" CRLF); if (string_check_sigdash(draft->role->signature)) bputs(b, "-- " CRLF); bprintf(b, "%s" CRLF, draft->role->signature); } else if (prefs->signature && prefs->signature[0]) { bputs(b, "" CRLF "" CRLF); if (string_check_sigdash(prefs->signature)) bputs(b, "-- " CRLF); bprintf(b, "%s" CRLF, prefs->signature); } /* Get full copy of buffer */ draft->body = buffer_fetch(b, 0, buffer_size(b), NIL); if (prefs->line_wrap_on_reply) draft_line_wrap_body(draft); if (!(env = ml_fetch_structure(session, stream, msgno, NIL, 0))) { session_redirect(session, request, "restart"); return; } if (env->subject && env->subject) { char *s = string_decode_mime(request->pool, env->subject); if (!strncasecmp(s, "Re: ", strlen("Re: "))) draft->subject = pool_strdup(draft->pool, s); else draft->subject = pool_strcat(draft->pool, "Re: ", s); } session_message(session, "Replying to message %d.%s", msgno, postponed_text); session_redirect(session, request, "compose"); } ������������������������������������������./prayer-1.3.5/cmd/cmd_rename_item.c����������������������������������������������������������������0000644�0065130�0065130�00000007244�11245750767�015635� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_rename_item.c,v 1.7 2009/08/28 12:47:51 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_rename_item(struct session *session) { struct options *options = session->options; struct prefs *prefs = options->prefs; struct favourite_list *fl = options->favourite_list; struct request *request = session->request; struct pool *pool = request->pool; MAILSTREAM *stream; char *newname = NIL; char *parent; if (request->method == POST) request_decode_form(request); else request_decode_form(request); if (assoc_lookup(request->form, "cancel")) { session_message(session, "Rename operation cancelled"); session_redirect(session, request, "folders"); return; } newname=utf8_to_imaputf7(pool, assoc_lookup(request->form, "name")); if (!(session->rename_foldername && newname)) { session_redirect(session, request, "folders"); return; } if ((parent = assoc_lookup(request->form, "parent"))) string_canon_decode(parent); if (parent && parent[0]) newname = pool_strcat3(request->pool, parent, session->hiersep, newname); /* Protect against attempt to rename outside maildir */ if (prefs->maildir && prefs->maildir[0] && session->hiersep && session->hiersep[0]) { char *tmp = pool_strcat(request->pool, prefs->maildir, session->hiersep); if (strncmp(newname, tmp, strlen(tmp)) != 0) { newname = pool_strcat3(request->pool, prefs->maildir, session->hiersep, newname); } } if (!strcasecmp(session->rename_foldername, "INBOX")) { session_alert(session, "Unable to rename inbox folder"); session_redirect(session, request, "folders"); return; } if (session->foldername && session->other_foldername && !strcmp(session->foldername, session->other_foldername) && !strcmp(session->foldername, session->rename_foldername)) { /* Attempt to rename current mailbox other than INBOX */ /* Switch to inbox, shut down other stream */ session_streams_change(session, "INBOX"); ml_close(session, session->other_stream); session->other_stream = NIL; } stream = session->stream; ml_clear_error(); ml_clear_have_close(); ml_rename(session, stream, session_mailbox(session, pool, session->rename_foldername), session_mailbox(session, pool, newname)); if (ml_have_close()) { session_redirect(session, request, "restart"); return; } if (ml_have_error()) { session_alert(session, "Failed to rename mailbox: %s - %s", utf8_from_imaputf7(pool, session->rename_foldername), ml_errmsg()); } else { session_message(session, "Renamed mailbox %s to be %s", utf8_from_imaputf7(pool, session->rename_foldername), utf8_from_imaputf7(pool, newname)); folderlist_rename(session->folderlist, session->rename_foldername, newname); } if (favourite_rename(fl, session->rename_foldername, newname)) options->save = T; session_redirect(session, request, "folders"); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_quota.c����������������������������������������������������������������������0000644�0065130�0065130�00000012111�11071677156�014463� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_quota.c,v 1.5 2008/10/04 14:32:14 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* ====================================================================== */ /* Slightly naughty interface to undocumented QUOTAROOT support in c-client */ #include "imap4r1.h" static unsigned long my_quota_active = NIL; static unsigned long my_quota_current = 0; static unsigned long my_quota_limit = 0; static void my_quotalist_callback(MAILSTREAM *stream, char *qroot, QUOTALIST *qlist) { while (qlist) { if (qlist->name && !strcmp(qlist->name, "STORAGE")) { my_quota_current = qlist->usage; my_quota_limit = qlist->limit; my_quota_active = T; } qlist = qlist->next; } } static BOOL mailstore_quotacheck(struct session *session, unsigned long *currentp, unsigned long *limitp) { void *old_callback; my_quota_active = NIL; my_quota_current = 0; my_quota_limit = 0; *currentp = 0; *limitp = 0; old_callback = mail_parameters (session->inbox_stream, GET_QUOTA, NIL); mail_parameters (session->inbox_stream, SET_QUOTA, my_quotalist_callback); if (!imap_getquotaroot(session->inbox_stream, "INBOX")) { return(NIL); } mail_parameters (session->inbox_stream, SET_QUOTA, old_callback); if (!my_quota_active) return(NIL); *currentp = my_quota_current; *limitp = my_quota_limit; return(T); } /* ====================================================================== */ static char * mbytes(unsigned long kbytes) { static char buf[64]; unsigned long whole = kbytes / 1024; unsigned long fraction = ((kbytes % 1024) * 100) / 1024; if (fraction > 9) sprintf(buf, "%lu.%lu", whole, fraction); else sprintf(buf, "%lu.0%lu", whole, fraction); return(buf); } static char * percent(unsigned long used, unsigned long limit) { static char buf[64], *s; int i, digit; if (used >= limit) { strcpy(buf, "100.00%"); return(buf); } /* Calculate first 4 places of percentage (may have leading zeros) */ s = buf; for (i = 0 ; i < 4 ; i++) { used *= 10; digit = used/limit; used -= (digit*limit); *s++ = '0' + digit; if (i == 1) *s++ = '.'; } *s++ = '%'; *s = '\0'; /* Trim leading zero in "0x.yz */ return((buf[0] == '0') ? buf+1 : buf); } void cmd_quota(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; struct account *account = session->account; unsigned long current, limit; if (request->method == POST) { session_redirect(session, request, "manage"); return; } if (account_check_quota(account, request->pool)) { session_message(session, "Quota check operation complete"); } else { char *msg = account_fetch_message(account); session_alert(session, "Unable to check quota: %s", msg); session_log(session, "[cmd_quota] Unable to check quota: %s", msg); } template_vals_foreach_init(tvals, "@line", 0); template_vals_foreach_string(tvals, "@line", 0, "type", "File Quota"); template_vals_foreach_ulong(tvals, "@line", 0, "used", account->iused); template_vals_foreach_ulong(tvals, "@line", 0, "limit", account->ilimit); template_vals_foreach_string(tvals, "@line", 0, "percent", percent(account->iused, account->ilimit)); template_vals_foreach_init(tvals, "@line", 1); template_vals_foreach_string(tvals, "@line", 1, "type", "Block Quota (MBytes)"); template_vals_foreach_string(tvals, "@line", 1, "used", mbytes(account->bused)); template_vals_foreach_string(tvals, "@line", 1, "limit", mbytes(account->blimit)); template_vals_foreach_string(tvals, "@line", 1, "percent", percent(account->bused, account->blimit)); mailstore_quotacheck(session, ¤t, &limit); template_vals_foreach_init(tvals, "@line", 2); template_vals_foreach_string(tvals, "@line", 2, "type", "Mailstore Quota (MBytes)"); template_vals_foreach_string(tvals, "@line", 2, "used", mbytes(current)); template_vals_foreach_string(tvals, "@line", 2, "limit", mbytes(limit)); template_vals_foreach_string(tvals, "@line", 2, "percent", percent(current, limit)); session_seed_template(session, tvals); template_expand("quota", tvals, b); response_html(request, 200); /* Success */ } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_folders.c��������������������������������������������������������������������0000644�0065130�0065130�00000003672�11063701633�014771� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_folders.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_folders(struct session *session) { struct template_vals *tvals = session->template_vals; struct folderlist *fl = folderlist_fetch(session); struct prefs *prefs = session->options->prefs; BOOL suppress_dotfiles = prefs->suppress_dotfiles; struct request *request = session->request; struct buffer *b = request->write_buffer; struct folderitem *fi; char *name; /* Record last command for compose/cancel and friends */ if (!session->draft->have_draft) session->compose_parent_cmd = "folders"; if ((request->argc == 3) && !strcmp(request->argv[1], "toggle")) { name = string_canon_decode(request->argv[2]); fi = folderlist_lookup(folderlist_fetch(session), name); if (fi) { if (fi->expanded) { session_message(session, "Collapsed \"%s\"", name); fi->expanded = NIL; } else { folderlist_expand(session, fi); session_message(session, "Expanded \"%s\"", name); fi->expanded = T; } } } /* Save options if anything changed */ if (session->options->save) session_streams_save_options(session); folderlist_template_vals_tree(fl, suppress_dotfiles, tvals, "@folder"); folderlist_template_vals_list(fl, suppress_dotfiles, tvals, T, "@dirlist"); template_vals_string(tvals, "fcmd", "change"); session_seed_template(session, tvals); template_expand("folders", tvals, b); response_html(request, 200); } ����������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_list_sort.c������������������������������������������������������������������0000644�0065130�0065130�00000012565�11063701633�015356� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_list_sort.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_list_sort(struct session *session) { struct request *request = session->request; int mode = msgmap_current_sort_mode(session->zm); BOOL reverse = msgmap_sort_reverse(session->zm); char *verb; char *text; if (request->argc < 2) { session_redirect(session, request, "list"); return; } if (!strcmp(request->argv[1], "reverse")) { if (msgmap_sort_reverse(session->zm)) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else if (!strcmp(request->argv[1], "arrival")) { if (mode == ARRIVAL) { if (reverse) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else { msgmap_sort_mode(session->zm, ARRIVAL); msgmap_sort_reverse_disable(session->zm); } } else if (!strcmp(request->argv[1], "date")) { if (mode == DATE) { if (reverse) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else { msgmap_sort_mode(session->zm, DATE); msgmap_sort_reverse_disable(session->zm); } } else if (!strcmp(request->argv[1], "from")) { if (mode == FROM) { if (reverse) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else { msgmap_sort_mode(session->zm, FROM); msgmap_sort_reverse_disable(session->zm); } } else if (!strcmp(request->argv[1], "to")) { if (mode == TO) { if (reverse) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else { msgmap_sort_mode(session->zm, TO); msgmap_sort_reverse_disable(session->zm); } } else if (!strcmp(request->argv[1], "cc")) { if (mode == CC) { if (reverse) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else { msgmap_sort_mode(session->zm, CC); msgmap_sort_reverse_disable(session->zm); } } else if (!strcmp(request->argv[1], "size")) { if (mode == SIZE) { if (reverse) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else { msgmap_sort_mode(session->zm, SIZE); msgmap_sort_reverse_disable(session->zm); } } else if (!strcmp(request->argv[1], "subject")) { if (mode == SUBJECT) { if (reverse) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else { msgmap_sort_mode(session->zm, SUBJECT); msgmap_sort_reverse_disable(session->zm); } } else if (!strcmp(request->argv[1], "references")) { if (mode == REFERENCES) { if (reverse) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else { msgmap_sort_mode(session->zm, REFERENCES); msgmap_sort_reverse_disable(session->zm); } } else if (!strcmp(request->argv[1], "orderedsubject")) { if (mode == ORDEREDSUBJECT) { if (reverse) msgmap_sort_reverse_disable(session->zm); else msgmap_sort_reverse_enable(session->zm); } else { msgmap_sort_mode(session->zm, ORDEREDSUBJECT); msgmap_sort_reverse_disable(session->zm); } } verb = "Sorting"; switch (msgmap_current_sort_mode(session->zm)) { case ARRIVAL: text = "arrival time"; break; case DATE: text = "Date"; break; case FROM: text = "From"; break; case TO: text = "To"; break; case CC: text = "Cc"; break; case SIZE: text = "Size"; break; case SUBJECT: text = "Subject"; break; case REFERENCES: verb = "Threading"; text = "Reference"; break; case ORDEREDSUBJECT: verb = "Threading"; text = "Ordered Subject"; break; default: verb = "Sorting"; text = "(unknown)"; break; } if (msgmap_sort_reverse(session->zm)) session_message(session, "%s by reverse %s (current message: %lu)", verb, text, session->current); else session_message(session, "%s by %s (current message: %lu)", verb, text, session->current); msgmap_invalidate(session->zm); session_redirect(session, request, "list"); } �������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_undelete.c�������������������������������������������������������������������0000644�0065130�0065130�00000003170�11064236131�015126� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_undelete.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_undelete(struct session *session) { struct request *request = session->request; MAILSTREAM *stream = session->stream; unsigned long msgno, msguid; if (request->argc < 2) { session_redirect(session, request, "error"); return; } msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } if (!ml_flag(session, stream, string_itoa_tmp(msgno), "\\DELETED", 0)) { session_alert(session, "Failed to undelete message number %lu: %s", msgno, ml_errmsg()); session_log(session, ("[cmd_undelete] Failed to undelete " "message number %lu from %s: %s"), msgno, session->foldername, ml_errmsg()); session_redirect(session, request, "restart"); return; } session_message(session, "Undeleted message number %lu", msgno); session_log(session, "[cmd_undelete] Undeleted message number %lu from %s", msgno, session->foldername); session_redirect(session, request, "list"); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_add_address.c����������������������������������������������������������������0000644�0065130�0065130�00000003020�11063701633�015553� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_add_address.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Used by abook search */ void cmd_add_address(struct session *session) { struct request *request = session->request; struct draft *draft = session->draft; char *back, *field, *name, *email; char *tmp; if (!draft->have_draft) /* Impossible? */ draft_init(draft); if (request->argc < 5) { session_redirect(session, request, "error"); return; } back = request->argv[1]; field = request->argv[2]; name = request->argv[3]; email = request->argv[4]; string_canon_decode(name); string_canon_decode(email); tmp = abook_text_to_string(request->pool, name, email); tmp = string_trim_whitespace(tmp); if (!strcmp(field, "To")) { draft_add_to(draft, tmp); session_message(session, "Added to To header: %s", tmp); } else if (!strcmp(field, "Cc")) { draft_add_cc(draft, tmp); session_message(session, "Added to Cc header: %s", tmp); } else if (!strcmp(field, "Bcc")) { draft_add_bcc(draft, tmp); session_message(session, "Added to Bcc header: %s", tmp); } session_redirect(session, request, back); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/Makefile�������������������������������������������������������������������������0000644�0065130�0065130�00000004407�11160500433�013772� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# $Cambridge: hermes/src/prayer/cmd/Makefile,v 1.4 2009/03/19 17:30:03 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2008 # See the file NOTICE for conditions of use and distribution. ifeq ($(strip $(RPM_BUILD)), true) include ../Config-RPM else include ../Config endif BASECFLAGS += -I../lib -I../shared -I../session MYCFLAGS = $(BASECFLAGS) $(CCLIENT_INCLUDE) CMD_LIB = cmd.a CMD_OBJS = cmd.o \ cmd_abook_add.o cmd_abook_compose.o cmd_abook_compose2.o \ cmd_abook_export.o cmd_abook_import.o cmd_abook_list.o \ cmd_abook_lookup.o cmd_abook_lookup_add.o \ cmd_abook_save.o cmd_abook_search.o cmd_abook_sort.o \ cmd_abook_update.o cmd_abook_take.o cmd_abook_xfer.o \ cmd_add_address.o cmd_aggregate.o cmd_aggregate_tmp.o \ cmd_attachments.o cmd_change.o cmd_check_cookie.o \ cmd_compose.o cmd_compose1.o cmd_copy.o cmd_copy_msg.o cmd_create.o \ cmd_delete.o cmd_dictionary.o \ cmd_dir_check.o cmd_disp_delete.o cmd_disp_undelete.o cmd_detach.o \ cmd_display.o cmd_printable.o cmd_download.o cmd_download_xfer.o \ cmd_error.o cmd_exit.o cmd_favourites.o \ cmd_block.o cmd_filter.o cmd_filter_mbox.o cmd_filter_select.o \ cmd_folders.o cmd_forward.o cmd_forward1.o cmd_fullname.o \ cmd_help.o cmd_hdrs.o cmd_include.o cmd_init.o cmd_list.o \ cmd_list_sort.o cmd_logout.o cmd_manage.o cmd_passwd.o \ cmd_preferred.o cmd_prefs.o cmd_checkpoint.o \ cmd_expunge.o cmd_expunge1.o cmd_quota.o \ cmd_rawdisplay.o cmd_redirect.o cmd_reply.o \ cmd_reply1.o cmd_reply2.o cmd_rm.o cmd_rm1.o cmd_roles_entry.o \ cmd_roles_list.o cmd_rename.o cmd_rename_item.o \ cmd_restart.o cmd_resume.o cmd_search.o cmd_send.o cmd_sizes.o \ cmd_spam.o cmd_spell.o cmd_subscribe.o cmd_unsubscribe.o cmd_undelete.o \ cmd_transfer.o cmd_upload_select.o cmd_upload_xfer.o cmd_upload_exit.o \ cmd_vacation.o cmd_vaclog.o \ cmd_welcome.o cmd_zoom.o cmd_mark.o \ cmd_unmark.o cmd_disp_mark.o cmd_disp_unmark.o cmd_sieve.o \ cmd_action_stub.o ######################################################################### all: cmd.a cmd.a: $(CMD_OBJS) rm -f cmd.a ar r cmd.a $(CMD_OBJS) clean: rm -f cmd.a $(CMD_OBJS) core *.flc *~ \#*\# # Default build rule %.o: %.c *.h Makefile $(CC) $(MYCFLAGS) -c $< ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd.c����������������������������������������������������������������������������0000644�0065130�0065130�00000012410�11063701633�013241� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" #include "cmd.h" static struct cmd session_cmds[] = { {"abook_add", cmd_abook_add}, {"abook_compose", cmd_abook_compose}, {"abook_compose2", cmd_abook_compose2}, {"abook_export", cmd_abook_export}, {"abook_import", cmd_abook_import}, {"abook_list", cmd_abook_list}, {"abook_lookup", cmd_abook_lookup}, {"abook_lookup_add", cmd_abook_lookup_add}, {"abook_save", cmd_abook_save}, {"abook_search", cmd_abook_search}, {"abook_sort", cmd_abook_sort}, {"abook_take", cmd_abook_take}, {"abook_update", cmd_abook_update}, {"abook_xfer", cmd_abook_xfer}, {"action_stub", cmd_action_stub}, {"add_address", cmd_add_address}, {"aggregate", cmd_aggregate}, {"aggregate_tmp", cmd_aggregate_tmp}, {"attachments", cmd_attachments}, {"block", cmd_block}, {"change", cmd_change}, {"check_cookie", cmd_check_cookie}, {"checkpoint", cmd_checkpoint}, {"compose", cmd_compose}, {"compose1", cmd_compose1}, {"copy", cmd_copy}, {"copy_msg", cmd_copy_msg}, {"create", cmd_create}, {"delete", cmd_delete}, {"detach", cmd_detach}, {"dictionary", cmd_dictionary}, {"dir_check", cmd_dir_check}, {"disp_delete", cmd_disp_delete}, {"disp_mark", cmd_disp_mark}, {"disp_undelete", cmd_disp_undelete}, {"disp_unmark", cmd_disp_unmark}, {"display", cmd_display}, {"download", cmd_download}, {"download_xfer", cmd_download_xfer}, {"error", cmd_error}, {"exit", cmd_exit}, {"expunge", cmd_expunge}, {"expunge1", cmd_expunge1}, {"favourites", cmd_favourites}, {"filter", cmd_filter}, {"filter_mbox", cmd_filter_mbox}, {"filter_select", cmd_filter_select}, {"folders", cmd_folders}, {"forward", cmd_forward}, {"forward1", cmd_forward1}, {"fullname", cmd_fullname}, {"hdrs", cmd_hdrs}, {"help", cmd_help}, {"include", cmd_include}, {"init", cmd_init}, {"list", cmd_list}, {"list_sort", cmd_list_sort}, {"logout", cmd_logout}, {"manage", cmd_manage}, {"mark", cmd_mark}, {"passwd", cmd_passwd}, {"preferred", cmd_preferred}, {"prefs", cmd_prefs}, {"printable", cmd_printable}, {"quota", cmd_quota}, {"rawdisplay", cmd_rawdisplay}, {"redirect", cmd_redirect}, {"rename", cmd_rename}, {"rename_item", cmd_rename_item}, {"reply", cmd_reply}, {"reply1", cmd_reply1}, {"reply2", cmd_reply2}, {"restart", cmd_restart}, {"resume", cmd_resume}, {"rm", cmd_rm}, {"rm1", cmd_rm1}, {"roles_entry", cmd_roles_entry}, {"roles_list", cmd_roles_list}, {"search", cmd_search}, {"send", cmd_send}, {"sieve", cmd_sieve}, {"sizes", cmd_sizes }, {"spam", cmd_spam}, {"spell", cmd_spell}, {"subscribe", cmd_subscribe}, {"transfer", cmd_transfer}, {"undelete", cmd_undelete}, {"unmark", cmd_unmark}, {"unsubscribe", cmd_unsubscribe}, {"upload_exit", cmd_upload_exit}, {"upload_select", cmd_upload_select}, {"upload_xfer", cmd_upload_xfer}, {"vacation", cmd_vacation}, {"vaclog", cmd_vaclog}, {"welcome", cmd_welcome}, {"zoom", cmd_zoom}, {NIL, NIL} }; static unsigned long session_cmd_count = 0L; static unsigned long session_cmd_maxlen = 0L; /* cmd_dispatch_init() *************************************************** * * Initialise dispatch tables. ************************************************************************/ void cmd_dispatch_init(void) { struct cmd *cmd = session_cmds; unsigned long len; unsigned long maxlen = 0; session_cmd_count = 0; while (cmd[0].cmd && cmd[0].fn) { if ((len = strlen(cmd[0].cmd)) > maxlen) maxlen = len; if (cmd[1].cmd && cmd[1].fn) { if (strcmp(cmd[0].cmd, cmd[1].cmd) > 0) log_fatal("cmd.c: cmd array sorted incorrectly at %s\n", cmd[0].cmd); } session_cmd_count++; cmd++; } session_cmd_maxlen = maxlen; } /* ====================================================================== */ /* cmd_dispatch() ******************************************************** * * Dispatch a command * session * text: Command to dispatch ************************************************************************/ BOOL cmd_dispatch(struct session *session, char *text) { struct cmd *cmd; unsigned long first, last, middle; int rc; cmd = session_cmds; first = 0; last = session_cmd_count; /* Binary chop */ while (first < last) { middle = (first + last) / 2; rc = strcmp(cmd[middle].cmd, text); if (rc == 0) { /* Record command that we are about to run */ (cmd[middle].fn) (session); session_record_last_cmd(session, text); return (T); } if (rc < 0) first = middle + 1; else last = middle; } /* Not found */ return (NIL); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_rawdisplay.c�����������������������������������������������������������������0000644�0065130�0065130�00000007434�11063701633�015512� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_rawdisplay.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_rawdisplay(struct session *session) { struct options *options = session->options; struct prefs *prefs = options->prefs; struct request *request = session->request; struct buffer *b = request->write_buffer; MAILSTREAM *stream = session->stream; unsigned long msgno, msguid; char *section, *name, *type; char *init_msg; unsigned char *decode_msg; unsigned long len; BODY *body; unsigned long i; if (request->argc < 6) { /* User playing silly buggers, or hit browser back button after asynchronous rawdisplay event */ session_redirect(session, request, "display"); return; } msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "list"); return; } section = request->argv[3]; type = request->argv[4]; name = request->argv[5]; string_url_decode(type); string_url_decode(name); if (!prefs->preserve_mimetype) type = "application/octet-stream"; if (!ml_fetch_structure(session, stream, msgno, &body, NIL)) { session_redirect(session, request, "restart"); return; } /* Tranlate section "0" -> main body */ if (section && !strcmp(section, "0")) section = "1"; if (!(body = ml_body(session, stream, msgno, section))) { session_redirect(session, request, "restart"); return; } if ((body->type == TYPEMESSAGE) || (body->type == TYPEMULTIPART)) { char *hdrs, *msg; unsigned long hlen, len; hdrs = ml_fetch_header(session, stream, msgno, section, NIL, &hlen, 0); msg = ml_fetch_body(session, stream, msgno, section, &len, 0); type = "application/octet-stream"; if (!(hdrs && msg)) { session_redirect(session, request, "restart"); return; } for (i = 0; i < hlen; i++) bputc(b, hdrs[i]); for (i = 0; i < len; i++) bputc(b, msg[i]); response_raw(request, name, type, 200); return; } if (!(init_msg = ml_fetchbody(session, stream, msgno, section, &len))) { session_redirect(session, request, "restart"); return; } /* Strip off encoding */ switch (body->encoding) { case ENCBASE64: if (!(decode_msg = rfc822_base64((unsigned char *) init_msg, body->size.bytes, &len))) { /* Decode failed */ decode_msg = (unsigned char *) init_msg; len = body->size.bytes; } break; case ENCQUOTEDPRINTABLE: if (!(decode_msg = rfc822_qprint((unsigned char *) init_msg, body->size.bytes, &len))) { /* Decode failed */ decode_msg = (unsigned char *) init_msg; len = body->size.bytes; } break; case ENC7BIT: case ENC8BIT: case ENCBINARY: case ENCOTHER: default: decode_msg = (unsigned char *) init_msg; len = body->size.bytes; } if (!decode_msg) { session_redirect(session, request, "restart"); return; } for (i = 0; i < len; i++) bputc(b, decode_msg[i]); if (init_msg != (char *) decode_msg) fs_give((void **) &decode_msg); response_raw(request, name, type, 200); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_filter.c���������������������������������������������������������������������0000644�0065130�0065130�00000014535�11064236131�014615� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_filter.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; struct account *account = session->account; struct list_item *item; unsigned long count; char *type; char *type_strong; char *value; count = 0; for (item = account->filter_list->head; item; item = item->next) { struct filter *filter = (struct filter *) item; template_vals_foreach_init(tvals, "@filters", count); template_vals_foreach_ulong(tvals, "@filters", count, "offset", count); switch (filter->type) { case FILTER_SENDER: type = "sender"; type_strong = "SENDER"; value = pool_printf(tvals->pool, "%s@%s", filter->local_part, filter->domain); break; case FILTER_RECIPIENT: type = "recipient"; type_strong = "RECIPIENT"; value = pool_printf(tvals->pool, "%s@%s", filter->local_part, filter->domain); break; case FILTER_SUBJECT: type = "subject"; type_strong = "SUBJECT"; value = filter->subject; break; default: type = "unknown"; type_strong = "UNKNOWN"; value = ""; break; } template_vals_foreach_string(tvals, "@filters", count, "type_strong", type_strong); template_vals_foreach_string(tvals, "@filters", count, "type", type); template_vals_foreach_string(tvals, "@filters", count, "value", value); if (filter->mailbox) template_vals_foreach_string(tvals, "@filters", count, "mailbox", filter->mailbox); if (filter->copy) template_vals_foreach_ulong(tvals, "@filters", count, "copy", 1); count++; } session_seed_template(session, tvals); template_expand("filter", tvals, b); response_html(request, 200); /* Success */ } static void generate_error(struct session *session) { struct template_vals *tvals = session->template_vals; struct account *account = session->account; struct request *request = session->request; char *msg = account_fetch_message(account); struct buffer *b = request->write_buffer; if (!(msg && msg[0])) msg = "Unable to check mail processing status"; template_vals_string(tvals, "msg", msg); session_seed_template(session, tvals); template_expand("filter_fail", tvals, b); response_html(request, 200); } void cmd_filter(struct session *session) { struct request *request = session->request; struct account *account = session->account; unsigned long offset; struct assoc *h = NIL; struct filter *filter = filter_alloc(); char *type; char *param; if (request->method != POST) { if (!account_mail_check(account, request->pool)) { generate_error(session); return; } if (session->half_filter) { filter_free(session->half_filter); session->half_filter = NIL; } if ((request->argc >= 3) && !strcmp(request->argv[1], "remove")) { offset = atoi(request->argv[2]); account_filter_remove(session->account, offset); if (account_mail_update(session->account, request->pool)) { session_message(session, "Removed filter number: %lu", offset + 1); } else { char *msg = account_fetch_message(account); session_alert(session, "Failed to remove filter number: %lu", offset + 1, msg); session_log(session, "[cmd_filter] Failed to remove filter number: %lu", offset + 1, msg); } } generate_form(session); return; } request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, "manage"); return; } type = assoc_lookup(h, "type"); param = assoc_lookup(h, "param"); if (!(type && type[0])) { session_alert(session, "Missing type field"); generate_form(session); return; } if (param && param[0]) param = string_trim_whitespace(param); if (!(param && param[0])) { session_alert(session, "Missing or empty parameter field"); generate_form(session); return; } if (!strcmp(type, "block") || !strcmp(type, "sender") || !strcmp(type, "recipient")) { /* Param is address or address wildcard */ if (!filter_test_addr(filter, session, param)) { session_alert(session, "Invalid filter pattern"); generate_form(session); return; } } if (!strcmp(type, "subject")) { session_message(session, "Adding SUBJECT filter: \"%s\"", param); filter_set_type(filter, FILTER_SUBJECT); filter_set_subject(filter, param); } else if (!strcmp(type, "sender")) { session_message(session, "Adding SENDER filter: \"%s\"", param); filter_set_type(filter, FILTER_SENDER); filter_set_addr(filter, session, param); } else if (!strcmp(type, "recipient")) { session_message(session, "Adding RECIPIENT filter: \"%s\"", param); filter_set_type(filter, FILTER_RECIPIENT); filter_set_addr(filter, session, param); } else { session_alert(session, "Bad/Unknown filter type"); session_redirect(session, request, "error"); return; } session->half_filter = filter; session_redirect(session, request, "filter_select"); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_save.c�����������������������������������������������������������������0000644�0065130�0065130�00000001343�11063701633�015435� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_save.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_abook_save(struct session *session) { struct request *request = session->request; session_streams_save_options(session); if (session->abook_parent_cmd && session->abook_parent_cmd[0]) session_redirect(session, request, session->abook_parent_cmd); else session_redirect(session, request, "list"); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_roles_list.c�����������������������������������������������������������������0000644�0065130�0065130�00000004173�11063701633�015507� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_roles_list.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_roles_list(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct options *options = session->options; struct buffer *b = request->write_buffer; struct list_item *li; struct assoc *h = NIL; unsigned long offset = 0; if (request->method == POST) { request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, "manage"); return; } if (assoc_lookup(h, "sub_new")) { session_redirect(session, request, "roles_entry"); return; } } for (li = options->role_list->head; li; li = li->next) { struct role *role = (struct role *) li; template_vals_foreach_init(tvals, "@roles", offset); template_vals_foreach_string(tvals, "@roles", offset, "alias", role->name); template_vals_foreach_string(tvals, "@roles", offset, "personal", role->personal); template_vals_foreach_string(tvals, "@roles", offset, "from", role->from); template_vals_foreach_string(tvals, "@roles", offset, "reply_to", role->reply_to); template_vals_foreach_string(tvals, "@roles", offset, "fcc", role->fcc); template_vals_foreach_string(tvals, "@roles", offset, "signature", role->signature); offset++; } session_seed_template(session, tvals); template_expand("roles_list", tvals, b); response_html(request, 200); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_search.c���������������������������������������������������������������0000644�0065130�0065130�00000014044�11656510704�015753� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_search.c,v 1.4 2011/11/09 14:44:20 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static int abook_search_field_form_to_enum(char *key) { int field = ABOOK_SEARCH_FIELD_NONE; if (!strcmp(key, "alias")) field = ABOOK_SEARCH_FIELD_ALIAS; else if (!strcmp(key, "name")) field = ABOOK_SEARCH_FIELD_NAME; else if (!strcmp(key, "comment")) field = ABOOK_SEARCH_FIELD_COMMENT; else if (!strcmp(key, "email")) field = ABOOK_SEARCH_FIELD_EMAIL; return (field); } static int abook_search_type_form_to_enum(char *op) { int type = ABOOK_SEARCH_TYPE_NONE; if (!strcmp(op, "is")) type = ABOOK_SEARCH_TYPE_IS; else if (!strcmp(op, "begins")) type = ABOOK_SEARCH_TYPE_BEGINS; else if (!strcmp(op, "ends")) type = ABOOK_SEARCH_TYPE_ENDS; else if (!strcmp(op, "contains")) type = ABOOK_SEARCH_TYPE_CONTAINS; return (type); } static void generate_form(struct session *session, struct abook_search_list *asl, BOOL do_search) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; struct options *options = session->options; struct abook *abook = options->abook; unsigned long i, count; struct abook_search_elt *ase; struct abook_entry *abe; char *field, *type; if (asl->match_all) template_vals_ulong(tvals, "$match_all", 1); for (i = 0, ase = asl->first; ase; ase = ase->next, i++) { template_vals_foreach_init(tvals, "@filters", i); template_vals_foreach_ulong(tvals, "@filters", i, "count", i); template_vals_foreach_string(tvals, "@filters", i, "value", ase->value); switch (ase->field) { case ABOOK_SEARCH_FIELD_NONE: field = "name"; break; case ABOOK_SEARCH_FIELD_ALIAS: field = "alias"; break; case ABOOK_SEARCH_FIELD_NAME: default: field = "name"; break; case ABOOK_SEARCH_FIELD_COMMENT: field = "comment"; break; case ABOOK_SEARCH_FIELD_EMAIL: field = "email"; break; } template_vals_foreach_string(tvals, "@filters", i, "selected", field); switch (ase->type) { case ABOOK_SEARCH_TYPE_NONE: type = "contains"; break; case ABOOK_SEARCH_TYPE_IS: type = "is"; break; case ABOOK_SEARCH_TYPE_BEGINS: type = "begins"; break; case ABOOK_SEARCH_TYPE_ENDS: type = "ends"; break; case ABOOK_SEARCH_TYPE_CONTAINS: default: type = "contains"; break; } template_vals_foreach_string(tvals, "@filters", i, "type", type); } if (do_search) { abook_search_init(abook); count = 0; while (abook_search_find_next(abook, asl)) count++; template_vals_ulong(tvals, "$count", count); abook_search_init(abook); i = 0; while ((abe = abook_search_find_next(abook, asl))) { template_vals_foreach_init(tvals, "@results", i); template_vals_foreach_string(tvals, "@results", i, "alias", abe->alias); template_vals_foreach_string(tvals, "@results", i, "name", abe->name); template_vals_foreach_string(tvals, "@results", i, "comment", abe->comment); template_vals_foreach_string (tvals, "@results", i, "email", string_email_split(tvals->pool,abe->email)); i++; } } session_seed_template(session, tvals); template_expand("abook_search", tvals, b); response_html(request, 200); } void cmd_abook_search(struct session *session) { struct request *request = session->request; struct assoc *h = NIL; unsigned long i; char *key, *op, *value, *s, *t; int field, type; struct abook_search_list *asl; if (request->method == POST) { request_decode_form(request); h = request->form; } if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, "abook_list"); return; } if ((s = assoc_lookup(h, "cond")) && !strcmp(s, "all")) asl = abook_search_list_create(T); else asl = abook_search_list_create(NIL); for (i = 0; 1; i++) { t = string_itoa(request->pool, i); s = pool_strcat(request->pool, "key", t); if ((key = assoc_lookup(h, s)) == NIL) break; s = pool_strcat(request->pool, "op", t); if ((op = assoc_lookup(h, s)) == NIL) break; s = pool_strcat(request->pool, "val", t); if ((value = assoc_lookup(h, s)) == NIL) break; field = abook_search_field_form_to_enum(key); type = abook_search_type_form_to_enum(op); if ((field == ABOOK_SEARCH_FIELD_NONE) || (type == ABOOK_SEARCH_TYPE_NONE)) break; abook_search_list_add(asl, field, type, value); } /* Add new (empty) filter to end of list if empty or additional requested */ if (!asl->first || assoc_lookup(h, "sub_add_cond")) abook_search_list_add(asl, ABOOK_SEARCH_FIELD_NAME, ABOOK_SEARCH_TYPE_CONTAINS, ""); generate_form(session, asl, (request->method == POST) ? T : NIL); abook_search_list_free(asl); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_lookup_add.c�����������������������������������������������������������0000644�0065130�0065130�00000003637�11064236131�016625� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_lookup_add.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_abook_lookup_add(struct session *session) { struct draft *draft = session->draft; struct request *request = session->request; struct assoc *h = NIL; char *field, *name, *email, *full; if (!draft) { session_alert(session, "Error: abook_lookup_add called without active draft"); session_redirect(session, request, "abook_list"); return; } request_decode_form(request); h = request->form; field = assoc_lookup(h, "field"); name = assoc_lookup(h, "name"); email = assoc_lookup(h, "email"); if (!(field && field[0] && name && name[0] && email && email[0])) { session_alert(session, "Error: abook_lookup_add called with missing args"); session_redirect(session, request, "abook_list"); return; } string_canon_decode(name); string_canon_decode(email); full = abook_text_to_string(request->pool, name, email); if (!strcmp(field, "to")) { draft_add_to(draft, full); session_message(session, "Added %s to To", email); } else if (!strcmp(field, "cc")) { draft_add_cc(draft, full); session_message(session, "Added %s to Cc", email); } else if (!strcmp(field, "bcc")) { draft_add_bcc(draft, full); session_message(session, "Added %s to Bcc", email); } else session_alert(session, "Error: abook_lookup_add called with invalid field"); session_redirect(session, request, "abook_list"); } �������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_download.c�������������������������������������������������������������������0000644�0065130�0065130�00000004445�11415121016�015131� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_download.c,v 1.4 2010/07/07 15:49:34 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* ====================================================================== */ void cmd_download(struct session *session) { struct request *request = session->request; struct msgmap *zm = session->zm; unsigned long msgno, msguid; char *text, *s; unsigned long len; MAILSTREAM *stream = session->stream; struct buffer *b = request->write_buffer; if (request->argc >= 3) { msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } } else { msgno = session->last_displayed; if ((msgno == 0) || (msgno > zm->nmsgs)) msgno = msgmap_value(session->zm, msgmap_size(session->zm)); msguid = ml_uid(session, stream, msgno); } session->current = msgno; session->last_displayed = msgno; if (msgno == 0) { session_redirect(session, request, "error"); return; } if (!(text = ml_fetch_header(session, stream, msgno, NIL, NIL, &len, 0))) { session_redirect(session, request, "restart"); return; } s = text; while (*s) { if ((*s == '\015') || (*s == '\012')) { s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; bputc(b, '\n'); } else bputc(b, *s++); } if (!(text = ml_fetch_text(session, stream, msgno, NIL, &len, 0))) { session_redirect(session, request, "restart"); return; } /* Don't free(text): lives in c-client message cache */ s = text; while (*s) { if ((*s == '\015') || (*s == '\012')) { s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; bputc(b, '\n'); } else bputc(b, *s++); } /* Send out the response */ response_text(request, 200); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_init.c�����������������������������������������������������������������������0000644�0065130�0065130�00000011711�11513072253�014266� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_init.c,v 1.9 2011/01/11 15:18:03 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_init(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct options *options = session->options; MAILSTREAM *stream = session->stream; struct msgmap *zm = session->zm; struct prefs *prefs; char *body; unsigned long size; char *ua; char *hostname; char *name; char *pname; /* Record sucessful user login */ if (!(ua = assoc_lookup(request->hdrs, "user-agent"))) ua = "Unknown"; if (config->log_name_nets && ipaddr_compare_list(session->ipaddr, config->log_name_nets)) hostname = ipaddr_name(session->ipaddr); else hostname = ipaddr_text(session->ipaddr); session_log(session, ("[cmd_init] User login " "[Client: %s] [IMAP server: %s] [User agent: %s]"), hostname, session->imapd_server, ua); /* Bit of a hack, but simplest way to reduce limit */ if (strstr(ua, " Crazy Browser ") && (config->recips_max_session > 0)) { config->recips_max_session = 15; session_log(session, "Probable spammer: recips per session limited"); } if (config->sending_block_dir && session->username) { struct stat sbuf; char *path = pool_strcat3(request->pool, config->sending_block_dir, "/", session->username); if (stat(path, &sbuf) == 0) { session->sending_block = T; session_message(session, "Outgoing email disabled (compromised account?)"); session_log(session, "Outgoing email disabled (compromised account?)"); } } /* Read in and parse user preferences file */ pname = session_mailbox_prefs(session, request->pool); stream = ml_open(session, stream, pname, OP_READONLY); if (stream && (stream->nmsgs >= 1) && (body = ml_fetch_body(session, stream, 1, "1", &size, 0))) { if (!options_parse(options, body, session)) { session_alert(session, "Invalid or obsolete preferences file"); session_log(session, "[cmd_init] Invalid or obsolete preferences file"); options->save = T; } } else { session_message(session, "No saved user preferences: using defaults"); session_log(session, "[cmd_init] No saved user preferences: using defaults"); } prefs = options->prefs; /* Make session adopt user preferences */ session_use_prefs(session, prefs, T); /* Check if user has blocked Raven logins */ if (config->raven_enable && !prefs->allow_raven_login && (strlen(session->password) > 256)) { struct template_vals *tvals = session->template_vals; struct buffer *b = request->write_buffer; session->want_disconnect = T; template_vals_string(tvals, "url_prefix", session->url_prefix); template_vals_string(tvals, "username", session->username); template_expand("raven_blocked", tvals, b); response_html(request, 200); return; } name = session_mailbox(session, request->pool, "inbox"); /* Open inbox, reusing initial stream */ session->stream = session->inbox_stream = stream = ml_open(session, stream, name, 0); if (!stream) { /* Should be impossible */ session_alert(session, "Couldn't open inbox folder"); session_log(session, "[cmd_init] Couldn't open inbox folder"); session_redirect(session, request, "restart"); return; } string_strdup(&session->foldername, "INBOX"); session->inbox_last_ping_time = time(NIL); /* Set up initial msgmap */ msgmap_associate(zm, session, stream); msgmap_update(zm); /* Set current and last_displayed message to last or first in zoommap * (cmd_welcome may override with this last unread message) */ if (zm->nmsgs > 0) { if (zm->sort_reverse) session->current = msgmap_value(zm, 1); else session->current = msgmap_value(zm, zm->nmsgs); } else session->current = 0; session->last_displayed = session->current; /* Define sane last_cmd: don't want to end up back here! */ session_record_last_cmd(session, "list"); if (session->user_agent->use_cookie) session_make_session_cookie_redirect(session, request, "check_cookie"); else session_redirect(session, request, "welcome"); } �������������������������������������������������������./prayer-1.3.5/cmd/cmd_block.c����������������������������������������������������������������������0000644�0065130�0065130�00000010647�11064236131�014422� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_block.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; struct account *account = session->account; struct list_item *item; unsigned long count; char *value; count = 0; for (item = account->block_list->head; item; item = item->next) { struct filter *filter = (struct filter *) item; if (filter->type != FILTER_BLOCK) { count++; continue; } value = pool_printf(tvals->pool, "%s@%s", filter->local_part, filter->domain); template_vals_foreach_init(tvals, "@blocks", count); template_vals_foreach_ulong(tvals, "@blocks", count, "offset", count); template_vals_foreach_string(tvals, "@blocks", count, "value", value); count++; } session_seed_template(session, tvals); template_expand("block", tvals, b); response_html(request, 200); /* Success */ } static void generate_error(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct account *account = session->account; char *msg = account_fetch_message(account); struct buffer *b = request->write_buffer; if (!(msg && msg[0])) msg = "Unable to check mail processing status"; template_vals_string(tvals, "msg", msg); session_seed_template(session, tvals); template_expand("block_fail", tvals, b); response_html(request, 200); } void cmd_block(struct session *session) { struct request *request = session->request; struct account *account = session->account; unsigned long offset; struct assoc *h = NIL; struct filter *filter; char *param; if (request->method != POST) { if (!account_mail_check(account, request->pool)) { generate_error(session); return; } if ((request->argc >= 3) && !strcmp(request->argv[1], "remove")) { offset = atoi(request->argv[2]); account_block_remove(account, offset); if (account_mail_update(account, request->pool)) { session_message(session, "Removed block number: %lu", offset + 1); } else { char *msg = account_fetch_message(account); session_alert(session, "Failed to remove block number: %lu: %s", offset + 1, msg); session_log(session, "[cmd_block] Failed to remove block number: %lu: %s", offset + 1, msg); } } generate_form(session); return; } filter = filter_alloc(); request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, "manage"); return; } param = assoc_lookup(h, "param"); if (param && param[0]) param = string_trim_whitespace(param); if (!(param && param[0])) { session_alert(session, "Missing or empty parameter field"); generate_form(session); return; } /* Param is address or address wildcard */ if (!filter_test_addr(filter, session, param)) { session_alert(session, "Invalid filter pattern"); generate_form(session); return; } /* Block is special: doesn't require target folder */ filter_set_type(filter, FILTER_BLOCK); filter_set_addr(filter, session, param); account_block_add(session->account, filter); if (account_mail_update(account, request->pool)) { session_message(session, "Added BLOCK filter"); } else { char *msg = account_fetch_message(account); session_alert(session, "Failed to add BLOCK filter: %s", msg); session_log(session, "[cmd_block] Failed to add BLOCK filter: %s", msg); } generate_form(session); } �����������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_attachments.c����������������������������������������������������������������0000644�0065130�0065130�00000011360�11064236131�015634� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_attachments.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct draft *draft = session->draft; struct buffer *b = request->write_buffer; unsigned long count; struct attlist *a; for (count = 0, a = draft->attlist; a; a = a->next, count++) { template_vals_foreach_init(tvals, "@atts", count); template_vals_foreach_ulong(tvals, "@atts", count, "offset", count+1); template_vals_foreach_string(tvals, "@atts", count, "name", a->name); template_vals_foreach_string(tvals, "@atts", count, "type", a->type); template_vals_foreach_ulong(tvals, "@atts", count, "size", a->size); } session_seed_template(session, tvals); template_expand("attachments", tvals, b); response_html(request, 200); /* Success */ } static void process_form(struct session *session) { struct config *config = session->config; struct request *request = session->request; struct draft *draft = session->draft; struct assoc *hdrs = assoc_create(request->pool, 16, T); char *start, *end; char *type, *disp, *encoding, *name, *s; unsigned long len; if (!request_decode_post_multipart(request, hdrs, &start, &end)) return; if (end > start) len = (char *) end - (char *) start; else len = 0; if (len < 1) { session_alert(session, "Please choose a file to attach"); return; } if ((config->draft_att_single_max > 0) && (len > config->draft_att_single_max)) { session_alert(session, "Attachment too large: %lu bytes exceeds limit %lu", len, config->draft_att_single_max); session_log(session, ("[cmd_attachments] Attachment too large: " "%lu bytes exceeds limit %lu"), len, config->draft_att_single_max); return; } if ((config->draft_att_total_max > 0) && ((len + draft_att_size(draft)) > config->draft_att_total_max)) { session_alert(session, "Total size of attachments exceeds limit: %lu bytes", config->draft_att_total_max); session_log(session, ("[cmd_attachments] Total size of attachments " "exceeds limit: %lu bytes"), config->draft_att_total_max); return; } if (!(type = assoc_lookup(hdrs, "content-type"))) type = "application/octet-stream"; /* Opera attaches filename to Content-Type header e.g: * Content-Type: application/octet-stream; name="<whatever>" */ if ((s = strchr(type, ';'))) *s = '\0'; if (!(encoding = assoc_lookup(hdrs, "content-transfer-encoding"))) encoding = ""; name = ""; if ((disp = assoc_lookup(hdrs, "content-disposition"))) { for (s = disp; *s; s++) { if (!strncasecmp(s, "filename=\"", strlen("filename=\""))) { name = s = s + strlen("filename=\""); while (*s && (*s != '"')) s++; *s = '\0'; name = string_trim_whitespace(name); break; } else if (!strncasecmp(s, "filename=", strlen("filename="))) { name = s + strlen("filename="); name = string_trim_whitespace(name); break; } } } /* Isolate last component of name */ if ((s = strrchr(name, '/'))) /* Unix names */ name = s + 1; else if ((s = strrchr(name, '\\'))) /* Windows names */ name = s + 1; /* Mac Netscape sends names with URL encoding. Sigh! */ if (name && name[0]) name = string_url_decode(name); draft_add_attachment(draft, name, type, encoding, NIL, 0, start, len); session_message(session, "Added attachment \"%s\"", name); session_log(session, "[cmd_attachments] Added attachment \"%s\" (%lu bytes)", name, len); } void cmd_attachments(struct session *session) { struct request *request = session->request; if ((request->argc >= 2) && (!strcmp(request->argv[1], "cancel"))) { session_redirect(session, request, "compose"); return; } if (request->method == POST) process_form(session); generate_form(session); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_check_cookie.c���������������������������������������������������������������0000644�0065130�0065130�00000003043�11415121016�015721� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_check_cookie.c,v 1.5 2010/07/07 15:49:34 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_check_cookie(struct session *session) { struct request *request = session->request; char *s = assoc_lookup(request->hdrs, "cookie"); char *t; char *u; BOOL have_cookie = NIL; char *key; unsigned long pid = (unsigned long)getpid(); key = pool_printf(request->pool, "%s:%lu", session->username, pid); /* Look for username:port=VALUE in cookie */ while (s && *s && (t = strchr(s, '='))) { *t++ = '\0'; if ((u = strchr(t, ';'))) *u++ = '\0'; if (!strcmp(key, string_trim_whitespace(s))) { if (!strcmp(session->sessionid, string_trim_whitespace(t))) have_cookie = T; break; } s = u; } if (have_cookie) { /* Force update for session URLs */ session->use_cookie = T; session_update_sequence(session); } /* Define sane last_cmd: don't want to end up back here! */ session_record_last_cmd(session, "welcome"); if (have_cookie) session_make_session_redirect(session, request, "welcome"); else session_redirect(session, request, "welcome"); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_prefs.c����������������������������������������������������������������������0000644�0065130�0065130�00000074052�11067131055�014451� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_prefs.c,v 1.4 2008/09/26 09:58:05 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* ====================================================================== */ /* General options */ static void generate_general_form(struct session *session, struct prefs *prefs) { struct template_vals *tvals = session->template_vals; struct config *config = session->config; struct request *request = session->request; struct buffer *b = request->write_buffer; template_vals_string(tvals, "template_set", prefs->template_set); if (config->template_list) { unsigned long offset = 0; struct list_item *li; for (li = config->template_list->head; li; li = li->next) { struct config_template *template = (struct config_template *) li; template_vals_foreach_init(tvals, "@templates", offset); template_vals_foreach_string(tvals, "@templates", offset, "name", template->name); template_vals_foreach_string(tvals, "@templates", offset, "fullname", template->description); offset++; } } template_vals_string(tvals, "theme_main_name", prefs->theme_main_name); template_vals_string(tvals, "theme_help_name", prefs->theme_help_name); if (config->theme_list && (list_length(config->theme_list) > 1)) { struct config_theme *theme; unsigned long offset = 0; theme = (struct config_theme *) config->theme_list->head; while (theme) { template_vals_foreach_init(tvals, "@themes", offset); template_vals_foreach_string(tvals, "@themes", offset, "name", theme->name); template_vals_foreach_string(tvals, "@themes", offset, "fullname", theme->description); theme = theme->next; offset++; } } if (prefs->use_welcome) template_vals_ulong(tvals, "use_welcome", 1); if (config->raven_enable) template_vals_ulong(tvals, "raven_enable", 1); if (prefs->allow_raven_login) template_vals_ulong(tvals, "allow_raven_login", 1); if (prefs->confirm_expunge) template_vals_ulong(tvals, "confirm_expunge", 1); if (prefs->confirm_logout) template_vals_ulong(tvals, "confirm_logout", 1); if (prefs->expunge_on_exit) template_vals_ulong(tvals, "expunge_on_exit", 1); if (prefs->use_mark_persist) template_vals_ulong(tvals, "use_mark_persist", 1); if (prefs->use_search_zoom) template_vals_ulong(tvals, "use_search_zoom", 1); if (prefs->use_agg_unmark) template_vals_ulong(tvals, "use_agg_unmark", 1); session_seed_template(session, tvals); template_expand("prefs_general", tvals, b); } static BOOL process_general_prefs(struct session *session, struct prefs *prefs, struct assoc *h) { struct config *config = session->config; char *s; if ((s = assoc_lookup(h, "template_set")) && s[0]) { if (config->template_list && list_lookup_byname(config->template_list, s)) prefs->template_set = pool_strdup(prefs->pool, s); } if ((s = assoc_lookup(h, "theme_main_name")) && s[0]) { prefs->theme_main_name = pool_strdup(prefs->pool, s); } if ((s = assoc_lookup(h, "theme_help_name")) && s[0]) { prefs->theme_help_name = pool_strdup(prefs->pool, s); } prefs->use_welcome = (assoc_lookup(h, "use_welcome")) ? T : NIL; prefs->use_mark_persist = (assoc_lookup(h, "use_mark_persist")) ? T : NIL; prefs->use_search_zoom = (assoc_lookup(h, "use_search_zoom")) ? T : NIL; prefs->use_agg_unmark = (assoc_lookup(h, "use_agg_unmark")) ? T : NIL; if (config->raven_enable) { prefs->allow_raven_login = (assoc_lookup(h, "allow_raven_login")) ? T : NIL; } prefs->confirm_expunge = (assoc_lookup(h, "confirm_expunge")) ? T : NIL; prefs->confirm_logout = (assoc_lookup(h, "confirm_logout")) ? T : NIL; prefs->expunge_on_exit = (assoc_lookup(h, "expunge_on_exit")) ? T : NIL; return (T); } /* ====================================================================== */ /* Display Preferences */ static void generate_display_form(struct session *session, struct prefs *prefs) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; SORTMODE sort_mode = prefs->sort_mode; BOOL sort_reverse = prefs->sort_reverse; abook_sort_mode abook_sort_mode = prefs->abook_sort_mode; BOOL abook_sort_reverse = prefs->abook_sort_reverse; if (prefs->use_icons) template_vals_ulong(tvals, "use_icons", 1); if (prefs->use_tail_banner) template_vals_ulong(tvals, "use_tail_banner", 1); if (prefs->html_inline) template_vals_ulong(tvals, "html_inline", 1); if (prefs->html_inline_auto) template_vals_ulong(tvals, "html_inline_auto", 1); if (prefs->html_remote_images) template_vals_ulong(tvals, "html_remote_images", 1); if (prefs->preserve_mimetype) template_vals_ulong(tvals, "preserve_mimetype", 1); if (prefs->use_unread) template_vals_ulong(tvals, "use_unread", 1); switch (sort_mode) { case ARRIVAL: template_vals_string(tvals, "folder_sort_mode", (sort_reverse) ? "reverse-arrival" : "arrival"); break; case DATE: template_vals_string(tvals, "folder_sort_mode", (sort_reverse) ? "reverse-date" : "date"); break; case FROM: template_vals_string(tvals, "folder_sort_mode", (sort_reverse) ? "reverse-from" : "from"); break; case TO: template_vals_string(tvals, "folder_sort_mode", (sort_reverse) ? "reverse-to" : "to"); break; case CC: template_vals_string(tvals, "folder_sort_mode", (sort_reverse) ? "reverse-cc" : "cc"); break; case SIZE: template_vals_string(tvals, "folder_sort_mode", (sort_reverse) ? "reverse-size" : "size"); break; case SUBJECT: template_vals_string(tvals, "folder_sort_mode", (sort_reverse) ? "reverse-subject" : "subject"); break; case REFERENCES: template_vals_string(tvals, "folder_sort_mode", (sort_reverse) ? "reverse-references" : "references"); break; case ORDEREDSUBJECT: template_vals_string(tvals, "folder_sort_mode", (sort_reverse) ? "reverse-orderedsubject" : "orderedsubject"); break; } template_vals_ulong(tvals, "msgs_per_page", prefs->msgs_per_page); switch (abook_sort_mode) { case ABOOK_SORT_ORDER: template_vals_string(tvals, "abook_sort_mode", (abook_sort_reverse) ? "reverse-order" : "order"); break; case ABOOK_SORT_ALIAS: template_vals_string(tvals, "abook_sort_mode", (abook_sort_reverse) ? "reverse-alias" : "alias"); break; case ABOOK_SORT_NAME: template_vals_string(tvals, "abook_sort_mode", (abook_sort_reverse) ? "reverse-name" : "name"); break; case ABOOK_SORT_COMMENT: template_vals_string(tvals, "abook_sort_mode", (abook_sort_reverse) ? "reverse-comment" : "comment"); break; case ABOOK_SORT_EMAIL: template_vals_string(tvals, "abook_sort_mode", (abook_sort_reverse) ? "reverse-email" : "email"); break; } template_vals_ulong(tvals, "abook_per_page", prefs->abook_per_page); template_vals_string(tvals, "alt_addr", prefs->alt_addr); session_seed_template(session, tvals); template_expand("prefs_display", tvals, b); } static BOOL process_display_prefs(struct session *session, struct prefs *prefs, struct assoc *h) { struct config *config = session->config; struct pool *pool = prefs->pool; char *s; ADDRESS *addr = NIL; ADDRESS *a = NIL; BOOL rc = T; if ((s = assoc_lookup(h, "msgs_per_page"))) { int value = atoi(s); if (value < config->msgs_per_page_min) { session_message(session, ("Messages per page too small" " (minimum allowed: %lu)"), config->msgs_per_page_min); return (NIL); } if (value > config->msgs_per_page_max) { session_message(session, ("Messages per page too large" " (maximum allowed: %lu)"), config->msgs_per_page_max); return (NIL); } prefs->msgs_per_page = value; } if ((s = assoc_lookup(h, "abook_per_page"))) { int value = atoi(s); if (value < config->abook_per_page_min) { session_message(session, ("Addressbook entries per page too small " "(minimum allowed: %lu)"), config->abook_per_page_min); return (NIL); } if (value > config->abook_per_page_max) { session_message(session, ("Addressbook entries per page too large " "(maximum allowed: %lu)"), config->abook_per_page_max); return (NIL); } prefs->abook_per_page = value; } if ((s = assoc_lookup(h, "alt_addr"))) { prefs->alt_addr = pool_strdup(pool, string_trim_whitespace(s)); if (prefs->alt_addr && prefs->alt_addr[0]) { if (!(addr=addr_parse_destructive(s, ""))) { session_message(session, "Alt addresses invalid: %s", ml_errmsg()); rc = NIL; } else { for (a = addr; a; a = a->next) { if (!(a->host && a->host[0])) { session_message(session, ("Unqualified address (%s) " "in Alt Address list"), a->mailbox); rc = NIL; break; } } mail_free_address(&addr); } } } prefs->use_icons = (assoc_lookup(h, "use_icons")) ? T : NIL; prefs->use_tail_banner = (assoc_lookup(h, "use_tail_banner")) ? T : NIL; prefs->html_inline = (assoc_lookup(h, "html_inline")) ? T : NIL; prefs->html_inline_auto = (assoc_lookup(h, "html_inline_auto")) ? T : NIL; prefs->html_remote_images = (assoc_lookup(h, "html_remote_images")) ? T : NIL; prefs->preserve_mimetype = (assoc_lookup(h, "preserve_mimetype")) ? T : NIL; prefs->use_unread = (assoc_lookup(h, "use_unread")) ? T : NIL; if ((s = assoc_lookup(h, "folder_sort_mode"))) { if (!strncmp(s, "reverse-", strlen("reverse-"))) { prefs->sort_reverse = T; s += strlen("reverse-"); } else prefs->sort_reverse = NIL; if (!strcmp(s, "arrival")) prefs->sort_mode = ARRIVAL; else if (!strcmp(s, "date")) prefs->sort_mode = DATE; else if (!strcmp(s, "from")) prefs->sort_mode = FROM; else if (!strcmp(s, "to")) prefs->sort_mode = TO; else if (!strcmp(s, "cc")) prefs->sort_mode = CC; else if (!strcmp(s, "size")) prefs->sort_mode = SIZE; else if (!strcmp(s, "subject")) prefs->sort_mode = SUBJECT; else if (!strcmp(s, "references")) prefs->sort_mode = REFERENCES; else if (!strcmp(s, "orderedsubject")) prefs->sort_mode = ORDEREDSUBJECT; } if ((s = assoc_lookup(h, "abook_sort_mode"))) { abook_sort_mode mode_original = prefs->abook_sort_mode; BOOL reverse_original = prefs->abook_sort_reverse; if (!strncmp(s, "reverse-", strlen("reverse-"))) { prefs->abook_sort_reverse = T; s += strlen("reverse-"); } else prefs->abook_sort_reverse = NIL; if (!strcmp(s, "order")) prefs->abook_sort_mode = ABOOK_SORT_ORDER; else if (!strcmp(s, "alias")) prefs->abook_sort_mode = ABOOK_SORT_ALIAS; else if (!strcmp(s, "name")) prefs->abook_sort_mode = ABOOK_SORT_NAME; else if (!strcmp(s, "comment")) prefs->abook_sort_mode = ABOOK_SORT_COMMENT; else if (!strcmp(s, "email")) prefs->abook_sort_mode = ABOOK_SORT_EMAIL; if ((prefs->abook_sort_mode != mode_original) || (prefs->abook_sort_reverse != reverse_original)) { abook_set_sort(session->options->abook, prefs->abook_sort_mode, prefs->abook_sort_reverse); } } return (rc); } /* ====================================================================== */ /* Folder Preferences */ static void generate_folder_form(struct session *session, struct prefs *prefs) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; if (prefs->suppress_dotfiles) template_vals_ulong(tvals, "suppress_dotfiles", 1); if (prefs->confirm_rm) template_vals_ulong(tvals, "confirm_rm", 1); template_vals_string(tvals, "maildir", prefs->maildir); template_vals_string(tvals, "sent_mail_folder", prefs->sent_mail_folder); template_vals_string(tvals, "postponed_folder", prefs->postponed_folder); session_seed_template(session, tvals); template_expand("prefs_folder", tvals, b); } static BOOL process_folder_prefs(struct session *session, struct prefs *prefs, struct assoc *h) { struct pool *pool = prefs->pool; char *s; BOOL old_dotfiles = prefs->suppress_dotfiles; prefs->suppress_dotfiles = (assoc_lookup(h, "suppress_dotfiles")) ? T : NIL; if (prefs->suppress_dotfiles != old_dotfiles) folderlist_invalidate(session->folderlist); if ((s = assoc_lookup(h, "maildir"))) { s = string_trim_whitespace(s); if (strcmp(s, prefs->maildir) != 0) prefs->maildir = pool_strdup(pool, s); if (!string_filename_valid(s)) { session_message(session, "Invalid Mail Directory Name"); return (NIL); } folderlist_invalidate(session->folderlist); } if ((s = assoc_lookup(h, "sent_mail_folder"))) { s = string_trim_whitespace(s); if (strcmp(s, prefs->sent_mail_folder) != 0) prefs->sent_mail_folder = pool_strdup(pool, s); if (*s == '\0') { session_message(session, "Invalid (Empty) Sent Mail Folder Name"); return (NIL); } if (!string_filename_valid(s)) { session_message(session, "Invalid Sent Mail Folder Name"); return (NIL); } } if ((s = assoc_lookup(h, "postponed_folder"))) { s = string_trim_whitespace(s); if (strcmp(s, prefs->postponed_folder) != 0) prefs->postponed_folder = pool_strdup(pool, s); if (*s == '\0') { session_message(session, "Invalid (Empty) Postponed Folder Name"); return (NIL); } if (!string_filename_valid(s)) { session_message(session, "Invalid Postponed Folder Name"); return (NIL); } } prefs->confirm_rm = (assoc_lookup(h, "confirm_rm")) ? T : NIL; return (T); } /* ====================================================================== */ /* Compose Preferences */ static void generate_compose1_form(struct session *session, struct prefs *prefs) { struct template_vals *tvals = session->template_vals; struct config *config = session->config; struct request *request = session->request; struct buffer *b = request->write_buffer; template_vals_string(tvals, "from_personal", prefs->from_personal); /* Calculate default from personal */ if (!(prefs->from_personal && prefs->from_personal[0]) && config->local_domain_list) { struct list_item *li; char *value; char *default_domain = prefs->default_domain; for (li = config->local_domain_list->head; li; li = li->next) { struct config_local_domain *cld = (struct config_local_domain *) li; if (cld->cdb_map && !strcmp(default_domain, cld->name) && cdb_find(cld->cdb_map, session->username, strlen(session->username), &value) && value && value[0] && (value = string_trim_whitespace(value))) { template_vals_string(tvals, "default_from_personal", value); break; } } } if (config->fix_from_address) template_vals_ulong(tvals, "fix_from_address", 1); template_vals_string(tvals, "from_address", prefs->from_address); if (!(prefs->from_address && prefs->from_address[0])) { char *s = session->username; if (!strchr(session->username, '@')) { s = pool_printf(request->pool, "%s@%s", session->username, prefs->default_domain); } template_vals_string(tvals, "default_from_address", s); } template_vals_string(tvals, "default_reply_to", prefs->default_reply_to); template_vals_string(tvals, "signature", prefs->signature); session_seed_template(session, tvals); template_expand("prefs_compose", tvals, b); } static BOOL process_compose_prefs(struct session *session, struct prefs *prefs, struct assoc *h) { struct config *config = session->config; struct pool *pool = prefs->pool; char *s; ADDRESS *a = NIL; ADDRESS *addr = NIL; BOOL rc = T; if ((s = assoc_lookup(h, "from_personal"))) prefs->from_personal = pool_strdup(pool, string_trim_whitespace(s)); if (!config->fix_from_address && (s = assoc_lookup(h, "from_address"))) { prefs->from_address = pool_strdup(pool, string_trim_whitespace(s)); if (prefs->from_address[0]) { if (!(addr=addr_parse_destructive(s, ""))) { session_message(session, "From Address invalid: %s", ml_errmsg()); rc = NIL; } else { if ((addr->next) || (addr->personal && addr->personal[0]) || (!(addr->host && addr->host[0]))) { session_message(session, ("From Address must be single, simple " "and fully qualified email address")); rc = NIL; } mail_free_address(&addr); } } } if ((s = assoc_lookup(h, "default_reply_to"))) { prefs->default_reply_to = pool_strdup(pool, string_trim_whitespace(s)); if (prefs->default_reply_to[0]) { if (!(addr = addr_parse_destructive(s, ""))) { session_message(session, "Default Reply-To Address invalid: %s", ml_errmsg()); rc = NIL; } else { for (a = addr; a; a = a->next) { if (!(a->host && a->host[0])) { session_message(session, ("Unqualified address in " "Default Reply-To list")); rc = NIL; break; } } mail_free_address(&addr); } } } if ((s = assoc_lookup(h, "signature"))) prefs->signature = pool_strdup(pool, s); return (rc); } /* ====================================================================== */ /* Compose2 Preferences */ static void generate_compose2_form(struct session *session, struct prefs *prefs) { struct template_vals *tvals = session->template_vals; struct config *config = session->config; struct request *request = session->request; struct buffer *b = request->write_buffer; if (prefs->use_sent_mail) template_vals_ulong(tvals, "use_sent_mail", 1); if (config->aspell_path) template_vals_ulong(tvals, "have_aspell_path", 1); if (prefs->spell_skip_quoted) template_vals_ulong(tvals, "spell_skip_quoted", 1); if (prefs->line_wrap_on_reply) template_vals_ulong(tvals, "line_wrap_on_reply", 1); if (prefs->line_wrap_on_spell) template_vals_ulong(tvals, "line_wrap_on_spell", 1); if (prefs->line_wrap_on_send) template_vals_ulong(tvals, "line_wrap_on_send", 1); if (prefs->line_wrap_advanced) template_vals_ulong(tvals, "line_wrap_advanced", 1); template_vals_ulong(tvals, "line_wrap_len", prefs->line_wrap_len); template_vals_ulong(tvals, "small_cols", prefs->small_cols); template_vals_ulong(tvals, "small_rows", prefs->small_rows); template_vals_ulong(tvals, "large_cols", prefs->large_cols); template_vals_ulong(tvals, "large_rows", prefs->large_rows); /* Start of default domain */ template_vals_string(tvals, "default_domain", prefs->default_domain); if (config->local_domain_list) { unsigned long offset = 0; struct list_item *li; for (li = config->local_domain_list->head; li; li = li->next) { struct config_local_domain *cld = (struct config_local_domain *) li; template_vals_foreach_init(tvals, "@domains", offset); template_vals_foreach_string(tvals, "@domains", offset, "name", cld->name); offset++; } } template_vals_string(tvals, "ispell_language", prefs->ispell_language); if (config->ispell_language_list) { unsigned long offset = 0; struct list_item *li; for (li = config->ispell_language_list->head; li; li = li->next) { struct config_language *lang = (struct config_language *) li; template_vals_foreach_init(tvals, "@langs", offset); template_vals_foreach_string(tvals, "@langs", offset, "name", lang->name); template_vals_foreach_string(tvals, "@langs", offset, "desc", lang->desc); offset++; } } session_seed_template(session, tvals); template_expand("prefs_compose2", tvals, b); } static BOOL process_compose2_prefs(struct session *session, struct prefs *prefs, struct assoc *h) { struct config *config = session->config; struct pool *pool = prefs->pool; char *s; int value; if ((s = assoc_lookup(h, "small_cols"))) { if (((value = atoi(s)) > 0) && (value <= 120)) { prefs->small_cols = value; } else { session_message(session, "Small columns option out of range"); return (NIL); } } if ((s = assoc_lookup(h, "small_rows"))) { if (((value = atoi(s)) > 0) && (value <= 120)) { prefs->small_rows = value; } else { session_message(session, "Small rows option out of range"); return (NIL); } } if ((s = assoc_lookup(h, "large_cols"))) { if (((value = atoi(s)) > 0) && (value <= 120)) { prefs->large_cols = value; } else { session_message(session, "Large columns option out of range"); return (NIL); } } if ((s = assoc_lookup(h, "large_rows"))) { if (((value = atoi(s)) > 0) && (value <= 120)) { prefs->large_rows = value; } else { session_message(session, "Large rows option out of range"); return (NIL); } } if ((s = assoc_lookup(h, "line_wrap_len"))) { if (((value = atoi(s)) > 40) && (value <= 120)) { prefs->line_wrap_len = value; } else { session_message(session, "Line wrap length option out of range"); return (NIL); } } if (config->aspell_path) { prefs->spell_skip_quoted = (assoc_lookup(h, "spell_skip_quoted")) ? T : NIL; } prefs->use_sent_mail = (assoc_lookup(h, "use_sent_mail")) ? T : NIL; prefs->line_wrap_on_reply = (assoc_lookup(h, "line_wrap_on_reply")) ? T : NIL; prefs->line_wrap_on_send = (assoc_lookup(h, "line_wrap_on_send")) ? T : NIL; prefs->line_wrap_on_spell = (assoc_lookup(h, "line_wrap_on_spell")) ? T : NIL; prefs->line_wrap_advanced = (assoc_lookup(h, "line_wrap_advanced")) ? T : NIL; if ((s = assoc_lookup(h, "default_domain"))) prefs->default_domain = pool_strdup(pool, string_trim_whitespace(s)); if ((s = assoc_lookup(h, "ispell_language"))) prefs->ispell_language = pool_strdup(pool, string_trim_whitespace(s)); return (T); } /* ====================================================================== */ static void generate_form(struct session *session, char *type, struct prefs *prefs) { struct request *request = session->request; if (!strcmp(type, "general")) generate_general_form(session, prefs); else if (!strcmp(type, "display")) generate_display_form(session, prefs); else if (!strcmp(type, "folder")) generate_folder_form(session, prefs); else if (!strcmp(type, "compose1")) generate_compose1_form(session, prefs); else if (!strcmp(type, "compose2")) generate_compose2_form(session, prefs); response_html(request, 200); } /* ====================================================================== */ void cmd_prefs(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct prefs *prefs; struct pool *pool; struct assoc *h = NIL; char *s; char *type; if (!options->prefs_work) options->prefs_work = prefs_copy(options->prefs); prefs = options->prefs_work; pool = prefs->pool; if (request->method != POST) { generate_form(session, "general", prefs); session_log(session, "[cmd_prefs] General Preferences"); return; } request_decode_form(request); h = request->form; /* Cancel doesn't need any preferences */ if ((s = assoc_lookup(h, "sub_cancel"))) { /* Free up working preferences and return to list screen */ prefs_free(options->prefs_work); options->prefs_work = NIL; session_redirect(session, request, "manage"); return; } /* Make sure that working preferences updated before we go anywhere */ if (!(type = assoc_lookup(h, "type"))) type = ""; if (!strcmp(type, "general")) { session_log(session, "[cmd_prefs] General Preferences"); if (!process_general_prefs(session, prefs, h)) { generate_form(session, "general", prefs); return; } } else if (!strcmp(type, "display")) { session_log(session, "[cmd_prefs] Display Preferences"); if (!process_display_prefs(session, prefs, h)) { generate_form(session, "display", prefs); return; } } else if (!strcmp(type, "folder")) { session_log(session, "[cmd_prefs] Folder Preferences"); if (!process_folder_prefs(session, prefs, h)) { generate_form(session, "folder", prefs); return; } } else if (!strcmp(type, "compose1")) { session_log(session, "[cmd_prefs] Compose Preferences"); if (!process_compose_prefs(session, prefs, h)) { generate_form(session, "compose1", prefs); return; } } else if (!strcmp(type, "compose2")) { session_log(session, "[cmd_prefs] Extra Compose Preferences"); if (!process_compose2_prefs(session, prefs, h)) { generate_form(session, "compose2", prefs); return; } } /* Switch to other preference screens */ if (assoc_lookup(h, "sub_general")) { generate_form(session, "general", prefs); return; } if (assoc_lookup(h, "sub_display")) { generate_form(session, "display", prefs); return; } if (assoc_lookup(h, "sub_folder")) { generate_form(session, "folder", prefs); return; } if (assoc_lookup(h, "sub_compose1")) { generate_form(session, "compose1", prefs); return; } if (assoc_lookup(h, "sub_compose2")) { generate_form(session, "compose2", prefs); return; } if (assoc_lookup(h, "sub_session")) { generate_form(session, "session", prefs); return; } if (assoc_lookup(h, "sub_save")) { /* Update save preferences */ if (options->prefs_save) prefs_free(options->prefs_save); options->prefs_save = prefs_copy(options->prefs_work); options->save = T; } /* Update live preferences */ if (options->prefs) prefs_free(options->prefs); options->prefs = prefs_copy(options->prefs_work); session_use_prefs(session, prefs, NIL); /* Free up working preferences and return to list screen */ prefs_free(options->prefs_work); options->prefs_work = NIL; session_redirect(session, request, "manage"); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_filter_select.c��������������������������������������������������������������0000644�0065130�0065130�00000003210�11313664310�016141� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_filter_select.c,v 1.4 2009/12/21 12:23:36 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_filter_select(struct session *session) { struct template_vals *tvals = session->template_vals; struct folderlist *fl = folderlist_fetch(session); struct prefs *prefs = session->options->prefs; BOOL suppress_dotfiles = prefs->suppress_dotfiles; struct request *request = session->request; struct buffer *b = request->write_buffer; struct folderitem *fi; char *name; if ((request->argc == 3) && !strcmp(request->argv[1], "toggle")) { name = string_canon_decode(request->argv[2]); fi = folderlist_lookup(folderlist_fetch(session), name); if (fi) { if (fi->expanded) { session_message(session, "Collapsed \"%s\"", name); fi->expanded = NIL; } else { folderlist_expand(session, fi); session_message(session, "Expanded \"%s\"", name); fi->expanded = T; } } } folderlist_template_vals_tree(fl, suppress_dotfiles, tvals, "@folder"); folderlist_template_vals_list(fl, suppress_dotfiles, tvals, T, "@dirlist"); session_seed_template(session, tvals); template_expand("filter_select", tvals, b); response_html(request, 200); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd.h����������������������������������������������������������������������������0000644�0065130�0065130�00000011544�11063701633�013255� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd.h,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* Prototypes for cmd_* functions */ void cmd_abook_add(struct session *session); void cmd_abook_compose(struct session *session); void cmd_abook_compose2(struct session *session); void cmd_abook_export(struct session *session); void cmd_abook_import(struct session *session); void cmd_abook_list(struct session *session); void cmd_abook_lookup(struct session *session); void cmd_abook_lookup_add(struct session *session); void cmd_abook_save(struct session *session); void cmd_abook_search(struct session *session); void cmd_abook_sort(struct session *session); void cmd_abook_take(struct session *session); void cmd_abook_update(struct session *session); void cmd_abook_xfer(struct session *session); void cmd_action_stub(struct session *session); void cmd_add_address(struct session *session); void cmd_aggregate(struct session *session); void cmd_aggregate_tmp(struct session *session); void cmd_attachments(struct session *session); void cmd_block(struct session *session); void cmd_change(struct session *session); void cmd_check_cookie(struct session *session); void cmd_checkpoint(struct session *session); void cmd_compose(struct session *session); void cmd_compose1(struct session *session); void cmd_copy(struct session *session); void cmd_copy_msg(struct session *session); void cmd_create(struct session *session); void cmd_delete(struct session *session); void cmd_detach(struct session *session); void cmd_dir_check(struct session *session); void cmd_disp_delete(struct session *session); void cmd_disp_mark(struct session *session); void cmd_disp_undelete(struct session *session); void cmd_disp_unmark(struct session *session); void cmd_dictionary(struct session *session); void cmd_display(struct session *session); void cmd_download(struct session *session); void cmd_download_xfer(struct session *session); void cmd_error(struct session *session); void cmd_exit(struct session *session); void cmd_expunge(struct session *session); void cmd_expunge1(struct session *session); void cmd_favourites(struct session *session); void cmd_filter(struct session *session); void cmd_filter_mbox(struct session *session); void cmd_filter_select(struct session *session); void cmd_folders(struct session *session); void cmd_forward(struct session *session); void cmd_forward1(struct session *session); void cmd_fullname(struct session *session); void cmd_help(struct session *session); void cmd_hdrs(struct session *session); void cmd_init(struct session *session); void cmd_include(struct session *session); void cmd_list(struct session *session); void cmd_list_sort(struct session *session); void cmd_logout(struct session *session); void cmd_mark(struct session *session); void cmd_manage(struct session *session); void cmd_passwd(struct session *session); void cmd_preferred(struct session *session); void cmd_prefs(struct session *session); void cmd_printable(struct session *session); void cmd_quota(struct session *session); void cmd_rawdisplay(struct session *session); void cmd_redirect(struct session *session); void cmd_reply(struct session *session); void cmd_reply1(struct session *session); void cmd_reply2(struct session *session); void cmd_rm(struct session *session); void cmd_rm1(struct session *session); void cmd_rename(struct session *session); void cmd_rename_item(struct session *session); void cmd_restart(struct session *session); void cmd_resume(struct session *session); void cmd_roles_entry(struct session *session); void cmd_roles_list(struct session *session); void cmd_search(struct session *session); void cmd_send(struct session *session); void cmd_sieve(struct session *session); void cmd_sizes(struct session *session); void cmd_spam(struct session *session); void cmd_spell(struct session *session); void cmd_subscribe(struct session *session); void cmd_transfer(struct session *session); void cmd_undelete(struct session *session); void cmd_unmark(struct session *session); void cmd_unsubscribe(struct session *session); void cmd_upload_exit(struct session *session); void cmd_upload_select(struct session *session); void cmd_upload_xfer(struct session *session); void cmd_user_agent(struct session *session); void cmd_user_level(struct session *session); void cmd_vacation(struct session *session); void cmd_vaclog(struct session *session); void cmd_welcome(struct session *session); void cmd_zoom(struct session *session); struct cmd { char *cmd; void (*fn) (struct session * session); }; /* cmd.c defines dispatch tables used by prayer frontend and session */ void cmd_dispatch_init(void); BOOL cmd_dispatch(struct session *session, char *text); ������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_import.c���������������������������������������������������������������0000644�0065130�0065130�00000002622�11064236131�016007� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_import.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Import Pine format addressbook from accountd system */ void cmd_abook_import(struct session *session) { struct request *request = session->request; struct abook *abook = session->options->abook; char *text; unsigned long count; /* Fetch .addressbook from account server */ if (!(text = account_abook_get(session->account, request->pool))) { session_alert(session, "Unable to download addressbook file"); session_redirect(session, request, "abook_xfer"); return; } if (!abook_import_pine_valid(text)) { session_alert(session, "Invalid/Unsupported addressbook format"); session_redirect(session, request, "abook_list"); return; } count = abook_import_pine(abook, text); if (count != 1) session_message(session, "Imported %lu aliases", count); else session_message(session, "Imported 1 alias"); if (count > 0) session->options->save = T; session_redirect(session, request, "abook_list"); } ��������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_expunge.c��������������������������������������������������������������������0000644�0065130�0065130�00000002756�11063701633�015010� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_expunge.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" #include "cmd.h" void cmd_expunge(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct options *options = session->options; struct prefs *prefs = options->prefs; struct buffer *b = request->write_buffer; unsigned long msgno, count; MAILSTREAM *stream = session->stream; MESSAGECACHE *elt; if (!prefs->confirm_expunge) { cmd_expunge1(session); return; } /* Count deleted messages in folder */ for (count = 0, msgno = 1; msgno <= stream->nmsgs; msgno++) { if (!(elt = ml_elt(session, stream, msgno))) { session_redirect(session, request, "restart"); return; } if (elt->deleted) count++; } if (count == 0) { session_message(session, "No messages to expunge"); session_redirect(session, request, "list"); return; } template_vals_ulong(tvals, "count", count); session_seed_template(session, tvals); template_expand("expunge", tvals, b); response_html(request, 200); } ������������������./prayer-1.3.5/cmd/cmd_resume.c���������������������������������������������������������������������0000644�0065130�0065130�00000003676�11064236131�014634� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_resume.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_resume(struct session *session) { struct request *request = session->request; struct draft *draft = session->draft; MAILSTREAM *stream = session->stream; unsigned long msgno; unsigned long msguid; if (request->argc < 3) { session_alert(session, "Unexpected resume"); session_redirect(session, request, "list"); return; } msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "restart"); return; } draft_role_set(draft, NIL); /* Set up default role */ draft_init(draft); /* Reload draft message */ if (!draft_restore_postponed(draft, request->pool, session->draft_stream, msgno)) { session_redirect(session, request, "restart"); return; } /* Remove from draft folder */ if (!draft_delete(session, msgno)) { session_redirect(session, request, "restart"); return; } if (draft_att_count(draft) > 1) session_message(session, "Restored postponed draft, including %lu attachments", draft_att_count(draft)); else if (draft_att_count(draft) == 1) session_message(session, "Restored postponed draft, including 1 attachment"); else session_message(session, "Restored postponed draft, no attachments"); session_redirect(session, request, "compose"); } ������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_checkpoint.c�����������������������������������������������������������������0000644�0065130�0065130�00000005623�11063701633�015460� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_checkpoint.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" /* Unix Date conversion is ghastly. Stole following from c-client */ static char *current_time(void) { static char current[64]; time_t tn = time(0); struct tm *t = gmtime(&tn); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime(&tn); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if ((julian = t->tm_yday - julian) != 0) zone += ((julian < 0) == (abs(julian) == 1)) ? -24 * 60 : 24 * 60; /* output the time */ sprintf(current, "%02d:%02d:%02d %+03d%02d", t->tm_hour, t->tm_min, t->tm_sec, zone / 60, abs(zone) % 60); return (current); } void cmd_checkpoint(struct session *session) { struct request *request = session->request; MAILSTREAM *stream = session->stream; struct msgmap *zm = session->zm; unsigned long count = zm->nmsgs; time_t last, now; if (stream == session->inbox_stream) last = session->inbox_last_ping_time; else if (stream == session->draft_stream) last = session->draft_last_ping_time; else last = session->other_last_ping_time; now = time(NIL); if ((last > 0) && (now > last) && ((now - last) < 5)) { /* Prevent denial of service attack */ session_message(session, "No new mail at %s", current_time()); session_redirect(session, request, "list"); return; } if (!ml_check(session, stream)) { session_redirect(session, request, "restart"); return; } msgmap_update(session->zm); if (stream == session->inbox_stream) session->inbox_last_ping_time = now; else if (stream == session->draft_stream) session->draft_last_ping_time = now; else session->other_last_ping_time = now; if (zm->nmsgs > count) { session->current = zm->nmsgs; session_message(session, "New mail has arrived at %s", current_time()); session_redirect(session, request, "list"); } else { session_message(session, "No new mail at %s", current_time()); session_redirect(session, request, "list"); } } �������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_printable.c������������������������������������������������������������������0000644�0065130�0065130�00000005512�11415401425�015303� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_printable.c,v 1.10 2010/07/08 16:55:49 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_printable(struct session *session) { struct template_vals *tvals = session->template_vals; struct options *options = session->options; struct prefs *prefs = options->prefs; struct request *request = session->request; struct msgmap *zm = session->zm; unsigned long msgno, msguid; char *section; struct buffer *b = request->write_buffer; MAILSTREAM *stream = session->stream; BOOL html_show_images = prefs->html_remote_images; if (!msgmap_update(zm)) { session_alert(session, "Failed to update msgmap"); session_redirect(session, request, "restart"); return; } if (msgmap_size(zm) == 0) { session_message(session, "Folder is empty"); session_redirect(session, request, "list"); return; } /* Save options if anything changed */ if (options->save) session_streams_save_options(session); /* Record last command for compose/cancel and friends */ if (!session->draft->have_draft) session->compose_parent_cmd = "display"; /* Record last command for save/cancel */ session->copy_parent_cmd = "display"; /* Record last command for addressbook take */ session->take_parent_cmd = "display"; if ((request->argc == 5) && !strcmp(request->argv[4], "show_images")) html_show_images = T; section = NIL; if (request->argc >= 4) section = request->argv[3]; if (request->argc >= 3) { msgno = atoi(request->argv[1]); msguid = atoi(request->argv[2]); if (!(msgno = stream_check_uid(session, stream, msgno, msguid))) { session_redirect(session, request, "list"); return; } } else { msgno = session->last_displayed; if ((msgno == 0) || (msgno > msgmap_size(zm))) msgno = msgmap_value(zm, msgmap_size(zm)); msguid = ml_uid(session, stream, msgno); } session->current = msgno; session->last_displayed = msgno; display_addnav(session, stream, msgno); display_addhdrs(session, stream, msgno); session_seed_template(session, tvals); template_expand("printable", tvals, b); if (!display_body(session, request, stream, msgno, section, "printable", html_show_images)) { session_redirect(session, request, "restart"); return; } template_expand("printable_tail", tvals, b); /* Send out the response */ response_html(request, 200); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_abook_take.c�����������������������������������������������������������������0000644�0065130�0065130�00000007576�11064236131�015436� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_take.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session, struct assoc *h) { struct template_vals *tvals = session->template_vals; struct abook *abook = session->options->abook; struct request *request = session->request; struct buffer *b = request->write_buffer; char *alias = assoc_lookup(h, "alias"); /* Check for existing alias */ if (alias && abook_lookup(abook, alias)) session_message(session, "Email address matches addressbook entry: \"%s\"", alias); template_vals_string(tvals, "alias", alias); template_vals_string(tvals, "name", assoc_lookup(h, "name")); template_vals_string(tvals, "comment", assoc_lookup(h, "comment")); template_vals_string(tvals, "email", assoc_lookup(h, "email")); session_seed_template(session, tvals); template_expand("abook_take", tvals, b); response_html(request, 200); /* Success */ } void cmd_abook_take(struct session *session) { struct request *request = session->request; struct options *options = session->options; struct assoc *h = NIL; if (request->method != POST) { if (request->get_suffix) { request_decode_form(request); h = request->form; } generate_form(session, h); return; } request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_cancel")) { session_redirect(session, request, session->take_parent_cmd); return; } if (assoc_lookup(h, "sub_add")) { char *alias = assoc_lookup(h, "alias"); char *name = assoc_lookup(h, "name"); char *fcc = pool_strdup(request->pool, ""); /* Not yet */ char *comment = assoc_lookup(h, "comment"); char *email = assoc_lookup(h, "email"); if (alias) alias = string_trim_whitespace(alias); else alias = ""; if (!alias[0]) { session_alert(session, "No alias provided"); generate_form(session, h); return; } if (strchr(alias, ' ') || strchr(alias, '\t')) { session_alert(session, "Alias cannot contain spaces"); generate_form(session, h); return; } if (!(name && comment && email)) { session_alert(session, "Missing form entries"); generate_form(session, h); return; } name = string_trim_whitespace(name); fcc = string_trim_whitespace(fcc); comment = string_trim_whitespace(comment); email = string_trim_whitespace(email); if (email[0] == '\0') { session_alert(session, "No email address supplied"); generate_form(session, h); return; } abook_replace(options->abook, alias, name, fcc, comment, email); if (!addr_check_valid(request->pool, email)) { session_alert(session, "%s", ml_errmsg()); generate_form(session, h); return; } if (!abook_check_loop(request->pool, options->abook, alias, T)) { session_alert(session, "Addressbook loop involving alias \"%s\"", assoc_lookup(h, "alias")); generate_form(session, h); return; } session_message(session, "Updated address book entry: \"%s\"", alias); session->options->save = T; } session_redirect(session, request, session->take_parent_cmd); } ����������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_exit.c�����������������������������������������������������������������������0000644�0065130�0065130�00000004071�11413374146�014302� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_exit.c,v 1.4 2010/07/02 14:32:06 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_exit(struct session *session) { struct user_agent *user_agent = session->user_agent; struct config *config = session->config; struct request *request = session->request; struct template_vals *tvals = session->template_vals; struct buffer *b = request->write_buffer; char *url; session->want_disconnect = T; session_streams_close(session); session_log(session, "[cmd_exit] User logout"); if ((config->raven_enable) && (strlen(session->password) > 256)) { session_seed_template(session, tvals); template_expand("logout_raven", tvals, b); response_html(request, 200); return; } /* Back to login screen */ if (config->hostname_service) { if (session->use_ssl) { if (session->frontend_port == 443) url = pool_printf(request->pool, "https://%s", config->hostname_service); else url = pool_printf(request->pool, "https://%s:%lu", config->hostname_service, session->frontend_port); } else { if (session->frontend_port == 80) url = pool_printf(request->pool, "http://%s", config->hostname_service); else url = pool_printf(request->pool, "http://%s:%lu", config->hostname_service, session->frontend_port); } } else url = session->url_prefix; if (user_agent->use_debug) url = pool_strcat(request->pool, url, "/debug"); response_redirect(request, url); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_action_stub.c����������������������������������������������������������������0000644�0065130�0065130�00000001512�11063701633�015634� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_action_stub.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_action_stub(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; char *last_cmd = memblock_string(session->last_cmd); template_vals_string(tvals, "$last_command", last_cmd); session_seed_template(session, tvals); template_expand("action_stub", tvals, b); response_html(request, 200); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_vaclog.c���������������������������������������������������������������������0000644�0065130�0065130�00000004314�11063701633�014600� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_vaclog.c,v 1.3 2008/09/16 09:59:55 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_error(struct session *session) { struct template_vals *tvals = session->template_vals; struct account *account = session->account; struct request *request = session->request; char *msg = account_fetch_message(account); struct buffer *b = request->write_buffer; if (!(msg && msg[0])) msg = "Unable to check mail processing status"; template_vals_string(tvals, "msg", msg); session_seed_template(session, tvals); template_expand("vaclog_fail", tvals, b); response_html(request, 200); } void cmd_vaclog(struct session *session) { struct template_vals *tvals = session->template_vals; struct account *account = session->account; struct request *request = session->request; struct buffer *b = request->write_buffer; char *vaclog; if (request->method == POST) { request_decode_form(request); if (assoc_lookup(request->form, "sub_clear")) { if (account_vaclog_clear(session->account, request->pool)) { session_message(session, "Cleared vacation log"); } else { char *msg = account_fetch_message(session->account); session_message(session, "Failed to clear vacation log: %s", msg); session_log(session, "[cmd_vaclog] Failed to clear vacation log: %s", msg); } } session_redirect(session, request, "manage"); return; } if (!(vaclog = account_vaclog_fetch(account, request->pool))) { generate_error(session); return; } template_vals_string(tvals, "vaclog", vaclog); session_seed_template(session, tvals); template_expand("vaclog", tvals, b); response_html(request, 200); /* Success */ } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_create.c���������������������������������������������������������������������0000644�0065130�0065130�00000007623�11245744104�014600� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_create.c,v 1.5 2009/08/28 12:06:28 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" void cmd_create(struct session *session) { struct config *config = session->config; struct prefs *prefs = session->options->prefs; struct request *request = session->request; char *mailbox, *type, *parent; char *path, *ml_path; if (request->argc < 2) { session_redirect(session, request, "error"); return; } request_decode_form(request); mailbox = utf8_to_imaputf7(request->pool, assoc_lookup(request->form, "name")); if (!mailbox) { session_redirect(session, request, "error"); return; } type = assoc_lookup(request->form, "type"); if (!type) type = "mailbox"; if ((parent = assoc_lookup(request->form, "parent"))) string_canon_decode(parent); if (parent && parent[0]) mailbox = pool_strcat3(request->pool, parent, session->hiersep, mailbox); else if ((prefs->maildir && prefs->maildir[0])) { /* No parent and we have maildir so add that to the start of mailbox */ mailbox = pool_strcat3(request->pool, prefs->maildir, session->hiersep, mailbox); } if (!string_filename_valid(mailbox)) { session_alert(session, "Name contained illegal characters"); /* Redirect back to previous command */ session_redirect(session, request, request->argv[1]); return; } path = mailbox; if (type && !strcmp(type, "directory")) ml_path = pool_strcat(request->pool, path, session->hiersep); else ml_path = path; ml_clear_error(); ml_have_close(); if (!ml_create(session, session->stream, session_mailbox(session, request->pool, ml_path))) { if (ml_have_close()) { session_redirect(session, request, "restart"); return; } } if (type && !strcmp(type, "directory")) { if (ml_have_error()) { session_alert(session, "Failed to create directory: %s - %s", utf8_from_imaputf7(request->pool, path), ml_errmsg()); session_log(session, "[cmd_create] Failed to create directory: %s", path); } else { session_message(session, "Created directory: %s", utf8_from_imaputf7(request->pool, path)); session_log(session, "[cmd_create] Created directory: %s", path); if (config->dualuse) folderlist_add(session->folderlist, path, NIL, NIL); else folderlist_add(session->folderlist, path, T, NIL); } } else if (ml_have_error()) { session_alert(session, "Failed to create mailbox: %s - %s", utf8_from_imaputf7(request->pool, path), ml_errmsg()); session_log(session, "[cmd_create] Failed to create mailbox: %s", path); } else { session_message(session, "Created mailbox: %s", utf8_from_imaputf7(request->pool, path)); session_log(session, "[cmd_create] Created mailbox: %s", path); if (config->dualuse) folderlist_add(session->folderlist, path, NIL, NIL); else folderlist_add(session->folderlist, path, NIL, T); } /* Redirect back to previous command */ session_redirect(session, request, request->argv[1]); } �������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_fullname.c�������������������������������������������������������������������0000644�0065130�0065130�00000006041�11064236131�015124� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_fullname.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void generate_form(struct session *session, char *new) { struct template_vals *tvals = session->template_vals; struct config *config = session->config; struct request *request = session->request; struct buffer *b = request->write_buffer; struct account *account = session->account; char *oldname, *delay = NIL; oldname = account_fullname(account, request->pool); if (config->accountd_fullname_delay > (2 * 60 * 60)) delay = pool_printf(tvals->pool, "%lu hours", config->accountd_fullname_delay / (60 * 60)); else if (config->accountd_fullname_delay > 120) delay = pool_printf(tvals->pool, "%lu minutes", config->accountd_fullname_delay / 60); else if (config->accountd_fullname_delay > 1) delay = pool_printf(tvals->pool, "%lu seconds", config->accountd_fullname_delay); if (oldname && oldname[0]) template_vals_string(tvals, "fullname", oldname); else template_vals_string(tvals, "fullname", "(Unknown)"); template_vals_string(tvals, "new", new); if (delay) template_vals_string(tvals, "delay", delay); session_seed_template(session, tvals); template_expand("fullname", tvals, b); response_html(request, 200); } /* ====================================================================== */ static BOOL process_form(struct session *session, char *new) { struct request *request = session->request; struct pool *pool = request->pool; if (!(new && new[0])) { session_message(session, "New password not supplied"); return (NIL); } if (!account_change_fullname(session->account, pool, new)) { char *msg = account_fetch_message(session->account); session_alert(session, "Unable to change fullname: %s", msg); session_log(session, "[cmd_fullname] Unable to change fullname: %s", msg); return (NIL); } session_message(session, "Fullname updated"); return (T); } void cmd_fullname(struct session *session) { struct request *request = session->request; char *new; if (request->method == POST) { struct assoc *h; request_decode_form(request); h = request->form; if (assoc_lookup(h, "sub_change")) { if ((new = assoc_lookup(h, "new"))) new = string_trim_whitespace(new); if (!process_form(session, new)) { generate_form(session, new); return; } } session_redirect(session, request, "manage"); return; } generate_form(session, NIL); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/cmd/cmd_compose.c��������������������������������������������������������������������0000644�0065130�0065130�00000043063�11064236131�014773� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $Cambridge: hermes/src/prayer/cmd/cmd_compose.c,v 1.5 2008/09/17 17:20:25 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2008 */ /* See the file NOTICE for conditions of use and distribution. */ #include "prayer_session.h" static void cmd_compose_generate_form(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct draft *draft = session->draft; struct prefs *prefs = session->options->prefs; struct buffer *b = request->write_buffer; template_vals_string(tvals, "hdr_to", draft->to); template_vals_string(tvals, "hdr_cc", draft->cc); template_vals_string(tvals, "hdr_bcc", draft->bcc); template_vals_string(tvals, "hdr_fcc", draft->fcc); template_vals_string(tvals, "hdr_reply_to", draft->reply_to); template_vals_string(tvals, "hdr_subject", draft->subject); template_vals_ulong(tvals, "att_count", draft_att_count(draft)); template_vals_string(tvals, "body", draft->body); if (draft->rich_headers) template_vals_ulong(tvals, "rich_headers", 1); if (prefs->line_wrap_advanced) template_vals_ulong(tvals, "line_wrap_advanced", 1); if (draft->line_wrap) template_vals_ulong(tvals, "line_wrap", 1); if (draft->save_copy) template_vals_ulong(tvals, "copy_outgoing", 1); if (session->compose_large) template_vals_ulong(tvals, "large", 1); template_vals_ulong(tvals, "large_cols", prefs->large_cols); template_vals_ulong(tvals, "large_rows", prefs->large_rows); template_vals_ulong(tvals, "small_cols", prefs->small_cols); template_vals_ulong(tvals, "small_rows", prefs->small_rows); session_seed_template(session, tvals); template_expand("compose", tvals, b); /* Send out HTML */ response_html(request, 200); } /* ====================================================================== */ static BOOL cmd_compose_generate_postponed_list(struct session *session) { struct template_vals *tvals = session->template_vals; struct config *config = session->config; struct request *request = session->request; struct buffer *b = request->write_buffer; MAILSTREAM *stream = session->draft_stream; unsigned long msgno; unsigned long count = 0; for (msgno = 1; msgno <= stream->nmsgs; msgno++) { MESSAGECACHE *elt; ENVELOPE *env; ADDRESS *addr; char *string; template_vals_foreach_init(tvals, "@list", count); if (!((elt = ml_elt(session, stream, msgno)) && (env = ml_fetch_structure(session, stream, msgno, NIL, 0)))) return (NIL); /* Msg No */ template_vals_foreach_ulong(tvals, "@list", count, "msgno", msgno); /* Message Date */ template_vals_foreach_string(tvals, "@list", count, "date", mc_date_to_string(elt)); /* To/Cc/Bcc address (use first non-empty address) */ if (!((addr = env->to) && addr->mailbox && addr->host)) if (!((addr = env->cc) && addr->mailbox && addr->host)) addr = env->bcc; if (addr && addr->personal) { string = addr->personal; } else if (addr && addr->mailbox && addr->host) { string = pool_printf(request->pool, "%s@%s", addr->mailbox, addr->host); } else { string = "(unknown)"; } string = (char *) rfc1522_decode(pool_alloc(request->pool, strlen(string)), strlen(string), string, NIL); string = utf8_prune(request->pool, string, config->list_addr_maxlen); template_vals_foreach_string(tvals, "@list", count, "name", string); /* Message size */ if (elt->rfc822_size > 1024) string = pool_printf(tvals->pool, "%luK", elt->rfc822_size / 1024); else string = "<1K"; template_vals_foreach_string(tvals, "@list", count, "size", string); /* Message subject */ if (env->subject && env->subject[0]) { string = env->subject; string = (char *) rfc1522_decode(pool_alloc(request->pool, strlen(string)), strlen(string), string, NIL); string = utf8_prune(request->pool, string, config->list_subject_maxlen); } else string = "(No subject)"; template_vals_foreach_string(tvals, "@list", count, "subject", string); count++; } session_seed_template(session, tvals); template_expand("compose_postponed", tvals, b); response_html(request, 200); return (T); } /* ====================================================================== */ static void cmd_compose_generate_role_list(struct session *session) { struct template_vals *tvals = session->template_vals; struct request *request = session->request; struct buffer *b = request->write_buffer; struct options *options = session->options; struct list_item *li; unsigned long count = 0; template_vals_foreach_init(tvals, "@roles", count); template_vals_foreach_string(tvals, "@roles", count, "name", "default"); count++; for (li = options->role_list->head; li; li = li->next) { struct role *role = (struct role *) li; template_vals_foreach_init(tvals, "@roles", count); template_vals_foreach_string(tvals, "@roles", count, "name", role->name); count++; } template_vals_string(tvals, "next", "compose1"); session_seed_template(session, tvals); template_expand("roles_select", tvals, b); response_html(request, 200); } /* ====================================================================== */ /* Check draft message * Returns: T if draft exists or created by end of function * NIL if redirect or page issued in order to generate draft */ static BOOL cmd_compose_check_draft(struct session *session) { struct request *request = session->request; struct draft *draft = session->draft; struct options *options = session->options; struct assoc *h = NIL; char *s; unsigned long value; if (draft->have_draft) return (T); if (request->method == GET) { request_decode_form(request); h = request->form; if (assoc_lookup(h, "postponed_cancel")) { session_redirect(session, request, session->compose_parent_cmd); return (NIL); } if (assoc_lookup(h, "postponed_list")) { struct pool *pool = request->pool; char *name; name = string_url_encode(pool, session->draft_foldername); session_redirect(session, request, pool_strcat(pool, "change/", name)); return (NIL); } } if (!h && draft_check(session)) { if (!cmd_compose_generate_postponed_list(session)) session_redirect(session, request, "restart"); return (NIL); } if (h && !assoc_lookup(h, "postponed_fresh") && (s = assoc_lookup(h, "postponed")) && ((value = atoi(s)) > 0)) { /* Conceivable that session has gone to sleep on postponed list page */ if (!draft_check(session)) { session_redirect(session, request, "restart"); return (NIL); } draft_role_set(draft, NIL); /* Set up default role */ draft_init(draft); /* Reload draft message */ if (!draft_restore_postponed(draft, request->pool, session->draft_stream, value)) { session_redirect(session, request, "restart"); return (NIL); } /* Remove from draft folder */ if (!draft_delete(session, value)) { session_redirect(session, request, "restart"); return (NIL); } if (draft_att_count(draft) > 1) session_message(session, "Restored postponed draft, including %lu attachments", draft_att_count(draft)); else if (draft_att_count(draft) == 1) session_message(session, "Restored postponed draft, including 1 attachment"); else session_message(session, "Restored postponed draft, no attachments"); } else if (list_length(options->role_list) > 0L) { /* Fresh new message and need to select role */ session_message(session, "Composing fresh message: please select a role"); cmd_compose_generate_role_list(session); return (NIL); } else { /* Set up default role */ draft_role_set(draft, NIL); draft_init(draft); session_message(session, "Composing fresh message"); } session->compose_large = NIL; draft_init_rich_headers(draft); return (T); } /* ====================================================================== */ void cmd_compose(struct session *session) { struct request *request = session->request; struct draft *draft = session->draft; struct draft *draft0 = session->draft0; struct options *options = session->options; struct assoc *h = NIL; char *hdr; if ((request->argc >= 2) && (!strcmp(request->argv[1], "cancel"))) { session_log(session, "[cmd_compose] Cancel"); session->compose_large = NIL; session->abook_parent_cmd = "list"; /* Kill the draft */ draft_clear_atts(draft); draft_free(draft); draft_free(draft0); session_redirect(session, request, session->compose_parent_cmd); return; } if (!cmd_compose_check_draft(session)) return; /* If we get this far then draft exists with correct role */ if (request->method != POST) { cmd_compose_generate_form(session); return; } request_decode_form(request); h = request->form; /* Undo is special: rewind to previous version */ if (assoc_lookup(h, "sub_undo")) { struct draft *tmp; if (!draft0->have_draft) draft_init(draft0); /* Update existing draft so that undo can be toggled */ if (session->compose_large) draft_update_body(draft, h); else draft_update(draft, h); /* Then switch draft and draft0 */ tmp = session->draft; session->draft = session->draft0; session->draft0 = tmp; cmd_compose_generate_form(session); return; } /* Create backup copy of existing draft */ draft_free(draft0); draft_copy(draft0, draft); /* Address book lookups on To:/Cc:/Bcc: */ /* Need to do this before draft structure is updated */ if ((assoc_lookup(h, "sub_abook_To")) && (hdr = assoc_lookup(h, "hdr_To"))) { hdr = string_trim_whitespace(hdr); if (hdr[0]) { if ((hdr = abook_substitute(session, request->pool, options->abook, hdr))) assoc_update(h, "hdr_To", hdr, T); session_message(session, "Header To Lookup Complete"); session_log(session, "[cmd_compose] Header To Lookup Complete"); } else { session_message(session, "Header To Empty"); session_log(session, "[cmd_compose] Header To Empty"); } } if ((assoc_lookup(h, "sub_abook_Cc")) && (hdr = assoc_lookup(h, "hdr_Cc"))) { hdr = string_trim_whitespace(hdr); if (hdr[0]) { if ((hdr = abook_substitute(session, request->pool, options->abook, hdr))) assoc_update(h, "hdr_Cc", hdr, T); session_message(session, "Header Cc Lookup Complete"); session_log(session, "[cmd_compose] Header Cc Lookup Complete"); } else { session_message(session, "Header Cc Empty"); session_log(session, "[cmd_compose] Header Cc Empty"); } } if ((assoc_lookup(h, "sub_abook_Bcc")) && (hdr = assoc_lookup(h, "hdr_Bcc"))) { hdr = string_trim_whitespace(hdr); if (hdr[0]) { if ((hdr = abook_substitute(session, request->pool, options->abook, hdr))) assoc_update(h, "hdr_Bcc", hdr, T); session_message(session, "Header Bcc Lookup Complete"); session_log(session, "[cmd_compose] Header Bcc Lookup Complete"); } else { session_message(session, "Header Bcc Empty"); session_log(session, "[cmd_compose] Header Bcc Empty"); } } /* Create new draft from updated assoc table (i.e: contents of form) */ if (session->compose_large) draft_update_body(draft, h); else draft_update(draft, h); /* Process buttons which move us to other screens */ /* Three most common operations first */ if (assoc_lookup(h, "sub_cancel")) { session_log(session, "[cmd_compose] Cancel"); session->compose_large = NIL; /* Kill the draft */ draft_clear_atts(draft); draft_free(draft); draft_free(draft0); session_message(session, "Draft message cancelled"); session_redirect(session, request, session->compose_parent_cmd); return; } if (assoc_lookup(h, "sub_postpone")) { session_log(session, "[cmd_compose] Postpone"); /* Save, then kill the draft */ if (draft_write(draft)) { session->abook_parent_cmd = "list"; draft_clear_atts(draft); draft_free(draft); draft_free(draft0); session_message(session, "Draft message postponed"); session_redirect(session, request, session->compose_parent_cmd); return; } else { session_alert(session, "Failed to write postponed message"); session_log(session, "[cmd_compose] Failed to write postponed message: %s", ml_errmsg()); } } if (assoc_lookup(h, "sub_send")) { session_log(session, "[cmd_compose] Sending message"); session->compose_large = NIL; session_redirect(session, request, "send"); return; } /* Toolbar actions moving us to other screens */ if (assoc_lookup(h, "sub_list")) { session_redirect(session, request, "list"); return; } if (assoc_lookup(h, "sub_display")) { session_redirect(session, request, "display"); return; } if (assoc_lookup(h, "sub_abook_list")) { session->abook_parent_cmd = "compose"; session_redirect(session, request, "abook_list"); return; } if (assoc_lookup(h, "sub_folders")) { session_redirect(session, request, "folders"); return; } if (assoc_lookup(h, "sub_manage")) { session_redirect(session, request, "manage"); return; } if (assoc_lookup(h, "sub_folder_dialogue")) { char *name = assoc_lookup(request->form, "folder"); if (name && name[0]) { session_redirect(session, request, pool_strcat(request->pool, "change/", name)); return; } else session_alert(session, "Invalid mail folder"); } if (assoc_lookup(h, "sub_help")) { session_log(session, "[cmd_compose] Help"); session->help_enabled = (session->help_enabled) ? NIL : T; } if (assoc_lookup(h, "sub_logout")) { session_log(session, "[cmd_compose] Logout"); session_redirect(session, request, "logout/compose"); return; } /* Subsiduary screens */ if (assoc_lookup(h, "sub_import")) { session_redirect(session, request, "include"); return; } if (assoc_lookup(h, "sub_attachments")) { session_redirect(session, request, "attachments"); return; } if (assoc_lookup(h, "sub_spell")) { session_log(session, "[cmd_compose] Spell Check"); session_redirect(session, request, "spell"); return; } /* Subsiduary actions which leave us on compose screen */ /* Enable/Disable rich headers */ if (assoc_lookup(h, "sub_rich_headers")) { session_log(session, "[cmd_compose] Rich headers enabled"); draft_rich_headers(draft, T); } if (assoc_lookup(h, "sub_no_rich_headers")) { session_log(session, "[cmd_compose] Rich headers disabled"); draft_rich_headers(draft, NIL); } if (assoc_lookup(h, "sub_large")) { session_log(session, "[cmd_compose] Large compose window"); session->compose_large = T; } if (assoc_lookup(h, "sub_small")) { session_log(session, "[cmd_compose] Small compose window"); session->compose_large = NIL; } if (assoc_lookup(h, "sub_clear_headers")) { session_log(session, "[cmd_compose] Clear headers"); draft_clear_hdrs(draft); } if (assoc_lookup(h, "sub_clear_body")) { session_log(session, "[cmd_compose] Clear body"); draft_clear_body(draft); } if (assoc_lookup(h, "sub_line_wrap")) { session_log(session, "[cmd_compose] Line wrap body"); draft_line_wrap_body(draft); } cmd_compose_generate_form(session); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/Makefile�����������������������������������������������������������������������������0000644�0065130�0065130�00000002503�11071071427�013231� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# $Cambridge: hermes/src/prayer/Makefile,v 1.5 2008/10/02 07:07:03 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2008 # See the file NOTICE for conditions of use and distribution. ifeq ($(strip $(RPM_BUILD)), true) include Config-RPM else include Config endif SUBDIRS = files lib shared session cmd templates servers utils ifeq ($(strip $(ACCOUNTD_ENABLE)), true) SUBDIRS += accountd endif all: for i in $(SUBDIRS); do $(MAKE) -C $$i all || exit; done cert: (cd files; $(MAKE) cert) install-cert: (cd files; $(MAKE) install-cert) install: $(MAKE) -C files install $(MAKE) -C man install # $(MAKE) -C templates install $(MAKE) -C servers install $(MAKE) -C utils install ifeq ($(strip $(ACCOUNTD_ENABLE)), true) $(MAKE) -C accountd install endif ifeq ($(strip $(RPM_BUILD)), true) (cd files; $(MAKE) redhat-install-init.d) endif redhat-start: (cd files; $(MAKE) redhat-install-init.d) chkconfig prayer --level 2345 on /etc/init.d/prayer start redhat-stop: @if [ -x /etc/init.d/prayer ]; then \ /etc/init.d/prayer stop; \ fi clean: rm -f core *.o *.flc *~ \#*\# rm -f defaults/*~ defaults/\#*\# rm -rf docs/*~ docs/\#*\# for i in $(SUBDIRS); do $(MAKE) -C $$i clean || exit; done distclean: clean (cd files; $(MAKE) distclean) cp defaults/Config defaults/Config-RPM . ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/Config�������������������������������������������������������������������������������0000644�0065130�0065130�00000014151�11775262635�012741� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# $Cambridge: hermes/src/prayer/defaults/Config,v 1.20 2011/06/17 15:22:57 dpc22 Exp $ # # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2002 # See the file NOTICE for conditions of use and distribution. # # Conventional Configure file. SSL_ENABLE = true # SSL requires OpenSSL SESSION_CACHE_ENABLE = true # SSL session cache Requires Berkeley DB 3 or 4 GZIP_ENABLE = true # Enable on the fly compression of pages LDAP_ENABLE = true # Add LDAP interface FENCE_ENABLE = false # Use Electric Fence to catch malloc problems MUTEX_SEMAPHORE = false # Use SYSV mutexes rather than file locking TIDY_ENABLE = true # Use libtidy for HTML sanitisation. # Following depend on the way that you have configured c-client CCLIENT_SSL_ENABLE = false # C-client was built with SSL support CCLIENT_PAM_ENABLE = false # C-client was built with PAM support CCLIENT_KERB_ENABLE = false # C-client was built with Kerberos support # Probably don't need the following RAVEN_ENABLE = false # Only of use in Cambridge at the moment. ACCOUNTD_ENABLE = false # Only of use in Cambridge at the moment. ACCOUNTD_SSL_ENABLE = false # Enable SSL support in account management daemon ACCOUNTD_PAM_ENABLE = true # Enable PAM support in account management daemon ############################################################################ # Location of compiler CC = gcc # Location of make program (GNU make required) MAKE = gmake # Location of install program (GNU install or compatible required) INSTALL = install # Base Compiler options for GCC (use CPPFLAGS and LDFLAGS if passed in) ifdef CPPFLAGS BASECFLAGS = $(CPPFLAGS) else BASECFLAGS = -Wall -g -O2 endif ifdef INCLUDES BASECFLAGS += $(INCLUDES) endif ifdef LDFLAGS BASELDFLAGS = $(LDFLAGS) else BASELDFLAGS = -g endif # Minimal libraries needed by Linux BASE_LIBS = -lcrypt -lutil # FreeBSD needs some extra libraries: # BASE_LIBS = -lcrypt -liconv -lutil # Solaris needs even more libararies: # BASE_LIBS = -lcrypt -lxnet -lnsl -lsocket # Base Compiler options for Sun SUNWspro compiler #CC = /opt/SUNWspro/bin/cc #BASECFLAGS = -fast #BASELDFLAGS = -s ############################################################################ # Location of various include files and libraries. ############################################################################ # Location of c-client library. # # Following works if we have a vanilla c-client installation at same level # as the prayer installation. Relies on a symbolic link ./prayer/c-client # which points to ../../imap/c-client. This just reduces the amount of # noise output on each line when building the package. # CCLIENT_DIR=../c-client CCLIENT_INCLUDE=-I $(CCLIENT_DIR) CCLIENT_LIBS=./$(CCLIENT_DIR)/c-client.a # # Following works with imap-devel RPM package from Redhat 7. # #CCLIENT_INCLUDE = -I/usr/include/imap #CCLIENT_LIBS = -lc-client # # Complication: # The Redhat RPM package links against SSL, PAM and kerberos libraries. # #CCLIENT_SSL_ENABLE = true #CCLIENT_PAM_ENABLE = true #CCLIENT_KERB_ENABLE = true # # Following works with the mail/cclient port from FreeBSD # #CCLIENT_INCLUDE = -I/usr/local/include/c-client #CCLIENT_LIBS = -L/usr/local/lib -lc-client4 # # Complication: # The FreeBSD port uses PAM and optionally SSL if built WITH_SSL=yes. # #CCLIENT_SSL_ENABLE = true #CCLIENT_KERB_ENABLE = true ############################################################################ # Electric fence (required if FENCE_ENABLE set) FENCE_INCLUDE= FENCE_LIBS=-lmcheck # Tidy library (required if TIDY_ENABLE set) TIDY_INCLUDE=-I/usr/include/tidy TIDY_LIBS=-ltidy # Add following if using tidyp fork. # TIDY_IS_TIDYP=true # Zlib (required if GZIP_ENABLE set) Z_INCLUDE = Z_LIBS = -lz # LDAP (required if LDAP_ENABLE set) LDAP_INCLUDE = LDAP_LIBS = -lldap # Pam (required if CCLIENT_PAM_ENABLE set) PAM_INCLUDE = PAM_LIBS = -lpam # Kerberos (required if CCLIENT_KERB_ENABLE set) KERB_INCLUDE = -I/usr/kerberos/include KERB_LIBS = -L/usr/kerberos/lib -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err # SSL definitions (required if SSL_ENABLE or CCLIENT_SSL_ENABLE set) # # Following suitable for Linux and FreeBSD which have SSL preinstalled # (Header files from OpenSSL 0.9.7 want to include various Kerboros stuff) # SSL_INCLUDE= -I/usr/kerberos/include SSL_LIBS=-lssl -lcrypto OPENSSL=openssl # Following definitions suitable for our Sun systems. #SSL_BASE=/opt/local/ssl/current #SSL_INCLUDE=-I ${SSL_BASE}/include #SSL_LIBS=-L ${SSL_BASE}/lib -lssl -lcrypto #OPENSSL=${SSL_BASE}/bin/openssl # DB definitions (required if SESSION_CACHE_ENABLE set) # # Following suitable for Redhat Linux which has DB 3 preinstalled DB_INCLUDE= DB_LIBS=-ldb # Following suitable for FreeBSD with DB 4 package installed #DB_INCLUDE=-I/usr/local/include/db4 #DB_LIBS=-L/usr/local/lib -ldb4 ############################################################################ # Install location of prayer configuration and support files. The initial # config file runs prayer processes as user "prayer" and group "prayer". # If you are using SSL, the certificate file must be readable by RW_USER or # RW_GROUP. It is important that nothing else can read the certificate file. # Build root (used by Redhat RPM system) BROOT= # Directory, User and group for read-write files: log files, sockets etc VAR_PREFIX = /var/spool/prayer RW_USER = prayer RW_GROUP = prayer # Root Directory, User and group for read-only configuration files. # Default configuration and permissions does not allow prayer user to # update prayer configuration file. PREFIX = /usr/local/prayer RO_USER = root RO_GROUP = prayer # Access permissions for general objects (wrt above users and groups) PUBLIC_EXEC = 0755 PUBLIC_DIR = 0755 PUBLIC_FILE = 0644 # Access permissions for private objects (wrt above users and groups) PRIVATE_EXEC = 0750 PRIVATE_DIR = 0750 PRIVATE_FILE = 0640 # Location of configuration files and binaries PRAYER_CONFIG_FILE = ${PREFIX}/etc/prayer.cf BIN_DIR = ${PREFIX}/sbin ACCOUNTD_CONFIG_FILE = ${PREFIX}/etc/prayer-accountd.cf �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/.cvsignore���������������������������������������������������������������������������0000644�0065130�0065130�00000000143�11063701632�013566� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# $Cambridge: hermes/src/prayer/.cvsignore,v 1.3 2008/09/16 09:59:54 dpc22 Exp $ Config Config-RPM �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/docs/��������������������������������������������������������������������������������0000755�0065130�0065130�00000000000�11775262602�012531� 5����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./prayer-1.3.5/docs/DONE-OLD������������������������������������������������������������������������0000644�0065130�0065130�00000152650�11063701634�013617� 0����������������������������������������������������������������������������������������������������ustar �dpc22���������������������������dpc22������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������$Cambridge: hermes/src/prayer/docs/DONE-OLD,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ 10/01/2002 ========== Lots of undocumented work cleaning up the user interface. This file probably now redundant! 18/11/2001 ========== Folder delete with confirmation disabled --> bang prayer process could end up hanging if far end gets stuck: added (long) timeout as countermeasure. <h3> --> <strong> on login and logout page until we can come up with something better. (and later fixed stray </h3>: sigh). Added (sometimes rather large) timeouts to all iostreams. Search for closest map in zoommap. Fixed logout screen Added html_session_message to help screen. Why does postmaster --> postmaster@hermes expansion work correctly even though no entry in map? Suspect some help from c-client here... - postmaster alias defined: need to include in map! list/unmark finds "closest" message before unmarking => no silly jumping around. Add "Sender:" to messages if/when From address changed. QP decoding on messages when Reply/ Forward: check closely! 16/11/2001 ========== Post message with invalid address --> boom. - Was failing to catch NIL response. Run through validator. - Done (check on live system tomorrow!). config file for accountd? Need to lift out stuff e.g: password strings. - First pass achieved Run through filter file test. Test QP engine again! Silly little bugs: Added "cc" to short header list for compose and display. Doh! rfc1522_decode stuff not working correctly in msg list screen? Refresh no longer pushs to last message in folder if new mail. Cc not copied when forwarding messages. "Compose new message" on abook_lookup screen not getting on well with roles. 15/11/2001 ========== Reply -> Linewrap -> send causes reproducible crash. - Fixed: rfc1522_encode being painful.. Restart from list with substitution: garbage in output - response_redirect has to discard any accumulated body data. Bugs: Sucessful passwd change crashes engine compare and contrast. Need to spot empty .MSforward upload - suggest read into array and then scan before writing file! Reverse arrival sort was broken. 14/11/2001 ========== Negotiate filter_restrict on login 13/11/2001 ========== Send binary downloads as HTTP/1.0 with use_persist disabled. - should work will all browsers this way. Need background colour set on some frontend pages: set of utility routines? Work out why icons pulled _every_ time that someone logs in from new session. - No idea: ask Jon Add foreground, link colours to documents Switched back to using text links rather than form entries on various folder screens: appears that forms within tables are illegal in HTML 4.01! - See Interface Changes Passed all screens through HTML validator looking for HTML markup bugs. 12/11/2001 ========== "-- " optimisations. IP address lock now selective. 06/11/2001 ========== Check/rationalise ping events: SSL Key generate. Log cycling. CDB reopen. Check error handling esp. logging of invalid input Fixed abook import stuff Save options more: After initial user interface level selection. Whenever abook updated. Done: may wish to only save when exiting abook_list screen? 02/11/2001 ========== BUG: Crash if sorting switched on in empty mailbox mail_sort doesn't like being passed an empty list? Fixed with special case. prayer-session crashes if ispell not present - catch error condition. Lost core dumps? - "daemon" option in Redhat init.d scripts disables this - Solution: just run prayer by hand 01/11/2001 ========== Fix rename -> Cancel bug __ICONS__ == /icons/ Need log rotation script User Preferences: Should have use_welcome and confirm logout on novice mode - help text correct? 30/10/2001 ========== Fix Date headers Fix check_cookie -> fail case. Simple redirection Lost core dumps? - No: just need to set ulimit -c unlimited - How do this portably? Help text on preferences screen should update immediately if user-level changed. 26/10/2001 ========== Sort out logging code (again): Either reopen log file for every entry or record inode and check it every couple of minutes ("struct log" as wrapper might help). 25/10/2001 ========== Fixed (Un)Delete and (Un)Mark bugs on display screen when sorting != arrival (didn't use zoommap). 23/10/2001 ========== Fix log/CDB file rotation. - DONE Make sure that invalid page requests return 404. robots.txt 22/10/2001 ========== Test concurrent access to mailfolder code with MBX folders Forward messages needs to track zoommap for sorted message Fixed Text/HTML stuff 19/10/2001 ========== Compose: Send, Cancel, Postpone should all return to correct parent screen. Does compose parent exist? Increased width of abook_xfer field 18/10/2001 ========== Folder transfer: replaced Buttons with links Extend compose lines Expanded welcome and user_level screen 13/10/2001 ========== User Preferences for sent-mail and postponed-msgs folders Mailbox --> Folder on Preferences screen 14/10/2001 ========== Change preferences code to only save stuff which is != default? means that we can quitely change defaults if problems emerge. Need to extend config to add missing option! 13/10/2001 ========== Completed code documentation after 4 days. Yuck! Need config options for sent-mail and postponed-msgs. Mailbox --> Folder on Preferences screen 09/10/2001 ========== account.c: Need to fix transparent reconnection + timeouts properly. accountd: Conver int -> BOOL accountd_server: need to support "red-intramail, yellow-intramail, ..." 08/10/2001 ========== Replace config_mailbox and config_maildir with session_XXX equivalents -> can apply more intelligence when building server locations. config: Add cdb maps for imapd, accountd server - DONE: Need to test, use in config_mailbox and config_dir Add support for separate accountd_nis server. Accountd: Use prayer style logging. config: Need support for imapd_server = "yellow-intramail : red-intramail : ..." config: Improve Documentation. Rename a few options? config: Parser should allocate into one pool, then copy into second to minimise overhead. Decided not (at least for the time being: quite a lot of work). Changed my mind! DONE. Check install procedure - Fix silly permissions. Generate self signed certificate as part of install (see stunnel install scripts). 08/10/2001 ========== Document command line options prayer+prayer_session Separate SSL startup from iostream_create: need two separate routines for client and server size startup. Add SSL to (both ends of) the accountd stuff - DONE: Need to fix + test Fix SSL accountd support. Accountd: Need config option plus accountd command line options to work around mail/ restriction! 06/10/2001 ========== Replaced MSconvert.pl with equivalent C. Need to test fully 03/10/2001 ========== Add config option to determine prayer_background Prayer session needs to support all options used by prayer frontend. Prayer -> prayer-session startup Close down unused sockets Need config option for min servers, max servers Session Idle mode: shut down IMAP connections after few minutes idle time. 28/09/2001 ========== Second go at install script: make config, edit ./Config, make, make install + make install-config + make install need proper redhat start and stop scripts. "make clean" should clear out Emacs backup files in docs directory. Rename prayer-backend ---> prayer-session Document properly (user + technical documentation). - docs/ mostly done now (will need to review!) 25/09/2001 ========== prayer-frontend --> prayer, should fork off subprocess First go an install scripts 25/09/2001 ========== Need correct MIME encoding when sending messages containing 8 bit chars - Done. Fixed attachment upload. Still some kind of problem involving download... Added directory cache upload button for cmd_folders and cmd_transfer. Need on other mailbox manipulation screens. 19/09/2001 ========== Short URLs links e.g: "AAAD@list@34@2" --> .../session/dpc22//AAAD@list@34@2 "/icons/fred.gif" --> .../icons:fred.gif Port to FreeBSD and Solaris. - Factor out OS dependant code into os.c: STARTED - Solaris needs EDG support, maybe fake urandom daemon using pwd hashes 12/09/2001 ========== Problem with SSL and Mac Netscape 4.7X: double clicks for many operations - Suggest: Use old/new versions of stunnel, see if any difference. - Answer Mac Netscape 4.7X appears to be broken. - Disable user_agent use_persist for Mac Netcape 4, come back and be more efficient later. 10/09/2001 ========== User Interface: Back --> Mailbox on some screens. Mailboxes--> folders. - DONE: may need to rename list --> mailbox (tedious!). Correct MIME encoding for ISO-latin-1 in headers please! - DONE: Test please! 10/09/2001 ========== string_printf() --> pool_printf(). Fix Makefile. Fix compilation with -Wall -W? - No: Lots of cases involving session where we might actually want - to use session logs etc at some later point 05/09/2001 ========== Why no coredump when running as root? - Answer: programs which start out running as root are paranoid about leaking state on at least some operating systems . Answer would be to bind ports, exec subprocess as unpriveldged user. Links should be buttons on mailboxes etc screen - Try one and see what it looks like. - Answer: looks good. Have done this everywhere. Add "Compose New message" to abook listing screen. Should backend_session_inet use asynchronous send as well as receive for normal requests? Appears to work just fine with aync input, sync output. One last go at "Undo"? - Undo is working correct, just not entirely intuitively. 03/09/2001 ========== Shortcuts in novice mode. Fix line wrap algorithmn: "I have" "Save message" needs to do a ml_check if save to open stream. From address on list screen should be link to display, not reply Address book import should translate: "Surname, Firstname". Small problem with compose and postponed messages? - tripping over own feet. Colour clues for Compose screen? 30/08/2001 ========== Problem with empty mail folders & compose? - can't duplicate! Login screen: Emphasis SSL Warning. Enter on Login screen should be login: NO: Don't think that you can do this w/o Javascript? Warning to user page: cmd_welcome Emphasise fact that people should log out! Tell them to use navigation icons on page rather than browser. Add abook alias: should be form button. Others? Add new addressbook entry should warn if overwriting existing alias cmd_seach: Year as input field rather than select. Single name rather than First Name/Last Name in addressbook 28/08/2001 ========== MIME torture test: Passed first time (thanks to c-client!). Mozilla however falls over in a heap. <Giggles>. See Interface Changes file. 28/08/2001 ========== Moved Favourite manipulation to subscreen of mailboxes. Replaced Logout icon Added "Check" icon. Added banner to bottom of display screen. Others too? - New: use_tail_banner option Switched icons on list screen around to match display screen. This might take several attempts to get it right. Add "check for new mail" button to list screen. Rearrange icons so that list and display correspond better? DONE Added "(Hermes) Webmail service" to title bar of all screens. Paperclip on cmd_display screen All: Put "Hermes Email Service: xxx" or similiar in title bar Initial User level: Indicate "_Webmail_ User Interface Level". Logout button. Logout screen should say logout from Hermes. 26/08/2001 ========== Improve directory cache: Shouldn't need to invalidate parts of cache automatically Need invalidate link! Factor out os dependant code into os.c - Added IP address handing code Preferences file: Need some useful way to wrap lines. - Can't think of terribly sensible way to do this without two stage parsing: string_get_lws_line followed by decode, _then_ split into tokens. - Lets stick with the current approach for the time being! frontend/session should bail out on illegal option 25/08/2001 ========== Folder transfer slow: Use multiappend for upload. Any way to improve download speeds? Done. Howeer, no obvious imporvement. Sigh! Caching problems with Mozilla, Netscape. Look at what hotmail do. - Answer: use Javascript to clear out history and Cache. Sigh :(. - Leave as is for the time being. Hide history list: Look at Javascript? - Leave as is for the time being 24/08/2001 ========== Better role system: NO Other languages: Later Fixed ghastly SSL bug: SSL * can mention own local read buffer. Need to check this before we select(). (use_persist == NIL) broken with direct connection. Almost certainly a problem with SSL * buffering? No: a completely separate bug. Hmmm! Mozilla caching far too much (Expires: ignored). - Yep: Doesn't seem any way to stop it. Sigh! - Check bug database. Warning message? Seperate window? - Seems to be true of all browsers. Check what Hotmail do. 23/08/2001 ========== Added border to abook_list Save deletes message Icons: Prev --> Previous on list and display pages Abook --> Addressbook on list and display pages Moved Back icon on display screen to the canonical place Added banner to reply page Lookup --> Expand on Directory page. Need Abook search to? Save message => mark as deleted. Should be option? 23/08/2001 ========== Abook lookups: case insensitive lookup done right at the assoc_lookup level... Save icon replaced (need a small version). Address Books -> Addressbooks singulat. Save Msgs: mark messages as deleted. Emphasis status line. (And hide if no status) Abook --> Addressbook, Prebv --> Previous etc 22/08/2001 ========== TUS meeting. 21/08/2001 ========== Warning on HTTP screen (infer default HTTPS channel!) Accountd needs to have new canon encoding iostream.c: SSL_accept should not be fatal error Translate to be end of file Attachment download: Need to translate ' ' -> '_' in URL for attachment name somehow 17/08/2001 ========== Upload/Download mail folder broken? - Fixed. Still some speed issues here. Verify configuration properly! - Done. May need to test fully abook.c: Use hash for lookup Lost favourites list? Clean up management screens when accountd disabled. - No: they are fine the way that they are I think Added icons to logout and rm screens to keep vrw10 happy... r -> request in request.c and response.c Fixed string_get_lws and use for e.g prefences. Added whole bunch of stuff to config file Need length limits for method and headers as well as body - DONE. Also fixed the response_error stuff (again) 16/08/2001 ========== Sanity check prefs esp: From, Reply-To and alt-addresses Session preferences handled correctly? Automatic update should take effect Add user_agent debug page SSL: Do we need to support DH? Yes What is DH? Still no idea! Separate out as module? : NO Check Quota error handling - First part complete: on the right track! - Test things more extensively as we go on Verify Reply-To address in role system! - DONE. Also fixed silly bug with empty alias! 15/08/2001 ========== Better logging: More session events. Log HTTP level + response code sent to broswer 09/08/2001 ========== string_canon_encode() && string_canon_decode() - appears to be some kind of obscure bug with '@' in URLs and Mozilla 0.9.2? Appeared to be specific to cmd_display and cmd_rawdisplay. Replace with url_encode/url_decode throughout? - Need to investigate some. - Switched string_canon_encode to use '%' rather than '@' - lets see if this has any unpleasant side effects! Bugs: Folder download broken? Long delay: - Downloading large folder from IMAP server takes time! - Some kind of feedback would be useful! Attachment Download names silly - Fixed (I hope...) Forward and reply should forward attachments too, (as an option). - Already does this! Put sessions into own process group so that kill signal to server doesn't kill everything (actually rather useful while developing!) - Probably not Personalisated From as well as default domain - DONE Stuff affecting UI: Rich headers? Dircache invalidate root doesn't work! - Now fixed Fix frontend reuse-connection stuff for ports 9090 etc - Need test case to show to Ben! Check that every string printed as html goes through buffer_puts_quote_html! - DONE 08/08/2001 ========== Need override mechanism for session setup: user_agent=mozilla, netscape, ie, lynx, other debug record_telemetry. failsafe (equiv: disable = all) disable = 1.1, persist, <-- Only one that frontend interested in icons, cookie, frame, html_inline, html_inline_auto, preserve_mimetype enable = (the same) - fixed silly bug with user-agent stuff Abook lookup should convert hermes -> hermes.cam.ac.uk etc? - NO Better hash function. - Look at Perl algorithm - No: Existing one seems fine. Use sigaction plus robust repear everywhere. Signal handling code: At very least backend master server should remove session sockets. - No: current arrangement works rather well thank you! Netscape has problems if images disabled - but only if frame in use => Netscape bug! Added return_path_domain config option. 06/08/2001 ========== Mike O'Donahue needs quoting. backend_session_inet can now cope with arbitary number of simultaneous connections to backend. Question: Do we need asynchronous responses too? Fix ml stuff: no automatic reopen... : DONE Streams: Flush .prayer file after each prefs/abook update: Would need special stream. :: DONE Special stream for uploads/downloaded :: DONE Crash after timeout (UIDs changed)? - Need to check this consistency. Check all session_redirect --> "restart" - FIXED: was failure to call zoommap_associate after reopen! Need to test all ioXXX fns for error codes No: io fns all silently discard output on error condition Only need to worry about this for fns that generate lots of output. - Should be safe 31/07/2001 ========== Pat thinks that "maintainly maintained forward file" stuff not obvious. Can't distinguish "no such file" from other NO responses from accountd server. Propose either: NO [NOEXISTS] ... or OK {0} Message sending using c-client SMTP routines Use c-client routines to construct message with attachments - less likely to break down? - Look at Pine code for sending messages - NO: own version is fine. - apart from CRLF -> LF conversion which is a ghastly hack. - Consistent use of c-client message handling code could make our life much easier... - NO: Exim handling error queue much nicer. Abook sorting. Probably not. Adopt Exim style syntax for configuration file. 30/07/2001 ========== Possible to use Keep-Alive for permanant sessions, not for icons? - Removes overhead associated with SSL channel startup. - Part of the way there: HTTP redirects are a pain... - DONE: separate timeouts for icons and session connections. Use short session_prefix if User agent can cope? - Netscape + Outlook seem fine. Lynx chokes. - 12K -> 10K (cmd_list) - 16K -> 12K (cmd_list) - 30K -> 24K (cmd_mailboxes) - Is a 30% saving really worthwhile? :: NO, probably not! Repeated headers in HTTP request: Currently concatinated, Any situation where this is incorrect thing to do? What does Apache do in this situation? Check Apache behaviour in general: might learn a few useful lesons. - cookies only likely problem case: have list/last split - Do nothing, at least for the moment. Possible to remove intermediate copies of HTTP Requests/Responses using chunked encoding. Looks like we have to supprt chunked requests at least properly. Sigh... - One case still to be dealt with. Marked in source Rename: zoommap -> msgmap to reflect additional functionality - NO: Leave it alone! Capability database for user agents: Session Persist (yes for everything which supports persistent) Icons Persist (no for Netscape, ?Mozilla) HTTP Pipeline (yes if we ever find a broswer which supports it!) Use icons (yes by default, no for Lynx and other text only) Use frame (yes if likely to be useful) Use Javascript (yes if likely to be useful) HTTP Redirect Persist (yes if session can persist across HTTP redirect) HTTP POST Persist (yes if session can persist across HTTP POST) Send icons over HTTP link Need consistant way of splitting up User-Agent strings Clean up .prayer file: Version number Wrap/unwrap long lines true/false rather than 0/1. _Some_ level of sanity checking. However current strategy of ignoring everything that we don't understand works reasonably well. Password changes: Need to remember two passwords, switch magically - DONE: Still need to test properly. Add confirmation dialogue for delete mail folder - DONE 29/07/2001 ========== Remove proxy (as option) o could run each backend server on different port, :: DONE with master server a la inetd to catch requests to expired :: DONE slots which have not been reused. 24/07/2001 ========== o Possible to send icons over non-https channel? : DONE as hack - Icons channels should only use Keep-Alive if we are confident that it is likely to be a benifit e.g: HTTP/1.1 pipeline - RAN TEST: Works in IE and Mozilla but not Netscape (sigh) - Need some kind of capability table for browsers... Added extra links on cmd_list screen Added year to Dates on cmd_list, cmd_reply eytc screens. Use prefork at frontend 23/07/2001 ========== Need directory permissions in prayer.cf file - DONE Move files to /usr/local/prayer/[version] and /var/spool/prayer/[stuff] - DONE Added check_directory_perms option to check directory permissions on $var_prefix and directories that appear under it. - not 100% there but should be good enough. Automatically create directory hierachy if doesn't exist. - Need some way to define directory permissions in config file. Better line wrap algorithmn - DONE earlier Split frontend/backend? DONE! 20/07/2001 ========== iostream.c -> frontend_iostream.c & backend_iostream.c. Only compile in SSL support if it is required! 19/07/2001 ========== Add setproctitle with some useful information. 16/07/2001 ========== Add session default preferences to config option e.g: window sizes 13/07/2001 ========== Configuration file tuning. Address lookups: If unqualified address doesn't appear in abook, hermes or cam databases then its an invalid address: should report as such immediately rather than trying to send mail? 12/07/2001 ========== Configuration file. 10/07/2001 ========== Rename: int -> unsigned long or BOOL forall int printf routines should support/use lu rather than d - DONE. About 3 hours work! Generic List function. - DONE: moved all the obvious things over to use it Replace ioputs, bgetc, bputs etc with macros 09/07/2001 ========== Further work on Line Wrap algorithmn Mixed cased aliases in name. Funny interactions with Mozilla: need extra CRLFs somewhere? - Extra CRLF at end of each response appears to fix this - read RFCs a bit more closely Sort out modal help text. Forward as postmaster, lookup "Pat" crashes? - No: large amount of text in Compose window stops User Agent = from sending. - Look at RFCs, make sure that its not Prayer doing something - stupid with byte counts. session_check_streams? - ml_ping inbox and other if > 20 mins : DONE - close postponed, transfer and prefs streams if > 20 mins : DONE abook_entry_to_string: code duplicated in one or two places: should try and factor out set of routines that are single place so that any updates can be made consistantly. - abook_entry_to_string() itself - abook_list - should interpret strings better: See "joel" entry - add_address - clone of abooj_entry_to_strin() code is marked XXX - DONE 05/07/2001 ========== Need better line wrap algorithmn which wraps in blocks... - DONE. Hurrah! That was hard work! Date search broken - Fixed 04/07/2001 ========== Pat: has some messages that blow up Prayer Fixed: invalid QP messages Roger managed to blow system up on preferences screen: Yes - works for me too now. The only thing I had done in the previous session before attempting to change the reply-to header default value was to send a message. However, doing that now still works. - Fixed: options->prefs_save = options->prefs without copy. DPC: Small button loses headers. Deja vu... - Fixed DPC: Spell check in "Large" mode corrupts headers - Fixed PH: Fixed cmd_help() to record last help text displayed for reload. redirect file: I went to the mail redirection screen. It correctly showed my redirection to CUS. However, below the top line of links it said: Status: Account Server response: no such file which seems a bit odd. Believe that he means vacation screen, however need to check this. Added a few literal_catch_no - may be better to have server generate OK {0} for empty files. Added "Send" button on Large screen. 6. I did a speeling check. It picked up the error and said it was highlighted, but it wasn't. Seems to be there! <pre> <b>Hllo</b> Wrld </pre> cmd_add_address wasn't dealing with: Joel Seymour "Joel Seymour <addr>" in same way as main abook_entry -> string routine. [Have companion routine?] CJ: Wants rawdisplay to rawdisplay: DONE PH: Would like "Switch to inbox" on list screen Not done unless someone else asks for it. 03/07/2001 ========== Use cdb database of CRSid->Full name mapping in both places. - Come back and do this later - Can also use CRSid database to decide when unqualified filter is safe (dpc22 --> dpc22@*cam.ac.uk) - Partly (mostly!) done. Add comment: "including XX attachments" in postpone and forward code. Addressbook lookup bug? Stella -> bang? Assorted tidying up. Fixed mailboxes bug Address parsing --------------- Default domain for outgoing messages. Stella stuff ============ June 25 - Reply all with 1 address in cc: produces a surplus comma To: Stella Page <sp253@cam.ac.uk> Cc: , spage@kanina.freeserve.co.uk - can't reproduce this 02/07/2001 ========== T/C/B links on abook_list/abook_search pages now To/Cc/Bcc Extra checks on form input into abook_entry... Sort out HTTP headers in response Current situation is overkill - DONE. Mozilla caches regardless :(. Extra user options: Display HTML mail Display text/plain that start <HTML> as HTML... DONE cmd_display(), cmd_reply2() and cmd_forward1(): All call ml_fetchbody(), then immediately set initial_msg[len] = '\0'; - is this safe? - better way to do this? - factor out common code - Made all consistent. - Sufficient space is allocated, so string[len] = '\0'; can't hurt? Postpone message with attachments: Attachements get lost? - can't reproduce Fix <td nowrap> problems in mailbox etc screens - Possible to define single mailbox "class" that calls back defined routines to fill in the skeleton. - appears to be sorted now. 29/06/2001 ========== Replace list_add, list_remove with: list_push, list_pop, list_shift, list_unshift - use unshift in filter menu Fix frame use: init2 shouldn't be visible! Reverse sort toggle 28/06/2001 ========== cmd_list: Trailer banner not correct if mail folder empty. Display HTML inline with links Need to do this carefully to remove scripts Any conventions about correct way to do this? - steal code from sqwebmail which appears to have the right ideas. - DONE Need to improve html_secure_strip_all() - replace with html_to_text fn that strips all tags, and can translate <&> style codes! - DONE 27/06/2001 ========== sp253 bug reports: June 07 - problem with Addressbook Entry regrettably not reliably reproducible After a series of actions, e.g. adding and deleting entries, there comes a point when an attempt to add an entry fails quietly - i.e. after the Add/Update entry button is used the user is returned to the Addressbook list screen but the new entry has not been added June 07 - possible enhancement don't let the buggers add an address entry without an alias part. June 19 - HTML buglet - Address Search two <form> and only one </form> June 19 - I would like to add some general words of wisdom somewhere along the lines of if you don't logout and the session times out you'll lose any changes you made to addressbook or options. Could be somewhere general or could be on options and addressbook entry pages. Latter easier owing to handy links already there. General location would also be nice - where? June 21 - bug in novice message list screen - remove "Mark" td in tr June 21 - with frames off I still get a target=_top assoc with Logout Options screen June 22 - problem with changing password. After an initial couple of deliberate mistakes entered correct current and valid new. After selecting Change Password the session "hung" in the sense that the only action accepted was to use the "Stop" button in Netscape. An accountd was started on prism at the time at which the Change Password button used sp999 15271 5250 0 12:27:38 ? 0:00 ./accountd --daemon June 25 - Message list screen. If "Mark All" selected, then "Zoom" should not appear June 25 - small buglet in message listing - to do with division of number of messages in mailbox by number you want to list? Scenario:- Start with listing 20 messages Take a mailbox with 20 messages in it. Change to listing 10 Using the Prev/Next/First/Last buttons will only show you 1-10 and 20 (it is not possible to list 11-19) There is a subtly different thing if you change to, say, 9 or the default 12 messages per screen, the movement through the mailbox using Prev/Next/First/Last is:- - choosing 12 messages lists 1-12 and 12-20 (rather than 13-20) - choosing 9 lists 1-9, 9-17, 18-20 June 25 - stray (control) characters in "ACTION=" in forms. Unfortunately I can't trace when/how this started but I am now noticing it every time I View Source or save a page, e.g. in mailbox list screen (not maybe the most useful bug report :-( ) FIXED: Actually stray <form> on banner screens after favourite folders set up. Missing fl->form = NIL in banner_reset; June 25 - there are some stray wrapping of text in table cells. Examples include - mailbox list after one or more "favourite" mailboxes selected - Need to fix systematically - single mailbox listing fn with callbacks would be very useful. - Moved to separate TODO list 27/06/2001 ========== Passwords, quota etc screen: We are missing a screen for changing passwords, checking quotas and setting vacation/forward messages. This is going to require some kind of special protocol server at the Hermes end. 21/06/2001 ========== Added: Password Change Fullname Change Check Quota Added (Un)Mark All to cmd_list screen Moved search icon from top to bottom of screen Experimental: Removed nowrap from banner lines Switch off 'font size="2"' for time being Added sort on To and Cc 16/06/2001 ========== Add "favorite favourite" folder - DONE Add shortcuts for subscribed folders at bottom of list screen. - (Not convinced that we actually want to do this) - Save marked messages to nominated folder - Change to nominated folder - DONE! Use HTTP/1.1 Pipelining when Mozilla/Outlook support it reliably. - Should be able to push lots of icons down a single connection! - DONE previously 14/06/2001 ========== Help text layout from Stella: I think the following should all be part of one page compose/{role_list, normal, large} options/{general, folder, compose, advanced} I am easy on search - I am quite happy to amalgamate the existing separate pages for Text, Date, Status and Size into the main Search page. You're letting novices transfer mailboxes but not addressbooks? Folder sorting - new improved zoommap that combines sorting and zoom mode - should probably rename as "msgmap". 12/06/2001 ========== Rearranged source tree: src and files subdirectories... Pine addressbook import/export - Partly done: have address book export/import - Need to switch to using Pine format address books, which appear to be a series of TAB separated items: Single item: alias\tName\taddress\tComment Distribution list: alias\tName\t(addr1,addr2,addr3)\tFcc\tComment In both cases LWS padding in use! - FINISHED modulo testing. Hurrah! Mail folder import/export (standard Unix format mail folder). - DONE mostly: still need to clean up a little bit. 11/06/2001 ========== Use Frame to remove history list - DONE Mail folder import/export (standard Unix format mail folder). - DONE (need to clean up a little bit!) Address book import/export - First attempt finished. Need to refine. Record session_redirects in log! - DONE Improve HTTP error page (have links back to main session?) - DONE 07/06/2001 ========== Added HTTP 1.1 Pipeling? - Need some way to test this? Extra options: Autozoom after search Autounzoom after aggregate operation "save to sent-mail" should be permanently unsettable Use frameset to hide history Use HTTP redirects Check user interface: Add session_message() and session_log calls as appropriate. - DONE PARTLY come back later and see what else is possible. Need extra abstraction level to remove duplicate calls? : NO Make sure that every ml_ call checked for error conditions about 1 days work. Do a ml_ping if session idle for more than approx 20 minutes. - Need separate timestamps for each MAILSTREAM. - ml_XXX routines can recover last access on each stream... - Actually now do ping and then checkpoint - might what to make the checkpoingt optional Try to reduce nnumber of random cmd_restart calls? Possible: Make cmd_XXX fns return (T) or (NIL) - NIL -> automatic redirect to cmd_restart? - Tried this: ended up being far more complex that needed - Current situation is better arrangement: each cmd_XXX routine will always generate a page or redirect even if it wasn't the page that you were expecting after a few transparent redirects. Session caching Get rid of HTTP redirects: (as option only!) This causes session to disconnect. Netscape only: IE better behaved (sigh!) Better now, however POST still seems to confuse Netscape. <Sigh>. Record session sequence number and replay last command if sequence number doesn't match 06/06/2001 ========== Worked out why Mozilla is not using Persistent HTTP connections: Mozilla is broken! Logging: Possible to log more information than at the moment? - User_Agent and other headers. 05/06/2001 ========== Help text: Need stubs for forms in help text. (Must be way to have inactive form!) Need __PREFIX__ and __SESSION_PREFIX__ substitution in help text. 11 remaining XXX comments! - remove 2->3, include remainder in this file for sorting. - DONE Bugs: ----- Better handling for undo. - Undo completely broken. Remove entirely? - _believe_ that this is working now. Let Stella loose on it? Spell checker needs some work: Case problems. Why does it convert first word to lower case? - Appears to be okay now that we have removed a few lcases! Remove html_table*, html_form* nonsense with minimal set of functions, plus some macros to generate form and table elements. - No: current naming scheme makes much more sense. - Only problem is that some of the names are > 14 characters zoommap: - Use memblock to avoid need to allocate, reallocate block? : DONE - Partial invalidation should now be possible! No, typically more work to work out which parts of the zoommap are still valid then to you rebuild the entire thing (esp now malloc()/free() overhead is removed, MAILSTREAM scan is only remaining bottleneck). zoommap - Define stream/zoommap abstraction: - mark message - unmark message - clear all marks - set all marks => won't need to worry about getting zm_invalidates correct => no main program use of elt->spae => may be able to optimise certain cases - DONE 04/06/2001 ========== Should be possible to eliminate a lot of strip_whitespaces if string processing routines do this automatically. Does anything actually _need_ leading/trailing whitespace preserved? Look for strip_whitespace references. - Was done at some point in the past. request_decode_get() and request_decode_post() do string_url_decode for us. Check that we aren't duplicating this elsewhere. - DONE. Need maximum Request-Size: (25 Mbytes?) - DONE (need to clean up error strings a bit!) Check Makefile dependancies. makedepend? - DONE cmd_dispatch(): - Switch to use binary chop SSL support: Need to regenerate RSA temporary key once an hour - DONE zoommap_find(): Switch to use binary chop - DONE Fixed silly bug in mark/unmark code: - Forgot to run zoommap invalidate - Would be be better to abstract out all changes to the zoommap -> know when to invalidate. - FIXED Use STR * instead of char * for strings - record size in each string could make a number of string operations a lot more efficient - Lots of work: Think some about this. - Thought: I don't think that we need this. Only real use is to make strip_whitespace more efficient, and should be possible to do this automatically. - DISCARD 30/05/2001 ========== Need to get rid of icons on mailboxes etc screen - DONE Add message status icons unless (prefs->use_icons == NIL) - DONE. Need combined icons for mark? Many assorted small cleanups (Reduced XXX comment count 75 --> 12) - replace individual mail_flag with sequences - replace mail_append with mail_copy (inc sequence) when appropriate - ml_append does auto_create on TRYCREATE - add &len parameter to draft_make_recipients and draft_make_msg (removes silly strlens on msg) - paniclog <-> mm_fatal cleanup and rationalisation (still need to log errrors). - alt_addr stuff in cmd_display lifted one level - ml_fill_overview() [still need zoommap version!] - html_XXX routines renames html_XXX_table where appropriate Replace delete/undelete etc aggregate with sequence range stuff from cmd_list.c - DONE folder object to route mail folder manipulation through one location? - NO Addressbook lookup applies far too many strip_whitespaces. - No longer the case! Session timeouts: backend should just shut down after n mins of inactivity (should be easy!) - Did this some time ago! 29/05/2001 ========== Added address and subject length cap (using string_prune) on cmd_compose (postponed message) and cmd_list screens. Replace all UID tests in cmd_delete etc with single call. 25/05/2001 ========== May 23 - HTML buglet - Options form - <H3>General Options:</H3> <td><input type="hidden" name="type" value="general"></td> The <TD></TD> is not inside a table - No <P></P> round "User Interface Level:" although I agree this buggers the spacing. Works with another TABLE May 23 - HTML buglet - Options -> Roles Multiple occurrences of <HTML> <HEAD><TITLE>Roles etc. No

    round "Options:" May 24 - Did you say you were going to add a "Back" to the main options screen? May 22 - Options form - What's on each sub-form in the way of "Help", "Back" etc is different. There's nothing under "General", "Folder" or "Compose". There's 3 GIFS under "Roles" and a "Back" input choice under "Personal Dictionary". - there doesn't seem to be an "action" defined for the POST at the top of the form? May 24 - two probably thick queries about the Dictionary screen. - If they can delete worms by clicking on them do they really need a "Remove" field as well? - Won't it confuse the little dears if they enter a Worm with a capital and it appears as a worm without a capital and in front of the all-lower-case worms? May 22 - odd needs - Forms in help text, if help is HTML rather than GIF based. - We need a null stub for POST and GET. One to cover both that just returns a "Nope, not active" type message? Named something like action="https://magenta.csi.cam.ac.uk:8080/actionstub" maybe? - I imagine input type="submit" things would be dealt with as-if-by-magic if the action changed? ------------------------------------------- May 24 - trouble with Spell Check. My original message was:- Morandacat and I would like to invite you to join us, that is me and mirandacat at home at CB1 3LL or rather CB1 3LD. That should trigger something in the spell checker! By the time I'd spell checked it (a) it didn't seem to pick up my all my Personal Dictionary words - these contain CB1 (which it did accept as OK), mirandacat and 3LD (which it didn't), and it changed everything to lower case thus morandacat and I would like to invite you to join us, that is me and mirandacat at home at CB1 3ll or rather CB1 3ld. That should trigger something in the spell checker! This appears to be related to the fact that the Personal Dictionary screen seems to auto-convert everything to lower case - see point above this? 22/05/2001 ========== Add lots of help text icons, just to cheer up Stella Delete folder fails to remove from dircache? Message status for messages > 100 in folder not displayed correctly!!! - DONE (silly string -> number conversion bug !) Fixed running against Netscape 4.08 (ghastly hack stolen from old version of Stunnel is not required with modern versions of openssl library: #define SSL_CTX_set_tmp_rsa_callback(ctx,cb) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,0,(char *)cb) Small spelling buglets - Compose screen reached in expert mode after "Forward marked" selected. Subject: ^seperate^separate Small HTML buglets and queries - change fairly generic, seen in message list screen, mailboxes screen - delete the after the CRSid of the logged-in-user screens so far - message list, mailboxes, addressbook - in the message list screen - the first add " "
    so far seen in - message list screen - can the blank ALT tags be filled in with something? - tables - delete the and matching just before bit as it's in/applicable to TDs screens so far - message list, mailboxes, addressbook Stella ====== Date visible in message srceen listing changes when saving a message: Message sent on 17th May shows as that in inbox 20. No May 17 Pat Stewart 1K An FAQ? D S R F Save message to folder Date visible in message screen listing is date of save 157. No May 18 Pat Stewart 1K An FAQ? D S R F ============================================================= Random small things - Sometimes they're mailboxes and sometimes mail folders, e.g. see the "Mailboxes" screen with Subscribed "mail folders" and creating "mailbox". Is there any point in standardising on one name? 21/05/2001 ========== Check running against Mozilla - Hangs: expecting more input that it is getting on each transaction? Extraneous CRLF in send_html interaction. Something funny going on with Back button in Roles screen: HTTP/1.0 200 OK Date: Tue, 08 May 2001 12:18:07 GMT Server: Prayer/0.0 MIME-Version: 1.0 Allow: GET, HEAD, POST Connection: Keep-Alive Content-Type: text/html; charset=iso-8859-1 Pragma: no-cache Cache-control: no-cache Expires: Tue, 08 May 2001 12:18:07 GMT Content-Length: 1589 blatted across the top of the screen, above the otherwise normal remainder of the form. A long pause showing the watch cursor ensues. I was going "back" from "roles" to "options". In fact it seems to be repeatable. FIXED: either CRLF bug or string_itoa_tmp bug 17/05/2001 ========== IMAP connection dropped after 30 minutes idle time. - Need automatic/transparent reconnect:: DONE 16/05/2001 ========== Transparently create sent-mail folder just like the others. - Should work. TRYCREATE stuff broken? - TRYCREATE stuff fixed, hopefully consistent. Putting an entry such as cs-info in the addressbook shows us as cs%2Dinfo - Fixed: missing buffer_puts_quote_html 15/05/2001 ========== Need inactive icons on message display screen. - DONE Text under icons too small. - Made them a bit bigger. Draft <-> Role integration - Select role on compose screen - Trigger role based on address book. - NO: at least not on this interation. 09/05/2001 ========== Objective: ========== Have something useful by next MDCM (9th May). - DONE! 04/05/2001 ========== Looking for silly MM bug. Session disconnect. 03/05/2001 ========== Logging ------- Need to log normal + abnormal events - 2/3 days work. - DONE Extra options - about two days work. ------------- Simple options: - Use icons. - Size of Small and Large Compose windows: DONE Advanced options, disabled by default: DONE using USER_LEVEL - Roles : DONE - Postpone message : DONE - Spell check : DONE - Large/Small window. : DONE Prettify the interface - DONE (some tweaking remains?) Unmark after aggregate operation - DONE (test fully!) 02/05/2001 ========== Icons ----- Need to apply icons - Need separate HTTP and HTTPS listeners! Easy route: - repeat headers x 2 Harder route: - build up list and apply. 01/05/2001 ========== Fixed ISO-8859-1 address display. Question: other charsets? 30/04/2001 ========== Assorted things that I've decided not to do. -------------------------------------------- Printing? - should be reasonably easy for plain text. - what to we do about inline graphics etc? - NO: Not unless we are specifically asked for this. Private version of rfc822_parse_adrlist based on pool allocation might be useful. Would remove lots of fun memory allocation. - Quick look suggests lots of duplication from c-client. - Private library of address parsing code might be appropriate! Spelling list ------------- - need ability to add and remove words from the personal dictionary Search ------ Search on date, status and size addr.c ------ Nasty mess: must be a better way to do this! - DONE. (Stolen some code from Pine to estimate size of ADDR!) Misc ---- Eliminated a few strlen and sprintf calls. msgno should be long throughout: check. 27/04/2001 ========== Fixed include and attachments options ------------------------------------- - string_get_lws_line was broken. Sigh... Fixed "reply" bug: Need to check Makefile dependancies are correct Clean up session structure :: Unknown -------------------------- Move data out into sub-structures :: NO - Probably not: just clean up into groups. :: DONE Possible to support multiple folders? :: DONE - inbox and other. Why do we have two IMAP sessions open at the moment? - FIXED Use multiple IMAP sessions: DONE INBOX postponed messages One other folder != inbox Cleaned up cmd_restart code: DONE Cleaned up init code: only needs single IMAP session to get started 26/04/2001 ========== Postponed messages :: 2 days ------------------ Proper postponed message folder - "Postpone" button saves to folder - "Compose" looks for postponed messages (have flag) - "Need to check for postponed messages at startup 25/04/2001 ========== Option screens :: 1 day :: DONE in entirity -------------- Make options screens work properly. - Need three copies of preferences data: initial : In case we want to rewrite .prayer folder active : Working options working : for updates within options screen before commit - Primitives: Create new empty preferences list Generate copy of preferences Free up list of preferences. - Question: use pools? Preferences don't change very frequently. Move abook and dictionary outside prefs. Address parsing :: 1 day --------------- Use local versions of c-client routines for both address book lookup and message sending. Also alt_addr stuff. DONE Use cdb database of CRSid->Full name mapping in both places. - Come back and do this later 11/04/2001 ========== - Clean up folder list - DONE - integrate directory cache - DONE - spread options over multiple screens - DONE (Add more options!) Address book lookup: Recursive aliases? - DONE Need some way to detect loops. - DONE Could be more efficient! Directory cache: DONE - at the moment invalidate whenever anything changes - possible to make this more efficient? cmd_mailboxes()/cmd_save()/cmd_rename(): - Sort out confusion and duplication - (suggest three separate cmd_files with common code factored out) - Done. 10/10/2000 ========== - "compose/fresh". - Expunge with large numbers of messages -> out of memory last < first at line 236 of cmd_list_simple(). - variant on the "Re: Re:" bug, now only applicable if the Re: is capitalised (RE:) - purge in zoom mode crashes need to invalidate zoom map and recalculate session->marked. - Undisclosed Recipient list. - Replying to From: "Eburne, Katharine" strips off the quotes and sends to To: Eburne@cam.ac.uk, Katharine - Should always download as octet/byte-stream - Attachment names. - Aggregate save misses stream->nmsgs Things done by 10/10/2000 ========================= cmd_compose(): Large window mode: DONE Sort out silly interdependancies: DONE Add undo option: DONE cmd_list(): Should prefetch envelope data as single mail_xxx operation. Currently many round trips to server. cmd_list(): Move search stuff to bottom of screen: DONE FULL hdrs in cmd_display Things done by 01/10/2000 ========================= Replace popen() in cmd_send with some sane code. - DONE (Need to test properly!) Add personal dictionary to spell check: DONE - Stage 1: Accept for spell check run - add to tmp personal dict - File processed line by line: need to remember accepts for current line (request->pool fine!) - Step 2: Add perseonal dictionary - Store as "Dict: " lines in prefs message. - send to /tmp file each time speller starts - record changes to personal dictionary immediately => don't have to parse /tmp file. - Try to clean up variable names used in struct speller: - multiple I/O streams rather confusing at the moment. Things done by 11/08/2000 ========================= Important: ========== Need some way to pass IP address of client on to backend to check okay. Suggest special header line at start of request that is only allowed on proxy connections. DON'T worry about HTTP/1.1 - make sure that HTTP/1.0 code is stable - HTTP 1.1 fron end can be bolted on afterwards, shouldn't affect rest of the code Add support for Cookies. Need unique session IDsx Other ===== Improve error reports. request_* code should use any of CR, LF and CRLF for line break - Break on CR or LF - If CR swallow LF if next character - not urgent, should be able to replace method by method Need to fix hash_insert Server response 501 (Not implemented) for anything that we recognise, don't implement. OLD list ======== Replace message -> buffer (so name reflects actual use) - New methods bputc (macro) bputchar buffer_seek_offset (simple implementation) buffer_printf (simple implementation: use sprintf) bprintf Add simple explanatory message body to error messages - response_error(status) - All responses other than following must have Content-Length header: 1xx (informational, not used in 1.0) 204 (no content) 304 (not modified) 0.9 request => reply with imformative message. DONE. Need some way to test. %XY decoding in URLs - Don't think that we actually need this for Webmail only app. Check ".." checking correct - don't expect ".." to be vaoid Add nodup option to hash_update. Need versions of hash and buffer data types which work without pool - suggest that NIL => no pool - use alloc (malloc with fatal) instead of pool_alloc - pool_alloc could use malloc if NIL Get rid of ALL fixed length buffers that might involve user input? POST requests must content Content-Length in 1.0 - should generate 400 (bad request) if they don't BUFFERSIZE of 0 for buffer_create etc should be same as iostream_create - use system provided default URL encoding: Currently using '@XY' to encode special characters for both URLs and GET forms. WING only uses '@' in URLs where '%' might be interpreted by Apache. Do the same thing? DONE: %XY used everywhere apart from filenames which are embedded directly in URLs HTTP 1.0 only server: Possible to merge iostream and buffer, reduce data copying only IO operations that we actually need are: read entire request write entire response. Actually rather messy as we need to calculate Content-Length in header. Simplest solution is to generate response body, then header and combined. Requires multiple small writes without iostream. ./prayer-1.3.5/docs/LICENCE0000644006513000651300000004321711063701634013516 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/LICENCE,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ./prayer-1.3.5/docs/FEATURES0000644006513000651300000000632711063701634013673 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/FEATURES,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ Performance/Scalability ======================= Persistent Login Sessions: - (Multiple) persistent connections to IMAP and support servers. - Directory cache: single round trip to IMAP server for directory listing. - Works well with UW IMAP server (even using Unix format mail folders). Written entirely in C as HTTP <--> IMAP Gateway. No scripting languages. - No discernible load on a Pentium III class system with 3,000 logins/day - Aggresive HTTP/1.0 and 1.1 connection caching to reduce SSL overhead. - Minimal use of fixed length buffers in C source code. Single Webmail gateway can run on a number of small independant systems: Simple horizontal scalability if needed. Simplicity ========== Few external dependancies (Libraries: c-client, OpenSSL. Optional: cdb). - No external database: user preferences stored on IMAP server. - Single configuration file. Doesn't use Javascript or Frames. - Runs quite happily with Netscape, Mozilla, IE, Lynx, Opera. - Text only mode for Lynx and w3m - Use of nested tables restricted to avoid confusing Lynx. Doesn't need cookies: - Single optional cookie used to hide session-ID from browser URL display. User Interface ============== Message display: Hierachical listing of MIME BODYSTRUCTURE for display/download. User preferences to display TEXT/HTML inline with dangerous tags removed. Special handing for postponed message folder http:// and https:// in body converted into links. Message text wrapped to 80 columns (maintaining correct message quotation) - Colour codes for quoted message text Mailbox list: Aggregate: save, forward, (un)delete, (un)read. Zoom mode. Sort and Reverse Sort folder listing (on one of 7 criteria). Change to/Save marked messages to favourite Folder. Supports Persistent and non-persistent message marking (user preference): Non-persistent: normal Webmail behavior using HTML checkboxes: - Fewer page refreshes, no way to maintain state if links used Persistant: - Marks are HTML links, mark state recorded while stream open. Seach (Message Headers/Text, Delivery Date, Status, Size). - Compound search on marked messages. Full Hierachical folder listing: - single level display with filters - Favourite/subscribed folders for shortcuts on list screen. - Transfer mailfolders to and from IMAP server using HTTP upload/download. Compose: Local address lookup and Gecos expansion. Recursive Addressbook Lookup (with loop detection) Spell Check with Personal dictionary. Adaptive (and hopefully quite intellegent) line wrap algorithm - breaks message into "paragraph" blocks and wraps blocks independently. Undo. Roles. Rich headers. Alt-addresses list and local domain list used when constructing Cc list. Arbitary number of postponed messages using postponed messages folder Personal Addressbook: Search. Import/Export local and remote pine .addressbook format files. Addressbook split into pages: can move to any page Account managment using auxillary "accountd" server: - Change password and Gecos fields. Check disk quota. - Mail redirection, filtering and vacation messages using Exim filter files. ./prayer-1.3.5/docs/README0000644006513000651300000001076511063701634013413 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/README,v 1.3 2008/09/16 09:59:56 dpc22 Exp $ Licence and Distribution ======================== See LICENSE and NOTICE in the docs directory. Installation ============ See INSTALL in the docs directory. Mailing lists ============= https://lists.cam.ac.uk/mailman/listinfo/prayer-announce https://lists.cam.ac.uk/mailman/listinfo/prayer-users Welcome to Prayer ================= Prayer is (yet another) Webmail interface for IMAP servers. Please look at the "FEATURES" file in the docs directory if you want more information. It exists because we weren't terribly happy about the characteristics of existing Webmail interfaces: in particular scalibility problems with common open source Webmail packages and the lack of flexibility that commercial packages would give us. This doesn't mean that Prayer is better than or trying to compete with existing Webmail packages. It just means that Prayer is better suited to our particular environment. We are releasing the code into the public domain in case others feel the same way. Prayer is a low level HTTP to IMAP gateway written from scratch in C. It is not built on top of Apache or any of the standard scripting languages. This is rather unusual. However, a dedicated Webmail gateway system is a very specialised Web server: the Web server component less than 10% of the code. Prayer maintains a great deal of internal state for each logged in user: far more than most interactive Web applications. It works hard to minimise the load induced by each login session by using persistent connections to the IMAP server. In fact Prayer uses anywhere up to five persistent IMAP connections for a single logged in user: a permanent inbox stream (which doubles to check user preferences and for postponed messages when a user first logs in), plus optional extra streams for an additional live mail folder plus user preferences, mail folder transfer and postponed-msgs as they are required. There is also an internal directory cache to factor out round trips to the IMAP server each time that a directory is listed. Prayer also tries quite hard to cache HTTP/1.0 and 1.1 connections to the user-agent to remove the overhead associated with starting up fresh connections, especially SSL connections. Why "Prayer"? ============= Malcolm Beattie, formerly of Oxford University Computing Services released a Webmail package named WING (http://users.ox.ac.uk/~mbeattie/wing/) early in 1999. It was unusual at the time in that it used persistent IMAP connections and it was written using Apache mod_perl rather than mod_php. We came to the conclusion that the WING code that was available to us in 1999 and 2000 was not sufficient mature to use for our own Webmail system. Consequently (and with some reluctance) we decided to start writing our own package. Prayer was the in house development name for this package, a simple play on words to acknowledge the strong influence that WING had over Prayer development, especially in the early days. But at the end of the day, everything needs a name. Acknowledgements ================ Espen Koht (a computer officer at the University of Cambridge) gave some very useful feedback on user interface design during the development process. The SSL session cache has been adapted from code used by the Cyrus IMAP server (See NOTICE in the "docs" directory). The Prayer design and early user interface was strongly influenced by WING as explained in the previous section. Two other packages which have more recently influenced the design are: Postman: ftp://ftp.uv.es/pub/unix/postman/postman.html An Apache CGI plugin written in C++ which uses a persistent connection to the IMAP server. This is probably what I would be using today if we hadn't got a long way into the development process when Postman was released. sqwebmail: http://www.inter7.com/sqwebmail/ A standalone Webmail gateway for maildir format mailfolders and the Courier IMAP server. I haven't looked in great detail at this package however the discussion regarding sanitation of text/HTML seems extremely sensible and was the starting point for what I have implemented in Prayer. We have also looked at the popular Webmail interfaces IMP and Squirrelmail from time to time. Authors: ======== David Carter - Design and implementation. Stella Page - Initial Webmail evaluation. Help Text. Comments / Bug-reports: mail-support@ucs.cam.ac.uk Software Download ================= ftp://ftp.csx.cam.ac.uk/pub/software/email/prayer/ ./prayer-1.3.5/docs/DESIGN0000644006513000651300000001605411063701634013424 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/DESIGN,v 1.4 2008/09/16 09:59:56 dpc22 Exp $ Overview ======== Prayer consists of two master daemons named "prayer" and "prayer-session", plus a small auxiliary server named "accountd" which is used for operations on user accounts such as quota checking and mail redirection which are not normally provided by the IMAP server. "prayer" and "prayer-session" both run on the same gateway system. In fact a "prayer-session" daemon is normally started automatically by the "prayer" frontend server, though it is possible to run the two daemons independently, typically when debugging. "prayer": HTTP server and proxy =============================== The "prayer" frontend server is a very simple HTTP/1.0 and HTTP/1.1 server (serving icons and login pages only) and HTTP proxy. The frontend server normally preforks a number of child processes which accept incoming HTTP connections: child process are added and retire as required, according to the load of the system and the prayer configuration. Each child process will process a defined number of HTTP connections (where each connection in turn will process a defined number of HTTP requests). The total number of child processes is capped to prevent denial of service attacks. This cap should not be reached during normal operation. "prayer-session": User logins ============================= A fresh prayer-session backend is forked off whenever a user logs in. This process contains all of the permanent state associated with that login session including one or more connections to a IMAP server and possibly connections to accountd servers. prayer-session communicates with the user using HTML over HTTP connections via the "prayer" proxy. Each login has a sessionid which the front end processes use to find the correct backend. This arrangement is rather unorthodox from a Web interface design point of view. However a Webmail interface is an extremely specialised application which contains much more permanent state than most interactive Web pages. This design has the advantage of being extremely efficient, at least compared to a Apache CGI or mod_php interface which maintains no internal session state and which has to reconnect to a database and the IMAP server for each HTTP request. Backend server processes move into a dormant state after a certain period of inactivity, shutting down IMAP and accountd connections which can be easily resuscitated when the session wakes up. After a long period of inactivity, typically several hours the session process shuts down. Session Security ================ Prayer starts off with a username and password when a user logs in. A successful login attempt translates this into a session URL which consists of a username and a crypographically session identifier. The session identifier is the key to security in Prayer. If someone can derive the session URL including the the session identifier then they may be able to break into someone's login session. Prayer provides the following counter-measures. 1) The session-ID is moved from the session URL to a HTTP Cookie if at all possible to stop people from simply reading session identifiers over each others shoulders. 2) People are strongly encouraged to use HTTPS rather than HTTP to prevent sniffers from pick up valid passwords and active session identifiers. The plaintext version of the login screen has a big banner warning. 3) The fix_client_ipaddr configuration option allows the sys admin to only accept incoming HTTP(S) connections from the IP address which originated the login address. This doesn't protect people on shared Unix systems, and it is a little bit harsh for people with private systems on dialup links which intermittently disconnect: now disabled by default. The Prayer URL address space ============================ There are three basic forms of URL that are in use in Prayer: Login URLS. Example: http://webmail1.hermes.cam.ac.uk/ http://webmail1.hermes.cam.ac.uk/login/dpc22 Icon URLS. Example: http://webmail1.hermes.cam.ac.uk/icons/left.gif Session URLS. Example: https://webmail1.hermes.cam.ac.uk/session/dpc22//list/last Login and icon URL should hopefully be fairly self explanatory. There are a number of modifiers and options which can be provided to either form of URL to alter the behaviour of the user interface. These are documented separately in the URL_OPTIONS file in this directory. Session URLS will require a little further explanation: .../session/dpc22//display/15/452 ^ ^ ^ ^ ^ | | | | +- Arguments | | | +--------- Command | | +----------- SessionID | +---------------- Username +------------------------ Session URL i.e: not icon Session-ID is either an 18 digit (URL friendly) BASE64 encoded value which is a crypographically secure random number or an empty string which indicates that the session ID is stored in a HTTP cookie which is based on the login name, and possibly the port used by the session process (example: "dpc22:5000=FhsFG6754bncdsfhd". Prayer will attempt to store the session-ID automatically in a Cookie if the use of cookies is not disabled in the User Preferences or explicitly by options on the login URL. However the use of cookies is also negotiated with the browser using a number of round trips to set a cookie and then test to find out if the cookie value has been accepted correctly by the browser. Concurrency =========== prayer-session processes are single threaded and very stateful: they can only process a single _complete_ HTTP request at a time. The prayer frontend servers can however cope with an arbitrary number of incoming connections and partially complete HTTP requests at the same time. This should handle browsers that open several concurrent connections to the same server and also prevent an obvious denial of service attack where an attacker connects to the the Internet domain socket associated with an active login session, preventing the genuine user from communicating with their login session. In normal use there should only be a single active session URL at a time: prayer-session manages an interactive interface. The one obvious exception is during download (and conceivably upload) of large attachments and mailfolders. It would be rather useful if mail folders and attachments could be downloaded asynchronously while the user proceeded to other parts of the user interface. This is possible in the proxy case if the prayer frontend servers buffer download requests. It would also be possible in the direct connection case if a separate process was forked off for the download. One complication: this only becomes asynchronous once the folder or attachment has been downloaded from the IMAP server. Unfortunately it is rather hard to make IMAP downloads asynchronous without opening concurrent IMAP connections to the same mail folder, which is only practical if the IMAP server and mail folder format used on that IMAP server both support safe concurrent access to mail folders. ./prayer-1.3.5/docs/LOGS0000644006513000651300000000505111063701634013212 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/LOGS,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ There are normally four separate log files active in Prayer: prayer: Miscellaneous logging for prayer frontend servers. Includes details of incoming connections and lots of informatation about SSL connections if verbose logging is switched on. prayer_session: Miscellaneous logging for prayer-session backend servers. Includes details of incoming connections and lots of informatation about SSL connections if verbose logging is switched on and direct connection mode is enabled. access_log: Records each HTTP request made by a browser, with response code session_log: Record session interactions - includes every command issued in verbose logging mode access_log: =========== Typical entry: Oct 28 20:04:30 [11433] [213.104.12.23] (443) GET / HTTP/1.0 -> 200 823 1.0 ^ ^ ^ ^ ^ | | | | +--- HTTP response line | | | +-------- HTTP Port number | | +------------------------ IP address of peer | +-------------------------------- Process ID (*) +------------------------------------------------- Date and Time (*) Process ID may be [number:number] for session URLs, which indicates process ID of both the frontend and session processes involved. Response part: -> 200 823 1.0 ^ ^ ^ | | +----- HTTP response type, typically 1.0 or 1.1 | +--------- Size if response in bytes +------------- HTTP response code session_log: ============ Typical entries: Oct 23 17:35:21 [3373] (dpc22) [session_exchange] disp_delete Oct 23 17:35:21 [3373] (dpc22) [cmd_disp_delete] Deleted message number 3 from INBOX Oct 23 17:35:21 [3373] (dpc22) [session_redirect] display/4/45210 The first and third line only appear if verbose logging switched on: they record the path of the program as new commands are dispatched. session_exchange() - represents a HTTP exchange with a client session_redirect() - represenet an internal page substitution. Typical format of lines in the session log: Oct 23 17:35:21 [3373] (dpc22) [cmd_disp_delete] Deleted message ... ^ ^ ^ ^ | | | +-- Function responsible for message | | +---------- Logged in user for this session | +----------------- Process ID of login session +---------------------------------- Time and date ./prayer-1.3.5/docs/DONE0000644006513000651300000016135611775260614013216 0ustar dpc22dpc22`$Cambridge: hermes/src/prayer/docs/DONE,v 1.70 2012/07/05 09:42:36 dpc22 Exp $ 05/07/2012 ========== Release: Prayer 1.3.5 01/07/2012 ========== Add ssl_cipher_list and ssl_server_preference config options. ssl_cipher_list now defaults to: ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!EXP Fix problem forwarding messages with complex MIME structure. Previously we looked for text in section 1, attachments from sections 2. If no text parts are found at top level of section 1 we displayed "Message body was not text: suppressed" and discarded that part. Better to include part 1 as attachment if we can't find text at the top level there. This is what PINE does in the same circumstances. Sieve filtering fixes: account_mail_check() didn't clear out any existing lists of filters and blocks. Normally protected by: if (account->mail_checked) return (T); However that gets reset by "Update" on the Advanced filtering page. Need to disable Sieve script before deleting with Cyrus 2.4. Old template set was missing
    at start of Sieve upload. 09/11/2011 ========== Addressbook display needs to wrap long lines of addresses without spaces: "dpc22,dpc22,dpc22,...". Otherwise layout breaks. 27/06/2010 ========== Release: Prayer 1.3.4 22/06/2011 ========== draft.c fixes: Fold long lines of addresses before the entry which reaches 78 characters when possible, rather than after the first entry which crosses that boundary. Long standing bug bear of mine but several support functions needed to be rewritten to use scratch string in place of output buffer. Long subject lines which are not RFC1522 encoded need to be folded. separately. Reported by Andrey N. Oktyabrski . RFC1522 is not allowed to fold lines in the middle of a UTF-8 multibyte character. Reported by Andrey N. Oktyabrski . Tidy library: Add support for tidyp fork of (apparently abandoned) tidy library. Fix cross site scripting problem: MSIE and Chrome think that is a complete comment. Allows people to hide scripts inside , , , , , , , , , , , , , , , , , , , , , . * The following HTML attributes are stripped from every tag: ONLOAD=, ONMOUSEOVER=, and all ON*= attributes; TARGET=, CODE=, CODETYPE=, and LANGUAGE= are removed; TARGET=_blank is added to all tags. * The HREF and SRC attributes are stripped, unless the URL starts with one of the following: http:, https:, ftp:, gopher:, wais:, or telnet, and cid:. * The HREF and SRC attribute values are prefixed with a URL that will resolve to SqWebMail, and with an additional TARGET="_blank" attribute. A request to that resulting URL will result in a blank page with a 0-second refresh to the original URL. This method strips mailbox IDs from Referer: tags sent to external web site. If the HREF attribute starts with a cid:, it is replaced by an http: reference to SqWebMail that will return the specified MIME part. * IMG tags are removed and replaced with an A tag, in order to keep the HTTP client from automatically loading any images from external web sites, upon opening a given message. ./prayer-1.3.5/docs/ICONLIST0000644006513000651300000000405311063701634013673 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/ICONLIST,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ List of icons in use here ========================= Sources: 1 www.graphxkingdom.com 2 www.iconbazaar.com 3 Apache Toolset 4 WING 5 Stella 6 Misc/unknown Icon Name Source File name/URL at source ========= ====== ====================== addressbook.gif iconbazaar book09.gif back.gif apache back.gif compose.gif graphxkingdom email35.gif expunge.gif graphxkingdom comp112.gif forward.gif graphxkingdom email13.gif (alt: email68.gif) help.gif graphxkingdom m330.gif logout.gif graphxkingdom m404.gif mailboxes.gif graphxkingdom doc20.gif options.gif graphxkingdom doc03.gif reply.gif graphxkingdom email102.gif logout.gif Vince? check.gif graphxkingdom email63.gif paperclip-small.gif graphxkingdom mini23.gif mailbox.gif graphxkingdom email111.gif or email01.gif display.gif graphxkingdom email84.gif save.gif iconbazaar doc45.gif (was diskett3.gif) delete.gif misc trashcan.gif full-headers.gid graphxkingdom doc04.gif mark.gif graphxkingdom email33.gif search.gif graphxkingdom email03.gif zoom.gif graphxkingdom doc40.gif reply-all.gif graphxkingdom email103.gif transfer.gif graphxkingdom doc23.gif reverse.gif graphxkingdom m566.gif (misc) dir.gif apache dir.gif left.gif apache right.gif apache leftleft.gif apache/Stella rightright.gif apache/Stella left-inactive.gif apache/Stella right-inactive.gif apache/Stella leftleft-inactive.gif apache/Stella rightright-inactive.gif apache/Stella on.gif Espen off.gif Espen./prayer-1.3.5/docs/INSTALL0000644006513000651300000001407211421275257013564 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/INSTALL,v 1.9 2010/07/20 10:30:07 dpc22 Exp $ Important ========= Prayer v1.1.0 automatically upgrades existing preferences mailboxes to UTF-8. If you need to downgrade for any reason, use v1.0.20, which transliterates back to ISO-8859-1. Otherwise preferences are discarded. Mailing lists ============= https://lists.cam.ac.uk/mailman/listinfo/prayer-announce https://lists.cam.ac.uk/mailman/listinfo/prayer-users Systems ======= Prayer has been ported to the following operating systems so far: SLES 10 (this is what we currently use) SuSE Linux 9.x Redhat Linux 9.x (I suspect that Fedora will work fine) FreeBSD 4.x Solaris 2.6 and 8. Other Unices should work with minimal porting effect: there is very little OS specific code in Prayer. Requirements: imap-2007 c-client toolkit A decent iconv library, such as GNU iconv. zlib (optional, if GZIP compression desired) openssl-0.9.6. (optional, if SSL desired) Berkeley DB 3 or 4 (optional, if SSL session cache desired) Tidy library (optional, if tidy library available for HTML) GNU make. GCC (or SUNWspro compiler on Solaris). INSTALL procedure: 1) Create a system account user and group named "prayer". On Redhat Linux: # useradd -r prayer 2) Configure your mail transfer agent so that the prayer user or group is able to change the envelope sender field using the "-f" command line option. Otherwise mail bounces will all go to the Prayer user. Exim: "trusted_users" or "trusted_groups" option Sendmail: T option or Class "t" (/etc/mail/trusted-users on Redhat). Other MTA: Please read the documentation that comes with your MTA. Prayer may eventually send messages using SMTP to a nominated SMTP smarthost. This route just seemed simpler for the first iteration... 3) Install the PRNG package if your system doesn't provide /dev/urandom for crypographically secure random numbers (at the moment this only applies to Solaris). PRNGD can be found at: http://ftp.aet.TU-Cottbus.DE/personen/jaenicke/postfix_tls/prngd.html 4) Install the OpenSSL libary if you want to support secure logins. Redhat Linux RPMs: openssl and openssl-devel 5) Install Berkley DB v3 or v4 if you have installed OpenSSL and want an SSL session cache. Redhat Linux RPMs: db3 and db3-devel The latest version of Berkeley DB should be available at: http://www.sleepycat.com/download.html 6) Install the c-client library. Prayer should be compatible with the IMAP 2000, 2001 and 2002 distributions. Redhat Linux RPM: imap-devel. The latest version of c-client should be available at: ftp://ftp.cac.washington.edu/imap/imap.tar.Z If you want Prayer to support IMAP sessions tunnelled over SSL as well as HTTP connections tunnelled over SSL then you will need to build c-client with SSL support. e.g: make slx SSLTYPE=unix SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib You may find that you need to set up a certificate authority bundle so that c-client recognises the certificate used by the server. An OpenSSL installation will typically look for its certificate bundle as a file named cert.pem in its installation directory (this file is preinstalled on RedHat). Alternatively you can add a "/novalidate-cert" flag to the end of the imapd_server option outlined below). The rest of this build process defaults to a c-client distrution which is unpacked at the same level as Prayer with a symbolic link "imap" e.g: lrwxrwxrwx 1 dpc22 dpc22 30 May 31 17:32 imap -> imap-2001.BETA.SNAP... drwxr-xr-x 6 dpc22 dpc22 4096 Sep 27 09:37 prayer-0.7.0 However this is easy enough to change in the Config file in the next step. 7) Check "Config" in the root directory of the distribution. This file defines compiler options and the location of files and is included by all the Makefiles in this and subsiduary directories. 8) Build the prayer binaries (needs GNU make) $ make 9) [Optional] Make a self-signed certificate for testing purposes: $ make cert 10) [Optional]. Test the ./prayer binary in the "prayer" subdirectory. $ cd prayer $ ./prayer --config-file=./prayer-debug.cf The standard prayer-debug configuration connects to the IMAP server on localhost. This can be overridden by changing the configuration file or adding a --config-option to override settings in the file. Examples: --config-option imapd_server=remote_system # Plaintext IMAP --config-option imapd_server=remote_system/ssl # IMAP over SSL --config-option imapd_server=localhost:8143 # SSH Port forwarding This should start up a Prayer Webmail service listening for plaintext HTTP connections on port 8080. It is easy to add SSL HTTP connections on port 8081 (using a self-signed certificate for the SSL connections), by uncommenting the "use_https_port" line in the configuration file. 11) Install the binaries and support files. # make install This automatically runs "make install-config" and "make install-cert" if the relevant files do not already exist. 12) Edit the main prayer configuration file to match your needs. The location is defined in the CONFIG file and the default location is "/usr/local/prayer/etc/prayer.cf". The values most likely to change are at the top of the file. The section "SSL NOTES" above applies here too. 13) Create a suitable startup file. On Redhat Linux: "make redhat-start" does: # cp defaults/prayer-redhat /etc/rc.d/init.d/prayer # chkconfig prayer on # /etc/init.d/prayer start Regular maintainance: ===================== prayer-ssl-prune: Removes expired sessions from the SSL session cache (Sessions set up to expire after config->ssl_session_timeout seconds) prayer-db-prune: Clear obsolete entries from the Berkeley DB transaction log used by the SSL session cache. Otherwise it will grow indefinitely. prayer-sem-prune: Remove a give semaphore after prayer is shut down. Only use this if MUTEX_SEMAPHORE is in use. ./prayer-1.3.5/docs/ACCOUNTD0000644006513000651300000000502311063701634013645 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/ACCOUNTD,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ Accountd uses a simple line based protocol similar to POP or IMAP. Data types ========== There are two basic data types: Tokens: Arbitary ASCII text. URL style encoding are used for anything other than alphanumerics e.g: Hello%20World. Literals: Bastardised version of IMAP literal strings used to insert arbitrary amounts of data into a line. Example: SOMETHING {5}CRLF Hello {5}CRLF World is equivalent to SOMETHING "Hello World" in IMAP. IMAP allows you do use literals and other string encoding interchangeably. This isn't the case with the accountd protocol. Protocol ======== Login LOGIN Password changing PASSWORD Gecos changing FULLNAME Both work by running a simple expect-like script against a Hermes specific "passwd" program running at the far end of a PTY. (messy, but easier than trying to reverse engineering Chris Thompson's code!) I don't know if the script language is general enough for other passwd programs. FreeBSD and generic Solaris seem to work just fine. There's some kind of race condition or other bug which means that passwd on Linux doesn't work reliably: I never worked out what was going on there. Quota checking: QUOTA accountd cheats on Hermes: I was too lazy to write the 10 line perl script which would translate output from the Hermes specific quota command into the canonical form described in accountd.cf files. Exim filter file management: Based around (and compatible with) the intermediate format (.MSforward) used by menu system on Hermes. This format is undocumented but simple. Basic accounts MAILSTATUS Returns copy of .MSforward file as literal after running consistency check on .forward file. Performs on the fly translation of simple .forward files which are not Exim filter files. Example: OK {102} # MSforward file: change only via Hermes menu system redirect address dpc22@cam.ac.uk copy true MAILCHANGE Uploads new .MSforward file, generates .forward from it. GET Returns given file as literal. Used to get vacation aliases and log file. PUT Upload file as literal. Used to upload vacation aliases. VACATION_CLEAR Clears vacation.log, vacation.once.dir, vacation.once.pag ./prayer-1.3.5/docs/TEMPLATES0000644006513000651300000001113511063701634014004 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/TEMPLATES,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ Basic premise ============= Simple macro expansion language where the majority of the data will come from template files. All HTML should live in the template files. Template source files are just HTML, with the following escapes: 1) <% $foo/$bar |X %> for inline variable expansion. 2) % at start of line introduces control structure, e.g: IF, FOREACH, CALL. Most control structures have a termination line: e.g: ENDIF, ENDFOREACH Requirements ============ HTML should appear mostly as is so that Web developers can make useful updates without having to grok C. Test suite so that we can update and test new templates without needing a full Prayer installation and interactive logins. Ability to update and test templates without needing to recompile anything for fast development. Precompiled version for production use. Variable expansion with various kind of quoting. Ability for one template to call another, with parameters: % CALL template, $a => 1, $b => "$foo/${bar}" Four very simple loop/control structures: % FOREACH $i @list ENDFOREACH % LOOP $count ENDLOOP % IFDEF $var ELSE ENDIF % IFEQ $var1 "fred" ELSE ENDIF Don't need to support complex expression inside the templates e.g: % IF ($a == 'hello'). Leave C to do the heavy lifting by adding variables template can IFDEF on. Variable Syntax and <% %> expansion =================================== Variable names: [a-zA-Z0-9_]+. Quote using '{}' to remove ambiguity e.g: ${a}b${c} Possible Variable quoting: $a ${a} $a->b $a->{b} ${a->b} Use \ to quote magic chars: \\, \$, \{ and \} Use Perl hash syntax to split up the namespace into managable chunks (so that we can include long list of possible expansions for each template). Internal varibale name to Prayer assoc lookup mapping: $a->b ==> "a-b" $a is normal reference setup by Prayer $i->b ==> "@a-b" $i is variable used on foreach LHS. Think that we only ever need to track one such. No complex expressions beyond string concatenation: $a/${b->c} Do need ability to filter HTML output. Mason uses following modifiers: |n No encoding: send raw data |h HTML quoting |u URL which should have % encoding applied e.g: <% "$a/${b->c}" |u %>. Prayer requires a filter on all <% %> expansions. Add the following: |s Session URL (either /session/user//... or ... using @) |S NOSEQ Session URL |c Prayer canon encoding |7 modified UTF7 to UTF8 conversion (single variables only) In addition there are places where we need to URL or canon encode variables between |s quoting is applied. Do this on a per variable basis, using ${foo|c}, e.g: <% rename/${name|c} |s %>, <% change/${name|7} |s %> Update: We now also allow: <% ", " IFDEF $a->next %> <% "$foo" IFEQ $bar $baz %> just to avoid: blah blah % IFDEF $a->next , % ENDIF blah blah Control structures ================== Following Mason style, use '%' at the start of line for control. We allow empty % lines and %# for comments. By convention control words uppercase just so that they stand out from the HTML. Doesn't actually matter. CALL ==== Basic form is: % CALL template However we also allow parameters, in a Mason like style: % CALL template, $a => 1, $b => "$foo/${bar}", % $c => "hh" We allow continuation lines here (and only here), as some templates take quite a lot of parameters. Variables defined by the argument list override existing variables for the duration of the called template. Many templates use leading _ (e.g: $_a to avoid conflicts). The parameter list only applies to the current template: if this template wants to pass variables into subsiduary templates then it needs to define them ifself e.g: % CALL template2, $a => $a, $b => $b. This approach seemed simplest, and less prone to unexpected side effects. IFDEF/IFNDEF and IFEQ/IFNEQ =========================== % IFDEF $a->{b} {
  5. Some item % ELSE
  6. Another item % ENDIF % IFEQ $a->{b} "fred" {
  7. Some item % ELSE
  8. Another item % ENDIF Nested ifdefs allow for: % IFDEF $a->{b} % ELSE % IFDEF $a->{b} % ENDIF % ENDIF Currently no ELIFDEF FOREACH ======= % FOREACH $i @list {
  9. % ENDFOREACH Can't think of any place where we needed nested foreach, which makes it easier to track %i magic variables. LOOP ==== %# Used in a few select places, typically for intentation. % LOOP $count   % ENDLOOP ./prayer-1.3.5/docs/CMD_LINE0000644006513000651300000000311411063701634013656 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/CMD_LINE,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ Command line options for the various servers ============================================ prayer: --config-file: Define prayer config file (Overrides compilation default and PRAYER_CONFIG_FILE) --config-option: Override single configuration option --foreground: Run single threaded server in foreground --disable-prefork: Run as simple fork()/exec() daemon --disable-session: Don't start up prayer-session server --help: Lists command line options --: End of prayer options: remaining options will be passed to prayer-session server process only. prayer-session: --config-file: Define prayer config file (Overrides compilation default and PRAYER_CONFIG_FILE) --config-option: Override single configuration option --foreground: Run single threaded session server in foreground --help: Lists command line options Example: prayer --config-file=./prayer-debug.cf \ --config-option service_name="Webmail" \ -- \ --config-option imapd_server=localhost:8143 \ --foreground Starts up prayer and prayer-session master servers, defining configuration file and "service_name" variable in both processes. In addition the imapd_server variable is defined in the prayer-session server and this server is run in "foreground" mode which is useful for debugging single login sessions. ./prayer-1.3.5/docs/NOTICE0000644006513000651300000000562211063701634013433 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/NOTICE,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ The Prayer Webmail Interface ---------------------------- Copyright (c) 2002 University of Cambridge This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. In addition, for the avoidance of any doubt, permission is granted to link this program with OpenSSL or any other library package. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. INCORPORATED CODE ----------------- Code implementing the SSL session cache has been adapted from code used by the Cyrus IMAP server, which is distributed under the following copyright: /* Copyright (c) 2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any other legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ ./prayer-1.3.5/docs/TODO0000644006513000651300000000371411773061651013225 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/TODO,v 1.64 2012/06/28 14:01:13 dpc22 Exp $ Small fixes =========== Possible for enter on password change page to select correct select button? Might involve Javascript. Handle RFC1522 encoding in attachment names? Broken but lots of things seem to do it including Thunderbird and Gmail Suspect all Outlooks fault. PINE does it right: RFC 2231 encoding Implement mark-fcc-seen to prevent slightly daft behaviour from MacOS mail. Sieve files should use UTF-8 rather than ACSII (requires coordinated fix at Cyrus end to remove HERMES_LMTP_USE_8859_1) Thunderbird uses different column names for CSV addressbooks (but otherwise the existing code should work). Single request that "Cancel" button on Compose screen should have confirm cycle given proximity to main edit display. User Interface Changes ====================== display screen should mention current mailbox. Remove attachments from message a la Pine Things to check =============== Address book import should cope with QP encoding for comments, addresses. Folder upload/download to Windows box -> CRLF translation Code cleanups ============= X-Cam-SpamScore should be config option. Document prayer_cyclog. Page substitition: Redirect URL cache so that browser history can work even with page substitution enabled. Otherwise remove page substiution nonsense entirely. Message filtering ================= Ability to filter on From: as well as return path would be nice Add message sender to spam blacklist/whitelist. Ability to reorder filters (and blocks). No real advantage given fixed order. Big things ========== Do better job of replying/forwarding HTML msgs: Look at how Pine processes HTML. Antiword: Look at IMP Addressbook search should really have persistent state, checkboxes to match main addressbook screen and directory lookup screen. Problem with pointer alignment on Sparc64 platform? Reported by: David Sheryn , 13/02/2007 ./prayer-1.3.5/docs/ROADMAP0000644006513000651300000003554111063701634013540 0ustar dpc22dpc22$Cambridge: hermes/src/prayer/docs/ROADMAP,v 1.2 2008/09/16 09:59:56 dpc22 Exp $ A brief overview of Prayer ========================== A function by function breakdown should eventually appear in TechDoc. This is just a quick guide to the files that you will see in the distribution. Finding your way around the distribution ======================================== README <--> docs/README INSTALL <--> docs/INSTALL docs/ README: Introduction to Prayer. INSTALL: Installation guide. FEATURES: A brief list of features for people wondering just what is different about this paricular Webmail package. LICENSE: Copy of the GNU GENERAL PUBLIC LICENSE NOTICE: Describes distribution terms and incorporated code. ROADMAP: An overview of the software distribution. This file! TODO: The current wishlist DONE: Items moved from the TODO list. Should probably use a ChangeLog. ICONLIST: A list of sources for various icons used by Prayer. SECURITY: Some thoughts about HTML security. Need to update XXX DESIGN: Some notes and discussion about the Prayer design URL_OPTIONS: Modifiers for login URLs CMD_LINE: Command line options for prayer and other binaries: modify behaviour add debugging etc LOGS: Describes format of the various log files. Makefile: Makefile which will install software from the subdirectories Config: Configuration file used by all subsiduary Makefiles. Config-RPM: Version of Configuration file tailored for RedHat RPM build process (triggered if RPM_BUILD=true passed as argument to make) defaults: Default versions of Config and Config-RPM (restored by "make distclean"), plus a RPM spec file for Prayer. accountd/ Source code for the accountd support daemon. prayer/ Source code for the main prayer daemons. Code layout for prayer/ directory ================================= There are lots of files in this directory: I like to split tasks up into lots of small pieces. However, I've tried quite hard to ensure that external (i.e non-static functions) have sensible names so that they are easy to find. Typically you should be able to rely on the fact that a given function e.g: pool_printf() will be defined in pool.c, with a prototype in the header file pool.h. The only real exception to this rule are c-client calls (which typically start mail_XXX) and a bunch of macros that I have defined for seven very common functions. Macro Corresponds to function ===== ======================= bputc buffer_putchar bputs buffer_puts bprint buffer_printf ioputc iostream_putchar ioputs iostream_puts ioprintf iostream_printf iogetc iostream_getchar Common support modules ====================== pool: Memory pool. Defines a group of arbitary size memory assignments. A pool is created using pool_create(). Allocations are made using a number of different functions including pool_alloc(), pool_strdup(), pool_strcat() and pool_printf(). Large blocks are allocated separately, small allocations come from aggregate memory blocks. pool_free() frees all of the memory assigned in the pool. The NIL pool is special: it allocated against conventional memory. list: Single linked list Defines generic list structure including add, remove and lookup (indexed by element name and by list offset). Lots of data structures "inherit" from list using "struct list" as a binary header. Expect to see a lot of for loops using generic list items that immediate cast the list_item pointer to a more specific list type. Lists are built on pools. assoc: Associative array (aka hash) Perl style associative array built on pools, with add, remove and lookup methods. Was originally called hash, but the c-client IMAP 2001 toolkit defines its own "hash" type. buffer: Arbitary length (typically large) strings with linear access methods Buffers are arbitary length strings built on pools which can extend indefinitely (typically using the bputc, bputs and bprintf macros). There are also functions to cast buffers or ranges of buffers into C "char *" strings in the same or a different pool. Used all over the place, mostly a comment on C string handling. Possible that "buffer" should be called something else to reflect widespread use within Prayer. memblock: Arbitary length (typically small) strings. A memblock is a contiguous block of memory that can be resized. Typically used for status messages and other feedback from Prayer to the users: strings that are typically quite short, but which may have arbitary size. Memblocks are useful for entities which persist across HTTP requests. Buffers are typically more useful for shortlives entities which may grow. user_agent: User agent properties and features A collection of features typically boolean flags that define capabilities of a particular browser. Is also use to restrict or force use of various optimisations and debugging techniques. iostream: Input/Output abstraction Simple replacement for stdio which provides: bidirectional I/O on sockets (stdio didn't seem to work for me), transparent SSL support, consistent error handling (I hope) and timeouts on both input and output requests Actually included by two simple wrapper classes iostream_prayer and iostream_session so that we can include SSL support for the two halves independantly at compile time. request: HTTP request parsing Routines to parse HTTP requests: method, headers and body. Also includes some auxillary routines for chopping up HTTP POST forms and file uploads. The request struct includes response information (see next section). response: HTTP response generation. Assorted routines used to generate HTTP response header for data that is queued in request->write_buffer e.g: response_html() response_raw(). Also includes routines for actually sending the response header and body over a nominated iostream plus session telemetry. This second part is largely historical: possible that it should be split off now. html_common: HTML markup routines used by frontend/error responses Just factoring out some common code which might happen to change... setproctitle: Argv mangling A bunch of routines stolen from Sendmail (eek!) for setting process header information to indicate what is going on. Will only work on certain platforms, but the more feedback that you can get the better... ipaddr: IP address manipulation A small class for manipulating IP addresses (convert to canonical form, convert to and from string, compare). Idea is to hide IP version specific information, however we still have to implement IPv6 addresses! log: Logging functions Functions for logging information at different priorities. There are also a bunch obsolete logging functions specific to the prayer and session systems which are now built on top of log_XXX functions. We should probably try to phase these out now. os: OS specific support functions. Actually #includes an OS specific file to avoid #ifdef soup within a single file. A wide range of function to set up Unix and Internet and Unix domain sockets, provide locking etc. Will only grow as time go on. The big idea is to try and avoid OS specific behaviour anywhere else within Prayer. config: Prayer configuration file struct config plus a series of routines for parsing and then testing the prayer configuration file with any overrides. Prayer Frontend Specific modules ================================ prayer_login: Routines responsible for generating initial login screen and processing subsequent HTTP POST request for login prayer_server: Main Frontend server module Simple and Prefork models which accept incoming HTTP requests and service them. Three classes of HTTP request: icons, generate/process login screen and requests which should be proxied through to the session process prayer_main: Parses command line options. Reads in configuration file from one of three places. Overrides configuration options from command line. Checks configuration. Binds to specified HTTP ports. If running as root: lose root privileges and re-exec self with "--ports" command line option to prevent core dump paranoia (goto line 1!). Starts prayer_server() Prayer Backend (Session) support modules ======================================== session: Main session state Lots and lots of state specific to this login session. Basically global state: lots of other modules dig in around struct session without a well defined interface. However this approach makes it rather easier to move to a single, massively multithreaded, process if the urge ever strikes. It also means that all of the "global" state is in a well defined place. addr: Address parsing routines. Routines for splitting up RFC822 addresses. Relies heavily on c-client to do the hard work at the moment ml: c-client interface Abstraction to the c-client mail_XXX with some automatic handling for some of the more obvious error conditions e.g: TRYCREATE. Callers also provide a struct session which provides a number of hooks for logging and user info callbacks. ml and mm are the only modules in Prayer which have their own global state: this is an unfortunate consequence of the c-client design. mm: C-client callbacks Callback routines used by c-client. Linked strongly to the ml module. stream: MAILSTREAM support A small number of helper functions for c-client MAILSTREAM objects. Should be merged into some generic c-client wrapper? dirlist: Directory Listing Cache for specific directory. Part of the dircache module (see below). dircache: Directory Cache A generalised tree structure directory cache. Used to cache directory structure for this user to optimise out round trips to the IMAP server. html: HTML Markup support Assorted routines for HTML markup to a target buffer modified by session configuration. Goal should be to move all non-trivial HTML markup here! html_secure: HTML sanity check Routines that translate HTML in source buffer into equivalent HTML in target buffer removing all dodgy constructs and tags. Experimental. string: String (i.e: char *) manipulation routines A range of routines for splitting up strings into their component sections and putting them back together again afterwards. Poors mans regexps, but probably rather faster. draft: Message draft A Draft message in its own pool, plus any attachments as separate entities. speller: Spelling check engine Low level interface to spell check engine. Hasn't changed in a long time, should probably be reviewed. msgmap: Message listing with sort and zoommap filters applied. Cache for current sorted+zoomed message view. Has special handling for default case (sort on arrival, no zoom applied) so that client routines can use zoommap as a generic access to the folder listing without having to worry about details of any underlying sort or zoom. Important that clients call zoommap_invalidate if they change the underlying folder listing and zoommap_associate when the current folder changes. cdb: Constant database Interface to Qmail style cdb files. Fast lookups for static data. options: User defined data Container class for user defined state: prefs, abook, dictionary, roles, favourites prefs: Preferences library Prayer user preferences data structure and a few support routines. abook: Addressbook Abstaction Routines and data structures for manipulating personal addressbook. dictionary: Dictionary Abstaction Routines and data structures for manipulating personal dictionary. role: Role Abstaction Routines and data structures for manipulating roles. favourite: Favourite mail folders Support class for favourite folders list. postponed: Postponed messages list Routines for manipulation postponed-msgs list. rfc1522: RFC822 header decoding Routines for decoding QP encoding in message header, adapted/stolen from Pine code. Should really be called rfc2XXX today... banner: Icon banner Support Class for manipulating list of icons that appear as a group. account: Account management Support Class for Account management via accountd server filter: Mail filtering Support Class for mail filtering (including mail redirection and vacation). wrap: Linewrap algorithmn Adaptive and hopefully quite intellegent routine for line wrapping large blocks of text as a series of small identifiable chunks. We still have to see how well things work in practice of course! portlist: List of HTTP ports Class used by session_inet() to manipulating long lists of active and idle HTTP ports. Experimental at the time of writing. session_config: Session server specific configuration Sets up parts of config structure which are specific to login sessions. session_exchange: Response for processing a single HTTP request that will update the state of this login session. Used by both session_unix() and session_inet() session_unix: Runs login session proxying all incoming requests via a Unix domain socket session_inet: Runs login session with HTTP requests coming direct to Internet domain socket. session_idle: Support routines for session_inet. Deal with HTTP requests to a Internet domain socket whose session has disconnected or timed out. session_server: Master server routine for prayer_session. Accepts login requests from frontend server and forks off a separate domain to validate the login request and run session_unix() or session_inet() as appropriate. session_main: main() function for session server Reads in configuration file from one of three places. Overrides configuration options from command line. Checks configuration. Binds to specified HTTP ports. If running as root: lose root privileges and re-exec self with "--ports" command line option to prevent core dump paranoia (goto line 1!). Starts frontend_server() Command modules: ================ cmd.c dispatches command request sent to a logged in prayer session. Each cmd_XXX module corresponds to a single part of the interface. Examples: /session/dpc22//compose --> cmd_compose() /session/dpc22//abook_list --> cmd_abook_list() Hopefully this should be fairly easy to find the relevant piece of code from the session URLs. The one caveat is that Prayer can be configured to use transparent page substutition to optimise out HTTP level redirects which would otherwise be sent to the user agent. For example there is a "POST" form on the initial welcome screen. When you press the submit button the user interface will redirect you to another screen, typically cmd_user_level() or cmd_list(). However the transparent subsitution means that the URL that appears at the top of the users screen will still read "welcome". The solution is to disable page substitution, either in the global configuration file, a specific user preferences or by using the debug screen to override the default setting. ./prayer-1.3.5/accountd/0000755006513000651300000000000011775262602013401 5ustar dpc22dpc22./prayer-1.3.5/accountd/checksum.c0000644006513000651300000000715611063701632015347 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/checksum.c,v 1.3 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* Little snippet of code to calculate file checksum and compare with * current value. Rather strange little checksum routine: just happens * to be compatible with what we are using at the moment... */ #include "accountd.h" /* checksum_hash_line() ************************************************** * * Convert single line of input into checksum value * line: Line to checksum * maxlen: Maximum length to checksum ************************************************************************/ static int checksum_hash_line(char *line, unsigned int maxlen) { unsigned int total; unsigned int i; char *p; total = 0; for (i = 0, p = line; *p != '\0' && *p != '\n' && i < maxlen; p++, i++) { total += (((unsigned int) *p) * (i + 1)); } return (total % 65536); } /* checksum_test() ******************************************************** * * Calculate checksum value for a string. * config: Global state * existing: Returns existing checksum found in file * current: Returns current checksum value for file * * Returns: T => Was able to checksum .forward file *************************************************************************/ BOOL checksum_test(struct config * config, unsigned long *existing, unsigned long *current) { FILE *file; unsigned long total; unsigned long file_checksum, checklen; static char buffer[MAXLENGTH], *endbuffer, *p; char *checkstring; endbuffer = &buffer[MAXLENGTH - 1]; if ((file = fopen(config->forward_name, "r")) == NULL) return (NIL); checkstring = "# END FILTER FILE. CHECKSUM="; checklen = strlen(checkstring); file_checksum = 0; total = 0; while (fgets(buffer, MAXLENGTH, file)) { if (buffer[0] == '#') { if (strncmp(buffer, checkstring, checklen) == 0) { p = buffer + strlen(checkstring); while (*p != '\0' && !Uisdigit(*p)) p++; if (*p != '\0') sscanf(p, "%lu", &file_checksum); } } else { *endbuffer = '\0'; total += checksum_hash_line(buffer, MAXLENGTH); total %= (1024 * 1024); /* Cap values to < 10^6 */ } } fclose(file); *existing = file_checksum; *current = total; return (T); } /* checksum_generate() **************************************************** * * Generate checksum value for a file * Name of file to checksum * * Returns: T => Was able to checksum .forward file *************************************************************************/ BOOL checksum_generate(char *name) { FILE *file; unsigned long total; static char buffer[MAXLENGTH], *endbuffer; endbuffer = &buffer[MAXLENGTH - 1]; if ((file = fopen(name, "r")) == NULL) return (NIL); total = 0; while (fgets(buffer, MAXLENGTH, file)) { if (buffer[0] == '#') continue; *endbuffer = '\0'; total += checksum_hash_line(buffer, MAXLENGTH); total %= (1024 * 1024); /* Cap values to < 10^6 */ } fclose(file); if ((file = fopen(name, "a")) == NULL) return (NIL); fprintf(file, "# END FILTER FILE. CHECKSUM=%lu\n", total); fclose(file); return (T); } ./prayer-1.3.5/accountd/config.h0000644006513000651300000000533311063701632015012 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/config.h,v 1.4 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* External interface prototypes to config.c */ typedef enum { AUTHTYPE_UNKNOWN, AUTHTYPE_PWD, AUTHTYPE_PWD_MD5, AUTHTYPE_SHADOW, AUTHTYPE_SHADOW_MD5, AUTHTYPE_PAM } AUTHTYPE; struct config { /* General options */ struct pool *pool; /* Pool for configuration */ unsigned long accountd_port; /* Port to run on 0 => none */ BOOL log_debug; /* Enable debug logging */ unsigned long child_timeout; /* For interaction with children */ AUTHTYPE authtype; /* Authenication method */ BOOL raven_enable; /* Enable raven support as well? */ char *raven_key_path; /* Path to raven keys */ /* Location of filter files */ char *msforward_name; /* Name of MSforward file on server */ char *forward_name; /* Name of .forward file on server */ char *aliases_name; /* Names of vacation aliases on server */ BOOL filter_restricted; /* T => restrict filters to "mail/" */ /* Password changing */ char *pwd_cmdline; /* Program to run to change passwords */ char *pwd_script; /* Script to run */ BOOL pwd_pty; /* Needs PTY? */ /* Fullname checking */ char *checkfull_cmdline; /* Program to run to change passwords */ char *checkfull_script; /* Script to run */ BOOL checkfull_pty; /* Needs PTY? */ /* Fullname changing */ char *full_cmdline; /* Program to run to change passwords */ char *full_script; /* Script to run */ BOOL full_pty; /* Needs PTY? */ /* Quota check */ char *quota_cmdline; /* Command line for check quota */ BOOL quota_hermes; /* T => interpret fquota output */ /* SSL support stuff */ BOOL use_ssl; char *ssl_cert_file; char *ssl_privatekey_file; char *ssl_dh_file; char *egd_socket; unsigned long ssl_rsakey_lifespan; unsigned long ssl_rsakey_freshen; unsigned long ssl_session_timeout; char *ssl_session_dir; }; struct config *config_create(void); void config_free(struct config *config); BOOL config_parse_option(struct config *config, char *option); BOOL config_parse_file(struct config *config, char *filename); BOOL config_check(struct config *config); void config_extract_ssl(struct config *config, struct ssl_config *ssl_config); ./prayer-1.3.5/accountd/common.h0000644006513000651300000000114311600401551015022 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/common.h,v 1.16 2011/06/22 14:59:53 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* Global constants */ #define ACCOUNTD_PORT "145" #define ACCOUNTD_TIMEOUT (300) /* Five minutes */ #define MAXLENGTH (8192) #define VERSION "v1.3.4" #define CRLF "\015\012" #define VACATION_ALIASES "vacation.aliases" ./prayer-1.3.5/accountd/log.c0000644006513000651300000001053011063701632014314 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/log.c,v 1.3 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" #include #include #include /* Syslog interface largely cripped from main Prayer code */ /* Record programs argv[0] so that we can give useful error messages */ static char *log_progname = NIL; /* log_init() ************************************************************ * * Initial the log subsystem * config: Accountd configuration * progname: Porgram name ************************************************************************/ void log_init(struct config *config, char *progname) { char *s; if ((s = strrchr(progname, '/'))) log_progname = strdup(s + 1); else log_progname = strdup(progname); /* XXX */ openlog(log_progname, LOG_PID, LOG_USER); } /* ====================================================================== */ /* Return size of log entry item. Doesn't include timestamps and other * (fixed length) padding that that the log function may what to add */ unsigned long log_entry_size(char *fmt, va_list ap) { return (pool_vprintf_size(fmt, ap)); } /* ====================================================================== */ /* log_out_of_memory() *************************************************** * * Out of memory while trying to report error. Send something to * syslog and paniclog so we have some idea what is going on. ************************************************************************/ static void log_out_of_memory(void) { if (log_progname) fprintf(stderr, "%s PANICLOG:\n", log_progname); else fprintf(stderr, "Prayer PANICLOG:\n"); fprintf(stderr, " [log_panic] Out of memory\n"); if (log_progname) openlog(log_progname, LOG_PID | LOG_CONS, LOG_MAIL); else openlog("prayer", LOG_PID | LOG_CONS, LOG_MAIL); syslog(LOG_ERR, "[log_panic] Out of memory"); closelog(); } /* ====================================================================== */ /* log_syslog_ap() ****************************************************** * * Log string message to syslog. ************************************************************************/ void log_syslog_ap(unsigned long len, char *fmt, va_list ap) { char *result; /* Alloc temporary buffer with space for Date + Expanded String + \n */ if ((result = malloc(len + 100)) == NIL) { log_out_of_memory(); return; } pool_vprintf(result, fmt, ap); syslog(LOG_INFO, "%s", result); free(result); } /* log_panic_ap() ******************************************************** * * Log string message to syslog and stderr ************************************************************************/ void log_panic_ap(unsigned long len, char *fmt, va_list ap) { char *result; /* Alloc temporary buffer with space for Date + Expanded String + \n */ if ((result = malloc(len + 100)) == NIL) { log_out_of_memory(); return; } pool_vprintf(result, fmt, ap); syslog(LOG_INFO, "%s", result); fprintf(stderr, "%s\n", result); free(result); } /* ====================================================================== */ void log_misc(char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = pool_vprintf_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_syslog_ap(len, fmt, ap); va_end(ap); } void log_debug(char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = pool_vprintf_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_syslog_ap(len, fmt, ap); va_end(ap); } void log_panic(char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = pool_vprintf_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_syslog_ap(len, fmt, ap); va_end(ap); } void log_fatal(char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = pool_vprintf_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_syslog_ap(len, fmt, ap); va_end(ap); exit(1); } ./prayer-1.3.5/accountd/test.c0000644006513000651300000000306211063701632014514 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/test.c,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" #define BUFFER_SIZE (1024) int main(int argc, char **argv) { int fd; struct iostream *stream; char buffer[BUFFER_SIZE]; struct termios attr, oldattr; if ((fd = open("/dev/tty", O_RDWR)) < 0) log_fatal("Couldn't open /dev/tty"); if (!(stream = iostream_create(NIL, fd, 0))) log_fatal("Couldn't open iostream"); ioprintf(stream, "Changing password for user dpc22.\n"); ioflush(stream); ioprintf(stream, "Changing password for dpc22\n"); ioflush(stream); ioprintf(stream, "(current) UNIX password: "); ioflush(stream); if (tcgetattr(fd, &oldattr) != 0) log_fatal("tcgetattr() failed"); memcpy(&attr, &oldattr, sizeof(struct termios)); attr.c_lflag &= ~(ISIG | ECHO); attr.c_lflag |= ECHONL; if (tcsetattr(fd, TCSANOW, &attr) != 0) log_fatal("tcgetattr() failed"); if (!iostream_getline(stream, buffer, BUFFER_SIZE)) log_fatal("Couldn't read line"); if (tcsetattr(fd, TCSANOW, &oldattr) != 0) log_fatal("tcgetattr() failed"); ioprintf(stream, "passwd: Authentication token manipulation error\n"); ioflush(stream); iostream_close(stream); exit(0); } ./prayer-1.3.5/accountd/file.h0000644006513000651300000000106411063701632014461 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/file.h,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* External Interfere Prototypes for file.c */ BOOL file_get(struct config *config, struct iostream *stream, char *line); BOOL file_put(struct config *config, struct iostream *stream, char *line); ./prayer-1.3.5/accountd/authenticate.h0000644006513000651300000000120111260106467016215 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/authenticate.h,v 1.1 2009/09/28 10:17:27 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* External Interfere Prototypes for authenicate.c */ BOOL authenticate(struct config *config, struct iostream *stream, char **usernamep); BOOL authenticate_preauth(struct config *config, struct iostream *stream, char **usernamep); ./prayer-1.3.5/accountd/filter.h0000644006513000651300000000077711063701632015041 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/filter.h,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* External Interfere Prototypes for filter.c */ BOOL filter_write_forward(struct config *config, char *text); BOOL filter_empty(char *text); ./prayer-1.3.5/accountd/config.c0000644006513000651300000006201511063701632015005 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/config.c,v 1.5 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" /* config_create() ********************************************************* * * Create a new config structure using own pool **************************************************************************/ struct config *config_create(void) { struct pool *pool = pool_create(0); struct config *config = pool_alloc(pool, sizeof(struct config)); /* General options */ config->pool = pool; config->accountd_port = 0L; config->log_debug = NIL; config->child_timeout = 10 * 60; config->authtype = AUTHTYPE_UNKNOWN; config->raven_enable = NIL; config->raven_key_path = ""; /* Location of filter files */ config->msforward_name = ".MSforward"; config->forward_name = ".forward"; config->aliases_name = "vacation.aliases"; config->filter_restricted = NIL; /* Password changing */ config->pwd_cmdline = NIL; config->pwd_script = NIL; config->pwd_pty = T; /* Fullname checking */ config->checkfull_cmdline = NIL; config->checkfull_script = NIL; config->checkfull_pty = T; /* Fullname changing */ config->full_cmdline = NIL; config->full_script = NIL; config->full_pty = T; /* Quota check */ config->quota_cmdline = NIL; config->quota_hermes = NIL; /* SSL configuration */ config->use_ssl = NIL; config->ssl_cert_file = NIL; config->ssl_privatekey_file = NIL; config->ssl_dh_file = NIL; config->ssl_rsakey_lifespan = (10 * 60); /* 10 mins */ config->ssl_rsakey_freshen = (10 * 60); /* 10 mins */ config->ssl_session_timeout = (24 * 60 * 60); /* 60 mins */ config->ssl_session_dir = NIL; config->egd_socket = NIL; return (config); } /* config_free() ********************************************************* * * Free config structure ************************************************************************/ void config_free(struct config *config) { pool_free(config->pool); } /* config_paniclog() ******************************************************* * * Special interation of paniclog() to print errrors consistently when * frontend or session starting up with introducing dependancies on code * which is specific to the frontend or session processes. **************************************************************************/ static void config_paniclog(struct config *config, char *fmt, ...) { unsigned long len; va_list ap; va_start(ap, fmt); len = log_entry_size(fmt, ap); va_end(ap); va_start(ap, fmt); log_panic_ap(len, fmt, ap); va_end(ap); } /* ====================================================================== */ /* conf used only to calculate offsets into live config structure */ static struct config conf; #define OFFSET(x) ((char*)(&conf.x) - (char *)&conf) /* Config options. Searched by binary chop => must be sorted correctly * However config_init() checks that order is correct, bails out otherwise */ static struct { char *name; enum { config_bool, config_number, config_time, config_string, config_path, config_perm, config_authtype, config_unknown } type; int offset; } config_options[] = { { "accountd_port", config_number, OFFSET(accountd_port)}, { "aliases_name", config_string, OFFSET(aliases_name)}, { "authtype", config_authtype, OFFSET(authtype)}, { "checkfull_cmdline", config_string, OFFSET(checkfull_cmdline)}, { "checkfull_pty", config_bool, OFFSET(checkfull_pty)}, { "checkfull_script", config_string, OFFSET(checkfull_script)}, { "child_timeout", config_time, OFFSET(child_timeout)}, { "egd_socket", config_path, OFFSET(egd_socket)}, { "filter_restricted", config_bool, OFFSET(filter_restricted)}, { "forward_name", config_string, OFFSET(forward_name)}, { "full_cmdline", config_string, OFFSET(full_cmdline)}, { "full_pty", config_bool, OFFSET(full_pty)}, { "full_script", config_string, OFFSET(full_script)}, { "msforward_name", config_string, OFFSET(msforward_name)}, { "pwd_cmdline", config_string, OFFSET(pwd_cmdline)}, { "pwd_pty", config_bool, OFFSET(pwd_pty)}, { "pwd_script", config_string, OFFSET(pwd_script)}, { "quota_cmdline", config_string, OFFSET(quota_cmdline)}, { "quota_hermes", config_bool, OFFSET(quota_hermes)}, { "raven_enable", config_bool, OFFSET(raven_enable)}, { "raven_key_path", config_path, OFFSET(raven_key_path)}, { "ssl_cert_file", config_path, OFFSET(ssl_cert_file)}, { "ssl_dh_file", config_path, OFFSET(ssl_dh_file)}, { "ssl_privatekey_file", config_path, OFFSET(ssl_privatekey_file)}, { "ssl_rsakey_freshen", config_time, OFFSET(ssl_rsakey_freshen)}, { "ssl_rsakey_lifespan", config_time, OFFSET(ssl_rsakey_lifespan)}, { "use_ssl", config_bool, OFFSET(use_ssl)}, { NIL, config_unknown, 0} }; static unsigned long options_size = 0L; /* ====================================================================== */ /* config_init() ********************************************************* * * Initialise config engine. Counts number of options in the "options" * array, and makes sure that they are properly sorted for binary chop * searches. ************************************************************************/ static BOOL config_init(void) { unsigned long offset; offset = 0; while (config_options[offset].name) { if (config_options[offset + 1].name) { if (strcmp(config_options[offset].name, config_options[offset + 1].name) > 0) { config_paniclog(NIL, "config.c: options array sorted incorrectly at %s", config_options[offset].name); return (NIL); } } offset++; } options_size = offset; return (T); } /* ====================================================================== */ /* config_find_key() ***************************************************** * * Find offset to "options" structure which corresponds to key * key: Key to lookup * * Returns: Array offset, (-1) on error. ************************************************************************/ static int config_find_option(char *key) { int first = 0; int last = options_size; int middle = 0; int rc; /* Binary chop */ while (first < last) { middle = (first + last) / 2; rc = strcmp(config_options[middle].name, key); if (rc == 0) return (middle); else if (rc < 0) first = middle + 1; else last = middle; } /* Check whether last interaction of loop found match */ if (!strcmp(config_options[middle].name, key)) return (middle); return (-1); /* Not found */ } /* ====================================================================== */ /* Various static utility routines for parsing elements of config file */ static BOOL config_parse_bool(BOOL * result, char *s) { if (!strcasecmp(s, "TRUE") || !strcasecmp(s, "T") || !strcmp(s, "1")) { *result = T; return (T); } if (!strcasecmp(s, "FALSE") || !strcasecmp(s, "NIL") || !strcmp(s, "0")) { *result = NIL; return (T); } return (NIL); } static BOOL config_parse_number(unsigned long *result, char *text) { char *s; for (s = text; *s; s++) if (!Uisdigit(*s)) return (NIL); *result = atoi(text); return (T); } static BOOL config_parse_perm(unsigned long *result, char *s) { if (s[0] != '0') return (NIL); if ((s[1] < '0') || (s[1] > '7')) return (NIL); if ((s[2] < '0') || (s[2] > '7')) return (NIL); if ((s[3] < '0') || (s[3] > '7')) return (NIL); *result = (((s[1] - '0') * (8 * 8)) + ((s[2] - '0') * (8)) + (s[3] - '0')); return (T); } static BOOL config_parse_authtype(AUTHTYPE * result, char *s) { *result = AUTHTYPE_UNKNOWN; if (!strcasecmp(s, "pam")) *result = AUTHTYPE_PAM; else if (!strcasecmp(s, "pwd")) *result = AUTHTYPE_PWD; else if (!strcasecmp(s, "pwd_md5")) *result = AUTHTYPE_PWD_MD5; else if (!strcasecmp(s, "shadow")) *result = AUTHTYPE_SHADOW; else if (!strcasecmp(s, "shadow_md5")) *result = AUTHTYPE_SHADOW_MD5; return ((*result != AUTHTYPE_UNKNOWN) ? T : NIL); } static BOOL config_parse_time(unsigned long *result, char *text) { char *s; unsigned long multiple; if (!(text && text[0])) return (NIL); for (s = text; s[1]; s++) if (!Uisdigit(*s)) return (NIL); if (Uisdigit(*s)) multiple = 1; else { switch (Utoupper(*s)) { case 'S': multiple = 1; break; case 'M': multiple = 60; break; case 'H': multiple = 60 * 60; break; case 'D': multiple = 24 * 60 * 60; break; default: return (NIL); } *s = '\0'; } *result = (multiple * atoi(text)); return (T); } static BOOL config_parse_string(char **result, char *text, struct pool *pool) { char *s; text = string_trim_whitespace(text); if (*text == '"') { text++; for (s = text; *s; s++) { if (*s == '"') { *s = '\0'; *result = pool_strdup(pool, text); return (T); } } return (NIL); } *result = pool_strdup(pool, text); return (T); } /* ====================================================================== */ /* config_parse_single() ************************************************* * * Parse a single (key, value) pair extracted from configuration file * or passed as command line option. * config: * key: Text for key * value: Text for value * lineno: Line number in configuration file (for error messages) * 0 if this option passed in on the command line. ************************************************************************/ static BOOL config_parse_single(struct config *config, char *key, char *value, unsigned long lineno) { struct pool *pool = config->pool; int i; char *ptr; if ((i = config_find_option(key)) < 0) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Unknown option \"%s\""), lineno, key); else config_paniclog(config, "Unknown option \"%s\"", key); return (NIL); } ptr = ((char *) config) + config_options[i].offset; switch (config_options[i].type) { case config_bool: if (!config_parse_bool((BOOL *) ptr, value)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes boolean argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes boolean argument", key); return (NIL); } break; case config_number: if (!config_parse_number((unsigned long *) ptr, value)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes a numeric argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes a numeric argument", key); return (NIL); } break; case config_perm: if (!config_parse_perm((unsigned long *) ptr, value)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes a permission argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes a permission argument", key); return (NIL); } break; case config_time: if (!config_parse_time((unsigned long *) ptr, value)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes a time argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes a time argument", key); return (NIL); } break; case config_string: case config_path: if (!config_parse_string((char **) ptr, value, pool)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes string argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes string argument", key); return (NIL); } break; case config_authtype: if (!config_parse_authtype((AUTHTYPE *) ptr, value)) { if (lineno > 0L) config_paniclog(config, ("Error parsing configuration file at line %lu: " "Option %s takes a authtype argument"), lineno, key); else config_paniclog(config, "option \"%s\" takes a authtype argument", key); return (NIL); } break; default: return (NIL); } return (T); } /* ====================================================================== */ /* config_skip_whitespace() ********************************************** * * Skip over whitespace in string (clone of string_skip_whitespace?) * sp: Ptr to string. Updated to reflect location of next token * * Returns: Location of the next token. ************************************************************************/ static char *config_skip_whitespace(char **sp) { char *s = *sp; if (!s) return (NIL); /* Skip leading whitespace */ while ((*s == ' ') || (*s == '\t')) s++; *sp = s; return ((*s) ? s : NIL); } /* config_get_key() ******************************************************* * * Get key token from config line (token terminated by whitespace or '=' * character). * sp: Ptr to string. Updated to reflect location of next token * * Returns: Location of the next token. *************************************************************************/ static char *config_get_key(char **sp) { char *s = *sp, *result; if (!s) return (NIL); while ((*s == ' ') || (*s == '\t')) s++; /* Record position of this token */ result = s; /* Find next whitespace character, '=', or end of string */ while ((*s) && (*s != ' ') && (*s != '\t') && (*s != '=')) s++; /* Tie off the string unless \0 already reached, or '=' separator */ if (*s && (*s != '=')) { *s++ = '\0'; while ((*s == ' ') || (*s == '\t')) s++; } if (*s != '=') return (NIL); *s++ = '\0'; while ((*s == ' ') || (*s == '\t')) s++; /* Record position of first non-whitespace character for next caller */ *sp = s; return (result); } /* ====================================================================== */ /* config_parse_option() ************************************************* * * Parse a single option passed in from the command line * config: * option: "key=value" or " " to parse * * Returns: T if option parsed successfully * NIL otherwise (message will be sent to paniclog). ************************************************************************/ BOOL config_parse_option(struct config * config, char *option) { char *key, *value; option = string_trim_whitespace(option); if (option[0] == '\0') return (T); if ((key = config_get_key(&option)) == NIL) { config_paniclog(config, "Option badly formatted: \"%s\"", option); return (NIL); } if ((value = config_skip_whitespace(&option)) == NIL) { config_paniclog(config, "Option badly formatted: \"%s %s\"", key, option); return (NIL); } return (config_parse_single(config, key, value, 0L)); } /* ====================================================================== */ /* config_get_line() **************************************************** * * Get a linear whitespace line (e.g: folded RFC822 or HTTP header line) * sp: Ptr to current string location * (updated to point to following line) * squeeze: Remove superfluous spaces from result. * * Returns: Ptr to this line ***********************************************************************/ static char *config_get_line(char **sp, BOOL squeeze) { char *s, *result; s = *sp; if (!(s && s[0])) return (NIL); /* CR, LF or CRLF before data proper starts? */ if ((s[0] == '\015') || (s[0] == '\012')) { result = s; if ((s[0] == '\015') && (s[1] == '\012')) { /* CRLF */ *s = '\0'; s += 2; } else *s++ = '\0'; /* CR or LF */ *sp = s; return (result); } result = s; /* Record position of non-LWS */ while (*s) { if ((*s == '\015') || (*s == '\012')) { /* CR, LF or CRLF */ char *t = s; s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; if ((*s != ' ') && (*s != '\t')) { *t = '\0'; break; } } else s++; } *sp = s; /* Set up for next caller */ return (result); } /* config_count_line() *************************************************** * * Count number of lines in string ************************************************************************/ static unsigned long config_count_line(char *s) { unsigned long lines = 1; while (*s) { if ((*s == '\015') || (*s == '\012')) { s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1; lines++; } else s++; } return (lines); } /* config_compress_line() ************************************************ * * Remove continuation sequences from LWS line ************************************************************************/ static BOOL config_compress_line(char *s) { char *t = s; while (*s) { /* Check for correctly folded line */ if ((s[0] == '\\') && ((s[1] == '\015') || (s[1] == '\012'))) { s += ((s[1] == '\015') && (s[2] == '\012')) ? 3 : 2; while (string_isspace(*s)) s++; continue; } /* Check for unexpected line break */ if ((s[0] == '\015') || (s[0] == '\012')) return (NIL); if (s > t) *t++ = *s++; else t++, s++; } *t = '\0'; return (T); } /* ====================================================================== */ /* config_parse_file() *************************************************** * * Parse configuration file * config: * filename: Name of configuration file (main() routine will pass * compile time default or user specified version). * * Returns: T if option parsed successfully * NIL otherwise (message will be sent to paniclog). ************************************************************************/ BOOL config_parse_file(struct config * config, char *filename) { char *buffer, *text; char *line, *key, *value; unsigned long next_lineno = 1; unsigned long cur_lineno = 1; BOOL okay; int fd; struct stat sbuf; unsigned long size; if ((fd = open(filename, O_RDONLY, 0)) < 0) { config_paniclog(config, "Couldn't open configuration file: \"%s\"", filename); return (NIL); } if ((fstat(fd, &sbuf)) < 0) { config_paniclog(config, "Couldn't fstat configuration file: \"%s\"", filename); return (NIL); } if ((text = buffer = malloc((size = sbuf.st_size) + 1)) == NIL) { config_paniclog(config, "Out of memory"); return (NIL); } if (read(fd, buffer, size) < size) { free(buffer); config_paniclog(config, "Couldn't read in configuration file: \"%s\"", filename); return (NIL); } buffer[size] = '\0'; /* Prep options array if we need to */ if ((options_size == 0L) && !config_init()) { free(buffer); return (NIL); } okay = T; while ((line = config_get_line(&text, NIL))) { cur_lineno = next_lineno; next_lineno += config_count_line(line); if (!config_compress_line(line)) { config_paniclog(config, "Invalid folded line starting at line %d: \"%s\"", cur_lineno, line); okay = NIL; continue; } if (line[0] == '#') continue; line = string_trim_whitespace(line); if (line[0] == '\0') continue; if ((key = config_get_key(&line)) == NIL) { config_paniclog(config, "Line %lu of config file badly formatted: \"%s\"", cur_lineno, line); okay = NIL; continue; } if ((value = config_skip_whitespace(&line)) == NIL) { config_paniclog(config, "Line %lu of config file badly formatted: \"%s %s\"", cur_lineno, key, line); okay = NIL; continue; } if (!config_parse_single(config, key, value, cur_lineno)) okay = NIL; } free(buffer); return (T); } /* ====================================================================== */ /* Couple of support macros to help test the integrity of the configuration * that we have just parsed */ #define TEST_STRING(x, y) \ { \ if (!(x && x[0])) { \ config_paniclog(config, "config: "y" not defined"); \ return(NIL); \ } \ } #define TEST_NUMBER(x, y) \ { \ if (x == 0) { \ config_paniclog(config, "config: "y" not defined"); \ return(NIL); \ } \ } /* config_check() ********************************************************* * * Check that a parsed configuration is sane and self-consistent. * config: * * Returns: T if config okay, NIL otherwise *************************************************************************/ BOOL config_check(struct config * config) { TEST_STRING(config->msforward_name, "msforward_name"); TEST_STRING(config->forward_name, "forward_name"); TEST_STRING(config->forward_name, "forward_name"); TEST_STRING(config->pwd_cmdline, "pwd_cmdline"); TEST_STRING(config->full_cmdline, "full_cmdline"); TEST_STRING(config->quota_cmdline, "quota_cmdline"); if (config->authtype == AUTHTYPE_UNKNOWN) { config_paniclog(config, "authtype not defined"); return (NIL); } return (T); } void config_extract_ssl(struct config *src, struct ssl_config *dst) { dst->ssl_session_dir = src->ssl_session_dir; dst->ssl_cert_file = src->ssl_cert_file; dst->ssl_privatekey_file = src->ssl_privatekey_file; dst->ssl_dh_file = src->ssl_dh_file; dst->ssl_session_timeout = src->ssl_session_timeout; dst->ssl_rsakey_lifespan = src->ssl_rsakey_lifespan; dst->ssl_rsakey_freshen = src->ssl_rsakey_freshen; dst->ssl_default_port = 0; /* XXX Not used */ dst->egd_socket = src->egd_socket; dst->log_debug = src->log_debug; } ./prayer-1.3.5/accountd/accountd-freebsd.cf0000644006513000651300000000346111063701632017116 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/accountd/accountd-freebsd.cf,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2002 # See the file NOTICE for conditions of use and distribution. # # Accountd configuration suitable for FreeBSD msforward_name = ".MSforward" forward_name = ".forward" aliases_name = "vacation.aliases" filter_restricted = FALSE # While debugging child_timeout = 0 # Authtype options: # PAM (preferred where available) # pwd :: Passwords accessed via getpwnam(), old fashioned crypt # pwd_md5 :: Passwords accessed via getpwnam(), GNU md5 crypt # shadow :: Passwords accessed via getspnam(), old fashioned crypt # shadow_md5 :: Passwords accessed via getspnam(), GNU md5 crypt # authtype = pam # Password changing - FreeBSD defaults pwd_cmdline = "/usr/bin/passwd" pwd_script = \ readline \ expect "Old password:" \ sendline "$old" \ expect "New password:" \ sendline "$new" \ expect "Retype new password:" \ sendline "$new" \ expect "passwd: updating the database...\n" \ expect "passwd: done\n" # Fullname checking checkfull_cmdline = "/bin/echo Script still needs to be written" checkfull_script = "result" # Fullname changing full_cmdline = "/bin/echo Script still needs to be written" full_script = "result" # Quota check quota_cmdline = "fquota -v" quota_hermes = FALSE # SSL configuration, if required #use_ssl = T #ssl_cert_file = "/usr/local/prayer/certs/prayer.pem" #ssl_dh_file = "/usr/local/prayer/certs/prayer.pem" #ssl_rsakey_lifespan = 10m #egd_socket = "/var/prngd/urandom" ./prayer-1.3.5/accountd/quota.h0000644006513000651300000000074111063701632014674 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/quota.h,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* External Interfere Prototypes for quota.c */ BOOL quota_check(struct config *config, struct iostream *stream); ./prayer-1.3.5/accountd/authenticate.c0000644006513000651300000002660311260106467016225 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/authenticate.c,v 1.6 2009/09/28 10:17:27 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" #ifdef BSD4_4 #define HAVE_SHADOW 0 #else #define HAVE_SHADOW 1 #endif #include #if HAVE_SHADOW #include #endif /* ====================================================================== */ #ifdef RAVEN_ENABLE static int check_domain(char *a, char *b) { int len = strlen(b); if (strncmp(a, b, len) != 0) return(0); /* Three possible terminators to host part of URL */ if (a[len] == '/' || a[len] == ':' || a[len] == '\0') return(1); return(0); } static int check_url(struct raven_wls_response *wls) { char *s = wls->url; char *t; if (!strncmp(s, "https://", strlen("https://"))) s += strlen("https://"); else if (!strncmp(s, "http://", strlen("http://"))) s += strlen("http://"); else return(0); if ((t = strchr(s, '.')) && check_domain(t+1, "hermes.cam.ac.uk")) return(1); if (check_domain(s, "magenta.csi.cam.ac.uk") || check_domain(s, "cyan.csi.cam.ac.uk")) return(1); return(0); } static int checkpassword_raven(struct config *config, char *username, char *password) { BOOL response = NIL; struct raven_wls_response *wls = raven_wls_response_parse ((char *)password, config->raven_key_path, NULL); if (!wls) return(NIL); if (!strcmp(wls->status, "200") && !strcmp(wls->principal, username) && check_url(wls) && raven_wls_response_check_timestamp(wls, RAVEN_WLS_TICKET_MAXSKEW, RAVEN_WLS_TICKET_LIFETIME)) response = T; raven_wls_response_free(wls); return(response); } #else static int checkpassword_raven(struct config *config, char *username, char *password) { return(0); } #endif /* ====================================================================== */ /* Code for authenticating user across iostream connection to client. * User interaction involving a root process: important that this code is * protected and properly verified! */ /* Definies a whole series of different authentication methods, including * PAM if PAM support configured in ../Config */ /* No prototype for crypt, at least on Linux */ #if HAVE_SHADOW extern char *crypt(char *password, char *salt); #endif /* ====================================================================== */ #ifdef ACCOUNTD_PAM_ENABLE #include #include /* checkpassword() code checks password using PAM library. Probably need * simple crypt and compare version as well */ static int chkpwconv(int num_msg, struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { char *password = (char *) appdata_ptr; const struct pam_message *m; struct pam_response *r; if (num_msg <= 0) return PAM_CONV_ERR; if (!(*resp = calloc(num_msg, sizeof(struct pam_response)))) return PAM_BUF_ERR; m = *msg; r = *resp; if (m->msg_style == PAM_PROMPT_ECHO_OFF) { if (!(r->resp = strdup(password))) { free(*resp); *resp = 0; return PAM_BUF_ERR; } } return PAM_SUCCESS; } static int checkpassword_pam(char *username, char *password) { pam_handle_t *pamh; struct pam_conv conv; int status; conv.conv = (int (*)()) chkpwconv; /* Prevents hdr mismatch */ conv.appdata_ptr = password; status = pam_start("accountd", username, &conv, &pamh); if (status == PAM_SUCCESS) status = pam_authenticate(pamh, 0); pam_end(pamh, status); return ((status == PAM_SUCCESS) ? T : NIL); } #else static int checkpassword_pam(char *username, char *password) { log_panic("PAM authentication selected but support not compiled in"); return (NIL); } #endif /* ====================================================================== */ /* Naive implementation: no support for expired passwords yet * (we don't use them) */ #if HAVE_SHADOW static int checkpassword_spnam(char *username, char *password, int md5) { struct spwd *spwd; char *crypted; int rc; if ((spwd = getspnam(username)) == NIL) return (NIL); if (md5) { char tmp[64]; sprintf(tmp, "%s", spwd->sp_pwdp); tmp[11] = '\0'; if ((crypted = crypt(password, tmp)) != NIL) rc = !strcmp(spwd->sp_pwdp, crypted) ? T : NIL; else rc = NIL; } else { if ((crypted = crypt(password, spwd->sp_pwdp)) != NIL) rc = !strcmp(spwd->sp_pwdp, crypted); else rc = NIL; } endspent(); return (rc); } #endif static int checkpassword_pwnam(char *username, char *password, int md5) { struct passwd *pwd; char *crypted; int rc; if ((pwd = getpwnam(username)) == NIL) return (NIL); if (md5) { char tmp[64]; sprintf(tmp, "$1$%s", pwd->pw_passwd); tmp[8] = '\0'; if ((crypted = crypt(password, tmp)) != NIL) rc = !strcmp(pwd->pw_passwd, crypted) ? T : NIL; else rc = NIL; } else { if ((crypted = crypt(password, pwd->pw_passwd)) != NIL) rc = !strcmp(pwd->pw_passwd, crypted); else rc = NIL; } endpwent(); return (rc); } /* ====================================================================== */ static void ucase(char *s) { while (*s) { *s = Utoupper(*s); s++; } } /* authenticate() ********************************************************* * * Authenticate login session and drop priveledges. * config: Global configuration * stream: iostream connection to client * usernamep: Used to return username of logged in user * * Returns: T => successful login. NIL otherwise ************************************************************************/ BOOL authenticate(struct config *config, struct iostream *stream, char **usernamep) { char buffer[MAXLENGTH]; char *username = NIL; char *password = NIL; struct passwd *pwd; char *cmd, *line; int rc = NIL; *usernamep = NIL; if (getuid() != 0) log_fatal("authenticate(): called without root priveledges"); ioputs(stream, "* "); if (config->filter_restricted) ioputs(stream, "[FILTER_RESTRICTED] "); ioprintf(stream, "Prayer ACCOUNTD server %s" CRLF, VERSION); ioflush(stream); while (1) { if (!iostream_getline(stream, buffer, MAXLENGTH)) return (NIL); if (buffer[0] == '\0') /* Ignore empty lines */ continue; line = buffer; if (!(cmd = string_get_token(&line))) { ioputs(stream, "BAD Invalid command" CRLF); ioflush(stream); continue; } ucase(cmd); if (!strcmp(cmd, "LOGOUT")) { ioputs(stream, "OK Logout" CRLF); ioflush(stream); return (NIL); } if (strcmp(cmd, "LOGIN") != NIL) { ioputs(stream, "BAD Invalid command" CRLF); ioflush(stream); continue; } if (!((username = string_get_token(&line)) && (username[0]))) { ioputs(stream, "BAD No username" CRLF); ioflush(stream); continue; } string_canon_decode(username); if (!((password = string_get_token(&line)) && (password[0]))) { ioputs(stream, "BAD No password" CRLF); ioflush(stream); continue; } string_canon_decode(password); /* Empty username/password already reported, just need to loop */ if (!(username && username[0] && password && password[0])) continue; /* Only need to authenticate if root */ if (config->raven_enable && (strlen(password) > 256)) { rc = checkpassword_raven(config, username, password); } else switch (config->authtype) { case AUTHTYPE_PAM: rc = checkpassword_pam(username, password); break; case AUTHTYPE_PWD: rc = checkpassword_pwnam(username, password, 0); break; case AUTHTYPE_PWD_MD5: rc = checkpassword_pwnam(username, password, 1); break; #if HAVE_SHADOW case AUTHTYPE_SHADOW: rc = checkpassword_spnam(username, password, 0); break; case AUTHTYPE_SHADOW_MD5: rc = checkpassword_spnam(username, password, 1); break; #endif default: log_fatal("Unsupported authentication type"); } if (!rc) { ioputs(stream, "NO Incorrect authentication" CRLF); ioflush(stream); log_misc("Incorrect authentication for: %s", username); continue; } /* getpwnam() shouldn't fail if PAM authentication working properly */ if ((pwd = getpwnam(username)) == NIL) { ioputs(stream, "NO Incorrect authentication" CRLF); ioflush(stream); log_misc("Incorrect authentication for: %s", username); continue; } if (pwd->pw_uid == 0) { ioputs(stream, "NO Root login disabled" CRLF); ioflush(stream); continue; } break; } setgid(pwd->pw_gid); /* Change GID permanently for session */ setuid(pwd->pw_uid); /* Change UID permanently for session */ if (chdir(pwd->pw_dir)) { ioputs(stream, "NO Can't select user home directory" CRLF); ioflush(stream); return (NIL); } ioputs(stream, "OK Session authenticated" CRLF); ioflush(stream); if (getuid() == 0) log_fatal("authenticate(): Ended up as root user!"); *usernamep = strdup(username); return (T); } /* ====================================================================== */ /* authenticate_preauth() ************************************************ * * Authenticate login session and drop priveledges. * config: Global configuration * stream: iostream connection to client * usernamep: Used to return username of logged in user * * Returns: T => successful login. NIL otherwise ************************************************************************/ BOOL authenticate_preauth(struct config * config, struct iostream * stream, char **usernamep) { struct passwd *pwd; if (getuid() == 0) log_fatal("authenticate_preauth(): called as root"); if ((pwd = getpwuid(getuid())) == NIL) log_fatal("session(): getpwuid() failed"); *usernamep = strdup(pwd->pw_name); ioputs(stream, "* "); if (config->filter_restricted) ioputs(stream, "[FILTER_RESTRICTED] "); ioprintf(stream, "PREAUTH Prayer ACCOUNTD server %s [user=%s]" CRLF, VERSION, *usernamep); ioflush(stream); if (chdir(pwd->pw_dir)) { ioputs(stream, "* Can't switch to PREAUTH user's home directory" CRLF); ioflush(stream); return (NIL); } return (T); } ./prayer-1.3.5/accountd/mail.c0000644006513000651300000002330411063701632014460 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/mail.c,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" /* mail_string_add() ***************************************************** * * Copy string to ptr, add pointer over string * Up to client to worry about bounds checking and buffer overruns. * mail_fake_simple is the only client * * sp: Targ string. Updated to point to end of copied string. * s: String to add ************************************************************************/ static void mail_string_add(char **sp, char *s) { strcpy(*sp, s); *sp += strlen(s); } /* mail_fake_simple() **************************************************** * * Convert simple format .forward files into equivalent MSforward so that * client doesn't have to worry about the distinguistion. * stream: iostream connection to client * file: .forward file to test * * Returns: * NIL => input file was not simple .forward file * T => .forward file was simple format. OK {literal} to output. ************************************************************************/ static BOOL mail_fake_simple(struct iostream *stream, FILE * file) { static char buffer[MAXLENGTH]; static char tmp[2 * MAXLENGTH]; /* Safe upper bound */ char *s; int c, i, count; int copy, vacation; char *address; /* Get first line from file */ if (!fgets(buffer, MAXLENGTH - 1, file)) return (NIL); buffer[strlen(buffer) - 1] = '\0'; /* Remove trailing \n */ /* Can't fake Exim filter files */ if (!strncasecmp(buffer, "# Exim filter ", strlen("# Exim filter "))) return (NIL); /* Can't fake multiline files */ while ((c = getc(file)) != EOF) if ((c != '\015') && (c != '\015') && (c != ' ') && (c != '\t')) return (NIL); /* Old style formats that we want to support: * * \user, vacation-user ==> VACATION action * \user, address ==> REDIRECT action */ copy = NIL; vacation = NIL; address = NIL; s = buffer; /* Skip leading whitespace */ while (*s == ' ') s++; if (*s == '\\') { /* "\dpc22, something" */ copy = T; if (!(s = strchr(s, ','))) return (NIL); /* Something funny going on */ s++; } else s = buffer; /* Skip leading whitespace */ while (*s == ' ') s++; if (!strncmp(s, "vacation-", strlen("vacation-"))) { if (strchr(s, '@')) /* Catch vacation-foo@some.remote.site */ return (NIL); vacation = T; address = NIL; } else address = s; /* .forward file passes our regex: convert to equivalent MSforward */ s = tmp; mail_string_add(&s, "# MSforward file created by prayer\n"); if (vacation) mail_string_add(&s, "vacation\n"); if (address && address[0]) { mail_string_add(&s, "redirect\n"); mail_string_add(&s, " address\t"); mail_string_add(&s, address); mail_string_add(&s, "\n"); if (copy) mail_string_add(&s, " copy true\n"); } count = (int) (s - tmp); ioprintf(stream, "OK {%d}" CRLF, count); for (i = 0; i < count; i++) ioputc(tmp[i], stream); ioputs(stream, "" CRLF); ioflush(stream); return (T); } /* ====================================================================== */ /* mail_status() ********************************************************* * * MAILSTATUS command. * config: Accountd configuration * stream: iostream connection to client * line: Arguments to MAILSTATUS: should be empty * * Returns: T on success, NIL otherwise * * Output: * OK {literal} => Current mail status as MSforward format * NO [Error message] => Couldn't determine mail status * BAD [Error message] => Protocol error ************************************************************************/ BOOL mail_status(struct config * config, struct iostream * stream, char *line) { unsigned long existing, current; FILE *file; struct stat sbuf; int c; if (!checksum_test(config, &existing, ¤t)) { ioputs(stream, "OK {0}" CRLF); /* No mail forwarding in place */ ioflush(stream); return (T); } if (existing != 0) { /* .forward file exists and contains checksum */ if (existing != current) { ioputs(stream, "NO Checksum mismatch: manually maintained .forward file?" CRLF); ioflush(stream); return (T); } if (stat(config->msforward_name, &sbuf) || ((file = fopen(config->msforward_name, "r")) == NULL)) { ioputs(stream, "NO Inconsistent state: Couldn't open .MSforward file" CRLF); ioflush(stream); return (T); } ioprintf(stream, "OK {%lu}" CRLF, (unsigned long) sbuf.st_size); while ((c = getc(file)) != EOF) ioputc(c, stream); ioputs(stream, "" CRLF); ioflush(stream); fclose(file); return (T); } /* No checksum in .forward file. Check for trivial case that we can fake * up as an automatically managed file */ if ((file = fopen(config->forward_name, "r")) == NULL) { /* Worked a second ago! */ ioputs(stream, "NO Checksum mismatch: manually maintained .forward file?" CRLF); ioflush(stream); return (T); } if (!mail_fake_simple(stream, file)) { ioputs(stream, "NO Manually maintained .forward file?" CRLF); ioflush(stream); } fclose(file); return (T); } /* ====================================================================== */ /* XXX Should really update temporary files, rename */ /* mail_change() ********************************************************* * * MAILCHANGE command * config: accountd configuration * stream: iostream connection to client * line: Arguments to MAILCHANGE. Literal containing MSforward * restricted: T => filters are restricted to "mail" subdirectory * * Returns: T on success, NIL otherwise * * Output: * OK [text]. MSforward file uploaded, filter filter generated * NO [text]. Upload or translation failed * BAD [text]. Protocol error ************************************************************************/ BOOL mail_change(struct config * config, struct iostream * stream, char *line) { char *size; FILE *file; int c, len; unsigned char *text = NIL; unsigned char *s; if (!((size = string_get_token(&line)) && (size[0]))) { ioputs(stream, "BAD No file size provided" CRLF); ioflush(stream); return (T); } if (((len = strlen(size)) < 2) || (size[0] != '{') || (size[len - 1] != '}')) { ioputs(stream, "BAD Invalid file size" CRLF); ioflush(stream); return (T); } /* Check that size[1] -> size[len-1] all digits? */ size[len - 1] = '\0'; /* Probably not needed */ len = atoi(size + 1); /* Copy filter value to string */ if ((text = malloc(len + 1)) == NIL) { ioputs(stream, "NO Out of memory" CRLF); ioflush(stream); return (T); } s = text; while ((len > 0) && (c = iogetc(stream))) { *s++ = (unsigned char) c; len--; } *s = '\0'; if (len > 0) { free(text); ioprintf(stream, "BAD %d bytes missing from input" CRLF, len); ioflush(stream); return (T); } /* Check whether filter file actually contains actions */ if (filter_empty((char *) text)) { free(text); unlink(config->msforward_name); unlink(config->forward_name); ioputs(stream, "OK Filter file disabled" CRLF); ioflush(stream); return (T); } /* Push filter value into .MSforward file */ if ((file = fopen(config->msforward_name, "w")) == NIL) { /* Swallow unwanted text */ while ((len > 0) && (c = iogetc(stream))) len--; fclose(file); ioputs(stream, "NO Couldn't open file" CRLF); ioflush(stream); return (T); } for (s = text; *s; s++) putc(*s, file); if (fclose(file) != 0) { free(text); ioputs(stream, "NO Failed to update filter file. Quota problems?" CRLF); ioflush(stream); return (T); } /* File successfully uploaded. Run update script */ if (filter_write_forward(config, (char *) text)) ioputs(stream, "OK Filter file uploaded" CRLF); else ioputs(stream, "NO Failed to update filter file. Quota problems?" CRLF); ioflush(stream); free(text); return (T); } /* ====================================================================== */ /* mail_vacclear() ******************************************************* * * Clear vacation log file * config: Accountd configuration * stream: iostream connection to client * line: Arguments for VACATION_CLEAR command. Should be empty * * Returns: T in all situations * Output: OK in all situations ************************************************************************/ BOOL mail_vacclear(struct config * config, struct iostream * stream, char *line) { unlink("vacation.log"); unlink("vacation.once.dir"); unlink("vacation.once.pag"); ioputs(stream, "OK Vacation Log cleared" CRLF); ioflush(stream); return (T); } ./prayer-1.3.5/accountd/mail.h0000644006513000651300000000121311063701632014460 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/mail.h,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* External Interfere Prototypes for mail.c */ BOOL mail_status(struct config *config, struct iostream *stream, char *line); BOOL mail_change(struct config *config, struct iostream *stream, char *line); BOOL mail_vacclear(struct config *config, struct iostream *stream, char *line); ./prayer-1.3.5/accountd/fullname.c0000644006513000651300000001101411063701632015334 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/fullname.c,v 1.3 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" /* fullname_change_internal() ******************************************** * * Start up passwd program and chat with it to change fullname * config: Accountd configuration * password: Account password, if needed * newname: New fullname * * Returns: Error string. NIL => all okay ************************************************************************/ static char *fullname_change_internal(struct config *config, char *password, char *new) { struct pool *pool = pool_create(0); struct assoc *h = assoc_create(pool, 16, T); struct process process; char *error; char *cmdline; assoc_update(h, "password", password, T); assoc_update(h, "newname", new, T); /* Expand */ cmdline = string_expand(pool, h, config->full_cmdline); process_clear(&process); if (!process_start(&process, cmdline, config->full_pty, config->child_timeout)) { pool_free(pool); return ("Couldn't start the password program"); } error = process_run_script(&process, pool, h, pool_strdup(pool, config->full_script), NIL, 0L); if (!process_stop(&process)) { pool_free(pool); return ("Error code from password program"); } pool_free(pool); return (error); } /* fullname_change() ***************************************************** * * Change passwd using the passwd program * config: Accountd configuration * stream: iostream connection to client * line: Arguments for FULLNAME command. * Should be new fullname. * * Returns: T in all situations * OK [text]. Password changed * NO [text]. Failed to change password * BAD [text]. Protocol error ************************************************************************/ BOOL fullname_change(struct config * config, struct iostream * stream, char *line) { char *s1, *s2, *password, *newname, *errmsg; if (!((s1 = string_get_token(&line)) && (s1[0]))) { ioputs(stream, "BAD No new fullname" CRLF); ioflush(stream); return (T); } if ((s2 = string_get_token(&line)) && (s2[0])) { password = s1; /* New format, "password Newname" */ newname = s2; string_canon_decode(password); string_canon_decode(newname); } else { password = ""; /* Old format, single "Newname" argument */ newname = s1; string_canon_decode(newname); } if (!(errmsg = fullname_change_internal(config, password, newname))) ioputs(stream, "OK Changed fullname" CRLF); else if (errmsg[0]) ioprintf(stream, "NO %s" CRLF, errmsg); else ioputs(stream, "NO Failed to change fullname" CRLF); ioflush(stream); return (T); } /* ====================================================================== */ /* fullname_check() ****************************************************** * * Check fullname with server. * config: Accountd configuration * stream: iostream connection to client ************************************************************************/ BOOL fullname_check(struct config * config, struct iostream * stream) { struct pool *pool = pool_create(0); struct assoc *h = assoc_create(pool, 16, T); char buffer[MAXLENGTH]; char *error; struct process process; process_clear(&process); if (!process_start(&process, config->checkfull_cmdline, config->checkfull_pty, config->child_timeout)) { pool_free(pool); ioputs(stream, "NO Couldn't fetch Fullname from server" CRLF); ioflush(stream); return (NIL); } error = process_run_script(&process, pool, h, pool_strdup(pool, config->checkfull_script), buffer, MAXLENGTH); process_stop(&process); pool_free(pool); if (error) { ioprintf(stream, "NO Couldn't fetch Fullname from server: %s" CRLF, error); ioflush(stream); return (NIL); } ioprintf(stream, "OK %s" CRLF, buffer); ioflush(stream); return (T); } ./prayer-1.3.5/accountd/accountd.c0000644006513000651300000002275711415123156015351 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/accountd.c,v 1.8 2010/07/07 16:08:14 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* Prayer account management daemon */ #include "accountd.h" static void ucase(char *s) { while (*s) { *s = Utoupper(*s); s++; } } /* ====================================================================== */ /* Process line of input once authenticated */ static BOOL do_authenticated_line(struct config *config, char *line, struct iostream *stream, char *username) { char *cmd; if (!(cmd = string_get_token(&line))) { ioputs(stream, "BAD Invalid command" CRLF); ioflush(stream); return (T); } ucase(cmd); log_misc("%s: %s", username, cmd); switch (cmd[0]) { case 'C': if (!strcmp(cmd, "CHECKFULLNAME")) { fullname_check(config, stream); return (T); } break; case 'F': if (!strcmp(cmd, "FULLNAME")) return (fullname_change(config, stream, line)); break; case 'G': if (!strcmp(cmd, "GET")) return (file_get(config, stream, line)); break; case 'M': /* Merge into single mail_upload command */ if (!strcmp(cmd, "MAILSTATUS")) return (mail_status(config, stream, line)); else if (!strcmp(cmd, "MAILCHANGE")) return (mail_change(config, stream, line)); break; case 'L': if (!strcmp(cmd, "LOGOUT")) { ioputs(stream, "OK Logout" CRLF); ioflush(stream); return (NIL); } else if (!strcmp(cmd, "LOGIN")) { ioputs(stream, "NO Already authenticated" CRLF); ioflush(stream); return (T); } break; case 'P': if (!strcmp(cmd, "PASSWORD")) return (password_change(config, stream, line)); else if (!strcmp(cmd, "PUT")) return (file_put(config, stream, line)); break; case 'Q': if (!strcmp(cmd, "QUOTA")) { quota_check(config, stream); return (T); } break; case 'V': if (!strcmp(cmd, "VACATION_CLEAR")) return (mail_vacclear(config, stream, line)); break; } ioputs(stream, "BAD Unknown command" CRLF); ioflush(stream); return (T); } /* ====================================================================== */ /* Run a single accountd session on the nominated socket descriptor */ static BOOL session(struct config *config, int sockfd) { char buffer[MAXLENGTH]; char *username = NIL; struct iostream *stream; if (! (stream = iostream_create(NIL, sockfd, IOSTREAM_PREFERRED_BLOCK_SIZE))) return (NIL); iostream_set_timeout(stream, ACCOUNTD_TIMEOUT); if (config->use_ssl && !iostream_ssl_start_server(stream)) return (NIL); if (getuid() == 0) { if (!authenticate(config, stream, &username)) return (NIL); } else { if (!authenticate_preauth(config, stream, &username)) return (NIL); } if (getuid() == 0) { log_fatal("Authenticated session running with root privilege"); /* NOTREACHED */ exit(1); } log_misc("User login: %s", username); while (1) { if (!iostream_getline(stream, buffer, MAXLENGTH)) break; if (buffer[0] == '\0') /* Ignore empty lines */ continue; if (!do_authenticated_line(config, buffer, stream, username)) break; } log_misc("User logout: %s", username); return (T); } /* ====================================================================== */ /* Code for running accountd as standalone daemon rather than from inetd */ void rundaemon(struct config *config, int use_fork, int port) { struct ipaddr ipaddr; int *sockfds; int newsockfd; pid_t childpid; #ifdef USE_SSL struct ssl_config ssl_config; #endif if (!(sockfds = os_bind_inet_socket(port, NIL))) log_fatal("socket() failed"); os_signal_child_init(os_child_reaper); #ifdef USE_SSL if (config->use_ssl) { config_extract_ssl(config, &ssl_config); iostream_init(&ssl_config); /* Required for SSL stuff */ } #endif for (;;) { fd_set fds; int maxsockfd, i; FD_ZERO(&fds); maxsockfd = 0; for (i=0; sockfds[i] >= 0; i++) { FD_SET(sockfds[i], &fds); if (sockfds[0] > maxsockfd) maxsockfd = sockfds[0]; } while (select(maxsockfd + 1, &fds, NIL, NIL, NIL) < 0) { if (errno != EINTR) log_fatal("prayer_server(): select() failed: %s", strerror(errno)); } for (i=0; sockfds[i] >= 0; i++) { if (FD_ISSET(sockfds[i], &fds)) { int sockfd = sockfds[i]; if ((newsockfd = os_accept_inet(sockfd, &ipaddr)) < 0) log_fatal("accept() failed: errno = %d", errno); log_misc("Incoming connection from %s", ipaddr_text(&ipaddr)); if (use_fork) { if ((childpid = fork()) < 0) log_fatal("fork() failed: errno = %d", errno); if (childpid == 0) { /* Child process */ close(sockfd); os_signal_child_clear(); session(config, newsockfd); close(newsockfd); exit(0); } } else session(config, newsockfd); /* Parent */ close(newsockfd); } } #ifdef USE_SSL /* Replace (shared) RSA key every few minutes */ if (config->use_ssl) { iostream_check_rsakey(&ssl_config); } #endif } } /* ====================================================================== */ /* Main routine: * Parse command line options, then run as either permanant daemon or * single shot login using file descriptor 0 for input and output */ int main(int argc, char **argv) { BOOL use_fork = T; BOOL hermes = NIL; char *config_filename = ACCOUNTD_CONFIG_FILE; struct config *config = config_create(); #ifdef USE_SSL struct ssl_config ssl_config; #endif int i; /* Disable supplementary groups, switch to group "other" (if it exists) */ if (getuid() == 0) { struct group *group; setgroups(0, NIL); if ((group = getgrnam("hermes")) != NIL) setgid(group->gr_gid); if ((group = getgrnam("other")) != NIL) setgid(group->gr_gid); else if ((group = getgrnam("user")) != NIL) setgid(group->gr_gid); } if (getenv("ACCOUNTD_CONFIG_FILE")) config_filename = getenv("ACCOUNTD_CONFIG_FILE"); log_init(config, argv[0]); /* Minimal Umask: don't want anyone reading user .forward files. */ umask(0077); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--enable-fork")) use_fork = T; else if (!strcmp(argv[i], "--disable-fork")) use_fork = NIL; else if (!strcmp(argv[i], "--hermes")) { hermes = T; } else if (!strncmp(argv[i], "--config-file=", strlen("--config-file="))) config_filename = strdup(argv[i] + strlen("--config-file=")); else if (!strcmp(argv[i], "--config-option")) i++; /* Processes next argv */ else if (!strcmp(argv[i], "--help")) { fprintf(stderr, "Command Line Options:\n"); fprintf(stderr, (" --config-file=x " "Define location of configuration file\n")); fprintf(stderr, (" --config-option x=y " "Override option from configuration file\n")); fprintf(stderr, (" --enable-fork " "Allow fork if running as daemon (default)\n")); fprintf(stderr, (" --disable-fork " "Disable fork if running as daemon (debugging)\n")); exit(0); } else log_fatal("Unknown command line option"); } if (!config_parse_file(config, config_filename)) exit(1); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--config-option")) { if (++i < argc) { if (!config_parse_option(config, strdup(argv[i]))) exit(1); } else fprintf(stderr, "--config processes following option"); } } if (!config_check(config)) exit(1); if (hermes) config->filter_restricted = T; /* Required for SSL stuff */ #ifdef USE_SSL if (config->use_ssl) { config_extract_ssl(config, &ssl_config); iostream_init(&ssl_config); } #endif /* Run as daemon on nominated port */ if (config->accountd_port) { rundaemon(config, use_fork, config->accountd_port); /* NOTREACHED */ exit(0); } /* Otherwise run as single shot session on file descriptor 0 * i.e: inetd service */ session(config, 0); exit(0); } ./prayer-1.3.5/accountd/checksum.h0000644006513000651300000000106411063701632015344 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/checksum.h,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* External Interfere Prototypes for checksum.c */ BOOL checksum_test(struct config *config, unsigned long *existing, unsigned long *current); BOOL checksum_generate(char *name); ./prayer-1.3.5/accountd/filter.c0000644006513000651300000005506011063701632015027 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/filter.c,v 1.4 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" /* Class for converting .MSforward rules into an Exim filter .forward file * Transliteration of some Perl that is used in our interactive menu system * interface, including a number of rather dubious rules */ struct filter { enum { CO_UNKNOWN, CO_VACATION, CO_SPAM, CO_SENDER, CO_RECIPIENT, CO_BLOCK, CO_SUBJECT, CO_REDIRECT } type; char *local_part; char *domain; char *subject; char *mailbox; char *address; char *threshold; BOOL copy; }; /* Quoting for metacharacters: two levels of quoting required */ #define QMETA "\\\\" /* Quoting for for wildcard characters: four levels of quoting required */ #define QWILD "\\\\\\\\" /* ====================================================================== */ /* Some Support routines for processing wildcards */ /* filter_quote_double() ************************************************* * * Print string to file, quoting '"' characters. * file: Output file * s: String to quote. ************************************************************************/ static void filter_quote_double(FILE * file, char *s) { char c; while ((c = *s++)) { if (c == '"') putc('\\', file); putc(c, file); } } /* filter_has_wildcard() ************************************************* * * Check whether string contains wildcard character. * s: String to check. * * Returns: T => string contains wildcard. NIL otherwise. ************************************************************************/ static BOOL filter_has_wildcard(char *s) { char c; while ((c = *s++)) { if ((c == '?') || (c == '*') || (c == '"')) return (T); } return (NIL); } /* filter_quote_wildcard() *********************************************** * * Print string to file, quoting wildcard characters. * file: Output file * s: String to quote. ************************************************************************/ static void filter_quote_wildcard(FILE * file, char *s) { char c; while ((c = *s++)) { switch (c) { case '[': case ']': case '\'': case '|': case '.': case '+': case '^': case '$': case '?': case '*': fprintf(file, "%s", QWILD); putc(c, file); break; case '"': fputc('\\', file); putc(c, file); break; default: putc(c, file); } } } /* filter_expand_wildcard() ********************************************** * * Print string to file, expanding simple wildcard characters (? and *) * into Perl 5 compatible regexps used by Exim. * file: Output file * s: String to quote. ************************************************************************/ static void filter_expand_wildcard(FILE * file, char *s) { char c; while ((c = *s++)) { switch (c) { case '[': case ']': case '\'': case '|': case '.': case '+': case '^': case '$': /* Quota regexp significant character */ fprintf(file, "%s", QWILD); putc(c, file); break; case '?': /* Translate '?' wildcard into appropriate Exim filter file syntax */ fprintf(file, "%s.", QMETA); break; case '*': /* Translate '*' wildcard into appropriate Exim filter file syntax */ fprintf(file, "%s.%s*", QMETA, QMETA); break; case '"': fputc('\\', file); putc(c, file); break; default: putc(c, file); } } } /* ====================================================================== */ /* filter_expand_local() ************************************************* * * Print local part to file, expanding simple wildcard characters (? and * into Perl 5 compatible regexps used by Exim. * file: Output file * s: String to quote. ************************************************************************/ static void filter_expand_local(FILE * file, char *s) { if (*s == '"') filter_quote_wildcard(file, s); else filter_expand_wildcard(file, s); } /* filter_expand_domain() ************************************************* * * Print domain to file, expanding simple wildcard characters (? and into * Perl 5 compatible regexps used by Exim. * file: Output file * s: String to quote. ************************************************************************/ static void filter_expand_domain(FILE * file, char *s) { filter_expand_wildcard(file, s); } /* ====================================================================== */ /* ====================================================================== */ /* Routines for generating parts of filter file */ /* filter_write_to() ***************************************************** * * Write target mailbox * config: Gloabl state * file: Output file * mailbox: Target mailbox * copy: Store copy in inbox ************************************************************************/ static void filter_write_to(struct config *config, FILE * file, char *mailbox, BOOL copy) { if (copy) fprintf(file, " unseen save \""); else fprintf(file, " save \""); /* Ghastly restriction on Hermes for historical reasons. Yuck! */ if (config->filter_restricted) fprintf(file, "mail/"); filter_quote_double(file, mailbox); fprintf(file, "\"\n"); fprintf(file, " finish\n"); fprintf(file, "endif\n"); } /* filter_print_aliases() ************************************************* * * Extract aliases list from vacation.aliases file and include in forward * file. * config: Global state * file: Output file ************************************************************************/ static BOOL filter_print_aliases(struct config *config, FILE * file) { FILE *aliases; char buffer[MAXLENGTH]; if ((aliases = fopen(config->aliases_name, "r")) == NIL) return (T); while (fgets(buffer, MAXLENGTH, aliases)) { unsigned long len = strlen(buffer); /* Chomp: buffer may or may not include a '\n' */ if ((len > 0) && (buffer[len - 1] == '\n')) buffer[--len] = '\0'; fprintf(file, " alias %s\n", buffer); } fclose(aliases); return (T); } /* filter_print_vacation() *********************************************** * * Add vacation message to filter file * config: Global state * filter: Filter action structure (actually unused) * file: Output file ************************************************************************/ static BOOL filter_print_vacation(struct config *config, struct filter *filter, FILE * file) { struct passwd *pwd; if (!(pwd = getpwuid(getuid()))) return (NIL); fprintf(file, "# MSshell :: vacation\n"); fprintf(file, "if personal\n"); fprintf(file, " alias %s@cam.ac.uk\n", pwd->pw_name); if (!filter_print_aliases(config, file)) return (NIL); fprintf(file, "then\n"); fprintf(file, " mail\n"); fprintf(file, " subject \"Auto reply Re: $h_subject\"\n"); fprintf(file, " text \"\\\n"); fprintf(file, ("This message is automatically generated " "in response to your mail\\n\\" "\n")); fprintf(file, ("message (perhaps re-directed) to " "$local_part@hermes.cam.ac.uk.\\n\\n\"\n")); fprintf(file, " file ${home}/vacation.message\n"); fprintf(file, " log ${home}/vacation.log\n"); fprintf(file, " once ${home}/vacation.once\n"); fprintf(file, "endif\n"); fprintf(file, "\n"); return (T); } /* filter_print_spam() *************************************************** * * Add spam clause to filter file * config: Global state * filter: Filter action structure (actually unused) * file: Output file ************************************************************************/ static BOOL filter_print_spam(struct config *config, struct filter *filter, FILE *file) { int threshold, i; if (!(filter->threshold && string_isnumber(filter->threshold))) return(NIL); threshold = atoi(filter->threshold); /* XXX (threshold == 0) okay? */ fprintf(file, "if $h_X-Cam-SpamScore contains \""); for (i=0 ; i < threshold; i++) fputc('s', file); fprintf(file, "\" then\n"); fprintf(file, " save mail/spam\n"); fprintf(file, " finish\n"); fprintf(file, "endif\n"); fprintf(file, "\n"); return(T); } /* ====================================================================== */ /* filter_print_sender() ************************************************* * * Print SENDER filter * config: Global state * filter: Filter action structure * file: Output file ************************************************************************/ static BOOL filter_print_sender(struct config *config, struct filter *filter, FILE * file) { if (!((filter->local_part && filter->domain))) return (NIL); fprintf(file, "# MSshell :: sender\n"); if (filter_has_wildcard(filter->local_part) || filter_has_wildcard(filter->domain)) { fprintf(file, "if $sender_address matches \"%s^", QMETA); filter_expand_local(file, filter->local_part); fprintf(file, "@"); filter_expand_domain(file, filter->domain); fprintf(file, "%s$\" then\n", QMETA); } else { fprintf(file, "if $sender_address is \"%s@%s\" then\n", filter->local_part, filter->domain); } filter_write_to(config, file, filter->mailbox, filter->copy); fprintf(file, "\n"); return (T); } /* ====================================================================== */ /* filter_print_recipient() ********************************************** * * Print RECIPIENT filter * config: Global state * filter: Filter action structure * file: Output file ************************************************************************/ static BOOL filter_print_recipient(struct config *config, struct filter *filter, FILE * file) { if (!((filter->local_part && filter->domain))) return (NIL); fprintf(file, "# MSshell :: recip\n"); if (filter_has_wildcard(filter->local_part) || filter_has_wildcard(filter->domain)) { fprintf(file, "if foranyaddress $h_to:,$h_cc:\n"); fprintf(file, " ($thisaddress matches \""); filter_expand_local(file, filter->local_part); fprintf(file, "@"); filter_expand_domain(file, filter->domain); fprintf(file, "\") then\n"); } else { fprintf(file, "if foranyaddress $h_to:,$h_cc:\n"); fprintf(file, " ($thisaddress is \"%s@%s\") then\n", filter->local_part, filter->domain); } filter_write_to(config, file, filter->mailbox, filter->copy); fprintf(file, "\n"); return (T); } /* ====================================================================== */ /* filter_print_block() ************************************************** * * Print BLOCK filter * config: Global state * filter: Filter action structure * file: Output file ************************************************************************/ static BOOL filter_print_block(struct config *config, struct filter *filter, FILE * file) { if (!((filter->local_part && filter->domain))) return (NIL); fprintf(file, "# MSshell :: block\n"); if (filter_has_wildcard(filter->local_part) || filter_has_wildcard(filter->domain)) { fprintf(file, "if $sender_address matches \"%s^", QMETA); filter_expand_local(file, filter->local_part); fprintf(file, "@"); filter_expand_domain(file, filter->domain); fprintf(file, "%s$\" then\n", QMETA); } else { fprintf(file, "if $sender_address is \"%s@%s\" then\n", filter->local_part, filter->domain); } fprintf(file, " seen finish\n"); fprintf(file, "endif\n"); fprintf(file, "\n"); return (T); } /* ====================================================================== */ /* filter_print_subject() ************************************************ * * Print SUBJECT filter * config: Global state * filter: Filter action structure * file: Output file ************************************************************************/ static BOOL filter_print_subject(struct config *config, struct filter *filter, FILE * file) { if (!filter->subject) return (NIL); fprintf(file, "# MSshell :: subject\n"); if (strchr(filter->subject, '?') || strchr(filter->subject, '*')) { fprintf(file, "if $h_subject: matches \"(?s)%s^", QMETA); filter_expand_wildcard(file, filter->subject); fprintf(file, "%s$\" then\n", QMETA); } else { fprintf(file, "if $h_subject: is \""); filter_quote_double(file, filter->subject); fprintf(file, "\" then\n"); } filter_write_to(config, file, filter->mailbox, filter->copy); fprintf(file, "\n"); return (T); } /* ====================================================================== */ /* filter_print_redirect() *********************************************** * * Print REDIRECT filter * config: Global state * filter: Filter action structure * file: Output file ************************************************************************/ static BOOL filter_print_redirect(struct config *config, struct filter *filter, FILE * file) { fprintf(file, "# MSshell :: redirect\n"); if (filter->copy) fprintf(file, "unseen deliver %s", filter->address); else fprintf(file, "deliver %s", filter->address); fprintf(file, "\n"); return (T); } /* ====================================================================== */ /* filter_clear() ******************************************************** * * Clear out filter structure. * filter: Filter action structure ************************************************************************/ static void filter_clear(struct filter *filter) { filter->type = CO_UNKNOWN; filter->local_part = NIL; filter->domain = NIL; filter->subject = NIL; filter->mailbox = NIL; filter->address = NIL; filter->copy = NIL; filter->threshold = NIL; } /* filter_print() ******************************************************** * * Print a single filter item, using the static support routines above. * config: Global configuration * filter: Filter action structure ************************************************************************/ static BOOL filter_print(struct config *config, struct filter *filter, FILE * file) { switch (filter->type) { case CO_UNKNOWN: return (NIL); case CO_VACATION: return (filter_print_vacation(config, filter, file)); case CO_SPAM: return (filter_print_spam(config, filter, file)); case CO_SENDER: return (filter_print_sender(config, filter, file)); case CO_RECIPIENT: return (filter_print_recipient(config, filter, file)); case CO_BLOCK: return (filter_print_block(config, filter, file)); case CO_SUBJECT: return (filter_print_subject(config, filter, file)); case CO_REDIRECT: return (filter_print_redirect(config, filter, file)); } return (NIL); } /* ====================================================================== */ /* Some simple string tokenisation routines stolen from prayer string.c */ /* filter_get_token() **************************************************** * * Get a token from current line * sp: Ptr to string. Returns ptr to following token * * Returns: ptr to next token ************************************************************************/ static char *filter_get_token(char **sp) { char *result; char *s = *sp; /* Isolate first token */ while ((*s == ' ') || (*s == '\t')) s++; result = s; while (*s && (*s != ' ') && (*s != '\t')) s++; if (*s) *s++ = '\0'; while ((*s == ' ') || (*s == '\t')) s++; *sp = s; return (result); } /* filter_next_token() **************************************************** * * Move to next token (skips whitespace) * sp: Ptr to string. Returns ptr to next token * * Returns: ptr to next token ************************************************************************/ static char *filter_next_token(char **sp) { char *s = *sp; /* Isolate first token */ while ((*s == ' ') || (*s == '\t')) s++; *sp = s; return (s); } /* filter_trim_whitespace() *********************************************** * * Trim leading and trailing whitespace from a string * string: String to trim * * Returns: Ptr to trimmed string *************************************************************************/ char *filter_trim_whitespace(char *string) { unsigned long len; /* Remove leading whitespace */ while ((string[0] == ' ') || (string[0] == '\t') || (string[0] == '\015') || (string[0] == '\012')) string++; /* Remove traiing whitespace */ len = strlen(string); while ((len > 0) && ((string[len - 1] == ' ') || (string[len - 1] == '\t') || (string[len - 1] == '\015') || (string[len - 1] == '\012'))) len--; /* Tie off the string */ string[len] = '\0'; return (string); } /* ====================================================================== */ /* filter_write() ******************************************************** * * Write out an entire filter file * config: Global configuration * file: Output file * text: Msforward contains to parse and translate into Exim .forward file * * Returns: T on sucess. NIL otherwise. ************************************************************************/ static BOOL filter_write(struct config *config, FILE * file, char *text) { struct filter filter_space; struct filter *filter = &filter_space; char *s = text; char *t; fprintf(file, "# Exim Filter <-- don't change this line\n"); fprintf(file, "# This file automatically generated. Do not edit!\n\n");; filter_clear(filter); for (; *s; s = t) { t = s; /* Get a line and tie it off */ while (*t && (*t != '\n')) t++; if (*t) *t++ = '\0'; /* Ignore comment lines */ if (*s == '#') continue; /* End of block: process filter */ if (*s == '\0') { if (!filter_print(config, filter, file)) return (NIL); filter_clear(filter); continue; } if ((*s == ' ') || (*s == '\t')) { char *arg = filter_get_token(&s); char *value = filter_next_token(&s); if (!strcmp(arg, "local_part")) filter->local_part = value; else if (!strcmp(arg, "domain")) filter->domain = value; else if (!strcmp(arg, "subject")) filter->subject = value; else if (!strcmp(arg, "mailbox")) filter->mailbox = value; else if (!strcmp(arg, "address")) filter->address = value; else if (!strcmp(arg, "copy")) filter->copy = !strcmp(value, "true") ? T : NIL; else if (!strcmp(arg, "threshold")) filter->threshold = value; else return (NIL); continue; } if ((filter->type != CO_UNKNOWN) && !filter_print(config, filter, file)) return (NIL); filter_clear(filter); s = filter_trim_whitespace(s); if (!strcmp(s, "vacation")) filter->type = CO_VACATION; else if (!strcmp(s, "spam")) filter->type = CO_SPAM; else if (!strcmp(s, "sender")) filter->type = CO_SENDER; else if (!strcmp(s, "recip")) filter->type = CO_RECIPIENT; else if (!strcmp(s, "recipient")) filter->type = CO_RECIPIENT; else if (!strcmp(s, "block")) filter->type = CO_BLOCK; else if (!strcmp(s, "subject")) filter->type = CO_SUBJECT; else if (!strcmp(s, "redirect")) filter->type = CO_REDIRECT; } if ((filter->type != CO_UNKNOWN) && !filter_print(config, filter, file)) return (NIL); return (T); } /* ====================================================================== */ /* filter_write_forward() ************************************************ * * Write out .forward file. This is external interface to filter module * config: Global configuration * text: MSforward text to parse and translate into Exim .forward * * Returns: T on success. NIL otherwise ************************************************************************/ BOOL filter_write_forward(struct config * config, char *text) { FILE *file; BOOL rc; if ((file = fopen(config->forward_name, "w")) == NIL) return (NIL); rc = filter_write(config, file, (char *) text); if (fclose(file)) /* Probable quota error */ rc = NIL; /* Better than leaving it in an inconsistent state */ if (!rc) unlink(config->forward_name); if (!checksum_generate(config->forward_name)) unlink(config->forward_name); return (rc); } /* ====================================================================== */ /* filter_empty() ******************************************************** * * Check whether filter text is empty (approximation: contains alphanumeric * characters outside comment line). * text: Filter file to test * * Returns: T => no actions defined by filter file. ************************************************************************/ BOOL filter_empty(char *s) { char c; while ((c = *s++)) { if (c == '#') { /* Skip comment line */ while ((c = *s) && (c != '\015') && (c != '\012')) s++; continue; } if (Uisalpha(c)) return (NIL); } return (T); } ./prayer-1.3.5/accountd/password.h0000644006513000651300000000077611063701632015415 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/password.h,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* Interfere Prototypes for password.c */ BOOL password_change(struct config *config, struct iostream *stream, char *line); ./prayer-1.3.5/accountd/accountd-canvas.cf0000644006513000651300000000611411063701632016755 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/accountd/accountd-canvas.cf,v 1.7 2008/09/16 09:59:54 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2002 # See the file NOTICE for conditions of use and distribution. # # Accountd configuration suitable for Solaris ## ## General options ## # Name of staging file to generate Exim filter file msforward_name = ".MSforward" # Name of Exim filter file in users home directory forward_name = ".forward" # List of aliases for user account for vacation purposes. # (currently no interface to this through Webmail interface) aliases_name = "vacation.aliases" # Mail filtering restricted to "mail/" directory by .MSforward file # (Only need this on Hermes where we have some history to contend with) filter_restricted = FALSE # Connections to child processes should time out after this long (0 => never) child_timeout = 30m # Authtype options: # PAM (preferred where available) # pwd :: Passwords accessed via getpwnam(), old fashioned crypt # pwd_md5 :: Passwords accessed via getpwnam(), GNU md5 crypt # shadow :: Passwords accessed via getspnam(), old fashioned crypt # shadow_md5 :: Passwords accessed via getspnam(), GNU md5 crypt # authtype = pam # Allow Raven WLS credentials on Hermes raven_enable = T raven_key_path = "/opt/accountd/raven_keys" ## ## Password changing - Hermes ## pwd_cmdline = "/opt/passwd/bin/minipasswd" pwd_pty = false pwd_script = \ sendline "$old" \ sendline "$new" \ expect "OK" ## ## Fullname checking ## checkfull_cmdline = "/opt/passwd/bin/minipasswd -s" checkfull_pty = false checkfull_script = \ result ## ## Fullname changing ## full_cmdline = "/opt/passwd/bin/minipasswd -g" full_pty = false full_script = \ sendline "$newname" \ expect "OK" ## ## Quota check ## quota_cmdline = "/opt/quota/bin/chkquota_accountd" # # quota_cmdline should generate a series of "key: value" pairs on one # or more lines to list the current block and inode use. Something like: # # bused: 2523 blimit: 10000 # iused: 13 ilimit: 1000 # quota_hermes = FALSE # # quota_hermes is a hack to automatically parse output from the quota # program on the big central mail system here in Cambridge (unsuprisingly # named Hermes...) which looks something like the following: # # User dpc99 (uid=28090) on /homes/1 # current quota limit timeleft # KBytes: 8284 20000 20000 - # Files: 77 1500 1500 - # # It exists simply because I was too lazy to write a 10 line Perl script to # translate the output of our quota program into the cannonical form for # accountd when I already had some code in accountd which was specific to # Hermes. # SSL configuration, if required in accountd #use_ssl = T #ssl_cert_file = "/usr/local/prayer/certs/prayer.pem" #ssl_dh_file = "/usr/local/prayer/certs/prayer.pem" #ssl_rsakey_lifespan = 10m #egd_socket = "/var/prngd/urandom" ./prayer-1.3.5/accountd/quota.c0000644006513000651300000000641711063701632014675 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/quota.c,v 1.3 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" /* quota_check() ********************************************************* * * Check disk quota. * config: accountd configuration * stream: iostream connection to client * * Returns: T on sucess, NIL otherwise (should be irrelevant) * * Output: * OK bused: (number) blimit: (number) iused: (number) ilimit: (number) * NO [Error message] - Couldn't derive disk quota * BAD [Error message] - Protocol error ************************************************************************/ BOOL quota_check(struct config * config, struct iostream * stream) { struct process process; char buffer[MAXLENGTH]; int bused = 0; int blimit = 0; int iused = 0; int ilimit = 0; process_clear(&process); if (!process_start (&process, config->quota_cmdline, NIL, config->child_timeout)) { ioputs(stream, "NO Couldn't invoke quota check program" CRLF); ioflush(stream); return (NIL); } if (!config->quota_hermes) { char *line, *key, *value; while (iostream_getline(process.stream, buffer, MAXLENGTH)) { line = buffer; while (*line) { if (!(key = string_get_token(&line))) break; if (!(value = string_get_token(&line))) break; if (!strcmp(key, "bused:")) bused = atoi(value); else if (!strcmp(key, "blimit:")) blimit = atoi(value); else if (!strcmp(key, "iused:")) iused = atoi(value); else if (!strcmp(key, "ilimit:")) ilimit = atoi(value); } } } else { while (iostream_getline(process.stream, buffer, MAXLENGTH)) { char *line, *type, *current, *quota, *limit; /* Process this line of input */ line = buffer; if ((type = string_get_token(&line)) == NIL) continue; if ((strcmp(type, "KBytes:") != NIL) && (strcmp(type, "Files:") != NIL)) continue; if ((current = string_get_token(&line)) == NIL) continue; if ((quota = string_get_token(&line)) == NIL) continue; if ((limit = string_get_token(&line)) == NIL) continue; if (!strcmp(type, "KBytes:")) { bused = atoi(current); blimit = atoi(limit); } else { iused = atoi(current); ilimit = atoi(limit); } } } if (!process_stop(&process)) { ioputs(stream, "NO fquota program terminated incorrectly" CRLF); ioflush(stream); return (NIL); } ioprintf(stream, "OK bused: %d blimit: %d iused: %d ilimit: %d" CRLF, bused, blimit, iused, ilimit); ioflush(stream); return (T); } ./prayer-1.3.5/accountd/accountd-linux.cf0000644006513000651300000000406011063701632016637 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/accountd/accountd-linux.cf,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2002 # See the file NOTICE for conditions of use and distribution. # # Accountd configuration suitable for Redhat Linux msforward_name = ".MSforward" forward_name = ".forward" aliases_name = "vacation.aliases" filter_restricted = FALSE # While debugging child_timeout = 0 # Authtype options: # PAM (preferred where available) # pwd :: Passwords accessed via getpwnam(), old fashioned crypt # pwd_md5 :: Passwords accessed via getpwnam(), GNU md5 crypt # shadow :: Passwords accessed via getspnam(), old fashioned crypt # shadow_md5 :: Passwords accessed via getspnam(), GNU md5 crypt # authtype = pam # Password changing - Linux defaults. (Warning: Strange race condition with # Linux passwd program. Following only works some of the time... pwd_cmdline = "/usr/bin/passwd" pwd_script = \ readline \ readline \ expect "(current) UNIX password: " \ sendline "$old" \ expect "New password: " \ sendline "$new" \ expect "Retype new password: " \ sendline "$new" \ expect "passwd: all authentication tokens updated successfully." # Fullname checking checkfull_cmdline = "/bin/echo Script still needs to be written" checkfull_script = "result" # Fullname changing full_cmdline = "/usr/bin/chfn -f ${newname}" full_script = \ readline \ expect "Password: " \ sendline "$password" \ expect "Finger information changed." # Quota check quota_cmdline = "fquota -v" quota_hermes = FALSE # SSL configuration, if required #use_ssl = T #ssl_cert_file = "/usr/local/prayer/certs/prayer.pem" #ssl_dh_file = "/usr/local/prayer/certs/prayer.pem" #ssl_rsakey_lifespan = 10m #egd_socket = "/var/prngd/urandom" ./prayer-1.3.5/accountd/log.h0000644006513000651300000000140411063701632014321 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/log.h,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* External Interfere Prototypes for log.c */ void log_init(struct config *config, char *progname); unsigned long log_entry_size(char *fmt, va_list ap); void log_syslog_ap(unsigned long len, char *fmt, va_list ap); void log_panic_ap(unsigned long len, char *fmt, va_list ap); void log_misc(char *fmt, ...); void log_debug(char *fmt, ...); void log_panic(char *fmt, ...); void log_fatal(char *fmt, ...); ./prayer-1.3.5/accountd/Makefile0000644006513000651300000000370111576130374015041 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/accountd/Makefile,v 1.12 2011/06/15 13:17:48 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2002 # See the file NOTICE for conditions of use and distribution. ifeq ($(strip $(RPM_BUILD)), true) include ../Config-RPM else include ../Config endif BASECFLAGS += -I../lib # Enable Electric Fence ifeq ($(strip $(FENCE_ENABLE)), true) BASECFLAGS += $(FENCE_INCLUDE) BASE_LIBS += $(FENCE_LIBS) endif # Add PAM if backend needs pam ifeq ($(strip $(ACCOUNTD_PAM_ENABLE)), true) BASE_INCLUDE += $(PAM_INCLUDE) BASE_LIBS += $(PAM_LIBS) ACCOUNTD_AUTH_DEFS += -DACCOUNTD_PAM_ENABLE=1 endif ifeq ($(strip $(RAVEN_ENABLE)), true) ACCOUNTD_AUTH_DEFS += -DRAVEN_ENABLE=1 ACCOUNTD_SSL_ENABLE=true endif MYCFLAGS = $(BASECFLAGS) MYLDFLAGS = $(BASELDFLAGS) MYLIBS = $(BASE_LIBS) ifeq ($(strip $(ACCOUNTD_SSL_ENABLE)), true) SSL_LIB = ../lib/lib_withssl.a MYLIBS += $(SSL_LIBS) ifeq ($(strip $(SESSION_CACHE_ENABLE)), true) # Berkeley DB required for SSL session cache. MYLIBS += $(DB_LIBS) endif else SSL_LIB = ../lib/lib_nossl.a endif all: prayer-accountd ######################################################################## OBJS = config.o log.o \ password.o fullname.o quota.o file.o mail.o \ filter.o checksum.o authenticate.o $(SSL_LIB) prayer-accountd: $(OBJS) accountd.o $(CC) $(MYLDFLAGS) -o prayer-accountd accountd.o $(OBJS) $(MYLIBS) test: test.o $(OBJS) $(CC) $(MYLDFLAGS) -o test test.o $(OBJS) $(MYLIBS) # Default build rule %.o: %.c *.h Makefile $(CC) $(MYCFLAGS) -c $< accountd.o: accountd.c *.h Makefile $(CC) $(MYCFLAGS) -c \ -DACCOUNTD_CONFIG_FILE=\"$(ACCOUNTD_CONFIG_FILE)\" $< authenticate.o: authenticate.c *.h Makefile $(CC) $(MYCFLAGS) -c $(ACCOUNTD_AUTH_DEFS) $< clean: -rm -f prayer-accountd test core *.o *~ \#*\# install: $(INSTALL) -m 755 -o ${RO_USER} -g ${RW_GROUP} \ prayer-accountd ${BROOT}${BIN_DIR} ./prayer-1.3.5/accountd/fullname.h0000644006513000651300000000111511063701632015342 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/fullname.h,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ /* External Interfere Prototypes for fullname.c */ BOOL fullname_change(struct config *config, struct iostream *stream, char *line); BOOL fullname_check(struct config *config, struct iostream *stream); ./prayer-1.3.5/accountd/accountd-hermes.cf0000644006513000651300000000673111063701632016772 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/accountd/accountd-hermes.cf,v 1.3 2008/09/16 09:59:54 dpc22 Exp $ # Prayer - a Webmail Interface # # Copyright (c) University of Cambridge 2000 - 2002 # See the file NOTICE for conditions of use and distribution. # # Accountd configuration suitable for Solaris ## ## General options ## # Name of staging file to generate Exim filter file msforward_name = ".MSforward" # Name of Exim filter file in users home directory forward_name = ".forward" # List of aliases for user account for vacation purposes. # (currently no interface to this through Webmail interface) aliases_name = "vacation.aliases" # Mail filtering restricted to "mail/" directory by .MSforward file # (Only need this on Hermes where we have some history to contend with) filter_restricted = FALSE # Connections to child processes should time out after this long (0 => never) child_timeout = 30m # Authtype options: # PAM (preferred where available) # pwd :: Passwords accessed via getpwnam(), old fashioned crypt # pwd_md5 :: Passwords accessed via getpwnam(), GNU md5 crypt # shadow :: Passwords accessed via getspnam(), old fashioned crypt # shadow_md5 :: Passwords accessed via getspnam(), GNU md5 crypt # authtype = pam # Allow Raven WLS credentials on Hermes raven_enable = T raven_key_path = "/opt/accountd/raven_keys" ## ## Password changing - Hermes ## pwd_cmdline = "/opt/local/bin/passwd" pwd_script = \ readline \ expect "Old password: " \ sendline "$old" \ expect "New password: " \ sendline "$new" \ expect "Type new password again: " \ sendline "$new" \ expect "Change made, but may not take effect on all hosts immediately" ## ## Fullname checking ## checkfull_cmdline = "/opt/local/bin/passwd -g" checkfull_script = \ readline \ expect "Old name: " \ result ## ## Fullname changing ## full_cmdline = "/opt/local/bin/passwd -g" full_script = \ readline \ expect "Old name: " \ readline \ expect "New name: " \ sendline "$newname" \ expect "Change made, but may not take effect on all hosts immediately" ## ## Quota check ## quota_cmdline = "/opt/local/bin/fquota -v" # # quota_cmdline should generate a series of "key: value" pairs on one # or more lines to list the current block and inode use. Something like: # # bused: 2523 blimit: 10000 # iused: 13 ilimit: 1000 # quota_hermes = TRUE # # quota_hermes is a hack to automatically parse output from the quota # program on the big central mail system here in Cambridge (unsuprisingly # named Hermes...) which looks something like the following: # # User dpc99 (uid=28090) on /homes/1 # current quota limit timeleft # KBytes: 8284 20000 20000 - # Files: 77 1500 1500 - # # It exists simply because I was too lazy to write a 10 line Perl script to # translate the output of our quota program into the cannonical form for # accountd when I already had some code in accountd which was specific to # Hermes. # SSL configuration, if required in accountd #use_ssl = T #ssl_cert_file = "/usr/local/prayer/certs/prayer.pem" #ssl_dh_file = "/usr/local/prayer/certs/prayer.pem" #ssl_rsakey_lifespan = 10m #egd_socket = "/var/prngd/urandom" ./prayer-1.3.5/accountd/password.c0000644006513000651300000000577111063701632015410 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/password.c,v 1.3 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" /* password_change_internal() ********************************************* * * Change passwd using the passwd program * config: Accountd configuration * old: Old password * new: New password * * Returns: Error response from passwd program. NIL => okay ************************************************************************/ static char *password_change_internal(struct config *config, char *old, char *new) { struct pool *pool = pool_create(0); struct assoc *h = assoc_create(pool, 16, T); struct process process; char *msg; char *cmdline; assoc_update(h, "old", old, T); assoc_update(h, "new", new, T); /* Expand */ cmdline = string_expand(pool, h, config->pwd_cmdline); process_clear(&process); if (!process_start(&process, cmdline, config->pwd_pty, config->child_timeout)) { pool_free(pool); return ("Couldn't start the password program"); } msg = process_run_script(&process, pool, h, pool_strdup(pool, config->pwd_script), NIL, 0L); if (!process_stop(&process)) { pool_free(pool); return ("Error code from password program"); } pool_free(pool); return (msg); } /* password_change() ***************************************************** * * Change passwd using the passwd program * config: Accountd configuration * stream: iostream connection to client * line: Arguments for PASSWORD command. * Should be old password, then new password canon encoded * * Returns: T in all situations * OK [text]. Password changed * NO [text]. Failed to change password * BAD [text]. Protocol error ************************************************************************/ BOOL password_change(struct config * config, struct iostream * stream, char *line) { char *old, *new; char *errmsg; if (!((old = string_get_token(&line)) && (old[0]))) { ioputs(stream, "BAD No old password" CRLF); ioflush(stream); return (T); } string_canon_decode(old); if (!((new = string_get_token(&line)) && (new[0]))) { ioputs(stream, "BAD No new password" CRLF); ioflush(stream); return (T); } string_canon_decode(new); if (!(errmsg = password_change_internal(config, old, new))) ioprintf(stream, "OK Changed password" CRLF); else if (errmsg[0]) ioprintf(stream, "NO %s" CRLF, errmsg); else ioprintf(stream, "NO Failed to change password" CRLF); ioflush(stream); return (T); } ./prayer-1.3.5/accountd/.cvsignore0000644006513000651300000000016011063701632015365 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/accountd/.cvsignore,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ prayer-accountd *.flc ./prayer-1.3.5/accountd/accountd.xinetd0000644006513000651300000000036111063701632016405 0ustar dpc22dpc22# $Cambridge: hermes/src/prayer/accountd/accountd.xinetd,v 1.5 2008/09/16 09:59:54 dpc22 Exp $ service accountd { socket_type = stream protocol = tcp wait = no user = root server = /opt/accountd/bin/prayer-accountd disable = no } ./prayer-1.3.5/accountd/file.c0000644006513000651300000001126411063701632014457 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/file.c,v 1.2 2008/09/16 09:59:54 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include "accountd.h" /* file_checkname() ****************************************************** * * Run saniy check on path. Looking for /.. * s: Filename to check * * Returns: T if name passes sanity check. ************************************************************************/ static BOOL file_checkname(char *s) { if (*s == '/') return (NIL); while (*s) { if ((s[0] == '.') && (s[1] == '.')) return (NIL); s++; } return (T); } /* file_get() ************************************************************ * * Get named file from peer. * config: Accountd configuration * stream: write file to this stream * line: Line following GET. Should be: * canon encoded filename e.g: Hello%20World * * Returns status on stream: * OK {size} - File download * NO (Text) - Couldn't download file (followed by reason) * BAD (Text) - Protocol error * ************************************************************************/ BOOL file_get(struct config * config, struct iostream * stream, char *line) { char *name; FILE *file; struct stat sbuf; int c; if (!((name = string_get_token(&line)) && (name[0]))) { ioputs(stream, "BAD No filename provided" CRLF); ioflush(stream); return (T); } string_canon_decode(name); if (!file_checkname(name)) { ioputs(stream, "NO Invalid file name" CRLF); ioflush(stream); return (T); } if (stat(name, &sbuf)) { ioputs(stream, "NO No such file" CRLF); ioflush(stream); return (T); } if (!(sbuf.st_mode & S_IFREG)) { ioputs(stream, "NO Not a regular file" CRLF); ioflush(stream); return (T); } if ((file = fopen(name, "r")) == NIL) { ioputs(stream, "NO Couldn't open file" CRLF); ioflush(stream); return (T); } ioprintf(stream, "OK {%lu}" CRLF, (unsigned long) sbuf.st_size); while ((c = getc(file)) != EOF) ioputc(c, stream); ioputs(stream, "" CRLF); ioflush(stream); fclose(file); return (T); } /* file_put() ************************************************************ * * Upload named file from peer. * config: Accountd configuration * stream: write file to this stream * line: Line following PUT command. Should be: * canon encoded filename e.g: Hello%20World * Size of following literal followed by CRLF * * Returns status on stream: * OK (Text) - File upload succeeded * NO (Text) - Couldn't upload file (followed by reason) * BAD (Text) - Protocol error ************************************************************************/ BOOL file_put(struct config * config, struct iostream * stream, char *line) { char *name, *size; FILE *file; int c, len; if (!((name = string_get_token(&line)) && (name[0]))) { ioputs(stream, "BAD No filename provided" CRLF); ioflush(stream); return (T); } string_canon_decode(name); if (!((size = string_get_token(&line)) && (size[0]))) { ioputs(stream, "BAD No file size provided" CRLF); ioflush(stream); return (T); } if (((len = strlen(size)) < 2) || (size[0] != '{') || (size[len - 1] != '}')) { ioputs(stream, "BAD Invalid file size" CRLF); ioflush(stream); return (T); } /* Check that size[1] -> size[len-1] all digits? */ size[len - 1] = '\0'; /* Probably not needed */ len = atoi(size + 1); if (!file_checkname(name)) { /* Swallow unwanted text */ while ((len > 0) && (c = iogetc(stream))) len--; ioputs(stream, "NO Invalid file name" CRLF); ioflush(stream); return (T); } if ((file = fopen(name, "w")) == NIL) { /* Swallow unwanted text */ while ((len > 0) && (c = iogetc(stream))) len--; ioputs(stream, "NO Couldn't open file" CRLF); ioflush(stream); return (T); } while ((len > 0) && (c = iogetc(stream))) { putc(c, file); len--; } if (len > 0) { ioprintf(stream, "BAD %d bytes missing from input" CRLF, len); ioflush(stream); return (T); } ioputs(stream, "OK File uploaded" CRLF); ioflush(stream); fclose(file); return (T); } ./prayer-1.3.5/accountd/accountd.h0000644006513000651300000000221111260106467015341 0ustar dpc22dpc22/* $Cambridge: hermes/src/prayer/accountd/accountd.h,v 1.4 2009/09/28 10:17:27 dpc22 Exp $ */ /************************************************ * Prayer - a Webmail Interface * ************************************************/ /* Copyright (c) University of Cambridge 2000 - 2002 */ /* See the file NOTICE for conditions of use and distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if 0 #include #endif #include #include extern int errno; #include "common.h" #include "lib.h" #include "config.h" #include "log.h" #include "password.h" #include "fullname.h" #include "quota.h" #include "file.h" #include "mail.h" #include "filter.h" #include "checksum.h" #include "authenticate.h"
    <% $i->a %> <% $i->{b}/$i->{c} %> <-- Treat block inside <% %> as quoted string?