diff options
author | ilja <ilja@7b491191-dbf0-0310-aff6-d879d4d69008> | 2004-03-19 14:11:53 +0000 |
---|---|---|
committer | ilja <ilja@7b491191-dbf0-0310-aff6-d879d4d69008> | 2004-03-19 14:11:53 +0000 |
commit | b3f64296e16029fa5b5c215d58a3cee14c620d94 (patch) | |
tree | 1f57650e8f6ea99431b9ff7947930d6bd1ddc9e4 | |
parent | 3e6f33ac32e6f09c770003503494af56bde1df88 (diff) |
indent -i8 -kr has now been used on all dbmail source files (*.c and *.h).
All files are now indented as K&R.
git-svn-id: https://svn.ic-s.nl/svn/dbmail/trunk/dbmail@1028 7b491191-dbf0-0310-aff6-d879d4d69008
-rw-r--r-- | dbmailtypes.h | 5 | ||||
-rw-r--r-- | dsn.c | 459 | ||||
-rw-r--r-- | dsn.h | 39 | ||||
-rw-r--r-- | forward.c | 18 | ||||
-rw-r--r-- | forward.h | 3 | ||||
-rw-r--r-- | header.c | 246 | ||||
-rw-r--r-- | header.h | 3 | ||||
-rw-r--r-- | imap4.c | 663 | ||||
-rw-r--r-- | imap4.h | 53 | ||||
-rw-r--r-- | imapcommands.c | 7261 | ||||
-rw-r--r-- | imapcommands.h | 64 | ||||
-rw-r--r-- | imapd.c | 408 | ||||
-rw-r--r-- | imaputil.c | 5044 | ||||
-rw-r--r-- | imaputil.h | 48 | ||||
-rw-r--r-- | list.c | 230 | ||||
-rw-r--r-- | list.h | 22 | ||||
-rw-r--r-- | lmtp.c | 1265 | ||||
-rw-r--r-- | lmtp.h | 109 | ||||
-rw-r--r-- | lmtpd.c | 402 | ||||
-rw-r--r-- | main.c | 566 | ||||
-rw-r--r-- | maintenance.c | 952 | ||||
-rw-r--r-- | maintenance.h | 1 | ||||
-rw-r--r-- | mbox2dbmail.c | 140 | ||||
-rw-r--r-- | md5.c | 343 | ||||
-rw-r--r-- | md5.h | 13 | ||||
-rw-r--r-- | memblock.c | 625 | ||||
-rw-r--r-- | memblock.h | 40 | ||||
-rw-r--r-- | mime.h | 16 | ||||
-rw-r--r-- | misc.c | 583 | ||||
-rw-r--r-- | misc.h | 14 | ||||
-rw-r--r-- | mysql/dbmysql.c | 227 | ||||
-rw-r--r-- | pgsql/dbpgsql.c | 423 | ||||
-rw-r--r-- | pipe.c | 934 | ||||
-rw-r--r-- | pipe.h | 9 | ||||
-rw-r--r-- | pop3.c | 1735 | ||||
-rw-r--r-- | pop3.h | 37 | ||||
-rw-r--r-- | pop3d.c | 436 | ||||
-rw-r--r-- | proctitleutils.c | 106 | ||||
-rw-r--r-- | proctitleutils.h | 5 | ||||
-rw-r--r-- | quota.c | 160 | ||||
-rw-r--r-- | quota.h | 20 | ||||
-rw-r--r-- | rfcmsg.c | 1337 | ||||
-rw-r--r-- | rfcmsg.h | 18 | ||||
-rw-r--r-- | server.c | 393 | ||||
-rw-r--r-- | server.h | 32 | ||||
-rw-r--r-- | serverchild.c | 536 | ||||
-rw-r--r-- | serverchild.h | 19 | ||||
-rw-r--r-- | settings.c | 139 | ||||
-rw-r--r-- | sievecmd.c | 558 | ||||
-rw-r--r-- | sievecmd.h | 5 | ||||
-rw-r--r-- | smtp-convert.c | 389 | ||||
-rw-r--r-- | sort.h | 14 | ||||
-rw-r--r-- | sort/sort.c | 560 | ||||
-rw-r--r-- | sort/sortsieve.c | 527 | ||||
-rw-r--r-- | sort/sortsieve.h | 5 | ||||
-rw-r--r-- | timsieve.c | 1434 | ||||
-rw-r--r-- | timsieve.h | 17 | ||||
-rw-r--r-- | timsieved.c | 402 | ||||
-rw-r--r-- | user.c | 1409 | ||||
-rw-r--r-- | user.h | 1 | ||||
-rw-r--r-- | vut2dbmail.c | 240 |
61 files changed, 16414 insertions, 15348 deletions
diff --git a/dbmailtypes.h b/dbmailtypes.h index 6d341d6c..df62adfc 100644 --- a/dbmailtypes.h +++ b/dbmailtypes.h @@ -123,7 +123,7 @@ typedef struct { #define IMAP_NFLAGS 6 enum IMAP4_CLIENT_STATES { IMAPCS_INITIAL_CONNECT, - IMAPCS_NON_AUTHENTICATED, + IMAPCS_NON_AUTHENTICATED, IMAPCS_AUTHENTICATED, IMAPCS_SELECTED, IMAPCS_LOGOUT }; @@ -135,7 +135,8 @@ enum IMAP4_FLAGS { IMAPFLAG_SEEN = 0x01, IMAPFLAG_ANSWERED = 0x02, enum IMAP4_PERMISSION { IMAPPERM_READ = 0x01, IMAPPERM_READWRITE = 0x02 }; enum IMAP4_FLAG_ACTIONS { IMAPFA_NONE, IMAPFA_REPLACE, IMAPFA_ADD, - IMAPFA_REMOVE }; + IMAPFA_REMOVE +}; enum BODY_FETCH_ITEM_TYPES { BFIT_TEXT, BFIT_HEADER, BFIT_MIME, BFIT_HEADER_FIELDS, @@ -10,259 +10,288 @@ #include "debug.h" -int dsnuser_init(deliver_to_user_t *dsnuser) +int dsnuser_init(deliver_to_user_t * dsnuser) { - dsnuser->useridnr = 0; - dsnuser->dsn.class = 0; - dsnuser->dsn.subject = 0; - dsnuser->dsn.detail = 0; + dsnuser->useridnr = 0; + dsnuser->dsn.class = 0; + dsnuser->dsn.subject = 0; + dsnuser->dsn.detail = 0; - dsnuser->address = NULL; - dsnuser->mailbox = NULL; + dsnuser->address = NULL; + dsnuser->mailbox = NULL; - dsnuser->userids = (struct list *)my_malloc(sizeof(struct list)); + dsnuser->userids = (struct list *) my_malloc(sizeof(struct list)); if (dsnuser->userids == NULL) return -1; - dsnuser->forwards = (struct list *)my_malloc(sizeof(struct list)); + dsnuser->forwards = (struct list *) my_malloc(sizeof(struct list)); if (dsnuser->forwards == NULL) return -1; - list_init(dsnuser->userids); - list_init(dsnuser->forwards); + list_init(dsnuser->userids); + list_init(dsnuser->forwards); trace(TRACE_DEBUG, "%s, %s: dsnuser initialized", - __FILE__, __FUNCTION__); + __FILE__, __FUNCTION__); return 0; } -void dsnuser_free(deliver_to_user_t *dsnuser) +void dsnuser_free(deliver_to_user_t * dsnuser) { - dsnuser->useridnr = 0; - dsnuser->dsn.class = 0; - dsnuser->dsn.subject = 0; - dsnuser->dsn.detail = 0; + dsnuser->useridnr = 0; + dsnuser->dsn.class = 0; + dsnuser->dsn.subject = 0; + dsnuser->dsn.detail = 0; /* These are nominally const, but * we really do want to free them. */ - my_free((char *)dsnuser->address); - my_free((char *)dsnuser->mailbox); + my_free((char *) dsnuser->address); + my_free((char *) dsnuser->mailbox); - list_freelist(&dsnuser->userids->start); - list_freelist(&dsnuser->forwards->start); + list_freelist(&dsnuser->userids->start); + list_freelist(&dsnuser->forwards->start); - my_free(dsnuser->userids); - my_free(dsnuser->forwards); + my_free(dsnuser->userids); + my_free(dsnuser->forwards); trace(TRACE_DEBUG, "%s, %s: dsnuser freed", - __FILE__, __FUNCTION__); + __FILE__, __FUNCTION__); } int dsnuser_resolve_list(struct list *deliveries) { - u64_t userid; - int alias_count = 0, domain_count = 0; - char *domain = NULL; - char *username = NULL; - struct element *element; - - /* Loop through the users list */ - for (element = list_getstart(deliveries); element != NULL; element = element->nextnode) - { - deliver_to_user_t *delivery = (deliver_to_user_t *)element->data; - - /* If the userid is already set, then we're doing direct-to-userid. */ - if (delivery->useridnr != 0) - { - /* This seems to be the only way to see if a useridnr is valid. */ - username = auth_get_userid(delivery->useridnr); - if (username != NULL) - { - /* Free the username, we don't actually need it. */ - my_free(username); - - /* Copy the delivery useridnr into the userids list. */ - if (list_nodeadd(delivery->userids, &delivery->useridnr, sizeof(delivery->useridnr)) == 0) - { - trace(TRACE_ERROR, "%s, %s: out of memory", - __FILE__, __FUNCTION__); - return -1; - } - - /* The userid was valid... */ - delivery->dsn.class = DSN_CLASS_OK; /* Success. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 5; /* Valid. */ - } - else /* from: 'if (username != NULL)' */ - { - /* The userid was invalid... */ - delivery->dsn.class = DSN_CLASS_FAIL; /* Permanent failure. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 1; /* Does not exist. */ - } - } - /* We don't have a useridnr, so we have either a username or an alias. */ - else /* from: 'if (delivery->useridnr != 0)' */ - { - /* See if the address is a username. */ - switch (auth_user_exists(delivery->address, &userid)) - { - case -1: - { - /* An error occurred */ - trace(TRACE_ERROR,"%s, %s: error checking user [%s]", - __FILE__, __FUNCTION__, delivery->address); - return -1; - break; - } - case 1: - { - if (list_nodeadd(delivery->userids, &userid, sizeof(u64_t)) == 0) - { - trace(TRACE_ERROR, "%s, %s: out of memory", - __FILE__, __FUNCTION__); - return -1; - } - else - { - - trace(TRACE_DEBUG, "%s, %s: added user [%s] id [%llu] to delivery list", - __FILE__, __FUNCTION__, delivery->address, userid); - /* The userid was valid... */ - delivery->dsn.class = DSN_CLASS_OK; /* Success. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 5; /* Valid. */ - } - break; - } - /* The address needs to be looked up */ - default: - { - alias_count = auth_check_user_ext(delivery->address, delivery->userids, delivery->forwards, -1); - trace(TRACE_DEBUG, "%s, %s: user [%s] found total of [%d] aliases", - __FILE__, __FUNCTION__, delivery->address, alias_count); - - /* No aliases found for this user */ - if (alias_count == 0) - { - trace(TRACE_INFO,"%s, %s: user [%s] checking for domain forwards.", - __FILE__, __FUNCTION__, delivery->address); - - domain = strchr(delivery->address, '@'); - - if (domain == NULL) - { - /* That's it, we're done here. */ - /* Permanent failure... */ - delivery->dsn.class = DSN_CLASS_FAIL; /* Permanent failure. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 1; /* Does not exist. */ - } - else - { - trace(TRACE_DEBUG, "%s, %s: domain [%s] checking for domain forwards", - __FILE__, __FUNCTION__, domain); - - /* Checking for domain aliases */ - domain_count = auth_check_user_ext(domain, delivery->userids, delivery->forwards, -1); - trace(TRACE_DEBUG,"%s, %s: domain [%s] found total of [%d] aliases", - __FILE__, __FUNCTION__, domain, domain_count); - - if (domain_count == 0) - { - /* Permanent failure... */ - delivery->dsn.class = DSN_CLASS_FAIL; /* Permanent failure. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 1; /* Does not exist. */ - } - else /* from: 'if (domain_count == 0)' */ - { - /* The userid was valid... */ - delivery->dsn.class = DSN_CLASS_OK; /* Success. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 5; /* Valid. */ - } /* from: 'if (domain_count == 0)' */ - } /* from: 'if (domain == NULL)' */ - } - else /* from: 'if (alias_count == 0)' */ - { - /* The userid was valid... */ - delivery->dsn.class = DSN_CLASS_OK; /* Success. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 5; /* Valid. */ - } /* from: 'if (alias_count == 0)' */ - } /* from: 'default:' */ - } /* from: 'switch (auth_user_exists(delivery->address, &userid))' */ - } /* from: 'if (delivery->useridnr != 0)' */ - } /* from: the main for loop */ - - return 0; + u64_t userid; + int alias_count = 0, domain_count = 0; + char *domain = NULL; + char *username = NULL; + struct element *element; + + /* Loop through the users list */ + for (element = list_getstart(deliveries); element != NULL; + element = element->nextnode) { + deliver_to_user_t *delivery = + (deliver_to_user_t *) element->data; + + /* If the userid is already set, then we're doing direct-to-userid. */ + if (delivery->useridnr != 0) { + /* This seems to be the only way to see if a useridnr is valid. */ + username = auth_get_userid(delivery->useridnr); + if (username != NULL) { + /* Free the username, we don't actually need it. */ + my_free(username); + + /* Copy the delivery useridnr into the userids list. */ + if (list_nodeadd + (delivery->userids, + &delivery->useridnr, + sizeof(delivery->useridnr)) == 0) { + trace(TRACE_ERROR, + "%s, %s: out of memory", + __FILE__, __FUNCTION__); + return -1; + } + + /* The userid was valid... */ + delivery->dsn.class = DSN_CLASS_OK; /* Success. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 5; /* Valid. */ + } else { /* from: 'if (username != NULL)' */ + + /* The userid was invalid... */ + delivery->dsn.class = DSN_CLASS_FAIL; /* Permanent failure. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 1; /* Does not exist. */ + } + } + /* We don't have a useridnr, so we have either a username or an alias. */ + else { /* from: 'if (delivery->useridnr != 0)' */ + + /* See if the address is a username. */ + switch (auth_user_exists + (delivery->address, &userid)) { + case -1: + { + /* An error occurred */ + trace(TRACE_ERROR, + "%s, %s: error checking user [%s]", + __FILE__, __FUNCTION__, + delivery->address); + return -1; + break; + } + case 1: + { + if (list_nodeadd + (delivery->userids, &userid, + sizeof(u64_t)) == 0) { + trace(TRACE_ERROR, + "%s, %s: out of memory", + __FILE__, + __FUNCTION__); + return -1; + } else { + + trace(TRACE_DEBUG, + "%s, %s: added user [%s] id [%llu] to delivery list", + __FILE__, + __FUNCTION__, + delivery->address, + userid); + /* The userid was valid... */ + delivery->dsn.class = DSN_CLASS_OK; /* Success. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 5; /* Valid. */ + } + break; + } + /* The address needs to be looked up */ + default: + { + alias_count = + auth_check_user_ext(delivery-> + address, + delivery-> + userids, + delivery-> + forwards, + -1); + trace(TRACE_DEBUG, + "%s, %s: user [%s] found total of [%d] aliases", + __FILE__, __FUNCTION__, + delivery->address, + alias_count); + + /* No aliases found for this user */ + if (alias_count == 0) { + trace(TRACE_INFO, + "%s, %s: user [%s] checking for domain forwards.", + __FILE__, + __FUNCTION__, + delivery->address); + + domain = + strchr(delivery-> + address, '@'); + + if (domain == NULL) { + /* That's it, we're done here. */ + /* Permanent failure... */ + delivery->dsn.class = DSN_CLASS_FAIL; /* Permanent failure. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 1; /* Does not exist. */ + } else { + trace(TRACE_DEBUG, + "%s, %s: domain [%s] checking for domain forwards", + __FILE__, + __FUNCTION__, + domain); + + /* Checking for domain aliases */ + domain_count = + auth_check_user_ext + (domain, + delivery-> + userids, + delivery-> + forwards, -1); + trace(TRACE_DEBUG, + "%s, %s: domain [%s] found total of [%d] aliases", + __FILE__, + __FUNCTION__, + domain, + domain_count); + + if (domain_count == + 0) { + /* Permanent failure... */ + delivery->dsn.class = DSN_CLASS_FAIL; /* Permanent failure. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 1; /* Does not exist. */ + } else { /* from: 'if (domain_count == 0)' */ + + /* The userid was valid... */ + delivery->dsn.class = DSN_CLASS_OK; /* Success. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 5; /* Valid. */ + } /* from: 'if (domain_count == 0)' */ + } /* from: 'if (domain == NULL)' */ + } else { /* from: 'if (alias_count == 0)' */ + + /* The userid was valid... */ + delivery->dsn.class = DSN_CLASS_OK; /* Success. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 5; /* Valid. */ + } /* from: 'if (alias_count == 0)' */ + } /* from: 'default:' */ + } /* from: 'switch (auth_user_exists(delivery->address, &userid))' */ + } /* from: 'if (delivery->useridnr != 0)' */ + } /* from: the main for loop */ + + return 0; } void dsnuser_free_list(struct list *deliveries) { - struct element *tmp; + struct element *tmp; - for(tmp = list_getstart(deliveries); tmp != NULL; tmp = tmp->nextnode) - dsnuser_free((deliver_to_user_t *)tmp->data); + for (tmp = list_getstart(deliveries); tmp != NULL; + tmp = tmp->nextnode) + dsnuser_free((deliver_to_user_t *) tmp->data); - list_freelist(&deliveries->start); + list_freelist(&deliveries->start); } dsn_class_t dsnuser_worstcase_int(int has_2, int has_4, int has_5) { - dsn_class_t exitcode; - - /* If only one code, use it. */ - if (has_2 && !has_4 && !has_5) /* Only 2 */ - exitcode = DSN_CLASS_OK; - else if (!has_2 && has_4 && !has_5) /* Only 4 */ - exitcode = DSN_CLASS_TEMP; - else if (!has_2 && !has_4 && has_5) /* Only 5 */ - exitcode = DSN_CLASS_FAIL; - /* If two codes, prefer temporary, otherwise fail. */ - else if (has_2 && has_4 && !has_5) /* 2 and 4 */ - exitcode = DSN_CLASS_TEMP; - else if (has_2 && !has_4 && has_5) /* 2 and 5 */ - exitcode = DSN_CLASS_FAIL; - else if (!has_2 && has_4 && has_5) /* 4 and 5 */ - exitcode = DSN_CLASS_TEMP; - /* All three or none, again prefer temporary. */ - else /* 2, 4, 5 */ - exitcode = DSN_CLASS_TEMP; - - return exitcode; + dsn_class_t exitcode; + + /* If only one code, use it. */ + if (has_2 && !has_4 && !has_5) /* Only 2 */ + exitcode = DSN_CLASS_OK; + else if (!has_2 && has_4 && !has_5) /* Only 4 */ + exitcode = DSN_CLASS_TEMP; + else if (!has_2 && !has_4 && has_5) /* Only 5 */ + exitcode = DSN_CLASS_FAIL; + /* If two codes, prefer temporary, otherwise fail. */ + else if (has_2 && has_4 && !has_5) /* 2 and 4 */ + exitcode = DSN_CLASS_TEMP; + else if (has_2 && !has_4 && has_5) /* 2 and 5 */ + exitcode = DSN_CLASS_FAIL; + else if (!has_2 && has_4 && has_5) /* 4 and 5 */ + exitcode = DSN_CLASS_TEMP; + /* All three or none, again prefer temporary. */ + else /* 2, 4, 5 */ + exitcode = DSN_CLASS_TEMP; + + return exitcode; } -dsn_class_t dsnuser_worstcase_list(struct list *deliveries) +dsn_class_t dsnuser_worstcase_list(struct list * deliveries) { - struct element *tmp; - int has_2 = 0, has_4 = 0, has_5 = 0; - - /* Get one reasonable error code for everyone. */ - for(tmp = list_getstart(deliveries); tmp != NULL; tmp = tmp->nextnode) - { - switch (((deliver_to_user_t *)tmp->data)->dsn.class) - { - case DSN_CLASS_OK: - /* Success. */ - has_2 = 1; - break; - case DSN_CLASS_TEMP: - /* Temporary transient failure. */ - has_4 = 1; - break; - case DSN_CLASS_FAIL: - /* Permanent failure. */ - has_5 = 1; - break; - } - } - - /* If we never made it into the list, all zeroes will - * yield a temporary failure, which is pretty reasonable. */ - return dsnuser_worstcase_int(has_2, has_4, has_5); -} + struct element *tmp; + int has_2 = 0, has_4 = 0, has_5 = 0; + /* Get one reasonable error code for everyone. */ + for (tmp = list_getstart(deliveries); tmp != NULL; + tmp = tmp->nextnode) { + switch (((deliver_to_user_t *) tmp->data)->dsn.class) { + case DSN_CLASS_OK: + /* Success. */ + has_2 = 1; + break; + case DSN_CLASS_TEMP: + /* Temporary transient failure. */ + has_4 = 1; + break; + case DSN_CLASS_FAIL: + /* Permanent failure. */ + has_5 = 1; + break; + } + } + + /* If we never made it into the list, all zeroes will + * yield a temporary failure, which is pretty reasonable. */ + return dsnuser_worstcase_int(has_2, has_4, has_5); +} @@ -12,28 +12,25 @@ * accessed by functions in dsn.c */ -typedef enum -{ - DSN_CLASS_OK = 2, - DSN_CLASS_TEMP = 4, - DSN_CLASS_FAIL = 5 +typedef enum { + DSN_CLASS_OK = 2, + DSN_CLASS_TEMP = 4, + DSN_CLASS_FAIL = 5 } dsn_class_t; -typedef struct -{ - dsn_class_t class; - int subject; - int detail; +typedef struct { + dsn_class_t class; + int subject; + int detail; } delivery_status_t; -typedef struct -{ - u64_t useridnr; /* Specific user id recipient (from outside). */ - const char *address; /* Envelope recipient (from outside). */ - const char *mailbox; /* Default mailbox to use for userid deliveries (from outside). */ - struct list *userids; /* List of u64_t* -- internal useridnr's to deliver to (internal). */ - struct list *forwards; /* List of char* -- external addresses to forward to (internal). */ - delivery_status_t dsn; /* Return status of this "delivery basket" (to outside). */ +typedef struct { + u64_t useridnr; /* Specific user id recipient (from outside). */ + const char *address; /* Envelope recipient (from outside). */ + const char *mailbox; /* Default mailbox to use for userid deliveries (from outside). */ + struct list *userids; /* List of u64_t* -- internal useridnr's to deliver to (internal). */ + struct list *forwards; /* List of char* -- external addresses to forward to (internal). */ + delivery_status_t dsn; /* Return status of this "delivery basket" (to outside). */ } deliver_to_user_t; /** @@ -43,9 +40,9 @@ typedef struct * - 0 on success * - -1 on failure */ -int dsnuser_init(deliver_to_user_t *dsnuser); +int dsnuser_init(deliver_to_user_t * dsnuser); -void dsnuser_free(deliver_to_user_t *dsnuser); +void dsnuser_free(deliver_to_user_t * dsnuser); void dsnuser_free_list(struct list *deliveries); /** @@ -86,4 +83,4 @@ dsn_class_t dsnuser_worstcase_list(struct list *deliveries); */ dsn_class_t dsnuser_worstcase_int(int has_2, int has_4, int has_5); -#endif /* DSN_H */ +#endif /* DSN_H */ @@ -82,15 +82,14 @@ int forward(u64_t msgidnr, struct list *targets, const char *from, } target = list_getstart(targets); - + while (target != NULL) { if ((((char *) target->data)[0] == '|') || (((char *) target->data)[0] == '!')) { /* external pipe command */ - command = - (char *) - my_malloc(strlen((char *) (target->data))); + command = (char *) + my_malloc(strlen((char *) (target->data))); if (!command) { trace(TRACE_ERROR, "%s,%s: out of memory", @@ -101,10 +100,10 @@ int forward(u64_t msgidnr, struct list *targets, const char *from, strcpy(command, (char *) (target->data) + 1); } else { /* pipe to sendmail */ - command = (char *) - my_malloc(strlen((char *) - (target->data)) + - strlen(sendmail) + 2); + command = (char *) + my_malloc(strlen((char *) + (target->data)) + + strlen(sendmail) + 2); /* +2 for extra space and \0 */ if (!command) { trace(TRACE_ERROR, @@ -170,7 +169,8 @@ int forward(u64_t msgidnr, struct list *targets, const char *from, * is no message to send. */ trace(TRACE_DEBUG, "%s,%s: writing header to " - "pipe", __FILE__, __FUNCTION__); + "pipe", __FILE__, + __FUNCTION__); fprintf(pipe, "%s", header); } @@ -29,6 +29,7 @@ #define FW_SENDMAIL SENDMAIL -int forward(u64_t msgidnr, struct list *targets, const char *from, const char *header, u64_t headersize); +int forward(u64_t msgidnr, struct list *targets, const char *from, + const char *header, u64_t headersize); #endif @@ -21,9 +21,9 @@ #include <string.h> #include <errno.h> -extern struct list mimelist; -extern struct list users; -extern struct list smtpItems; +extern struct list mimelist; +extern struct list users; +extern struct list smtpItems; #define HEADER_BLOCK_SIZE 1024 @@ -43,120 +43,130 @@ extern struct list smtpItems; * 1 on success * 0 on failure * */ -int read_header(FILE *instream, u64_t *headerrfcsize, u64_t *headersize, char **header) +int read_header(FILE * instream, u64_t * headerrfcsize, u64_t * headersize, + char **header) { - char *tmpline; - char *tmpheader; - u64_t tmpheadersize=0, tmpheaderrfcsize=0; - size_t usedmem=0, linemem=0; - size_t allocated_blocks=1; - int myeof=0; - - memtst((tmpheader = (char *)my_malloc(HEADER_BLOCK_SIZE))==NULL); - memtst((tmpline = (char *)my_malloc(MAX_LINE_SIZE))==NULL); - - /* Resetting */ - memset(tmpline, '\0', MAX_LINE_SIZE); - memset(tmpheader, '\0', HEADER_BLOCK_SIZE); - - /* here we will start a loop to read in the message header */ - /* the header will be everything up until \n\n or an EOF of */ - /* in_stream (instream) */ - - trace(TRACE_INFO, "read_header(): readheader start\n"); - - while (!feof(instream) && !myeof) - { - /* fgets will read until \n occurs, and \n is *included* in tmpline */ - if (!fgets(tmpline, MAX_LINE_SIZE, instream)) - break; - linemem = strlen(tmpline); - tmpheadersize += linemem; - tmpheaderrfcsize += linemem; - /* The RFC size assumes all lines end in \r\n, - * so if we have a newline (\n) but don't have - * a carriage return (\r), count it in rfcsize. */ - if (linemem > 0 && tmpline[linemem-1] == '\n') - if (linemem == 1 || (linemem > 1 && tmpline[linemem-2] != '\r')) - tmpheaderrfcsize++; - - if (ferror(instream)) - { - trace(TRACE_ERROR,"read_header(): error on instream: [%s]", strerror(errno)); - my_free(tmpline); - /* NOTA BENE: Make sure that the caller knows to free - * the header block even if there's been an error! */ - return -1; - } - - /* The end of the header could be \n\n, \r\n\r\n, - * or \r\n.\r\n, in the accidental case that we - * ate the whole SMTP message, too! */ - if (strcmp(tmpline, ".\r\n") == 0) - { - /* This is the end of the message! */ - trace (TRACE_DEBUG,"read_header(): single period found"); - myeof = 1; - } - else if (strcmp(tmpline, "\n") == 0 || strcmp(tmpline, "\r\n") == 0) - { - /* We've found the end of the header */ - trace (TRACE_DEBUG,"read_header(): single blank line found"); - myeof = 1; - } - - /* Even if we hit the end of the header, don't forget to copy the extra - * returns. They will always be needed to separate the header from the - * message during any future retrieval of the fully concatenated message. - * */ - - trace (TRACE_DEBUG,"read_header(): copying line into header"); - - /* If this happends it's a very big header */ - if (usedmem + linemem > (allocated_blocks*HEADER_BLOCK_SIZE)) - { - /* Update block counter */ - allocated_blocks++; - trace (TRACE_DEBUG,"read_header(): mem current: [%d] reallocated to [%d]", - usedmem, allocated_blocks*HEADER_BLOCK_SIZE); - memtst((tmpheader = (char *)realloc(tmpheader, allocated_blocks*HEADER_BLOCK_SIZE))==NULL); - } - - /* This *should* always happen, but better safe than overflowing! */ - if (usedmem + linemem < (allocated_blocks*HEADER_BLOCK_SIZE)) - { - /* Copy starting at the current usage offset */ - strncpy( (tmpheader+usedmem), tmpline, linemem); - usedmem += linemem; - - /* Resetting strlen for tmpline */ - tmpline[0] = '\0'; - linemem=0; - } - } - - trace (TRACE_DEBUG, "read_header(): readheader done"); - trace (TRACE_DEBUG, "read_header(): found header [%s] of len [%d] using mem [%d]", - tmpheader, strlen(tmpheader), usedmem); - - my_free(tmpline); - - if (usedmem==0) - { - /* FIXME: Why are we hard aborting? That's ridiculous. */ - trace(TRACE_STOP, "read_header(): no valid mail header found\n"); - return 0; - } - - /* Assign to the external variable */ - *header = tmpheader; - *headersize = tmpheadersize; - *headerrfcsize = tmpheaderrfcsize; - - /* The caller is responsible for freeing header/tmpheader. */ - - trace (TRACE_INFO, "read_header(): function successfull\n"); - return 1; + char *tmpline; + char *tmpheader; + u64_t tmpheadersize = 0, tmpheaderrfcsize = 0; + size_t usedmem = 0, linemem = 0; + size_t allocated_blocks = 1; + int myeof = 0; + + memtst((tmpheader = + (char *) my_malloc(HEADER_BLOCK_SIZE)) == NULL); + memtst((tmpline = (char *) my_malloc(MAX_LINE_SIZE)) == NULL); + + /* Resetting */ + memset(tmpline, '\0', MAX_LINE_SIZE); + memset(tmpheader, '\0', HEADER_BLOCK_SIZE); + + /* here we will start a loop to read in the message header */ + /* the header will be everything up until \n\n or an EOF of */ + /* in_stream (instream) */ + + trace(TRACE_INFO, "read_header(): readheader start\n"); + + while (!feof(instream) && !myeof) { + /* fgets will read until \n occurs, and \n is *included* in tmpline */ + if (!fgets(tmpline, MAX_LINE_SIZE, instream)) + break; + linemem = strlen(tmpline); + tmpheadersize += linemem; + tmpheaderrfcsize += linemem; + /* The RFC size assumes all lines end in \r\n, + * so if we have a newline (\n) but don't have + * a carriage return (\r), count it in rfcsize. */ + if (linemem > 0 && tmpline[linemem - 1] == '\n') + if (linemem == 1 + || (linemem > 1 + && tmpline[linemem - 2] != '\r')) + tmpheaderrfcsize++; + + if (ferror(instream)) { + trace(TRACE_ERROR, + "read_header(): error on instream: [%s]", + strerror(errno)); + my_free(tmpline); + /* NOTA BENE: Make sure that the caller knows to free + * the header block even if there's been an error! */ + return -1; + } + + /* The end of the header could be \n\n, \r\n\r\n, + * or \r\n.\r\n, in the accidental case that we + * ate the whole SMTP message, too! */ + if (strcmp(tmpline, ".\r\n") == 0) { + /* This is the end of the message! */ + trace(TRACE_DEBUG, + "read_header(): single period found"); + myeof = 1; + } else if (strcmp(tmpline, "\n") == 0 + || strcmp(tmpline, "\r\n") == 0) { + /* We've found the end of the header */ + trace(TRACE_DEBUG, + "read_header(): single blank line found"); + myeof = 1; + } + + /* Even if we hit the end of the header, don't forget to copy the extra + * returns. They will always be needed to separate the header from the + * message during any future retrieval of the fully concatenated message. + * */ + + trace(TRACE_DEBUG, + "read_header(): copying line into header"); + + /* If this happends it's a very big header */ + if (usedmem + linemem > + (allocated_blocks * HEADER_BLOCK_SIZE)) { + /* Update block counter */ + allocated_blocks++; + trace(TRACE_DEBUG, + "read_header(): mem current: [%d] reallocated to [%d]", + usedmem, + allocated_blocks * HEADER_BLOCK_SIZE); + memtst((tmpheader = + (char *) realloc(tmpheader, + allocated_blocks * + HEADER_BLOCK_SIZE)) == + NULL); + } + + /* This *should* always happen, but better safe than overflowing! */ + if (usedmem + linemem < + (allocated_blocks * HEADER_BLOCK_SIZE)) { + /* Copy starting at the current usage offset */ + strncpy((tmpheader + usedmem), tmpline, linemem); + usedmem += linemem; + + /* Resetting strlen for tmpline */ + tmpline[0] = '\0'; + linemem = 0; + } + } + + trace(TRACE_DEBUG, "read_header(): readheader done"); + trace(TRACE_DEBUG, + "read_header(): found header [%s] of len [%d] using mem [%d]", + tmpheader, strlen(tmpheader), usedmem); + + my_free(tmpline); + + if (usedmem == 0) { + /* FIXME: Why are we hard aborting? That's ridiculous. */ + trace(TRACE_STOP, + "read_header(): no valid mail header found\n"); + return 0; + } + + /* Assign to the external variable */ + *header = tmpheader; + *headersize = tmpheadersize; + *headerrfcsize = tmpheaderrfcsize; + + /* The caller is responsible for freeing header/tmpheader. */ + + trace(TRACE_INFO, "read_header(): function successfull\n"); + return 1; } - - @@ -23,6 +23,7 @@ * - 1 on success * - 0 on failure */ -int read_header(FILE *instream, u64_t *newlines, u64_t *headersize, char **header); +int read_header(FILE * instream, u64_t * newlines, u64_t * headersize, + char **header); #endif @@ -51,60 +51,64 @@ cache_t cached_msg; /* consts */ -const char AcceptedChars[] = -"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -"!@#$%^&*()-=_+`~[]{}\\|'\" ;:,.<>/? \n\r"; - -const char AcceptedTagChars[] = -"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -"!@#$%^&-=_`~\\|'\" ;:,.<>/? "; +const char AcceptedChars[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "!@#$%^&*()-=_+`~[]{}\\|'\" ;:,.<>/? \n\r"; + +const char AcceptedTagChars[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "!@#$%^&-=_`~\\|'\" ;:,.<>/? "; + +const char AcceptedMailboxnameChars[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=/ _.&,+"; + +const char *IMAP_COMMANDS[] = { + "", "capability", "noop", "logout", + "authenticate", "login", + "select", "examine", "create", "delete", "rename", "subscribe", + "unsubscribe", + "list", "lsub", "status", "append", + "check", "close", "expunge", "search", "fetch", "store", "copy", + "uid", + "getquotaroot", "getquota", + "setacl", "deleteacl", "getacl", "listrights", "myrights", + "namespace", + "***NOMORE***" +}; -const char AcceptedMailboxnameChars[] = -"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=/ _.&,+"; -const char *IMAP_COMMANDS[] = -{ - "", "capability", "noop", "logout", - "authenticate", "login", - "select", "examine", "create", "delete", "rename", "subscribe", "unsubscribe", - "list", "lsub", "status", "append", - "check", "close", "expunge", "search", "fetch", "store", "copy", "uid", - "getquotaroot", "getquota", - "setacl", "deleteacl", "getacl", "listrights", "myrights", - "namespace", - "***NOMORE***" +enum IMAP_COMMAND_TYPES { IMAP_COMM_NONE, + IMAP_COMM_CAPABILITY, IMAP_COMM_NOOP, IMAP_COMM_LOGOUT, + IMAP_COMM_AUTH, IMAP_COMM_LOGIN, + IMAP_COMM_SELECT, IMAP_COMM_EXAMINE, IMAP_COMM_CREATE, + IMAP_COMM_DELETE, IMAP_COMM_RENAME, IMAP_COMM_SUBSCRIBE, + IMAP_COMM_UNSUBSCRIBE, IMAP_COMM_LIST, IMAP_COMM_LSUB, + IMAP_COMM_STATUS, IMAP_COMM_APPEND, + IMAP_COMM_CHECK, IMAP_COMM_CLOSE, IMAP_COMM_EXPUNGE, + IMAP_COMM_SEARCH, IMAP_COMM_FETCH, IMAP_COMM_STORE, + IMAP_COMM_COPY, IMAP_COMM_UID, + IMAP_COMM_GETQUOTAROOT, IMAP_COMM_GETQUOTA, + IMAP_COMM_SETACL, IMAP_COMM_DELETEACL, IMAP_COMM_GETACL, + IMAP_COMM_LISTRIGHTS, IMAP_COMM_MYRIGHTS, + IMAP_COMM_NAMESPACE, + IMAP_COMM_LAST }; -enum IMAP_COMMAND_TYPES { IMAP_COMM_NONE, - IMAP_COMM_CAPABILITY, IMAP_COMM_NOOP, IMAP_COMM_LOGOUT, - IMAP_COMM_AUTH, IMAP_COMM_LOGIN, - IMAP_COMM_SELECT, IMAP_COMM_EXAMINE, IMAP_COMM_CREATE, - IMAP_COMM_DELETE, IMAP_COMM_RENAME, IMAP_COMM_SUBSCRIBE, - IMAP_COMM_UNSUBSCRIBE, IMAP_COMM_LIST, IMAP_COMM_LSUB, - IMAP_COMM_STATUS, IMAP_COMM_APPEND, - IMAP_COMM_CHECK, IMAP_COMM_CLOSE, IMAP_COMM_EXPUNGE, - IMAP_COMM_SEARCH, IMAP_COMM_FETCH, IMAP_COMM_STORE, - IMAP_COMM_COPY, IMAP_COMM_UID, - IMAP_COMM_GETQUOTAROOT, IMAP_COMM_GETQUOTA, - IMAP_COMM_SETACL, IMAP_COMM_DELETEACL, IMAP_COMM_GETACL, - IMAP_COMM_LISTRIGHTS, IMAP_COMM_MYRIGHTS, - IMAP_COMM_NAMESPACE, - IMAP_COMM_LAST }; - - -const IMAP_COMMAND_HANDLER imap_handler_functions[] = -{ - NULL, - _ic_capability, _ic_noop, _ic_logout, - _ic_authenticate, _ic_login, - _ic_select, _ic_examine, _ic_create, _ic_delete, _ic_rename, - _ic_subscribe, _ic_unsubscribe, _ic_list, _ic_lsub, _ic_status, _ic_append, - _ic_check, _ic_close, _ic_expunge, _ic_search, _ic_fetch, _ic_store, _ic_copy, _ic_uid, - _ic_getquotaroot, _ic_getquota, - _ic_setacl, _ic_deleteacl, _ic_getacl, _ic_listrights, _ic_myrights, - _ic_namespace, - NULL +const IMAP_COMMAND_HANDLER imap_handler_functions[] = { + NULL, + _ic_capability, _ic_noop, _ic_logout, + _ic_authenticate, _ic_login, + _ic_select, _ic_examine, _ic_create, _ic_delete, _ic_rename, + _ic_subscribe, _ic_unsubscribe, _ic_list, _ic_lsub, _ic_status, + _ic_append, + _ic_check, _ic_close, _ic_expunge, _ic_search, _ic_fetch, + _ic_store, _ic_copy, _ic_uid, + _ic_getquotaroot, _ic_getquota, + _ic_setacl, _ic_deleteacl, _ic_getacl, _ic_listrights, + _ic_myrights, + _ic_namespace, + NULL }; @@ -115,321 +119,332 @@ const IMAP_COMMAND_HANDLER imap_handler_functions[] = * * returns EOF on logout/fatal error or 1 otherwise */ -int IMAPClientHandler(ClientInfo *ci) +int IMAPClientHandler(ClientInfo * ci) { - char line[MAX_LINESIZE]; - char *tag = NULL,*cpy,**args,*command; - int i,done,result; - int nfaultyresponses; - imap_userdata_t *ud = NULL; - mailbox_t newmailbox; - int this_was_noop = 0; - - /* init: add userdata */ - ci->userData = my_malloc(sizeof(imap_userdata_t)); - if (!ci->userData) - { - /* out of mem */ - trace(TRACE_ERROR,"IMAPClientHandler(): not enough memory."); - return -1; - } - - memset(ci->userData, 0, sizeof(imap_userdata_t)); - ((imap_userdata_t*)ci->userData)->state = IMAPCS_NON_AUTHENTICATED; - ud = ci->userData; - - /* greet user */ - fprintf(ci->tx,"* OK dbmail imap (protocol version 4r1) server %s ready to run\r\n", - IMAP_SERVER_VERSION); - fflush(ci->tx); - - /* init: cache */ - if (init_cache() != 0) - { - trace(TRACE_ERROR, "IMAPClientHandler(): cannot open temporary file\n"); - fprintf(ci->tx, "* BYE internal system failure\r\n"); - - null_free(ci->userData); - return EOF; - } - - done = 0; - args = NULL; - nfaultyresponses = 0; - - do - { - if (nfaultyresponses >= MAX_FAULTY_RESPONSES) - { - /* we have had just about it with this user */ - sleep(2); /* avoid DOS attacks */ - fprintf(ci->tx,"* BYE [TRY RFC]\r\n"); - done = 1; - break; + char line[MAX_LINESIZE]; + char *tag = NULL, *cpy, **args, *command; + int i, done, result; + int nfaultyresponses; + imap_userdata_t *ud = NULL; + mailbox_t newmailbox; + int this_was_noop = 0; + + /* init: add userdata */ + ci->userData = my_malloc(sizeof(imap_userdata_t)); + if (!ci->userData) { + /* out of mem */ + trace(TRACE_ERROR, + "IMAPClientHandler(): not enough memory."); + return -1; } - if (ferror(ci->rx)) - { - trace(TRACE_ERROR, "IMAPClientHandler(): error [%s] on read-stream\n",strerror(errno)); - if (errno == EPIPE) - { - close_cache(); - null_free(((imap_userdata_t*)ci->userData)->mailbox.seq_list); - null_free(ci->userData); - - return -1; /* broken pipe */ - } - else - clearerr(ci->rx); + memset(ci->userData, 0, sizeof(imap_userdata_t)); + ((imap_userdata_t *) ci->userData)->state = + IMAPCS_NON_AUTHENTICATED; + ud = ci->userData; + + /* greet user */ + fprintf(ci->tx, + "* OK dbmail imap (protocol version 4r1) server %s ready to run\r\n", + IMAP_SERVER_VERSION); + fflush(ci->tx); + + /* init: cache */ + if (init_cache() != 0) { + trace(TRACE_ERROR, + "IMAPClientHandler(): cannot open temporary file\n"); + fprintf(ci->tx, "* BYE internal system failure\r\n"); + + null_free(ci->userData); + return EOF; } - if (ferror(ci->tx)) - { - trace(TRACE_ERROR, "IMAPClientHandler(): error [%s] on write-stream\n",strerror(errno)); - if (errno == EPIPE) - { - close_cache(); - null_free(((imap_userdata_t*)ci->userData)->mailbox.seq_list); - null_free(ci->userData); - - return -1; /* broken pipe */ - } - else - clearerr(ci->tx); - } + done = 0; + args = NULL; + nfaultyresponses = 0; + + do { + if (nfaultyresponses >= MAX_FAULTY_RESPONSES) { + /* we have had just about it with this user */ + sleep(2); /* avoid DOS attacks */ + fprintf(ci->tx, "* BYE [TRY RFC]\r\n"); + done = 1; + break; + } - alarm(ci->timeout); /* install timeout handler */ - fgets(line, MAX_LINESIZE, ci->rx); /* read command line */ - alarm(0); /* remove timeout handler */ - - if (!ci->rx || !ci->tx) - { - /* if a timeout occured the streams will be closed & set to NULL */ - trace(TRACE_ERROR, "IMAPClientHandler(): timeout occurred."); - close_cache(); - null_free(((imap_userdata_t*)ci->userData)->mailbox.seq_list); - null_free(ci->userData); - - return 1; - } + if (ferror(ci->rx)) { + trace(TRACE_ERROR, + "IMAPClientHandler(): error [%s] on read-stream\n", + strerror(errno)); + if (errno == EPIPE) { + close_cache(); + null_free(((imap_userdata_t *) ci-> + userData)->mailbox.seq_list); + null_free(ci->userData); - trace(TRACE_DEBUG,"IMAPClientHandler(): line read for PID %d\n",getpid()); + return -1; /* broken pipe */ + } else + clearerr(ci->rx); + } - if (!checkchars(line)) - { - /* foute tekens ingetikt */ - fprintf(ci->tx, "* BYE Input contains invalid characters\r\n"); - close_cache(); + if (ferror(ci->tx)) { + trace(TRACE_ERROR, + "IMAPClientHandler(): error [%s] on write-stream\n", + strerror(errno)); + if (errno == EPIPE) { + close_cache(); + null_free(((imap_userdata_t *) ci-> + userData)->mailbox.seq_list); + null_free(ci->userData); - null_free(((imap_userdata_t*)ci->userData)->mailbox.seq_list); - null_free(ci->userData); + return -1; /* broken pipe */ + } else + clearerr(ci->tx); + } - return 1; - } + alarm(ci->timeout); /* install timeout handler */ + fgets(line, MAX_LINESIZE, ci->rx); /* read command line */ + alarm(0); /* remove timeout handler */ - /* clarify data a little */ - cpy = &line[strlen(line)]; - cpy--; - while (cpy >= line && (*cpy == '\r' || *cpy == '\n')) - { - *cpy = '\0'; - cpy--; - } + if (!ci->rx || !ci->tx) { + /* if a timeout occured the streams will be closed & set to NULL */ + trace(TRACE_ERROR, + "IMAPClientHandler(): timeout occurred."); + close_cache(); + null_free(((imap_userdata_t *) ci->userData)-> + mailbox.seq_list); + null_free(ci->userData); -// clarify_data(line); + return 1; + } - trace(COMMAND_SHOW_LEVEL,"COMMAND: [%s]\n",line); - - if (!(*line)) - { - fprintf(ci->tx, "* BAD No tag specified\r\n"); - nfaultyresponses++; - continue; - } - - /* read tag & command */ - cpy = line; - - i = stridx(cpy,' '); /* find next space */ - if (i == (int) strlen(cpy)) - { - if (strcmp(cpy, "yeah!") == 0) - fprintf(ci->tx,"* YEAH dbmail ROCKS sunnyboy!\r\n"); - else - { - if (checktag(cpy)) - fprintf(ci->tx, "%s BAD No command specified\r\n",cpy); - else - fprintf(ci->tx, "* BAD Invalid tag specified\r\n"); - - nfaultyresponses++; - } - - continue; - } + trace(TRACE_DEBUG, + "IMAPClientHandler(): line read for PID %d\n", + getpid()); + if (!checkchars(line)) { + /* foute tekens ingetikt */ + fprintf(ci->tx, + "* BYE Input contains invalid characters\r\n"); + close_cache(); - tag = cpy; /* set tag */ - cpy[i] = '\0'; - cpy = cpy+i+1; /* cpy points to command now */ + null_free(((imap_userdata_t *) ci->userData)-> + mailbox.seq_list); + null_free(ci->userData); - /* check tag */ - if (!checktag(tag)) - { - fprintf(ci->tx, "* BAD Invalid tag specified\r\n"); - nfaultyresponses++; - continue; - } + return 1; + } - command = cpy; /* set command */ - i = stridx(cpy,' '); /* find next space */ - if (i == (int) strlen(cpy)) - { - /* no arguments present */ - args = build_args_array(""); - } - else - { - cpy[i] = '\0'; /* terminated command */ - cpy = cpy+i+1; /* cpy points to args now */ - args = build_args_array_ext(cpy, ci); /* build argument array */ - - if (!ci->rx || !ci->tx || ferror(ci->rx) || ferror(ci->tx)) - { - /* some error occurred during the read of extra command info */ - trace(TRACE_ERROR, "IMAPClientHandler(): error reading extra command info"); - close_cache(); - null_free(((imap_userdata_t*)ci->userData)->mailbox.seq_list); - null_free(ci->userData); - - return -1; - } - } + /* clarify data a little */ + cpy = &line[strlen(line)]; + cpy--; + while (cpy >= line && (*cpy == '\r' || *cpy == '\n')) { + *cpy = '\0'; + cpy--; + } - if (!args) - { - fprintf(ci->tx,"%s BAD invalid argument specified\r\n",tag); - nfaultyresponses++; - continue; - } +// clarify_data(line); - for (i=IMAP_COMM_NONE; i<IMAP_COMM_LAST && strcasecmp(command, IMAP_COMMANDS[i]); i++); - - if (i <= IMAP_COMM_NONE || i >= IMAP_COMM_LAST) - { - /* unknown command */ - fprintf(ci->tx,"%s BAD command not recognized\r\n",tag); - nfaultyresponses++; - - /* free used memory */ - for (i=0; args[i]; i++) - { - my_free(args[i]); - args[i] = NULL; - } - - continue; - } + trace(COMMAND_SHOW_LEVEL, "COMMAND: [%s]\n", line); - trace(TRACE_INFO, "IMAPClientHandler(): Executing command %s...\n",IMAP_COMMANDS[i]); + if (!(*line)) { + fprintf(ci->tx, "* BAD No tag specified\r\n"); + nfaultyresponses++; + continue; + } -// dirty hack to bypass a NOOP problem: -// unilateral server responses are not recognised by some clients -// if they are after the OK response - this_was_noop = 0; - - if (i != IMAP_COMM_NOOP) - result = (*imap_handler_functions[i])(tag, args, ci); - else - { - this_was_noop = 1; - result = 0; - } - - //result = (*imap_handler_functions[i])(tag, args, ci); - if (result == -1) - done = 1; /* fatal error occurred, kick this user */ - - if (result == 1) - nfaultyresponses++; /* server returned BAD or NO response */ - - if (result == 0 && i == IMAP_COMM_LOGOUT) - done = 1; - - - fflush(ci->tx); /* write! */ - - trace(TRACE_INFO, "IMAPClientHandler(): Finished command %s\n",IMAP_COMMANDS[i]); - - /* check if mailbox status has changed (notify client) */ - if (ud->state == IMAPCS_SELECTED) - { - if (i == IMAP_COMM_NOOP || - i == IMAP_COMM_CHECK || - i == IMAP_COMM_SELECT || - i == IMAP_COMM_EXPUNGE) { - /* update mailbox info */ - memset(&newmailbox, 0, sizeof(newmailbox)); - newmailbox.uid = ud->mailbox.uid; - - result = db_getmailbox(&newmailbox); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - trace(TRACE_ERROR, "IMAPClientHandler(): could not get mailbox info\n"); - + /* read tag & command */ + cpy = line; + + i = stridx(cpy, ' '); /* find next space */ + if (i == (int) strlen(cpy)) { + if (strcmp(cpy, "yeah!") == 0) + fprintf(ci->tx, + "* YEAH dbmail ROCKS sunnyboy!\r\n"); + else { + if (checktag(cpy)) + fprintf(ci->tx, + "%s BAD No command specified\r\n", + cpy); + else + fprintf(ci->tx, + "* BAD Invalid tag specified\r\n"); + + nfaultyresponses++; + } + + continue; + } + + + tag = cpy; /* set tag */ + cpy[i] = '\0'; + cpy = cpy + i + 1; /* cpy points to command now */ + + /* check tag */ + if (!checktag(tag)) { + fprintf(ci->tx, "* BAD Invalid tag specified\r\n"); + nfaultyresponses++; + continue; + } + + command = cpy; /* set command */ + i = stridx(cpy, ' '); /* find next space */ + if (i == (int) strlen(cpy)) { + /* no arguments present */ + args = build_args_array(""); + } else { + cpy[i] = '\0'; /* terminated command */ + cpy = cpy + i + 1; /* cpy points to args now */ + args = build_args_array_ext(cpy, ci); /* build argument array */ + + if (!ci->rx || !ci->tx || ferror(ci->rx) + || ferror(ci->tx)) { + /* some error occurred during the read of extra command info */ + trace(TRACE_ERROR, + "IMAPClientHandler(): error reading extra command info"); close_cache(); - null_free(((imap_userdata_t*)ci->userData)->mailbox.seq_list); + null_free(((imap_userdata_t *) ci-> + userData)->mailbox.seq_list); null_free(ci->userData); - for (i=0; args[i]; i++) - { - my_free(args[i]); - args[i] = NULL; - } - return -1; } + } + + if (!args) { + fprintf(ci->tx, + "%s BAD invalid argument specified\r\n", + tag); + nfaultyresponses++; + continue; + } + + for (i = IMAP_COMM_NONE; + i < IMAP_COMM_LAST + && strcasecmp(command, IMAP_COMMANDS[i]); i++); - if (newmailbox.exists != ud->mailbox.exists) - { - fprintf(ci->tx, "* %u EXISTS\r\n", newmailbox.exists); - trace(TRACE_INFO, "IMAPClientHandler(): ok update sent\r\n"); + if (i <= IMAP_COMM_NONE || i >= IMAP_COMM_LAST) { + /* unknown command */ + fprintf(ci->tx, + "%s BAD command not recognized\r\n", tag); + nfaultyresponses++; + + /* free used memory */ + for (i = 0; args[i]; i++) { + my_free(args[i]); + args[i] = NULL; } - if (newmailbox.recent != ud->mailbox.recent) - fprintf(ci->tx, "* %u RECENT\r\n", newmailbox.recent); + continue; + } + + trace(TRACE_INFO, + "IMAPClientHandler(): Executing command %s...\n", + IMAP_COMMANDS[i]); - my_free(ud->mailbox.seq_list); - memcpy(&ud->mailbox, &newmailbox, sizeof(newmailbox)); +// dirty hack to bypass a NOOP problem: +// unilateral server responses are not recognised by some clients +// if they are after the OK response + this_was_noop = 0; + + if (i != IMAP_COMM_NOOP) + result = + (*imap_handler_functions[i]) (tag, args, ci); + else { + this_was_noop = 1; + result = 0; } - } - if (this_was_noop) - fprintf(ci->tx, "%s OK NOOP completed\r\n", tag); - for (i=0; args[i]; i++) - { - my_free(args[i]); - args[i] = NULL; - } + //result = (*imap_handler_functions[i])(tag, args, ci); + if (result == -1) + done = 1; /* fatal error occurred, kick this user */ - } while (!done); + if (result == 1) + nfaultyresponses++; /* server returned BAD or NO response */ - /* cleanup */ - close_cache(); + if (result == 0 && i == IMAP_COMM_LOGOUT) + done = 1; - null_free(((imap_userdata_t*)ci->userData)->mailbox.seq_list); - null_free(ci->userData); - fprintf(ci->tx,"%s OK completed\r\n",tag); - trace(TRACE_MESSAGE,"IMAPClientHandler(): Closing connection for client from IP [%s]\n",ci->ip); + fflush(ci->tx); /* write! */ - __debug_dumpallocs(); + trace(TRACE_INFO, + "IMAPClientHandler(): Finished command %s\n", + IMAP_COMMANDS[i]); - return EOF; + /* check if mailbox status has changed (notify client) */ + if (ud->state == IMAPCS_SELECTED) { + if (i == IMAP_COMM_NOOP || + i == IMAP_COMM_CHECK || + i == IMAP_COMM_SELECT || + i == IMAP_COMM_EXPUNGE) { + /* update mailbox info */ + memset(&newmailbox, 0, sizeof(newmailbox)); + newmailbox.uid = ud->mailbox.uid; -} + result = db_getmailbox(&newmailbox); + if (result == -1) { + fprintf(ci->tx, + "* BYE internal dbase error\r\n"); + trace(TRACE_ERROR, + "IMAPClientHandler(): could not get mailbox info\n"); + + close_cache(); + null_free(((imap_userdata_t *) ci-> + userData)->mailbox. + seq_list); + null_free(ci->userData); + for (i = 0; args[i]; i++) { + my_free(args[i]); + args[i] = NULL; + } + return -1; + } + + if (newmailbox.exists != + ud->mailbox.exists) { + fprintf(ci->tx, "* %u EXISTS\r\n", + newmailbox.exists); + trace(TRACE_INFO, + "IMAPClientHandler(): ok update sent\r\n"); + } + if (newmailbox.recent != + ud->mailbox.recent) + fprintf(ci->tx, "* %u RECENT\r\n", + newmailbox.recent); + my_free(ud->mailbox.seq_list); + memcpy(&ud->mailbox, &newmailbox, + sizeof(newmailbox)); + } + } + if (this_was_noop) + fprintf(ci->tx, "%s OK NOOP completed\r\n", tag); + + for (i = 0; args[i]; i++) { + my_free(args[i]); + args[i] = NULL; + } + + } while (!done); + + /* cleanup */ + close_cache(); + + null_free(((imap_userdata_t *) ci->userData)->mailbox.seq_list); + null_free(ci->userData); + + fprintf(ci->tx, "%s OK completed\r\n", tag); + trace(TRACE_MESSAGE, + "IMAPClientHandler(): Closing connection for client from IP [%s]\n", + ci->ip); + + __debug_dumpallocs(); + + return EOF; + +} @@ -44,51 +44,47 @@ /* max number of retries when synchronizing mailbox with dbase */ #define MAX_RETRIES 20 -int IMAPClientHandler(ClientInfo *ci); +int IMAPClientHandler(ClientInfo * ci); -typedef int (*IMAP_COMMAND_HANDLER)(char*, char**, ClientInfo*); +typedef int (*IMAP_COMMAND_HANDLER) (char *, char **, ClientInfo *); -typedef struct -{ - int noseen; /* set the seen flag ? */ - int itemtype; /* the item to be fetched */ - int argstart; /* start index in the arg array */ - int argcnt; /* number of args belonging to this bodyfetch */ - long long octetstart,octetcnt; /* number of octets to be retrieved */ +typedef struct { + int noseen; /* set the seen flag ? */ + int itemtype; /* the item to be fetched */ + int argstart; /* start index in the arg array */ + int argcnt; /* number of args belonging to this bodyfetch */ + long long octetstart, octetcnt; /* number of octets to be retrieved */ - char partspec[IMAP_MAX_PARTSPEC_LEN]; /* part specifier (i.e. '2.1.3' */ + char partspec[IMAP_MAX_PARTSPEC_LEN]; /* part specifier (i.e. '2.1.3' */ } body_fetch_t; -typedef struct -{ +typedef struct { /* int nbodyfetches; body_fetch_t *bodyfetches; */ - body_fetch_t bodyfetch; + body_fetch_t bodyfetch; - int msgparse_needed; + int msgparse_needed; - int getBodyTotal,getBodyTotalPeek; - int getInternalDate,getFlags,getUID; - int getMIME_IMB,getEnvelope,getSize; - int getMIME_IMB_noextension; - int getRFC822Header,getRFC822Text; - int getRFC822,getRFC822Peek; + int getBodyTotal, getBodyTotalPeek; + int getInternalDate, getFlags, getUID; + int getMIME_IMB, getEnvelope, getSize; + int getMIME_IMB_noextension; + int getRFC822Header, getRFC822Text; + int getRFC822, getRFC822Peek; } fetch_items_t; -typedef struct -{ - int state; /* IMAP state of client */ - u64_t userid; /* userID of client in dbase */ - mailbox_t mailbox; /* currently selected mailbox */ +typedef struct { + int state; /* IMAP state of client */ + u64_t userid; /* userID of client in dbase */ + mailbox_t mailbox; /* currently selected mailbox */ } imap_userdata_t; -typedef enum -{ +typedef enum { IMAP_STORE_FLAG_SEEN, IMAP_STORE_FLAG_ANSWERED, IMAP_STORE_FLAG_DELETED, @@ -98,6 +94,3 @@ typedef enum } imap_store_flag_t; #endif - - - diff --git a/imapcommands.c b/imapcommands.c index af518470..730c7003 100644 --- a/imapcommands.c +++ b/imapcommands.c @@ -68,14 +68,13 @@ #define MAX_RETRIES 12 #endif -const char *imap_flag_desc[IMAP_NFLAGS] = -{ - "Seen", "Answered", "Deleted", "Flagged", "Draft", "Recent" +const char *imap_flag_desc[IMAP_NFLAGS] = { + "Seen", "Answered", "Deleted", "Flagged", "Draft", "Recent" }; -const char *imap_flag_desc_escaped[IMAP_NFLAGS] = -{ - "\\Seen", "\\Answered", "\\Deleted", "\\Flagged", "\\Draft", "\\Recent" +const char *imap_flag_desc_escaped[IMAP_NFLAGS] = { + "\\Seen", "\\Answered", "\\Deleted", "\\Flagged", "\\Draft", + "\\Recent" }; int imapcommands_use_uid = 0; @@ -105,15 +104,15 @@ extern int imap_before_smtp; * * returns a string to the client containing the server capabilities */ -int _ic_capability(char *tag, char **args, ClientInfo *ci) +int _ic_capability(char *tag, char **args, ClientInfo * ci) { - if (!check_state_and_args("CAPABILITY", tag, args, 0, -1, ci)) - return 1; /* error, return */ - - fprintf(ci->tx,"* CAPABILITY %s\r\n",IMAP_CAPABILITY_STRING); - fprintf(ci->tx,"%s OK CAPABILITY completed\r\n",tag); + if (!check_state_and_args("CAPABILITY", tag, args, 0, -1, ci)) + return 1; /* error, return */ - return 0; + fprintf(ci->tx, "* CAPABILITY %s\r\n", IMAP_CAPABILITY_STRING); + fprintf(ci->tx, "%s OK CAPABILITY completed\r\n", tag); + + return 0; } @@ -122,13 +121,13 @@ int _ic_capability(char *tag, char **args, ClientInfo *ci) * * performs No operation */ -int _ic_noop(char *tag, char **args, ClientInfo *ci) +int _ic_noop(char *tag, char **args, ClientInfo * ci) { - if (!check_state_and_args("NOOP", tag, args, 0, -1, ci)) - return 1; /* error, return */ - - fprintf(ci->tx,"%s OK NOOP completed\r\n",tag); - return 0; + if (!check_state_and_args("NOOP", tag, args, 0, -1, ci)) + return 1; /* error, return */ + + fprintf(ci->tx, "%s OK NOOP completed\r\n", tag); + return 0; } @@ -137,24 +136,25 @@ int _ic_noop(char *tag, char **args, ClientInfo *ci) * * prepares logout from IMAP-server */ -int _ic_logout(char *tag, char **args, ClientInfo *ci) +int _ic_logout(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - timestring_t timestring; - - create_current_timestring(×tring); - if (!check_state_and_args("LOGOUT", tag, args, 0, -1, ci)) - return 1; /* error, return */ + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + timestring_t timestring; - /* change status */ - ud->state = IMAPCS_LOGOUT; + create_current_timestring(×tring); + if (!check_state_and_args("LOGOUT", tag, args, 0, -1, ci)) + return 1; /* error, return */ - trace(TRACE_MESSAGE, "_ic_logout(): user (id:%llu) logging out @ [%s]\r\n", - ud->userid, timestring); + /* change status */ + ud->state = IMAPCS_LOGOUT; - fprintf(ci->tx,"* BYE dbmail imap server kisses you goodbye\r\n"); + trace(TRACE_MESSAGE, + "_ic_logout(): user (id:%llu) logging out @ [%s]\r\n", + ud->userid, timestring); - return 0; + fprintf(ci->tx, "* BYE dbmail imap server kisses you goodbye\r\n"); + + return 0; } /* @@ -166,60 +166,64 @@ int _ic_logout(char *tag, char **args, ClientInfo *ci) * * Performs login-request handling. */ -int _ic_login(char *tag, char **args, ClientInfo *ci) +int _ic_login(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t userid; - timestring_t timestring; - int validate_result; - - create_current_timestring(×tring); - - if (!check_state_and_args("LOGIN", tag, args, 2, IMAPCS_NON_AUTHENTICATED, ci)) - return 1; /* error, return */ - - trace(TRACE_DEBUG, "_ic_login(): trying to validate user"); - validate_result = auth_validate(args[0], args[1], &userid); - trace(TRACE_MESSAGE, "_ic_login(): user (id:%llu, name %s) tries login\r\n", - userid,args[0]); - - if (validate_result == -1) - { - /* a db-error occurred */ - fprintf(ci->tx,"* BYE internal db error validating user\r\n"); - trace(TRACE_ERROR,"_ic_login(): db-validate error while validating user %s (pass %s).", - args[0],args[1]); - return -1; - } - - if (validate_result == 0) - { - sleep(2); /* security */ - - /* validation failed: invalid user/pass combination */ - trace(TRACE_MESSAGE, "IMAPD [PID %d]: user (name %s) login rejected @ %s\r\n", - (int)getpid(),args[0],timestring); - fprintf(ci->tx, "%s NO login rejected\r\n",tag); - - return 1; - } - - /* login ok */ - trace(TRACE_MESSAGE, "_ic_login(): user (id %llu, name %s) login accepted @ %s\r\n", - userid,args[0],timestring); + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t userid; + timestring_t timestring; + int validate_result; + + create_current_timestring(×tring); + + if (!check_state_and_args + ("LOGIN", tag, args, 2, IMAPCS_NON_AUTHENTICATED, ci)) + return 1; /* error, return */ + + trace(TRACE_DEBUG, "_ic_login(): trying to validate user"); + validate_result = auth_validate(args[0], args[1], &userid); + trace(TRACE_MESSAGE, + "_ic_login(): user (id:%llu, name %s) tries login\r\n", + userid, args[0]); + + if (validate_result == -1) { + /* a db-error occurred */ + fprintf(ci->tx, + "* BYE internal db error validating user\r\n"); + trace(TRACE_ERROR, + "_ic_login(): db-validate error while validating user %s (pass %s).", + args[0], args[1]); + return -1; + } + + if (validate_result == 0) { + sleep(2); /* security */ + + /* validation failed: invalid user/pass combination */ + trace(TRACE_MESSAGE, + "IMAPD [PID %d]: user (name %s) login rejected @ %s\r\n", + (int) getpid(), args[0], timestring); + fprintf(ci->tx, "%s NO login rejected\r\n", tag); + + return 1; + } + + /* login ok */ + trace(TRACE_MESSAGE, + "_ic_login(): user (id %llu, name %s) login accepted @ %s\r\n", + userid, args[0], timestring); #ifdef PROC_TITLES - set_proc_title("USER %s [%s]", args[0], ci->ip); + set_proc_title("USER %s [%s]", args[0], ci->ip); #endif - /* update client info */ - ud->userid = userid; - ud->state = IMAPCS_AUTHENTICATED; + /* update client info */ + ud->userid = userid; + ud->state = IMAPCS_AUTHENTICATED; - if (imap_before_smtp) - db_log_ip(ci->ip); + if (imap_before_smtp) + db_log_ip(ci->ip); - fprintf(ci->tx,"%s OK LOGIN completed\r\n",tag); - return 0; + fprintf(ci->tx, "%s OK LOGIN completed\r\n", tag); + return 0; } @@ -230,93 +234,96 @@ int _ic_login(char *tag, char **args, ClientInfo *ci) * * */ -int _ic_authenticate(char *tag, char **args, ClientInfo *ci) +int _ic_authenticate(char *tag, char **args, ClientInfo * ci) { - u64_t userid; - char username[MAX_LINESIZE],buf[MAX_LINESIZE],pass[MAX_LINESIZE]; - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - int validate_result; - timestring_t timestring; - - create_current_timestring(×tring); - if (!check_state_and_args("AUTHENTICATE", tag, args, 1, IMAPCS_NON_AUTHENTICATED, ci)) - return 1; /* error, return */ - - /* check authentication method */ - if (strcasecmp(args[0], "login") != 0) - { - fprintf(ci->tx,"%s NO Invalid authentication mechanism specified\r\n",tag); - return 1; - } - - /* ask for username (base64 encoded) */ - memset(buf,0,MAX_LINESIZE); - base64encode("username\r\n",buf); - fprintf(ci->tx,"+ %s\r\n",buf); - fflush(ci->tx); - - alarm(ci->timeout); - fgets(buf, MAX_LINESIZE, ci->rx); - alarm(0); - - base64decode(buf, username); - - /* ask for password */ - memset(buf,0,MAX_LINESIZE); - base64encode("password\r\n",buf); - fprintf(ci->tx,"+ %s\r\n",buf); - fflush(ci->tx); - - alarm(ci->timeout); - fgets(buf, MAX_LINESIZE, ci->rx); - alarm(0); - - base64decode(buf,pass); - - - /* try to validate user */ - validate_result = auth_validate(username, pass, &userid); - - if (validate_result == -1) - { - /* a db-error occurred */ - fprintf(ci->tx,"* BYE internal db error validating user\r\n"); - trace(TRACE_ERROR,"IMAPD: authenticate(): db-validate error while validating user %s " - "(pass %s).", - username,pass); - return -1; - } - - if (validate_result == 0) - { - sleep(2); /* security */ - - /* validation failed: invalid user/pass combination */ - fprintf(ci->tx, "%s NO login rejected\r\n",tag); - - /* validation failed: invalid user/pass combination */ - trace(TRACE_MESSAGE, "IMAPD [PID %d]: user (name %s) login rejected @ %s\r\n", - (int)getpid(),username,timestring); - - return 1; - } - - /* login ok */ - /* update client info */ - ud->userid = userid; - ud->state = IMAPCS_AUTHENTICATED; - - if (imap_before_smtp) - db_log_ip(ci->ip); - - trace(TRACE_MESSAGE, "IMAPD [PID %d]: user (id %llu, name %s) login accepted @ %s\r\n",(int)getpid(), - userid,username,timestring); + u64_t userid; + char username[MAX_LINESIZE], buf[MAX_LINESIZE], pass[MAX_LINESIZE]; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + int validate_result; + timestring_t timestring; + + create_current_timestring(×tring); + if (!check_state_and_args + ("AUTHENTICATE", tag, args, 1, IMAPCS_NON_AUTHENTICATED, ci)) + return 1; /* error, return */ + + /* check authentication method */ + if (strcasecmp(args[0], "login") != 0) { + fprintf(ci->tx, + "%s NO Invalid authentication mechanism specified\r\n", + tag); + return 1; + } + + /* ask for username (base64 encoded) */ + memset(buf, 0, MAX_LINESIZE); + base64encode("username\r\n", buf); + fprintf(ci->tx, "+ %s\r\n", buf); + fflush(ci->tx); + + alarm(ci->timeout); + fgets(buf, MAX_LINESIZE, ci->rx); + alarm(0); + + base64decode(buf, username); + + /* ask for password */ + memset(buf, 0, MAX_LINESIZE); + base64encode("password\r\n", buf); + fprintf(ci->tx, "+ %s\r\n", buf); + fflush(ci->tx); + + alarm(ci->timeout); + fgets(buf, MAX_LINESIZE, ci->rx); + alarm(0); + + base64decode(buf, pass); + + + /* try to validate user */ + validate_result = auth_validate(username, pass, &userid); + + if (validate_result == -1) { + /* a db-error occurred */ + fprintf(ci->tx, + "* BYE internal db error validating user\r\n"); + trace(TRACE_ERROR, + "IMAPD: authenticate(): db-validate error while validating user %s " + "(pass %s).", username, pass); + return -1; + } + + if (validate_result == 0) { + sleep(2); /* security */ + + /* validation failed: invalid user/pass combination */ + fprintf(ci->tx, "%s NO login rejected\r\n", tag); + + /* validation failed: invalid user/pass combination */ + trace(TRACE_MESSAGE, + "IMAPD [PID %d]: user (name %s) login rejected @ %s\r\n", + (int) getpid(), username, timestring); + + return 1; + } + + /* login ok */ + /* update client info */ + ud->userid = userid; + ud->state = IMAPCS_AUTHENTICATED; + + if (imap_before_smtp) + db_log_ip(ci->ip); + + trace(TRACE_MESSAGE, + "IMAPD [PID %d]: user (id %llu, name %s) login accepted @ %s\r\n", + (int) getpid(), userid, username, timestring); #ifdef PROC_TITLES - set_proc_title("USER %s [%s]", args[0], ci->ip); + set_proc_title("USER %s [%s]", args[0], ci->ip); #endif - - fprintf(ci->tx,"%s OK AUTHENTICATE completed\r\n",tag); - return 0; + + fprintf(ci->tx, "%s OK AUTHENTICATE completed\r\n", tag); + return 0; } @@ -331,134 +338,156 @@ int _ic_authenticate(char *tag, char **args, ClientInfo *ci) * * select a specified mailbox */ -int _ic_select(char *tag, char **args, ClientInfo *ci) +int _ic_select(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t mboxid,key; - int result; - unsigned idx; - char permstring[80]; - - if (!check_state_and_args("SELECT", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { - fprintf(ci->tx, "* BYE internal dbase error\r\n"); - return -1; - } - if (mboxid == 0) { - fprintf(ci->tx, "%s NO Could not find specified mailbox\r\n", tag); - - ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - - return 1; - } - - /* check if user has right to select mailbox */ - result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_READ); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to select mailbox\r\n", tag); - ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - return 1; - } - - /* check if mailbox is selectable */ - result = db_isselectable(mboxid); - if (result == 0) - { - /* error: cannot select mailbox */ - fprintf(ci->tx, "%s NO specified mailbox is not selectable\r\n",tag); - - ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - - return 1; - } - if (result == -1) - { - fprintf(ci->tx, "* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - - ud->mailbox.uid = mboxid; - - /* read info from mailbox */ result = db_getmailbox(&ud->mailbox); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - - /* show mailbox info */ - /* msg counts */ - fprintf(ci->tx, "* %u EXISTS\r\n",ud->mailbox.exists); - fprintf(ci->tx, "* %u RECENT\r\n",ud->mailbox.recent); - - /* flags */ - fprintf(ci->tx, "* FLAGS ("); - - if (ud->mailbox.flags & IMAPFLAG_SEEN) fprintf(ci->tx, "\\Seen "); - if (ud->mailbox.flags & IMAPFLAG_ANSWERED) fprintf(ci->tx, "\\Answered "); - if (ud->mailbox.flags & IMAPFLAG_DELETED) fprintf(ci->tx, "\\Deleted "); - if (ud->mailbox.flags & IMAPFLAG_FLAGGED) fprintf(ci->tx, "\\Flagged "); - if (ud->mailbox.flags & IMAPFLAG_DRAFT) fprintf(ci->tx, "\\Draft "); - if (ud->mailbox.flags & IMAPFLAG_RECENT) fprintf(ci->tx, "\\Recent "); - - fprintf(ci->tx,")\r\n"); - - /* permanent flags */ - fprintf(ci->tx, "* OK [PERMANENTFLAGS ("); - if (ud->mailbox.flags & IMAPFLAG_SEEN) fprintf(ci->tx, "\\Seen "); - if (ud->mailbox.flags & IMAPFLAG_ANSWERED) fprintf(ci->tx, "\\Answered "); - if (ud->mailbox.flags & IMAPFLAG_DELETED) fprintf(ci->tx, "\\Deleted "); - if (ud->mailbox.flags & IMAPFLAG_FLAGGED) fprintf(ci->tx, "\\Flagged "); - if (ud->mailbox.flags & IMAPFLAG_DRAFT) fprintf(ci->tx, "\\Draft "); - if (ud->mailbox.flags & IMAPFLAG_RECENT) fprintf(ci->tx, "\\Recent "); - - fprintf(ci->tx,")]\r\n"); - - /* UID */ - fprintf(ci->tx,"* OK [UIDVALIDITY %llu] UID value\r\n",ud->mailbox.uid); - - /* show idx of first unseen msg (if present) */ - key = db_first_unseen(ud->mailbox.uid); - if (key == (u64_t)(-1)) - { - fprintf(ci->tx, "* BYE internal dbase error\r\n"); - return -1; - } - if (binary_search(ud->mailbox.seq_list, ud->mailbox.exists, - key, &idx) != -1) - fprintf(ci->tx,"* OK [UNSEEN %u] first unseen message\r\n",idx+1); - - /* permission */ - switch (ud->mailbox.permission) - { - case IMAPPERM_READ: sprintf(permstring, "READ-ONLY"); break; - case IMAPPERM_READWRITE: sprintf(permstring, "READ-WRITE"); break; - default: - /* invalid permission --> fatal */ - trace(TRACE_ERROR,"IMAPD: select(): detected invalid permission mode for mailbox %llu ('%s')", - ud->mailbox.uid, args[0]); - - fprintf(ci->tx, "* BYE fatal: detected invalid mailbox settings\r\n"); - return -1; - } - - /* ok, update state */ - ud->state = IMAPCS_SELECTED; - - fprintf(ci->tx,"%s OK [%s] SELECT completed\r\n",tag,permstring); - return 0; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t mboxid, key; + int result; + unsigned idx; + char permstring[80]; + + if (!check_state_and_args + ("SELECT", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + if (mboxid == 0) { + fprintf(ci->tx, + "%s NO Could not find specified mailbox\r\n", tag); + + ud->state = IMAPCS_AUTHENTICATED; + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + + return 1; + } + + /* check if user has right to select mailbox */ + result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_READ); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to select mailbox\r\n", tag); + ud->state = IMAPCS_AUTHENTICATED; + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + return 1; + } + + /* check if mailbox is selectable */ + result = db_isselectable(mboxid); + if (result == 0) { + /* error: cannot select mailbox */ + fprintf(ci->tx, + "%s NO specified mailbox is not selectable\r\n", + tag); + + ud->state = IMAPCS_AUTHENTICATED; + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + + return 1; + } + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + + ud->mailbox.uid = mboxid; + + /* read info from mailbox */ result = db_getmailbox(&ud->mailbox); + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + + /* show mailbox info */ + /* msg counts */ + fprintf(ci->tx, "* %u EXISTS\r\n", ud->mailbox.exists); + fprintf(ci->tx, "* %u RECENT\r\n", ud->mailbox.recent); + + /* flags */ + fprintf(ci->tx, "* FLAGS ("); + + if (ud->mailbox.flags & IMAPFLAG_SEEN) + fprintf(ci->tx, "\\Seen "); + if (ud->mailbox.flags & IMAPFLAG_ANSWERED) + fprintf(ci->tx, "\\Answered "); + if (ud->mailbox.flags & IMAPFLAG_DELETED) + fprintf(ci->tx, "\\Deleted "); + if (ud->mailbox.flags & IMAPFLAG_FLAGGED) + fprintf(ci->tx, "\\Flagged "); + if (ud->mailbox.flags & IMAPFLAG_DRAFT) + fprintf(ci->tx, "\\Draft "); + if (ud->mailbox.flags & IMAPFLAG_RECENT) + fprintf(ci->tx, "\\Recent "); + + fprintf(ci->tx, ")\r\n"); + + /* permanent flags */ + fprintf(ci->tx, "* OK [PERMANENTFLAGS ("); + if (ud->mailbox.flags & IMAPFLAG_SEEN) + fprintf(ci->tx, "\\Seen "); + if (ud->mailbox.flags & IMAPFLAG_ANSWERED) + fprintf(ci->tx, "\\Answered "); + if (ud->mailbox.flags & IMAPFLAG_DELETED) + fprintf(ci->tx, "\\Deleted "); + if (ud->mailbox.flags & IMAPFLAG_FLAGGED) + fprintf(ci->tx, "\\Flagged "); + if (ud->mailbox.flags & IMAPFLAG_DRAFT) + fprintf(ci->tx, "\\Draft "); + if (ud->mailbox.flags & IMAPFLAG_RECENT) + fprintf(ci->tx, "\\Recent "); + + fprintf(ci->tx, ")]\r\n"); + + /* UID */ + fprintf(ci->tx, "* OK [UIDVALIDITY %llu] UID value\r\n", + ud->mailbox.uid); + + /* show idx of first unseen msg (if present) */ + key = db_first_unseen(ud->mailbox.uid); + if (key == (u64_t) (-1)) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + if (binary_search(ud->mailbox.seq_list, ud->mailbox.exists, + key, &idx) != -1) + fprintf(ci->tx, + "* OK [UNSEEN %u] first unseen message\r\n", + idx + 1); + + /* permission */ + switch (ud->mailbox.permission) { + case IMAPPERM_READ: + sprintf(permstring, "READ-ONLY"); + break; + case IMAPPERM_READWRITE: + sprintf(permstring, "READ-WRITE"); + break; + default: + /* invalid permission --> fatal */ + trace(TRACE_ERROR, + "IMAPD: select(): detected invalid permission mode for mailbox %llu ('%s')", + ud->mailbox.uid, args[0]); + + fprintf(ci->tx, + "* BYE fatal: detected invalid mailbox settings\r\n"); + return -1; + } + + /* ok, update state */ + ud->state = IMAPCS_SELECTED; + + fprintf(ci->tx, "%s OK [%s] SELECT completed\r\n", tag, + permstring); + return 0; } @@ -467,102 +496,117 @@ int _ic_select(char *tag, char **args, ClientInfo *ci) * * examines a specified mailbox */ -int _ic_examine(char *tag, char **args, ClientInfo *ci) +int _ic_examine(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t mboxid; - int result; - - if (!check_state_and_args("EXAMINE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { - fprintf(ci->tx, "* BYE internal dbase error\r\n"); - return -1; - } - if (mboxid == 0) { - fprintf(ci->tx, "%s NO Could not find specified mailbox\r\n", tag); - return 1; - } - - /* check if user has right to examine mailbox */ - result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_READ); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to examine mailbox\r\n", tag); - ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - return 1; - } - - /* check if mailbox is selectable */ - result = db_isselectable(mboxid); - if (result == 0) - { - /* error: cannot select mailbox */ - fprintf(ci->tx, "%s NO specified mailbox is not selectable\r\n",tag); - return 1; /* fatal */ - } - if (result == -1) - { - fprintf(ci->tx, "* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - - ud->mailbox.uid = mboxid; - - /* read info from mailbox */ - result = db_getmailbox(&ud->mailbox); - - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - - /* show mailbox info */ - /* msg counts */ - fprintf(ci->tx, "* %u EXISTS\r\n",ud->mailbox.exists); - fprintf(ci->tx, "* %u RECENT\r\n",ud->mailbox.recent); - - /* flags */ - fprintf(ci->tx, "* FLAGS ("); - - if (ud->mailbox.flags & IMAPFLAG_SEEN) fprintf(ci->tx, "\\Seen "); - if (ud->mailbox.flags & IMAPFLAG_ANSWERED) fprintf(ci->tx, "\\Answered "); - if (ud->mailbox.flags & IMAPFLAG_DELETED) fprintf(ci->tx, "\\Deleted "); - if (ud->mailbox.flags & IMAPFLAG_FLAGGED) fprintf(ci->tx, "\\Flagged "); - if (ud->mailbox.flags & IMAPFLAG_DRAFT) fprintf(ci->tx, "\\Draft "); - if (ud->mailbox.flags & IMAPFLAG_RECENT) fprintf(ci->tx, "\\Recent "); - - fprintf(ci->tx,")\r\n"); - - /* permanent flags */ - fprintf(ci->tx, "* OK [PERMANENTFLAGS ("); - if (ud->mailbox.flags & IMAPFLAG_SEEN) fprintf(ci->tx, "\\Seen "); - if (ud->mailbox.flags & IMAPFLAG_ANSWERED) fprintf(ci->tx, "\\Answered "); - if (ud->mailbox.flags & IMAPFLAG_DELETED) fprintf(ci->tx, "\\Deleted "); - if (ud->mailbox.flags & IMAPFLAG_FLAGGED) fprintf(ci->tx, "\\Flagged "); - if (ud->mailbox.flags & IMAPFLAG_DRAFT) fprintf(ci->tx, "\\Draft "); - if (ud->mailbox.flags & IMAPFLAG_RECENT) fprintf(ci->tx, "\\Recent "); - - fprintf(ci->tx,")]\r\n"); - - /* UID */ - fprintf(ci->tx,"* OK [UIDVALIDITY %llu] UID value\r\n",ud->mailbox.uid); - - /* update permission: examine forces read-only */ - ud->mailbox.permission = IMAPPERM_READ; - - /* ok, update state */ - ud->state = IMAPCS_SELECTED; - - fprintf(ci->tx,"%s OK [READ-ONLY] EXAMINE completed\r\n",tag); - return 0; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t mboxid; + int result; + + if (!check_state_and_args + ("EXAMINE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + if (mboxid == 0) { + fprintf(ci->tx, + "%s NO Could not find specified mailbox\r\n", tag); + return 1; + } + + /* check if user has right to examine mailbox */ + result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_READ); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to examine mailbox\r\n", tag); + ud->state = IMAPCS_AUTHENTICATED; + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + return 1; + } + + /* check if mailbox is selectable */ + result = db_isselectable(mboxid); + if (result == 0) { + /* error: cannot select mailbox */ + fprintf(ci->tx, + "%s NO specified mailbox is not selectable\r\n", + tag); + return 1; /* fatal */ + } + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + + ud->mailbox.uid = mboxid; + + /* read info from mailbox */ + result = db_getmailbox(&ud->mailbox); + + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + + /* show mailbox info */ + /* msg counts */ + fprintf(ci->tx, "* %u EXISTS\r\n", ud->mailbox.exists); + fprintf(ci->tx, "* %u RECENT\r\n", ud->mailbox.recent); + + /* flags */ + fprintf(ci->tx, "* FLAGS ("); + + if (ud->mailbox.flags & IMAPFLAG_SEEN) + fprintf(ci->tx, "\\Seen "); + if (ud->mailbox.flags & IMAPFLAG_ANSWERED) + fprintf(ci->tx, "\\Answered "); + if (ud->mailbox.flags & IMAPFLAG_DELETED) + fprintf(ci->tx, "\\Deleted "); + if (ud->mailbox.flags & IMAPFLAG_FLAGGED) + fprintf(ci->tx, "\\Flagged "); + if (ud->mailbox.flags & IMAPFLAG_DRAFT) + fprintf(ci->tx, "\\Draft "); + if (ud->mailbox.flags & IMAPFLAG_RECENT) + fprintf(ci->tx, "\\Recent "); + + fprintf(ci->tx, ")\r\n"); + + /* permanent flags */ + fprintf(ci->tx, "* OK [PERMANENTFLAGS ("); + if (ud->mailbox.flags & IMAPFLAG_SEEN) + fprintf(ci->tx, "\\Seen "); + if (ud->mailbox.flags & IMAPFLAG_ANSWERED) + fprintf(ci->tx, "\\Answered "); + if (ud->mailbox.flags & IMAPFLAG_DELETED) + fprintf(ci->tx, "\\Deleted "); + if (ud->mailbox.flags & IMAPFLAG_FLAGGED) + fprintf(ci->tx, "\\Flagged "); + if (ud->mailbox.flags & IMAPFLAG_DRAFT) + fprintf(ci->tx, "\\Draft "); + if (ud->mailbox.flags & IMAPFLAG_RECENT) + fprintf(ci->tx, "\\Recent "); + + fprintf(ci->tx, ")]\r\n"); + + /* UID */ + fprintf(ci->tx, "* OK [UIDVALIDITY %llu] UID value\r\n", + ud->mailbox.uid); + + /* update permission: examine forces read-only */ + ud->mailbox.permission = IMAPPERM_READ; + + /* ok, update state */ + ud->state = IMAPCS_SELECTED; + + fprintf(ci->tx, "%s OK [READ-ONLY] EXAMINE completed\r\n", tag); + return 0; } @@ -571,206 +615,211 @@ int _ic_examine(char *tag, char **args, ClientInfo *ci) * * create a mailbox */ -int _ic_create(char *tag, char **args, ClientInfo *ci) +int _ic_create(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - int result,i; - u64_t mboxid, tmp_mboxid; - u64_t parent_mboxid = 0; /* id of parent mailbox (if applicable) */ - char **chunks,*cpy; - int other_namespace = 0; - - if (!check_state_and_args("CREATE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - /* remove trailing '/' if present */ - while (strlen(args[0]) > 0 && args[0][strlen(args[0]) - 1] == '/') - args[0][strlen(args[0]) - 1] = '\0'; - - /* remove leading '/' if present */ - for (i=0; args[0][i] && args[0][i] == '/'; i++) ; - memmove(&args[0][0],&args[0][i], (strlen(args[0]) - i) * sizeof(char)); - - /* check if this mailbox already exists */ - if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { - /* dbase failure */ - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - - if (mboxid != 0) - { - /* mailbox already exists */ - fprintf(ci->tx,"%s NO mailbox already exists\r\n",tag); - return 1; - } - - /* check if new name is valid */ - if (!checkmailboxname(args[0])) - { - fprintf(ci->tx,"%s BAD new mailbox name contains invalid characters\r\n",tag); - return 1; - } - - /* alloc a ptr which can contain up to the full name */ - cpy = (char*)my_malloc(sizeof(char) * (strlen(args[0]) + 1)); - if (!cpy) - { - /* out of mem */ - trace(TRACE_ERROR, "IMAPD: create(): not enough memory"); - fprintf(ci->tx, "* BYE server ran out of memory\r\n"); - return -1; - } - - /* split up the name & create parent folders as necessary */ - chunks = give_chunks(args[0], '/'); - - if (chunks == NULL) - { - /* serious error while making chunks */ - trace(TRACE_ERROR, "IMAPD: create(): could not create chunks"); - fprintf(ci->tx, "* BYE server ran out of memory\r\n"); - my_free(cpy); - return -1; - } - - if (chunks[0] == NULL) - { - /* wrong argument */ - fprintf(ci->tx,"%s NO invalid mailbox name specified\r\n",tag); - free_chunks(chunks); - my_free(cpy); - return 1; - } - - /* now go create */ - strcpy(cpy,""); - - for (i=0; chunks[i]; i++) - { - if (strlen(chunks[i]) == 0) - { - /* no can do */ - fprintf(ci->tx, "%s NO invalid mailbox name specified\r\n",tag); - free_chunks(chunks); - my_free(cpy); - return 1; - } - - if (i == 0) - { - if (strcasecmp(chunks[0], "inbox") == 0) - strcpy(chunks[0], "INBOX"); /* make inbox uppercase */ - - strcat(cpy, chunks[i]); - /* check to see if this is a folder in Other Users/ or Public - namespace */ - if (strcmp(cpy, NAMESPACE_USER) == 0 || - strcmp(cpy, NAMESPACE_PUBLIC) == 0) { - other_namespace = 1; - continue; - } + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + int result, i; + u64_t mboxid, tmp_mboxid; + u64_t parent_mboxid = 0; /* id of parent mailbox (if applicable) */ + char **chunks, *cpy; + int other_namespace = 0; + + if (!check_state_and_args + ("CREATE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + /* remove trailing '/' if present */ + while (strlen(args[0]) > 0 && args[0][strlen(args[0]) - 1] == '/') + args[0][strlen(args[0]) - 1] = '\0'; + + /* remove leading '/' if present */ + for (i = 0; args[0][i] && args[0][i] == '/'; i++); + memmove(&args[0][0], &args[0][i], + (strlen(args[0]) - i) * sizeof(char)); + + /* check if this mailbox already exists */ + if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { + /* dbase failure */ + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ } - else - { - strcat(cpy, "/"); - strcat(cpy, chunks[i]); - /* if this is in Other Users namespace, continue to the next chunk */ - if (i == 1 && strncmp(cpy, NAMESPACE_USER, strlen(NAMESPACE_USER)) == 0) - continue; - - } - - trace(TRACE_DEBUG,"checking for '%s'...",cpy); - - /* check if this mailbox already exists */ - if (db_findmailbox(cpy, ud->userid, &mboxid) == -1) { - /* dbase failure */ - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - free_chunks(chunks); - my_free(cpy); - return -1; /* fatal */ - } - - if (mboxid == 0) - { - /* mailbox does not exist */ - /* check if we have the right to create mailboxes in this - hierarchy */ - trace(TRACE_DEBUG, "%s,%s: Checking if we have the right to " - "create mailboxes under mailbox [%llu]", - __FILE__, __FUNCTION__, parent_mboxid); - if (parent_mboxid != 0) { - result = acl_has_right(ud->userid, parent_mboxid, - ACL_RIGHT_CREATE); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database " - "error\r\n"); - free_chunks(chunks); - my_free(cpy); - return -1; /* fatal */ + + if (mboxid != 0) { + /* mailbox already exists */ + fprintf(ci->tx, "%s NO mailbox already exists\r\n", tag); + return 1; + } + + /* check if new name is valid */ + if (!checkmailboxname(args[0])) { + fprintf(ci->tx, + "%s BAD new mailbox name contains invalid characters\r\n", + tag); + return 1; + } + + /* alloc a ptr which can contain up to the full name */ + cpy = (char *) my_malloc(sizeof(char) * (strlen(args[0]) + 1)); + if (!cpy) { + /* out of mem */ + trace(TRACE_ERROR, "IMAPD: create(): not enough memory"); + fprintf(ci->tx, "* BYE server ran out of memory\r\n"); + return -1; + } + + /* split up the name & create parent folders as necessary */ + chunks = give_chunks(args[0], '/'); + + if (chunks == NULL) { + /* serious error while making chunks */ + trace(TRACE_ERROR, + "IMAPD: create(): could not create chunks"); + fprintf(ci->tx, "* BYE server ran out of memory\r\n"); + my_free(cpy); + return -1; + } + + if (chunks[0] == NULL) { + /* wrong argument */ + fprintf(ci->tx, "%s NO invalid mailbox name specified\r\n", + tag); + free_chunks(chunks); + my_free(cpy); + return 1; + } + + /* now go create */ + strcpy(cpy, ""); + + for (i = 0; chunks[i]; i++) { + if (strlen(chunks[i]) == 0) { + /* no can do */ + fprintf(ci->tx, + "%s NO invalid mailbox name specified\r\n", + tag); + free_chunks(chunks); + my_free(cpy); + return 1; + } + + if (i == 0) { + if (strcasecmp(chunks[0], "inbox") == 0) + strcpy(chunks[0], "INBOX"); /* make inbox uppercase */ + + strcat(cpy, chunks[i]); + /* check to see if this is a folder in Other Users/ or Public + namespace */ + if (strcmp(cpy, NAMESPACE_USER) == 0 || + strcmp(cpy, NAMESPACE_PUBLIC) == 0) { + other_namespace = 1; + continue; + } + } else { + strcat(cpy, "/"); + strcat(cpy, chunks[i]); + /* if this is in Other Users namespace, continue to the next chunk */ + if (i == 1 + && strncmp(cpy, NAMESPACE_USER, + strlen(NAMESPACE_USER)) == 0) + continue; + + } + + trace(TRACE_DEBUG, "checking for '%s'...", cpy); + + /* check if this mailbox already exists */ + if (db_findmailbox(cpy, ud->userid, &mboxid) == -1) { + /* dbase failure */ + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + free_chunks(chunks); + my_free(cpy); + return -1; /* fatal */ + } + + if (mboxid == 0) { + /* mailbox does not exist */ + /* check if we have the right to create mailboxes in this + hierarchy */ + trace(TRACE_DEBUG, + "%s,%s: Checking if we have the right to " + "create mailboxes under mailbox [%llu]", + __FILE__, __FUNCTION__, parent_mboxid); + if (parent_mboxid != 0) { + result = + acl_has_right(ud->userid, + parent_mboxid, + ACL_RIGHT_CREATE); + if (result < 0) { + fprintf(ci->tx, + "* BYE internal database " + "error\r\n"); + free_chunks(chunks); + my_free(cpy); + return -1; /* fatal */ + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to create " + "mailbox here\r\n", tag); + free_chunks(chunks); + my_free(cpy); + return 1; + } + } else { + if (other_namespace) { + /* if we want to create a new mailbox in + another namespace, but we don't specify + the parent's mailbox, we should not be + allowed to do so */ + fprintf(ci->tx, + "%s NO no permission to create " + "mailbox here\r\n", tag); + free_chunks(chunks); + my_free(cpy); + return 1; + } + } + result = + db_createmailbox(cpy, ud->userid, &tmp_mboxid); + + + if (result == -1) { + fprintf(ci->tx, + "* BYE internal dbase error\r\n"); + return -1; /* fatal */ } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to create " - "mailbox here\r\n", tag); + } else { + /* this might be the parent of our new mailbox. store it's id */ + parent_mboxid = mboxid; + /* mailbox does exist, failure if no_inferiors flag set */ + result = db_noinferiors(mboxid); + if (result == 1) { + fprintf(ci->tx, + "%s NO mailbox cannot have inferior names\r\n", + tag); free_chunks(chunks); my_free(cpy); return 1; } - } else { - if (other_namespace) { - /* if we want to create a new mailbox in - another namespace, but we don't specify - the parent's mailbox, we should not be - allowed to do so */ - fprintf(ci->tx, "%s NO no permission to create " - "mailbox here\r\n", tag); + + + if (result == -1) { + /* dbase failure */ + fprintf(ci->tx, + "* BYE internal dbase error\r\n"); free_chunks(chunks); my_free(cpy); - return 1; + return -1; /* fatal */ } } - result = db_createmailbox(cpy, ud->userid, &tmp_mboxid); - - - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - } - else - { - /* this might be the parent of our new mailbox. store it's id */ - parent_mboxid = mboxid; - /* mailbox does exist, failure if no_inferiors flag set */ - result = db_noinferiors(mboxid); - if (result == 1) - { - fprintf(ci->tx, "%s NO mailbox cannot have inferior names\r\n",tag); - free_chunks(chunks); - my_free(cpy); - return 1; - } - - - if (result == -1) - { - /* dbase failure */ - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - free_chunks(chunks); - my_free(cpy); - return -1; /* fatal */ - } } - } - /* creation complete */ - free_chunks(chunks); - my_free(cpy); + /* creation complete */ + free_chunks(chunks); + my_free(cpy); - fprintf(ci->tx,"%s OK CREATE completed\r\n",tag); - return 0; + fprintf(ci->tx, "%s OK CREATE completed\r\n", tag); + return 0; } @@ -779,120 +828,121 @@ int _ic_create(char *tag, char **args, ClientInfo *ci) * * deletes a specified mailbox */ -int _ic_delete(char *tag, char **args, ClientInfo *ci) +int _ic_delete(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - int result,nchildren = 0; - u64_t *children = NULL,mboxid; - - if (!check_state_and_args("DELETE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - /* remove trailing '/' if present */ - while (strlen(args[0]) > 0 && args[0][strlen(args[0]) - 1] == '/') - args[0][strlen(args[0]) - 1] = '\0'; - - /* check if this mailbox exists */ - if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { - /* dbase failure */ - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - if (mboxid == 0) { - /* mailbox does not exist */ - fprintf(ci->tx,"%s NO mailbox does not exist\r\n",tag); - return 1; - } - - /* check if the user is the owner of this mailbox. If so, then - the user has the right to delete it. */ - result = db_user_is_mailbox_owner(ud->userid, mboxid); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to delete mailbox\r\n", tag); - ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - return 1; - } - - - /* check if there is an attempt to delete inbox */ - if (strcasecmp(args[0],"inbox") == 0) - { - fprintf(ci->tx,"%s NO cannot delete special mailbox INBOX\r\n",tag); - return 1; - } - - /* check for children of this mailbox */ - result = db_listmailboxchildren(mboxid, ud->userid, &children, &nchildren, "%"); - if (result == -1) - { - /* error */ - trace(TRACE_ERROR, "IMAPD: delete(): cannot retrieve list of mailbox children"); - fprintf(ci->tx, "* BYE dbase/memory error\r\n"); - return -1; - } - - if (nchildren != 0) - { - /* mailbox has inferior names; error if \noselect specified */ - result = db_isselectable(mboxid); - if (result == 0) - { - fprintf(ci->tx,"%s NO mailbox is non-selectable\r\n",tag); - my_free(children); - return 1; - } - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - my_free(children); - return -1; /* fatal */ - } - - /* mailbox has inferior names; remove all msgs and set noselect flag */ - result = db_removemsg(ud->userid, mboxid); - if (result != -1) - result = db_setselectable(mboxid, 0); /* set non-selectable flag */ - - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - my_free(children); - return -1; /* fatal */ - } - - /* check if this was the currently selected mailbox */ - if (mboxid == ud->mailbox.uid) - { - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - ud->state = IMAPCS_AUTHENTICATED; - } - - /* ok done */ - fprintf(ci->tx,"%s OK DELETE completed\r\n",tag); - my_free(children); - return 0; - } - - /* ok remove mailbox */ - db_delete_mailbox(mboxid, 0, 1); - - /* check if this was the currently selected mailbox */ - if (mboxid == ud->mailbox.uid) - { - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - ud->state = IMAPCS_AUTHENTICATED; - } - - fprintf(ci->tx,"%s OK DELETE completed\r\n",tag); - return 0; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + int result, nchildren = 0; + u64_t *children = NULL, mboxid; + + if (!check_state_and_args + ("DELETE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + /* remove trailing '/' if present */ + while (strlen(args[0]) > 0 && args[0][strlen(args[0]) - 1] == '/') + args[0][strlen(args[0]) - 1] = '\0'; + + /* check if this mailbox exists */ + if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { + /* dbase failure */ + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + if (mboxid == 0) { + /* mailbox does not exist */ + fprintf(ci->tx, "%s NO mailbox does not exist\r\n", tag); + return 1; + } + + /* check if the user is the owner of this mailbox. If so, then + the user has the right to delete it. */ + result = db_user_is_mailbox_owner(ud->userid, mboxid); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to delete mailbox\r\n", tag); + ud->state = IMAPCS_AUTHENTICATED; + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + return 1; + } + + + /* check if there is an attempt to delete inbox */ + if (strcasecmp(args[0], "inbox") == 0) { + fprintf(ci->tx, + "%s NO cannot delete special mailbox INBOX\r\n", + tag); + return 1; + } + + /* check for children of this mailbox */ + result = + db_listmailboxchildren(mboxid, ud->userid, &children, + &nchildren, "%"); + if (result == -1) { + /* error */ + trace(TRACE_ERROR, + "IMAPD: delete(): cannot retrieve list of mailbox children"); + fprintf(ci->tx, "* BYE dbase/memory error\r\n"); + return -1; + } + + if (nchildren != 0) { + /* mailbox has inferior names; error if \noselect specified */ + result = db_isselectable(mboxid); + if (result == 0) { + fprintf(ci->tx, + "%s NO mailbox is non-selectable\r\n", + tag); + my_free(children); + return 1; + } + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + my_free(children); + return -1; /* fatal */ + } + + /* mailbox has inferior names; remove all msgs and set noselect flag */ + result = db_removemsg(ud->userid, mboxid); + if (result != -1) + result = db_setselectable(mboxid, 0); /* set non-selectable flag */ + + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + my_free(children); + return -1; /* fatal */ + } + + /* check if this was the currently selected mailbox */ + if (mboxid == ud->mailbox.uid) { + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + ud->state = IMAPCS_AUTHENTICATED; + } + + /* ok done */ + fprintf(ci->tx, "%s OK DELETE completed\r\n", tag); + my_free(children); + return 0; + } + + /* ok remove mailbox */ + db_delete_mailbox(mboxid, 0, 1); + + /* check if this was the currently selected mailbox */ + if (mboxid == ud->mailbox.uid) { + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + ud->state = IMAPCS_AUTHENTICATED; + } + + fprintf(ci->tx, "%s OK DELETE completed\r\n", tag); + return 0; } @@ -901,190 +951,195 @@ int _ic_delete(char *tag, char **args, ClientInfo *ci) * * renames a specified mailbox */ -int _ic_rename(char *tag, char **args, ClientInfo *ci) +int _ic_rename(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t mboxid,newmboxid,*children,oldnamelen,parentmboxid; - int nchildren,i,result; - char newname[IMAP_MAX_MAILBOX_NAMELEN],name[IMAP_MAX_MAILBOX_NAMELEN]; - - if (!check_state_and_args("RENAME", tag, args, 2, IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - /* remove trailing '/' if present */ - while (strlen(args[0]) > 0 && args[0][strlen(args[0]) - 1] == '/') args[0][strlen(args[0]) - 1] = '\0'; - while (strlen(args[1]) > 0 && args[1][strlen(args[1]) - 1] == '/') args[1][strlen(args[1]) - 1] = '\0'; - - /* remove leading '/' if present */ - for (i=0; args[1][i] && args[1][i] == '/'; i++) ; - memmove(&args[1][0],&args[1][i], (strlen(args[1]) - i) * sizeof(char)); - - for (i=0; args[0][i] && args[0][i] == '/'; i++) ; - memmove(&args[0][0],&args[0][i], (strlen(args[0]) - i) * sizeof(char)); - - - /* check if new mailbox exists */ - if (db_findmailbox(args[1], ud->userid, &mboxid) == -1) { - /* dbase failure */ - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - if (mboxid != 0) - { - /* mailbox exists */ - fprintf(ci->tx,"%s NO new mailbox already exists\r\n",tag); - return 1; - } - - /* check if original mailbox exists */ - if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { - /* dbase failure */ - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - if (mboxid == 0) - { - /* mailbox does not exist */ - fprintf(ci->tx,"%s NO mailbox does not exist\r\n",tag); - return 1; - } - - /* check if the user is the owner of this mailbox. If so, then - the user has the right to delete it. */ - result = db_user_is_mailbox_owner(ud->userid, mboxid); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to rename mailbox\r\n", tag); - ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - return 1; - } - - /* check if new name is valid */ - if (!checkmailboxname(args[1])) - { - fprintf(ci->tx,"%s NO new mailbox name contains invalid characters\r\n",tag); - return 1; - } - - oldnamelen = strlen(args[0]); - - /* check if new name would invade structure as in - * test (exists) - * rename test test/testing - * would create test/testing but delete test - */ - if (strncasecmp(args[0], args[1], oldnamelen) == 0 && - strlen(args[1]) > oldnamelen && args[1][oldnamelen] == '/') - { - fprintf(ci->tx,"%s NO new mailbox would invade mailbox structure\r\n",tag); - return 1; - } - - - /* check if structure of new name is valid */ - /* i.e. only last part (after last '/' can be nonexistent) */ - for (i=strlen(args[1])-1; i>=0 && args[1][i] != '/'; i--) ; - if (i >= 0) - { - args[1][i] = '\0'; /* note: original char was '/' */ - - if (db_findmailbox(args[1], ud->userid, &parentmboxid) == -1) { - /* dbase failure */ - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - if (parentmboxid == 0) - { - /* parent mailbox does not exist */ - fprintf(ci->tx,"%s NO new mailbox would invade mailbox structure\r\n",tag); - return 1; - } - - /* ok, reset arg */ - args[1][i] = '/'; - } - - /* check if it is INBOX to be renamed */ - if (strcasecmp(args[0],"inbox") == 0) - { - /* ok, renaming inbox */ - /* this means creating a new mailbox and moving all the INBOX msgs to the new mailbox */ - /* inferior names of INBOX are left unchanged */ - result = db_createmailbox(args[1], ud->userid, &newmboxid); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } - - result = db_movemsg(newmboxid, mboxid); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t mboxid, newmboxid, *children, oldnamelen, parentmboxid; + int nchildren, i, result; + char newname[IMAP_MAX_MAILBOX_NAMELEN], + name[IMAP_MAX_MAILBOX_NAMELEN]; + + if (!check_state_and_args + ("RENAME", tag, args, 2, IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + /* remove trailing '/' if present */ + while (strlen(args[0]) > 0 && args[0][strlen(args[0]) - 1] == '/') + args[0][strlen(args[0]) - 1] = '\0'; + while (strlen(args[1]) > 0 && args[1][strlen(args[1]) - 1] == '/') + args[1][strlen(args[1]) - 1] = '\0'; + + /* remove leading '/' if present */ + for (i = 0; args[1][i] && args[1][i] == '/'; i++); + memmove(&args[1][0], &args[1][i], + (strlen(args[1]) - i) * sizeof(char)); + + for (i = 0; args[0][i] && args[0][i] == '/'; i++); + memmove(&args[0][0], &args[0][i], + (strlen(args[0]) - i) * sizeof(char)); + + + /* check if new mailbox exists */ + if (db_findmailbox(args[1], ud->userid, &mboxid) == -1) { + /* dbase failure */ + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ } - - /* ok done */ - fprintf(ci->tx,"%s OK RENAME completed\r\n",tag); - return 0; - } - - /* check for inferior names */ - result = db_listmailboxchildren(mboxid, ud->userid, &children, &nchildren, "%"); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } - - /* replace name for each child */ - for (i=0; i<nchildren; i++) - { - result = db_getmailboxname(children[i], ud->userid, name); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - my_free(children); - return -1; + if (mboxid != 0) { + /* mailbox exists */ + fprintf(ci->tx, "%s NO new mailbox already exists\r\n", + tag); + return 1; } - if (oldnamelen >= strlen(name)) - { - /* strange error, let's say its fatal */ - trace(TRACE_ERROR,"IMAPD: rename(): mailbox names are fucked up"); - fprintf(ci->tx,"* BYE internal error regarding mailbox names\r\n"); - my_free(children); - return -1; + /* check if original mailbox exists */ + if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { + /* dbase failure */ + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + if (mboxid == 0) { + /* mailbox does not exist */ + fprintf(ci->tx, "%s NO mailbox does not exist\r\n", tag); + return 1; } - - snprintf(newname, IMAP_MAX_MAILBOX_NAMELEN, "%s%s",args[1],&name[oldnamelen]); - result = db_setmailboxname(children[i], newname); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - my_free(children); - return -1; + /* check if the user is the owner of this mailbox. If so, then + the user has the right to delete it. */ + result = db_user_is_mailbox_owner(ud->userid, mboxid); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to rename mailbox\r\n", tag); + ud->state = IMAPCS_AUTHENTICATED; + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + return 1; + } + + /* check if new name is valid */ + if (!checkmailboxname(args[1])) { + fprintf(ci->tx, + "%s NO new mailbox name contains invalid characters\r\n", + tag); + return 1; + } + + oldnamelen = strlen(args[0]); + + /* check if new name would invade structure as in + * test (exists) + * rename test test/testing + * would create test/testing but delete test + */ + if (strncasecmp(args[0], args[1], oldnamelen) == 0 && + strlen(args[1]) > oldnamelen && args[1][oldnamelen] == '/') { + fprintf(ci->tx, + "%s NO new mailbox would invade mailbox structure\r\n", + tag); + return 1; + } + + + /* check if structure of new name is valid */ + /* i.e. only last part (after last '/' can be nonexistent) */ + for (i = strlen(args[1]) - 1; i >= 0 && args[1][i] != '/'; i--); + if (i >= 0) { + args[1][i] = '\0'; /* note: original char was '/' */ + + if (db_findmailbox(args[1], ud->userid, &parentmboxid) == + -1) { + /* dbase failure */ + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + if (parentmboxid == 0) { + /* parent mailbox does not exist */ + fprintf(ci->tx, + "%s NO new mailbox would invade mailbox structure\r\n", + tag); + return 1; + } + + /* ok, reset arg */ + args[1][i] = '/'; + } + + /* check if it is INBOX to be renamed */ + if (strcasecmp(args[0], "inbox") == 0) { + /* ok, renaming inbox */ + /* this means creating a new mailbox and moving all the INBOX msgs to the new mailbox */ + /* inferior names of INBOX are left unchanged */ + result = db_createmailbox(args[1], ud->userid, &newmboxid); + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + + result = db_movemsg(newmboxid, mboxid); + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + + /* ok done */ + fprintf(ci->tx, "%s OK RENAME completed\r\n", tag); + return 0; + } + + /* check for inferior names */ + result = + db_listmailboxchildren(mboxid, ud->userid, &children, + &nchildren, "%"); + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + + /* replace name for each child */ + for (i = 0; i < nchildren; i++) { + result = db_getmailboxname(children[i], ud->userid, name); + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + my_free(children); + return -1; + } + + if (oldnamelen >= strlen(name)) { + /* strange error, let's say its fatal */ + trace(TRACE_ERROR, + "IMAPD: rename(): mailbox names are fucked up"); + fprintf(ci->tx, + "* BYE internal error regarding mailbox names\r\n"); + my_free(children); + return -1; + } + + snprintf(newname, IMAP_MAX_MAILBOX_NAMELEN, "%s%s", + args[1], &name[oldnamelen]); + + result = db_setmailboxname(children[i], newname); + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + my_free(children); + return -1; + } } - } - if (children) - my_free(children); + if (children) + my_free(children); - /* now replace name */ - result = db_setmailboxname(mboxid, args[1]); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } + /* now replace name */ + result = db_setmailboxname(mboxid, args[1]); + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } - fprintf(ci->tx,"%s OK RENAME completed\r\n",tag); - return 0; + fprintf(ci->tx, "%s OK RENAME completed\r\n", tag); + return 0; } @@ -1093,51 +1148,51 @@ int _ic_rename(char *tag, char **args, ClientInfo *ci) * * subscribe to a specified mailbox */ -int _ic_subscribe(char *tag, char **args, ClientInfo *ci) +int _ic_subscribe(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t mboxid; - int result; - - - if (!check_state_and_args("SUBSCRIBE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } - if (mboxid == 0) - { - /* mailbox does not exist */ - fprintf(ci->tx,"%s NO mailbox does not exist\r\n", tag); - return 0; - } - - /* check for the lookup-right. RFC is unclear about which right to - use, so I guessed it should be lookup */ - result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_LOOKUP); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to subscribe to mailbox\r\n", - tag); - ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - return 1; - } - - if (db_subscribe(mboxid, ud->userid) == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } - - fprintf(ci->tx,"%s OK SUBSCRIBE completed\r\n",tag); - return 0; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t mboxid; + int result; + + + if (!check_state_and_args + ("SUBSCRIBE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + if (mboxid == 0) { + /* mailbox does not exist */ + fprintf(ci->tx, "%s NO mailbox does not exist\r\n", tag); + return 0; + } + + /* check for the lookup-right. RFC is unclear about which right to + use, so I guessed it should be lookup */ + result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_LOOKUP); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to subscribe to mailbox\r\n", + tag); + ud->state = IMAPCS_AUTHENTICATED; + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + return 1; + } + + if (db_subscribe(mboxid, ud->userid) == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + + fprintf(ci->tx, "%s OK SUBSCRIBE completed\r\n", tag); + return 0; } @@ -1146,51 +1201,51 @@ int _ic_subscribe(char *tag, char **args, ClientInfo *ci) * * removes a mailbox from the users' subscription list */ -int _ic_unsubscribe(char *tag, char **args, ClientInfo *ci) +int _ic_unsubscribe(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t mboxid; - int result; - - - if (!check_state_and_args("UNSUBSCRIBE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } - if (mboxid == 0) - { - /* mailbox does not exist */ - fprintf(ci->tx,"%s NO mailbox does not exist\r\n", tag); - return 0; - } - - /* check for the lookup-right. RFC is unclear about which right to - use, so I guessed it should be lookup */ - result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_LOOKUP); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to unsubscribe from mailbox\r\n", - tag); - ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - return 1; - } - - if (db_unsubscribe(mboxid, ud->userid) == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } - - fprintf(ci->tx,"%s OK UNSUBSCRIBE completed\r\n",tag); - return 0; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t mboxid; + int result; + + + if (!check_state_and_args + ("UNSUBSCRIBE", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + if (mboxid == 0) { + /* mailbox does not exist */ + fprintf(ci->tx, "%s NO mailbox does not exist\r\n", tag); + return 0; + } + + /* check for the lookup-right. RFC is unclear about which right to + use, so I guessed it should be lookup */ + result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_LOOKUP); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to unsubscribe from mailbox\r\n", + tag); + ud->state = IMAPCS_AUTHENTICATED; + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + return 1; + } + + if (db_unsubscribe(mboxid, ud->userid) == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + + fprintf(ci->tx, "%s OK UNSUBSCRIBE completed\r\n", tag); + return 0; } @@ -1199,146 +1254,143 @@ int _ic_unsubscribe(char *tag, char **args, ClientInfo *ci) * * executes a list command */ -int _ic_list(char *tag, char **args, ClientInfo *ci) +int _ic_list(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t *children=NULL; - int result; - unsigned slen,plen; - unsigned i,j; - unsigned nchildren; - char name[IMAP_MAX_MAILBOX_NAMELEN]; - char *pattern; - char *thisname = list_is_lsub ? "LSUB" : "LIST"; - - if (!check_state_and_args(thisname, tag, args, 2, IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - - /* check if args are both empty strings */ - if (strlen(args[0]) == 0 && strlen(args[1]) == 0) - { - /* this has special meaning; show root & delimiter */ - trace(TRACE_ERROR, "_ic_list(): showing delimiter [(\\NoSelect) \"/\" \"\"]"); - fprintf(ci->tx,"* %s (\\NoSelect) \"/\" \"\"\r\n",thisname); - fprintf(ci->tx,"%s OK %s completed\r\n",tag,thisname); - return 0; - } - - /* check the reference name, should contain only accepted mailboxname chars */ - for (i=0,slen=strlen(args[0]); args[0][i]; i++) - { - if (stridx(AcceptedMailboxnameChars, args[0][i]) == slen) - { - /* wrong char found */ - fprintf(ci->tx,"%s BAD reference name contains invalid characters\r\n",tag); - return 1; - } - } - - plen = strlen(args[1]) * 6; - pattern = (char*)my_malloc(sizeof(char) * (plen + slen + 10)); /* +10 for some xtra space */ - if (!pattern) - { - fprintf(ci->tx,"* BYE out of memory\r\n"); - return -1; - } - - memset(pattern, '\0', plen + slen + 10); - pattern[0] = '^'; - strcpy(&pattern[1], args[0]); - - i = slen+1; - for (j=0; args[1][j] && i < (plen + slen + 1); j++) - { - if (args[1][j] == '*') - { - pattern[i++] = '.'; - pattern[i++] = '*'; - } - else if (args[1][j] == '%') - { - pattern[i++] = '['; - pattern[i++] = '^'; - pattern[i++] = '\\'; - pattern[i++] = '/'; - pattern[i++] = ']'; - pattern[i++] = '*'; - } - else - pattern[i++] = args[1][j]; - } - - pattern[i] = '$'; - - trace(TRACE_INFO,"ic_list(): build the pattern: [%s]\n",pattern); - - result = db_findmailbox_by_regex(ud->userid, pattern, &children, &nchildren, list_is_lsub); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - my_free(children); - my_free(pattern); - return -1; - } - - if (result == 1) - { - fprintf(ci->tx,"%s BAD invalid pattern specified\r\n",tag); - my_free(children); - my_free(pattern); - return 1; - } - - - for (i=0; i<nchildren; i++) - { - /* get name */ - result = db_getmailboxname(children[i], ud->userid, name); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - my_free(children); - my_free(pattern); - return -1; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t *children = NULL; + int result; + unsigned slen, plen; + unsigned i, j; + unsigned nchildren; + char name[IMAP_MAX_MAILBOX_NAMELEN]; + char *pattern; + char *thisname = list_is_lsub ? "LSUB" : "LIST"; + + if (!check_state_and_args + (thisname, tag, args, 2, IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + + /* check if args are both empty strings */ + if (strlen(args[0]) == 0 && strlen(args[1]) == 0) { + /* this has special meaning; show root & delimiter */ + trace(TRACE_ERROR, + "_ic_list(): showing delimiter [(\\NoSelect) \"/\" \"\"]"); + fprintf(ci->tx, "* %s (\\NoSelect) \"/\" \"\"\r\n", + thisname); + fprintf(ci->tx, "%s OK %s completed\r\n", tag, thisname); + return 0; + } + + /* check the reference name, should contain only accepted mailboxname chars */ + for (i = 0, slen = strlen(args[0]); args[0][i]; i++) { + if (stridx(AcceptedMailboxnameChars, args[0][i]) == slen) { + /* wrong char found */ + fprintf(ci->tx, + "%s BAD reference name contains invalid characters\r\n", + tag); + return 1; + } } - fprintf(ci->tx,"* %s (",thisname); + plen = strlen(args[1]) * 6; + pattern = (char *) my_malloc(sizeof(char) * (plen + slen + 10)); /* +10 for some xtra space */ + if (!pattern) { + fprintf(ci->tx, "* BYE out of memory\r\n"); + return -1; + } - /* show flags */ - result = db_isselectable(children[i]); - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - my_free(children); - my_free(pattern); - return -1; + memset(pattern, '\0', plen + slen + 10); + pattern[0] = '^'; + strcpy(&pattern[1], args[0]); + + i = slen + 1; + for (j = 0; args[1][j] && i < (plen + slen + 1); j++) { + if (args[1][j] == '*') { + pattern[i++] = '.'; + pattern[i++] = '*'; + } else if (args[1][j] == '%') { + pattern[i++] = '['; + pattern[i++] = '^'; + pattern[i++] = '\\'; + pattern[i++] = '/'; + pattern[i++] = ']'; + pattern[i++] = '*'; + } else + pattern[i++] = args[1][j]; } - if (!result) fprintf(ci->tx,"\\noselect "); + pattern[i] = '$'; - result = db_noinferiors(children[i]); - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - my_free(children); - my_free(pattern); - return -1; + trace(TRACE_INFO, "ic_list(): build the pattern: [%s]\n", pattern); + + result = + db_findmailbox_by_regex(ud->userid, pattern, &children, + &nchildren, list_is_lsub); + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + my_free(children); + my_free(pattern); + return -1; + } + + if (result == 1) { + fprintf(ci->tx, "%s BAD invalid pattern specified\r\n", + tag); + my_free(children); + my_free(pattern); + return 1; } - if (result) fprintf(ci->tx,"\\noinferiors "); - /* show delimiter & name */ - fprintf(ci->tx,") \"/\" \"%s\"\r\n",name); - } + for (i = 0; i < nchildren; i++) { + /* get name */ + result = db_getmailboxname(children[i], ud->userid, name); + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + my_free(children); + my_free(pattern); + return -1; + } - if (children) - my_free(children); - - my_free(pattern); + fprintf(ci->tx, "* %s (", thisname); - fprintf(ci->tx,"%s OK %s completed\r\n",tag,thisname); - return 0; + /* show flags */ + result = db_isselectable(children[i]); + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + my_free(children); + my_free(pattern); + return -1; + } + + if (!result) + fprintf(ci->tx, "\\noselect "); + + result = db_noinferiors(children[i]); + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + my_free(children); + my_free(pattern); + return -1; + } + + if (result) + fprintf(ci->tx, "\\noinferiors "); + + /* show delimiter & name */ + fprintf(ci->tx, ") \"/\" \"%s\"\r\n", name); + } + + if (children) + my_free(children); + + my_free(pattern); + + fprintf(ci->tx, "%s OK %s completed\r\n", tag, thisname); + return 0; } @@ -1347,14 +1399,14 @@ int _ic_list(char *tag, char **args, ClientInfo *ci) * * list subscribed mailboxes */ -int _ic_lsub(char *tag, char **args, ClientInfo *ci) +int _ic_lsub(char *tag, char **args, ClientInfo * ci) { - int result; + int result; - list_is_lsub = 1; - result = _ic_list(tag,args,ci); - list_is_lsub = 0; - return result; + list_is_lsub = 1; + result = _ic_list(tag, args, ci); + list_is_lsub = 0; + return result; } @@ -1363,125 +1415,125 @@ int _ic_lsub(char *tag, char **args, ClientInfo *ci) * * inquire the status of a mailbox */ -int _ic_status(char *tag, char **args, ClientInfo *ci) +int _ic_status(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - mailbox_t mb; - int i,endfound,result; - - if (ud->state != IMAPCS_AUTHENTICATED && ud->state != IMAPCS_SELECTED) - { - fprintf(ci->tx,"%s BAD STATUS command received in invalid state\r\n", tag); - return 1; - } - - if (!args[0] || !args[1] || !args[2]) - { - fprintf(ci->tx,"%s BAD missing argument(s) to STATUS\r\n", tag); - return 1; - } - - if (strcmp(args[1],"(") != 0) - { - fprintf(ci->tx,"%s BAD argument list should be parenthesed\r\n", tag); - return 1; - } - - /* check final arg: should be ')' and no new '(' in between */ - for (i=2,endfound=0; args[i]; i++) - { - if (strcmp(args[i], ")") == 0) - { - endfound = i; - break; - } - - if (strcmp(args[i], "(") == 0) - { - fprintf(ci->tx,"%s BAD too many parentheses specified\r\n", tag); - return 1; - } - } - - if (endfound == 2) - { - fprintf(ci->tx,"%s BAD argument list empty\r\n", tag); - return 1; - } - - if (args[endfound+1]) - { - fprintf(ci->tx,"%s BAD argument list too long\r\n", tag); - return 1; - } - - - /* zero init */ - memset(&mb, 0, sizeof(mb)); - - /* check if mailbox exists */ - if (db_findmailbox(args[0], ud->userid, &(mb.uid)) == -1) { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } - - if (mb.uid == 0) - { - /* mailbox does not exist */ - fprintf(ci->tx,"%s NO specified mailbox does not exist\r\n",tag); - return 1; - } - - result = acl_has_right(ud->userid, mb.uid, ACL_RIGHT_READ); - if (result == -1) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no rights to get status for mailbox\r\n", - tag); - return 1; - } - - /* retrieve mailbox data */ - result = db_getmailbox(&mb); - - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - - fprintf(ci->tx, "* STATUS \"%s\" (", args[0]); - - for (i=2; args[i]; i++) - { - if (strcasecmp(args[i], "messages") == 0) - fprintf(ci->tx, "MESSAGES %u ",mb.exists); - else if (strcasecmp(args[i], "recent") == 0) - fprintf(ci->tx, "RECENT %u ",mb.recent); - else if (strcasecmp(args[i], "unseen") == 0) - fprintf(ci->tx, "UNSEEN %u ",mb.unseen); - else if (strcasecmp(args[i], "uidnext") == 0) - fprintf(ci->tx, "UIDNEXT %llu ",mb.msguidnext); - else if (strcasecmp(args[i], "uidvalidity") == 0) - fprintf(ci->tx, "UIDVALIDITY %llu ",mb.uid); - else if (strcasecmp(args[i], ")") == 0) - break; /* done */ - else - { - fprintf(ci->tx,"\r\n%s BAD unrecognized option '%s' specified\r\n",tag,args[i]); - my_free(mb.seq_list); - return 1; - } - } - - fprintf(ci->tx,")\r\n"); - - fprintf(ci->tx,"%s OK STATUS completed\r\n",tag); - - my_free(mb.seq_list); - return 0; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + mailbox_t mb; + int i, endfound, result; + + if (ud->state != IMAPCS_AUTHENTICATED + && ud->state != IMAPCS_SELECTED) { + fprintf(ci->tx, + "%s BAD STATUS command received in invalid state\r\n", + tag); + return 1; + } + + if (!args[0] || !args[1] || !args[2]) { + fprintf(ci->tx, "%s BAD missing argument(s) to STATUS\r\n", + tag); + return 1; + } + + if (strcmp(args[1], "(") != 0) { + fprintf(ci->tx, + "%s BAD argument list should be parenthesed\r\n", + tag); + return 1; + } + + /* check final arg: should be ')' and no new '(' in between */ + for (i = 2, endfound = 0; args[i]; i++) { + if (strcmp(args[i], ")") == 0) { + endfound = i; + break; + } + + if (strcmp(args[i], "(") == 0) { + fprintf(ci->tx, + "%s BAD too many parentheses specified\r\n", + tag); + return 1; + } + } + + if (endfound == 2) { + fprintf(ci->tx, "%s BAD argument list empty\r\n", tag); + return 1; + } + + if (args[endfound + 1]) { + fprintf(ci->tx, "%s BAD argument list too long\r\n", tag); + return 1; + } + + + /* zero init */ + memset(&mb, 0, sizeof(mb)); + + /* check if mailbox exists */ + if (db_findmailbox(args[0], ud->userid, &(mb.uid)) == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; + } + + if (mb.uid == 0) { + /* mailbox does not exist */ + fprintf(ci->tx, + "%s NO specified mailbox does not exist\r\n", tag); + return 1; + } + + result = acl_has_right(ud->userid, mb.uid, ACL_RIGHT_READ); + if (result == -1) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no rights to get status for mailbox\r\n", + tag); + return 1; + } + + /* retrieve mailbox data */ + result = db_getmailbox(&mb); + + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + + fprintf(ci->tx, "* STATUS \"%s\" (", args[0]); + + for (i = 2; args[i]; i++) { + if (strcasecmp(args[i], "messages") == 0) + fprintf(ci->tx, "MESSAGES %u ", mb.exists); + else if (strcasecmp(args[i], "recent") == 0) + fprintf(ci->tx, "RECENT %u ", mb.recent); + else if (strcasecmp(args[i], "unseen") == 0) + fprintf(ci->tx, "UNSEEN %u ", mb.unseen); + else if (strcasecmp(args[i], "uidnext") == 0) + fprintf(ci->tx, "UIDNEXT %llu ", mb.msguidnext); + else if (strcasecmp(args[i], "uidvalidity") == 0) + fprintf(ci->tx, "UIDVALIDITY %llu ", mb.uid); + else if (strcasecmp(args[i], ")") == 0) + break; /* done */ + else { + fprintf(ci->tx, + "\r\n%s BAD unrecognized option '%s' specified\r\n", + tag, args[i]); + my_free(mb.seq_list); + return 1; + } + } + + fprintf(ci->tx, ")\r\n"); + + fprintf(ci->tx, "%s OK STATUS completed\r\n", tag); + + my_free(mb.seq_list); + return 0; } @@ -1490,196 +1542,215 @@ int _ic_status(char *tag, char **args, ClientInfo *ci) * * append a message to a mailbox */ -int _ic_append(char *tag, char **args, ClientInfo *ci) +int _ic_append(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t mboxid; - u64_t msg_idnr; - int i, j, result; - timestring_t sqldate; - int flaglist[IMAP_NFLAGS]; - int flagcount = 0; - - for (i = 0; i < IMAP_NFLAGS; i++) - flaglist[i] = 0; - - if (!args[0] || !args[1]) - { - fprintf(ci->tx,"%s BAD invalid arguments specified to APPEND\r\n", tag); - return 1; - } - - /* find the mailbox to place the message */ - if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { - fprintf(ci->tx,"* BYE internal dbase error"); - return -1; - } - - if (mboxid == 0) - { - fprintf(ci->tx,"%s NO [TRYCREATE] could not find specified mailbox\r\n", tag); - return 1; - } - - trace(TRACE_DEBUG, "ic_append(): mailbox [%s] found, id: %llu\n",args[0],mboxid); - /* check if user has right to append to mailbox */ - result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_INSERT); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to append to mailbox\r\n", tag); - ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - return 1; - } - - - i=1; - - /* check if a flag list has been specified */ - /* FIXME: We need to take of care of the Flags that are set here. They - should be set to the new message! - */ - if (args[i][0] == '(') - { - /* ok fetch the flags specified */ - trace(TRACE_DEBUG, "ic_append(): flag list found:\n"); - - while (args[i] && args[i][0] != ')') - { - trace(TRACE_DEBUG, "%s ",args[i]); - for (j = 0; j < IMAP_NFLAGS; j++) { - if (strcasecmp(args[i], imap_flag_desc_escaped[j]) == 0) { - flaglist[j] = 1; - flagcount++; - break; - } - } - i++; - } - - i++; - trace(TRACE_DEBUG, ")\n"); - } - - if (!args[i]) - { - trace(TRACE_INFO,"ic_append(): unexpected end of arguments\n"); - fprintf(ci->tx,"%s BAD invalid arguments specified to APPEND\r\n", tag); - return 1; - } - - - for (j = 0; j < IMAP_NFLAGS; j++) - if (flaglist[j] == 1) - trace(TRACE_DEBUG, "%s,%s: %s set", - __FILE__, __FUNCTION__, imap_flag_desc[j]); - + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t mboxid; + u64_t msg_idnr; + int i, j, result; + timestring_t sqldate; + int flaglist[IMAP_NFLAGS]; + int flagcount = 0; + + for (i = 0; i < IMAP_NFLAGS; i++) + flaglist[i] = 0; + + if (!args[0] || !args[1]) { + fprintf(ci->tx, + "%s BAD invalid arguments specified to APPEND\r\n", + tag); + return 1; + } + + /* find the mailbox to place the message */ + if (db_findmailbox(args[0], ud->userid, &mboxid) == -1) { + fprintf(ci->tx, "* BYE internal dbase error"); + return -1; + } + + if (mboxid == 0) { + fprintf(ci->tx, + "%s NO [TRYCREATE] could not find specified mailbox\r\n", + tag); + return 1; + } + + trace(TRACE_DEBUG, "ic_append(): mailbox [%s] found, id: %llu\n", + args[0], mboxid); + /* check if user has right to append to mailbox */ + result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_INSERT); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to append to mailbox\r\n", + tag); + ud->state = IMAPCS_AUTHENTICATED; + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + return 1; + } + + + i = 1; + + /* check if a flag list has been specified */ + /* FIXME: We need to take of care of the Flags that are set here. They + should be set to the new message! + */ + if (args[i][0] == '(') { + /* ok fetch the flags specified */ + trace(TRACE_DEBUG, "ic_append(): flag list found:\n"); + + while (args[i] && args[i][0] != ')') { + trace(TRACE_DEBUG, "%s ", args[i]); + for (j = 0; j < IMAP_NFLAGS; j++) { + if (strcasecmp + (args[i], + imap_flag_desc_escaped[j]) == 0) { + flaglist[j] = 1; + flagcount++; + break; + } + } + i++; + } + + i++; + trace(TRACE_DEBUG, ")\n"); + } + + if (!args[i]) { + trace(TRACE_INFO, + "ic_append(): unexpected end of arguments\n"); + fprintf(ci->tx, + "%s BAD invalid arguments specified to APPEND\r\n", + tag); + return 1; + } + + + for (j = 0; j < IMAP_NFLAGS; j++) + if (flaglist[j] == 1) + trace(TRACE_DEBUG, "%s,%s: %s set", + __FILE__, __FUNCTION__, imap_flag_desc[j]); + /** check ACL's for STORE */ - if (flaglist[IMAP_STORE_FLAG_SEEN] == 1) { - result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_SEEN); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; /* fatal */ - } - if (result == 0) { - fprintf(ci->tx, "%s NO no right to store \\SEEN flag\r\n", - tag); - return 1; - } - } - if (flaglist[IMAP_STORE_FLAG_DELETED] == 1) { - result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_DELETE); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; /* fatal */ - } - if (result == 0) { - fprintf(ci->tx, "%s NO no right to store \\DELETED flag\r\n", - tag); - return 1; - } - } - if (flaglist[IMAP_STORE_FLAG_ANSWERED] == 1 || - flaglist[IMAP_STORE_FLAG_FLAGGED] == 1 || - flaglist[IMAP_STORE_FLAG_DRAFT] == 1 || - flaglist[IMAP_STORE_FLAG_RECENT] == 1) { - result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_WRITE); - if (result < 0) { - fprintf(ci->tx, "*BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no right to store flags\r\n", tag); - return 1; - } - } - - - /* there could be a literal date here, check if the next argument exists - * if so, assume this is the literal date. - * FIXME: this internal date has to be used in the append command to set - * the internal date of the message (if it should be something else than - * CURRENT_TIMESTAMP. - */ - if (args[i+1]) - { - struct tm tm; - - if (strptime(args[i], "%d-%b-%Y %T", &tm) != NULL) - strftime(sqldate, - sizeof(sqldate), "%Y-%m-%d %H:%M:%S", &tm); - else - sqldate[0] = '\0'; - /* internal date specified */ - - i++; - trace(TRACE_DEBUG, "ic_append(): internal date [%s] found, next arg [%s]\n", - sqldate, args[i]); - } - else { - sqldate[0] = '\0'; - } - - /* ok literal msg should be in args[i] */ - /* insert this msg */ - - result = db_imap_append_msg(args[i], strlen(args[i]), mboxid, ud->userid, - sqldate, &msg_idnr); - switch (result) - { - case -1: - trace(TRACE_ERROR,"ic_append(): error appending msg\n"); - fprintf(ci->tx,"* BYE internal dbase error storing message\r\n"); - break; - - case 1: - trace(TRACE_ERROR,"ic_append(): faulty msg\n"); - fprintf(ci->tx,"%s NO invalid message specified\r\n", tag); - break; - - case 2: - trace(TRACE_INFO,"ic_append(): quotum would exceed\n"); - fprintf(ci->tx,"%s NO not enough quotum left\r\n", tag); - break; - - case 0: - fprintf(ci->tx,"%s OK APPEND completed\r\n",tag); - break; - } - - if (result == 0 && flagcount > 0) { - if(db_set_msgflag(msg_idnr, mboxid, flaglist, IMAPFA_ADD) < 0) { - trace(TRACE_ERROR, "%s,%s: error setting flags for message " - "[%llu]", __FILE__, __FUNCTION__, msg_idnr); - return -1; - } - } - - return result; + if (flaglist[IMAP_STORE_FLAG_SEEN] == 1) { + result = acl_has_right(ud->userid, mboxid, ACL_RIGHT_SEEN); + if (result < 0) { + fprintf(ci->tx, + "* BYE internal database error\r\n"); + return -1; /* fatal */ + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no right to store \\SEEN flag\r\n", + tag); + return 1; + } + } + if (flaglist[IMAP_STORE_FLAG_DELETED] == 1) { + result = + acl_has_right(ud->userid, mboxid, ACL_RIGHT_DELETE); + if (result < 0) { + fprintf(ci->tx, + "* BYE internal database error\r\n"); + return -1; /* fatal */ + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no right to store \\DELETED flag\r\n", + tag); + return 1; + } + } + if (flaglist[IMAP_STORE_FLAG_ANSWERED] == 1 || + flaglist[IMAP_STORE_FLAG_FLAGGED] == 1 || + flaglist[IMAP_STORE_FLAG_DRAFT] == 1 || + flaglist[IMAP_STORE_FLAG_RECENT] == 1) { + result = + acl_has_right(ud->userid, mboxid, ACL_RIGHT_WRITE); + if (result < 0) { + fprintf(ci->tx, + "*BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no right to store flags\r\n", tag); + return 1; + } + } + + + /* there could be a literal date here, check if the next argument exists + * if so, assume this is the literal date. + * FIXME: this internal date has to be used in the append command to set + * the internal date of the message (if it should be something else than + * CURRENT_TIMESTAMP. + */ + if (args[i + 1]) { + struct tm tm; + + if (strptime(args[i], "%d-%b-%Y %T", &tm) != NULL) + strftime(sqldate, + sizeof(sqldate), "%Y-%m-%d %H:%M:%S", + &tm); + else + sqldate[0] = '\0'; + /* internal date specified */ + + i++; + trace(TRACE_DEBUG, + "ic_append(): internal date [%s] found, next arg [%s]\n", + sqldate, args[i]); + } else { + sqldate[0] = '\0'; + } + + /* ok literal msg should be in args[i] */ + /* insert this msg */ + + result = + db_imap_append_msg(args[i], strlen(args[i]), mboxid, + ud->userid, sqldate, &msg_idnr); + switch (result) { + case -1: + trace(TRACE_ERROR, "ic_append(): error appending msg\n"); + fprintf(ci->tx, + "* BYE internal dbase error storing message\r\n"); + break; + + case 1: + trace(TRACE_ERROR, "ic_append(): faulty msg\n"); + fprintf(ci->tx, "%s NO invalid message specified\r\n", + tag); + break; + + case 2: + trace(TRACE_INFO, "ic_append(): quotum would exceed\n"); + fprintf(ci->tx, "%s NO not enough quotum left\r\n", tag); + break; + + case 0: + fprintf(ci->tx, "%s OK APPEND completed\r\n", tag); + break; + } + + if (result == 0 && flagcount > 0) { + if (db_set_msgflag(msg_idnr, mboxid, flaglist, IMAPFA_ADD) + < 0) { + trace(TRACE_ERROR, + "%s,%s: error setting flags for message " + "[%llu]", __FILE__, __FUNCTION__, msg_idnr); + return -1; + } + } + + return result; } @@ -1695,27 +1766,29 @@ int _ic_append(char *tag, char **args, ClientInfo *ci) * request a checkpoint for the selected mailbox * (equivalent to NOOP) */ -int _ic_check(char *tag, char **args, ClientInfo *ci) +int _ic_check(char *tag, char **args, ClientInfo * ci) { int result; - imap_userdata_t *ud = (imap_userdata_t*) ci->userData; - - if (!check_state_and_args("CHECK", tag, args, 0, IMAPCS_SELECTED, ci)) - - return 1; /* error, return */ - - result = acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_READ); + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + + if (!check_state_and_args + ("CHECK", tag, args, 0, IMAPCS_SELECTED, ci)) + + return 1; /* error, return */ + + result = + acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_READ); if (result < 0) { fprintf(ci->tx, "* BYE Internal database error\r\n"); return -1; } if (result == 0) { - fprintf(ci->tx,"%s NO no permission to do check on " + fprintf(ci->tx, "%s NO no permission to do check on " "mailbox\r\n", tag); return 1; } - - fprintf(ci->tx,"%s OK CHECK completed\r\n",tag); + + fprintf(ci->tx, "%s OK CHECK completed\r\n", tag); return 0; } @@ -1725,36 +1798,39 @@ int _ic_check(char *tag, char **args, ClientInfo *ci) * * expunge deleted messages from selected mailbox & return to AUTH state * do not show expunge-output - */ -int _ic_close(char *tag, char **args, ClientInfo *ci) + */ +int _ic_close(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - int result; - - if (!check_state_and_args("CLOSE", tag, args, 0, IMAPCS_SELECTED, ci)) - return 1; /* error, return */ - - /* check if the user has to right to expunge all messages from the - mailbox. */ - result = acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_DELETE); - if (result < 0) { - fprintf(ci->tx, "* BYE Internal database error\r\n"); - return -1; - } - /* only perform the expunge if the user has the right to do it */ - if (result == 1) - if (ud->mailbox.permission == IMAPPERM_READWRITE) - db_expunge(ud->mailbox.uid, ud->userid, NULL, NULL); + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + int result; + + if (!check_state_and_args + ("CLOSE", tag, args, 0, IMAPCS_SELECTED, ci)) + return 1; /* error, return */ + + /* check if the user has to right to expunge all messages from the + mailbox. */ + result = + acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_DELETE); + if (result < 0) { + fprintf(ci->tx, "* BYE Internal database error\r\n"); + return -1; + } + /* only perform the expunge if the user has the right to do it */ + if (result == 1) + if (ud->mailbox.permission == IMAPPERM_READWRITE) + db_expunge(ud->mailbox.uid, ud->userid, NULL, + NULL); + - - /* ok, update state (always go to IMAPCS_AUTHENTICATED)*/ - ud->state = IMAPCS_AUTHENTICATED; + /* ok, update state (always go to IMAPCS_AUTHENTICATED) */ + ud->state = IMAPCS_AUTHENTICATED; - my_free(ud->mailbox.seq_list); - memset(&ud->mailbox, 0, sizeof(ud->mailbox)); + my_free(ud->mailbox.seq_list); + memset(&ud->mailbox, 0, sizeof(ud->mailbox)); - fprintf(ci->tx,"%s OK CLOSE completed\r\n",tag); - return 0; + fprintf(ci->tx, "%s OK CLOSE completed\r\n", tag); + return 0; } @@ -1764,80 +1840,81 @@ int _ic_close(char *tag, char **args, ClientInfo *ci) * expunge deleted messages from selected mailbox * show expunge output per message */ -int _ic_expunge(char *tag, char **args, ClientInfo *ci) +int _ic_expunge(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - mailbox_t newmailbox; - u64_t *msgids; - u64_t nmsgs, i; - unsigned idx; - int result; - - if (!check_state_and_args("EXPUNGE", tag, args, 0, IMAPCS_SELECTED, ci)) - return 1; /* error, return */ - - if (ud->mailbox.permission != IMAPPERM_READWRITE) - { - fprintf(ci->tx,"%s NO you do not have write permission on this folder\r\n",tag); - return 1; - } - - result = acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_DELETE); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO you do not have delete rights on this " - "mailbox\r\n", tag); - return -1; - } - - /* delete messages */ - result = db_expunge(ud->mailbox.uid, ud->userid, &msgids,&nmsgs); - if (result == -1) - { - fprintf(ci->tx,"* BYE dbase/memory error\r\n"); - return -1; - } - - /* show expunge info */ - for (i=0; i<nmsgs; i++) - { - /* find the message sequence number */ - binary_search(ud->mailbox.seq_list, ud->mailbox.exists, - msgids[i], &idx); - - fprintf(ci->tx,"* %u EXPUNGE\r\n",idx+1); /* add one: IMAP MSN starts at 1 not zero */ - } - my_free(msgids); - msgids = NULL; - - /* update mailbox info */ - - memset(&newmailbox, 0, sizeof(newmailbox)); - newmailbox.uid = ud->mailbox.uid; - - result = db_getmailbox(&newmailbox); - - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - my_free(newmailbox.seq_list); - return -1; /* fatal */ - } - - if (newmailbox.exists != ud->mailbox.exists) - fprintf(ci->tx,"* %u EXISTS\r\n", newmailbox.exists); - - if (newmailbox.recent != ud->mailbox.recent) - fprintf(ci->tx, "* %u RECENT\r\n", newmailbox.recent); - - my_free(ud->mailbox.seq_list); - memcpy(&ud->mailbox, &newmailbox, sizeof(newmailbox)); - - fprintf(ci->tx,"%s OK EXPUNGE completed\r\n",tag); - return 0; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + mailbox_t newmailbox; + u64_t *msgids; + u64_t nmsgs, i; + unsigned idx; + int result; + + if (!check_state_and_args + ("EXPUNGE", tag, args, 0, IMAPCS_SELECTED, ci)) + return 1; /* error, return */ + + if (ud->mailbox.permission != IMAPPERM_READWRITE) { + fprintf(ci->tx, + "%s NO you do not have write permission on this folder\r\n", + tag); + return 1; + } + + result = + acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_DELETE); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO you do not have delete rights on this " + "mailbox\r\n", tag); + return -1; + } + + /* delete messages */ + result = db_expunge(ud->mailbox.uid, ud->userid, &msgids, &nmsgs); + if (result == -1) { + fprintf(ci->tx, "* BYE dbase/memory error\r\n"); + return -1; + } + + /* show expunge info */ + for (i = 0; i < nmsgs; i++) { + /* find the message sequence number */ + binary_search(ud->mailbox.seq_list, ud->mailbox.exists, + msgids[i], &idx); + + fprintf(ci->tx, "* %u EXPUNGE\r\n", idx + 1); /* add one: IMAP MSN starts at 1 not zero */ + } + my_free(msgids); + msgids = NULL; + + /* update mailbox info */ + + memset(&newmailbox, 0, sizeof(newmailbox)); + newmailbox.uid = ud->mailbox.uid; + + result = db_getmailbox(&newmailbox); + + if (result == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + my_free(newmailbox.seq_list); + return -1; /* fatal */ + } + + if (newmailbox.exists != ud->mailbox.exists) + fprintf(ci->tx, "* %u EXISTS\r\n", newmailbox.exists); + + if (newmailbox.recent != ud->mailbox.recent) + fprintf(ci->tx, "* %u RECENT\r\n", newmailbox.recent); + + my_free(ud->mailbox.seq_list); + memcpy(&ud->mailbox, &newmailbox, sizeof(newmailbox)); + + fprintf(ci->tx, "%s OK EXPUNGE completed\r\n", tag); + return 0; } @@ -1847,87 +1924,90 @@ int _ic_expunge(char *tag, char **args, ClientInfo *ci) * search the selected mailbox for messages * */ -int _ic_search(char *tag, char **args, ClientInfo *ci) +int _ic_search(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - unsigned *result_set; - unsigned i; - int result=0,only_ascii=0,idx=0; - search_key_t sk; - - if (ud->state != IMAPCS_SELECTED) - { - fprintf(ci->tx,"%s BAD SEARCH command received in invalid state\r\n", tag); - return 1; - } - - memset(&sk, 0, sizeof(sk)); - list_init(&sk.sub_search); - - if (!args[0]) - { - fprintf(ci->tx,"%s BAD invalid arguments to SEARCH\r\n",tag); - return 1; - } - - if (strcasecmp(args[0], "charset") == 0) - { - /* charset specified */ - if (!args[1]) - { - fprintf(ci->tx,"%s BAD invalid argument list\r\n",tag); - return 1; - } - - if (strcasecmp(args[1], "us-ascii") != 0) - { - fprintf(ci->tx,"%s NO specified charset is not supported\r\n",tag); - return 0; - } - - only_ascii = 1; - idx = 2; - } - - /* parse the search keys */ - while ( args[idx] && (result = build_imap_search(args, &sk.sub_search, &idx)) >= 0); - - if (result == -2) - { - free_searchlist(&sk.sub_search); - fprintf(ci->tx, "* BYE server ran out of memory\r\n"); - return -1; - } - - if (result == -1) - { - free_searchlist(&sk.sub_search); - fprintf(ci->tx, "%s BAD syntax error in search keys\r\n",tag); - return 1; - } - - /* check if user has the right to search in this mailbox */ - result = acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_READ); - if (result < 0) { - fprintf(ci->tx,"* BYE internal database error\r\n"); - free_searchlist(&sk.sub_search); - return -1; - } - if (result == 0) { - fprintf(ci->tx,"%s NO no permission to search mailbox\r\n", tag); - free_searchlist(&sk.sub_search); - return 1; - } - - /* make it a top-level search key */ - sk.type = IST_SUBSEARCH_AND; - - i = 0; - do - { - /* update mailbox info */ - /* commented out: the search should be on the mailbox - as the client thinks it is (!) */ + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + unsigned *result_set; + unsigned i; + int result = 0, only_ascii = 0, idx = 0; + search_key_t sk; + + if (ud->state != IMAPCS_SELECTED) { + fprintf(ci->tx, + "%s BAD SEARCH command received in invalid state\r\n", + tag); + return 1; + } + + memset(&sk, 0, sizeof(sk)); + list_init(&sk.sub_search); + + if (!args[0]) { + fprintf(ci->tx, "%s BAD invalid arguments to SEARCH\r\n", + tag); + return 1; + } + + if (strcasecmp(args[0], "charset") == 0) { + /* charset specified */ + if (!args[1]) { + fprintf(ci->tx, "%s BAD invalid argument list\r\n", + tag); + return 1; + } + + if (strcasecmp(args[1], "us-ascii") != 0) { + fprintf(ci->tx, + "%s NO specified charset is not supported\r\n", + tag); + return 0; + } + + only_ascii = 1; + idx = 2; + } + + /* parse the search keys */ + while (args[idx] + && (result = + build_imap_search(args, &sk.sub_search, &idx)) >= 0); + + if (result == -2) { + free_searchlist(&sk.sub_search); + fprintf(ci->tx, "* BYE server ran out of memory\r\n"); + return -1; + } + + if (result == -1) { + free_searchlist(&sk.sub_search); + fprintf(ci->tx, "%s BAD syntax error in search keys\r\n", + tag); + return 1; + } + + /* check if user has the right to search in this mailbox */ + result = + acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_READ); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + free_searchlist(&sk.sub_search); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to search mailbox\r\n", tag); + free_searchlist(&sk.sub_search); + return 1; + } + + /* make it a top-level search key */ + sk.type = IST_SUBSEARCH_AND; + + i = 0; + do { + /* update mailbox info */ + /* commented out: the search should be on the mailbox + as the client thinks it is (!) */ /* result = db_getmailbox(&ud->mailbox); if (result == -1) @@ -1937,68 +2017,72 @@ fprintf(ci->tx,"* BYE internal dbase error\r\n"); return -1; } */ - - /* allocate memory for result set */ - result_set = (unsigned*)my_malloc(sizeof(unsigned) * ud->mailbox.exists); - if (!result_set) - { - free_searchlist(&sk.sub_search); - fprintf(ci->tx,"* BYE server ran out of memory\r\n"); - return -1; - } - - /* init set: select every message, this way the first search key - * will be copied entirely (it is ANDed with this initial set), as it should - */ - - for (i=0; i<ud->mailbox.exists; i++) - result_set[i] = 1; - - /* now perform the search operations */ - result = perform_imap_search(result_set, ud->mailbox.exists, &sk, &ud->mailbox); - - if (result < 0) - { - free_searchlist(&sk.sub_search); - my_free(result_set); - fprintf(ci->tx,"%s", (result == -1) ? - "* BYE internal dbase error\r\n" : - "* BYE server ran out of memory\r\n"); - - trace(TRACE_ERROR, "ic_search(): fatal error [%d] from perform_imap_search()\n",result); - return -1; - } - if (result == 1) - { - my_free(result_set); - result_set = NULL; - } + /* allocate memory for result set */ + result_set = + (unsigned *) my_malloc(sizeof(unsigned) * + ud->mailbox.exists); + if (!result_set) { + free_searchlist(&sk.sub_search); + fprintf(ci->tx, + "* BYE server ran out of memory\r\n"); + return -1; + } - } while (result == 1 && ++i < MAX_RETRIES) ; + /* init set: select every message, this way the first search key + * will be copied entirely (it is ANDed with this initial set), as it should + */ - free_searchlist(&sk.sub_search); + for (i = 0; i < ud->mailbox.exists; i++) + result_set[i] = 1; - if (result == 1) - { - fprintf(ci->tx,"* BYE error synchronizing dbase\r\n"); - return -1; - } - - /* ok, display results */ - fprintf(ci->tx, "* SEARCH"); + /* now perform the search operations */ + result = + perform_imap_search(result_set, ud->mailbox.exists, + &sk, &ud->mailbox); - for (i=0; i<ud->mailbox.exists; i++) - { - if (result_set[i]) - fprintf(ci->tx, " %llu", imapcommands_use_uid ? ud->mailbox.seq_list[i] : (u64_t)(i+1)); - } + if (result < 0) { + free_searchlist(&sk.sub_search); + my_free(result_set); + fprintf(ci->tx, "%s", (result == -1) ? + "* BYE internal dbase error\r\n" : + "* BYE server ran out of memory\r\n"); - fprintf(ci->tx,"\r\n"); - my_free(result_set); - - fprintf(ci->tx,"%s OK SEARCH completed\r\n",tag); - return 0; + trace(TRACE_ERROR, + "ic_search(): fatal error [%d] from perform_imap_search()\n", + result); + return -1; + } + + if (result == 1) { + my_free(result_set); + result_set = NULL; + } + + } while (result == 1 && ++i < MAX_RETRIES); + + free_searchlist(&sk.sub_search); + + if (result == 1) { + fprintf(ci->tx, "* BYE error synchronizing dbase\r\n"); + return -1; + } + + /* ok, display results */ + fprintf(ci->tx, "* SEARCH"); + + for (i = 0; i < ud->mailbox.exists; i++) { + if (result_set[i]) + fprintf(ci->tx, " %llu", + imapcommands_use_uid ? ud->mailbox. + seq_list[i] : (u64_t) (i + 1)); + } + + fprintf(ci->tx, "\r\n"); + my_free(result_set); + + fprintf(ci->tx, "%s OK SEARCH completed\r\n", tag); + return 0; } @@ -2007,1204 +2091,1705 @@ fprintf(ci->tx,"* BYE internal dbase error\r\n"); * * fetch message(s) from the selected mailbox */ -int _ic_fetch(char *tag, char **args, ClientInfo *ci) +int _ic_fetch(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t i,fetch_start,fetch_end; - unsigned fn; - int result,setseen,idx,j,k; - int only_main_header_parsing = 1, insert_rfcsize; - int isfirstout, isfirstfetchout, uid_will_be_fetched; - int partspeclen,only_text_from_msgpart = 0; - int bad_response_send = 0; - u64_t actual_cnt; - fetch_items_t *fi,fetchitem; - mime_message_t *msgpart; - char date[IMAP_INTERNALDATE_LEN],*endptr; - u64_t thisnum; - u64_t tmpdumpsize, rfcsize=0; - long long cnt; - int msgflags[IMAP_NFLAGS]; - struct list fetch_list; - mime_message_t headermsg; /* for main-header & rfcsize parsing */ - struct element *curr; - int setSeenSet[IMAP_NFLAGS] = { 1,0,0,0,0,0 }; - msginfo_t *msginfo; - u64_t lo,hi; - unsigned nmatching; - int no_parsing_at_all = 1, getrfcsize = 0, getinternaldate = 0, getflags = 0; - char *lastchar = NULL; - memset(&fetch_list, 0, sizeof(fetch_list)); - memset(&headermsg, 0, sizeof(headermsg)); - - if (ud->state != IMAPCS_SELECTED) - { - fprintf(ci->tx,"%s BAD FETCH command received in invalid state\r\n", tag); - return 1; - } - - if (!args[0] || !args[1]) - { - fprintf(ci->tx,"%s BAD missing argument(s) to FETCH\r\n", tag); - return 1; - } - - /* check if the user has the right to fetch messages in this mailbox */ - result = acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_READ); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to fetch from mailbox\r\n", tag); - return 1; - } - - /* fetch fetch items */ - list_init(&fetch_list); - idx = 1; - uid_will_be_fetched = 0; - do - { - idx = next_fetch_item(args, idx, &fetchitem); - if (idx == -2) - { - list_freelist(&fetch_list.start); - fprintf(ci->tx,"%s BAD invalid argument list to fetch\r\n", tag); - return 1; - } - - if (idx > 0 && !list_nodeadd(&fetch_list, &fetchitem, sizeof(fetchitem))) - { - list_freelist(&fetch_list.start); - fprintf(ci->tx,"* BYE out of memory\r\n"); - return 1; - } - - if (fetchitem.msgparse_needed) - { - no_parsing_at_all = 0; - } - else if (no_parsing_at_all) - { - if (fetchitem.getFlags) getflags = 1; - if (fetchitem.getSize) getrfcsize = 1; - if (fetchitem.getInternalDate) getinternaldate = 1; - /* the msgUID will be retrieved anyway so if it is requested, it will be fetched */ - } - - if (fetchitem.msgparse_needed && only_main_header_parsing) - { - /* check to see wether all the information can be retrieved from the - * main message header (not the entire message has to be parsed then) - * - * this is the case when: - * FETCH RFC822.HEADER - * BODY[HEADER] - * BODY[HEADER.FIELDS ] - * BODY[HEADER.FIELDS.NOT ] - * BODY.PEEK[HEADER] - * BODY.PEEK[HEADER.FIELDS ] - * BODY.PEEK[HEADER.FIELDS.NOT ] - * - */ - - if (! (fetchitem.getRFC822Header || - ((fetchitem.bodyfetch.itemtype == BFIT_HEADER || - fetchitem.bodyfetch.itemtype == BFIT_HEADER_FIELDS || - fetchitem.bodyfetch.itemtype == BFIT_HEADER_FIELDS_NOT) - && fetchitem.bodyfetch.partspec[0] == 0) - ) - ) - { - only_main_header_parsing = 0; - } - } - - if (fetchitem.getUID) - uid_will_be_fetched = 1; - - } while (idx > 0); - - if (!uid_will_be_fetched && imapcommands_use_uid) - { - /* make sure UID will be on the fetch-item list */ - memset(&fetchitem, 0, sizeof(fetchitem)); - fetchitem.getUID = 1; - fetchitem.bodyfetch.itemtype = -1; - - if (!list_nodeadd(&fetch_list, &fetchitem, sizeof(fetchitem))) - { - list_freelist(&fetch_list.start); - fprintf(ci->tx,"* BYE out of memory\r\n"); - return -1; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t i, fetch_start, fetch_end; + unsigned fn; + int result, setseen, idx, j, k; + int only_main_header_parsing = 1, insert_rfcsize; + int isfirstout, isfirstfetchout, uid_will_be_fetched; + int partspeclen, only_text_from_msgpart = 0; + int bad_response_send = 0; + u64_t actual_cnt; + fetch_items_t *fi, fetchitem; + mime_message_t *msgpart; + char date[IMAP_INTERNALDATE_LEN], *endptr; + u64_t thisnum; + u64_t tmpdumpsize, rfcsize = 0; + long long cnt; + int msgflags[IMAP_NFLAGS]; + struct list fetch_list; + mime_message_t headermsg; /* for main-header & rfcsize parsing */ + struct element *curr; + int setSeenSet[IMAP_NFLAGS] = { 1, 0, 0, 0, 0, 0 }; + msginfo_t *msginfo; + u64_t lo, hi; + unsigned nmatching; + int no_parsing_at_all = 1, getrfcsize = 0, getinternaldate = + 0, getflags = 0; + char *lastchar = NULL; + memset(&fetch_list, 0, sizeof(fetch_list)); + memset(&headermsg, 0, sizeof(headermsg)); + + if (ud->state != IMAPCS_SELECTED) { + fprintf(ci->tx, + "%s BAD FETCH command received in invalid state\r\n", + tag); + return 1; } - } - - fetch_list.start = dbmail_list_reverse(fetch_list.start); - - /* now fetch results for each msg */ - endptr = args[0]; - while (*endptr) - { - if (endptr != args[0]) - endptr++; /* skip delimiter */ - - fetch_start = strtoull(endptr, &endptr, 10); - - if (fetch_start == 0 || fetch_start > - (imapcommands_use_uid ? (ud->mailbox.msguidnext-1) : ud->mailbox.exists)) - { - if (imapcommands_use_uid) - fprintf(ci->tx,"%s OK FETCH completed\r\n",tag); - else - fprintf(ci->tx, "%s BAD invalid message range specified\r\n",tag); - - list_freelist(&fetch_list.start); - return !imapcommands_use_uid; - } - - switch (*endptr) - { - case ':': - fetch_end = strtoull(++endptr, &lastchar, 10); - endptr = lastchar; - - if (*endptr == '*') - { - fetch_end = (imapcommands_use_uid ? - (ud->mailbox.msguidnext-1) : ud->mailbox.exists); - endptr++; - break; - } - - if (fetch_end == 0 || fetch_end > - (imapcommands_use_uid ? (ud->mailbox.msguidnext-1) : ud->mailbox.exists)) - { - if (!imapcommands_use_uid) - { - fprintf(ci->tx, "%s BAD invalid message range specified\r\n",tag); - - list_freelist(&fetch_list.start); - return 1; - } - } - if (fetch_end < fetch_start) - { - i = fetch_start; - fetch_start = fetch_end; - fetch_end = i; - } - break; + if (!args[0] || !args[1]) { + fprintf(ci->tx, "%s BAD missing argument(s) to FETCH\r\n", + tag); + return 1; + } - case ',': - case 0: - fetch_end = fetch_start; - break; - - default: - fprintf(ci->tx, "%s BAD invalid character in message range\r\n",tag); - list_freelist(&fetch_list.start); - return 1; - } - - if (!imapcommands_use_uid) - { - fetch_start--; - fetch_end--; - } - - if (no_parsing_at_all) - { - trace(TRACE_DEBUG,"ic_fetch(): no parsing at all\n"); - - /* all the info we need can be retrieved by a single - * call to db_get_msginfo_range() - */ - if (!imapcommands_use_uid) - { - /* find the msgUID's to use */ - lo = ud->mailbox.seq_list[fetch_start]; - hi = ud->mailbox.seq_list[fetch_end]; - - } - else - { - lo = fetch_start; - hi = fetch_end; - } - - /* (always retrieve uid) */ - result = db_get_msginfo_range(lo, hi, ud->mailbox.uid, - getflags, getinternaldate, getrfcsize, 1, - &msginfo, &nmatching); - - if (result == -1) - { - list_freelist(&fetch_list.start); - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } - - if (result == -2) - { - list_freelist(&fetch_list.start); - fprintf(ci->tx,"* BYE out of memory\r\n"); - return -1; - } - - for (i=0; i<nmatching; i++) - { - if (getrfcsize && msginfo[i].rfcsize == 0) - { - /* parse the message to calc the size */ - result = db_fetch_headers(msginfo[i].uid, &headermsg); - if (result == -2) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - list_freelist(&fetch_list.start); - my_free(msginfo); - return -1; - } - if (result == -3) - { - fprintf(ci->tx,"\r\n* BYE out of memory\r\n"); - list_freelist(&fetch_list.start); - my_free(msginfo); - return -1; - } - - msginfo[i].rfcsize = (headermsg.rfcheadersize + - headermsg.bodysize + - headermsg.bodylines); - - db_set_rfcsize(msginfo[i].rfcsize, msginfo[i].uid, ud->mailbox.uid); - db_free_msg(&headermsg); + /* check if the user has the right to fetch messages in this mailbox */ + result = + acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_READ); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to fetch from mailbox\r\n", + tag); + return 1; + } + + /* fetch fetch items */ + list_init(&fetch_list); + idx = 1; + uid_will_be_fetched = 0; + do { + idx = next_fetch_item(args, idx, &fetchitem); + if (idx == -2) { + list_freelist(&fetch_list.start); + fprintf(ci->tx, + "%s BAD invalid argument list to fetch\r\n", + tag); + return 1; } - if (binary_search(ud->mailbox.seq_list, ud->mailbox.exists, - msginfo[i].uid, &fn) == -1) { - /* this is probably some sync error: - * the msgUID belongs to this mailbox but was not found - * when building the mailbox info - * let's call it fatal and let the client re-connect :) - */ - fprintf(ci->tx, "* BYE internal syncing error\r\n"); - - list_freelist(&fetch_list.start); - my_free(msginfo); - return -1; - } - - fprintf(ci->tx, "* %u FETCH (", (fn+1)); - - curr = list_getstart(&fetch_list); - isfirstfetchout = 1; - - while (curr) - { - trace(TRACE_DEBUG, "_ic_fetch(): no parsing, into fetch loop"); - - fi = (fetch_items_t*)curr->data; - - if (fi->getInternalDate) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx,"INTERNALDATE \"%s\"", - date_sql2imap(msginfo[i].internaldate)); - } - - if (fi->getUID) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx,"UID %llu", msginfo[i].uid); - } - - if (fi->getSize) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx,"RFC822.SIZE %llu", msginfo[i].rfcsize); - } - - if (fi->getFlags) - { - isfirstout = 1; - - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx, "FLAGS ("); - for (j=0; j<IMAP_NFLAGS; j++) - { - if (msginfo[i].flags[j]) - { - fprintf(ci->tx, "%s%s", isfirstout ? "" : " ", - imap_flag_desc_escaped[j]); - if (isfirstout) isfirstout = 0; - } - } - fprintf(ci->tx, ")"); - } - - curr = curr->nextnode; + if (idx > 0 + && !list_nodeadd(&fetch_list, &fetchitem, + sizeof(fetchitem))) { + list_freelist(&fetch_list.start); + fprintf(ci->tx, "* BYE out of memory\r\n"); + return 1; } - fprintf(ci->tx, ")\r\n"); - } - - my_free(msginfo); - } - - /* if there is no parsing at all, this loop is not needed */ - for (i=fetch_start; i<=fetch_end && !no_parsing_at_all; i++) - { - thisnum = (imapcommands_use_uid ? i : ud->mailbox.seq_list[i]); - insert_rfcsize = 0; - - if (imapcommands_use_uid) - { - if (i > ud->mailbox.msguidnext-1) - { - /* passed the last one */ - fprintf(ci->tx,"%s OK FETCH completed\r\n",tag); - list_freelist(&fetch_list.start); - return 0; + if (fetchitem.msgparse_needed) { + no_parsing_at_all = 0; + } else if (no_parsing_at_all) { + if (fetchitem.getFlags) + getflags = 1; + if (fetchitem.getSize) + getrfcsize = 1; + if (fetchitem.getInternalDate) + getinternaldate = 1; + /* the msgUID will be retrieved anyway so if it is requested, it will be fetched */ } - /* check if the message with this UID belongs to this mailbox */ - if (binary_search(ud->mailbox.seq_list, ud->mailbox.exists, - i, &fn) == -1) { - continue; - } - - fprintf(ci->tx,"* %u FETCH (", fn+1); - - } - else - fprintf(ci->tx,"* %llu FETCH (",i+1); - - trace(TRACE_DEBUG, "Fetching msgID %llu (fetch num %llu)", thisnum, i+1); - - curr = list_getstart(&fetch_list); - setseen = 0; - bad_response_send = 0; - - isfirstfetchout = 1; - - while (curr && !bad_response_send) - { - fi = (fetch_items_t*)curr->data; - fflush(ci->tx); - - only_text_from_msgpart = 0; - - /* check RFC822.SIZE request */ - if (fi->getSize) { - /* ok, try to fetch size from dbase */ - if(db_get_rfcsize(thisnum, ud->mailbox.uid, - &rfcsize) == -1) { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - list_freelist(&fetch_list.start); - return -1; - } - - if (rfcsize == 0) { - /* field is empty in dbase, message needs - to be parsed */ - fi->msgparse_needed = 1; - only_main_header_parsing = 0; - insert_rfcsize = 1; - } - } - - - /* update cache */ - if (fi->msgparse_needed && thisnum != cached_msg.num) - { - if (only_main_header_parsing) - { - /* don't update cache if only the main header is needed - * but do retrieve this main header - */ - - result = db_get_main_header(thisnum, &headermsg.rfcheader); - - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; + if (fetchitem.msgparse_needed && only_main_header_parsing) { + /* check to see wether all the information can be retrieved from the + * main message header (not the entire message has to be parsed then) + * + * this is the case when: + * FETCH RFC822.HEADER + * BODY[HEADER] + * BODY[HEADER.FIELDS ] + * BODY[HEADER.FIELDS.NOT ] + * BODY.PEEK[HEADER] + * BODY.PEEK[HEADER.FIELDS ] + * BODY.PEEK[HEADER.FIELDS.NOT ] + * + */ + + if (!(fetchitem.getRFC822Header || + ((fetchitem.bodyfetch.itemtype == BFIT_HEADER + || fetchitem.bodyfetch.itemtype == + BFIT_HEADER_FIELDS + || fetchitem.bodyfetch.itemtype == + BFIT_HEADER_FIELDS_NOT) + && fetchitem.bodyfetch.partspec[0] == 0) + ) + ) { + only_main_header_parsing = 0; } + } - if (result == -2) - { - fprintf(ci->tx,"\r\n* BYE out of memory\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } + if (fetchitem.getUID) + uid_will_be_fetched = 1; - } - else - { - /* parse message structure */ - if (cached_msg.msg_parsed) - db_free_msg(&cached_msg.msg); - - memset(&cached_msg.msg, 0, sizeof(cached_msg.msg)); - - cached_msg.msg_parsed = 0; - cached_msg.num = -1; - cached_msg.file_dumped = 0; - mreset(cached_msg.memdump); - - result = db_fetch_headers(thisnum, &cached_msg.msg); - if (result == -2) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } - if (result == -3) - { - fprintf(ci->tx,"\r\n* BYE out of memory\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } + } while (idx > 0); - cached_msg.msg_parsed = 1; - cached_msg.num = thisnum; - - rfcsize = (cached_msg.msg.rfcheadersize + - cached_msg.msg.bodysize + - cached_msg.msg.bodylines); - - if (insert_rfcsize) - { - /* insert the rfc822 size into the dbase */ - if (db_set_rfcsize(rfcsize, thisnum,ud->mailbox.uid) == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } - - insert_rfcsize = 0; - } - - } - } + if (!uid_will_be_fetched && imapcommands_use_uid) { + /* make sure UID will be on the fetch-item list */ + memset(&fetchitem, 0, sizeof(fetchitem)); + fetchitem.getUID = 1; + fetchitem.bodyfetch.itemtype = -1; - if (fi->getInternalDate) - { - result = db_get_msgdate(ud->mailbox.uid, thisnum, date); - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } - - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx,"INTERNALDATE \"%s\"", date_sql2imap(date)); + if (!list_nodeadd + (&fetch_list, &fetchitem, sizeof(fetchitem))) { + list_freelist(&fetch_list.start); + fprintf(ci->tx, "* BYE out of memory\r\n"); + return -1; } + } - if (fi->getUID) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); + fetch_list.start = dbmail_list_reverse(fetch_list.start); - fprintf(ci->tx,"UID %llu",thisnum); - } + /* now fetch results for each msg */ + endptr = args[0]; + while (*endptr) { + if (endptr != args[0]) + endptr++; /* skip delimiter */ - if (fi->getMIME_IMB) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx,"BODYSTRUCTURE "); - result = retrieve_structure(ci->tx, &cached_msg.msg, 1); - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE error fetching body structure\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } - } + fetch_start = strtoull(endptr, &endptr, 10); - if (fi->getMIME_IMB_noextension) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx,"BODY "); - result = retrieve_structure(ci->tx, &cached_msg.msg, 0); - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE error fetching body\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } - } + if (fetch_start == 0 || fetch_start > + (imapcommands_use_uid ? (ud->mailbox.msguidnext - 1) : + ud->mailbox.exists)) { + if (imapcommands_use_uid) + fprintf(ci->tx, + "%s OK FETCH completed\r\n", tag); + else + fprintf(ci->tx, + "%s BAD invalid message range specified\r\n", + tag); - if (fi->getEnvelope) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx,"ENVELOPE "); - result = retrieve_envelope(ci->tx, &cached_msg.msg.rfcheader); - - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE error fetching envelope structure\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } + list_freelist(&fetch_list.start); + return !imapcommands_use_uid; } - if (fi->getRFC822 || fi->getRFC822Peek) - { - if (cached_msg.file_dumped == 0 || cached_msg.num != thisnum) - { - mreset(cached_msg.memdump); - - cached_msg.dumpsize = - rfcheader_dump(cached_msg.memdump, &cached_msg.msg.rfcheader, args, 0, 0); - - cached_msg.dumpsize += - db_dump_range(cached_msg.memdump, cached_msg.msg.bodystart, - cached_msg.msg.bodyend, thisnum); - - cached_msg.file_dumped = 1; - - if (cached_msg.num != thisnum) - { - /* if there is a parsed msg in the cache it will be invalid now */ - if (cached_msg.msg_parsed) - { - cached_msg.msg_parsed = 0; - db_free_msg(&cached_msg.msg); - } - cached_msg.num = thisnum; + switch (*endptr) { + case ':': + fetch_end = strtoull(++endptr, &lastchar, 10); + endptr = lastchar; + + if (*endptr == '*') { + fetch_end = (imapcommands_use_uid ? + (ud->mailbox.msguidnext - + 1) : ud->mailbox.exists); + endptr++; + break; } - } - - mseek(cached_msg.memdump, 0, SEEK_SET); - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); + if (fetch_end == 0 || fetch_end > + (imapcommands_use_uid + ? (ud->mailbox.msguidnext - + 1) : ud->mailbox.exists)) { + if (!imapcommands_use_uid) { + fprintf(ci->tx, + "%s BAD invalid message range specified\r\n", + tag); + + list_freelist(&fetch_list.start); + return 1; + } + } - fprintf(ci->tx, "RFC822 {%llu}\r\n", cached_msg.dumpsize); - send_data(ci->tx, cached_msg.memdump, cached_msg.dumpsize); + if (fetch_end < fetch_start) { + i = fetch_start; + fetch_start = fetch_end; + fetch_end = i; + } + break; - if (fi->getRFC822) - setseen = 1; + case ',': + case 0: + fetch_end = fetch_start; + break; + default: + fprintf(ci->tx, + "%s BAD invalid character in message range\r\n", + tag); + list_freelist(&fetch_list.start); + return 1; } - - if (fi->getSize) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx,"RFC822.SIZE %llu", rfcsize); + + if (!imapcommands_use_uid) { + fetch_start--; + fetch_end--; } - if (fi->getBodyTotal || fi->getBodyTotalPeek) - { - if (cached_msg.file_dumped == 0 || cached_msg.num != thisnum) - { - cached_msg.dumpsize = - rfcheader_dump(cached_msg.memdump, &cached_msg.msg.rfcheader, args, 0, 0); - - cached_msg.dumpsize += - db_dump_range(cached_msg.memdump, cached_msg.msg.bodystart, - cached_msg.msg.bodyend, thisnum); - - - if (cached_msg.num != thisnum) - { - /* if there is a parsed msg in the cache it will be invalid now */ - if (cached_msg.msg_parsed) - { - cached_msg.msg_parsed = 0; - db_free_msg(&cached_msg.msg); - } - cached_msg.num = thisnum; + if (no_parsing_at_all) { + trace(TRACE_DEBUG, + "ic_fetch(): no parsing at all\n"); + + /* all the info we need can be retrieved by a single + * call to db_get_msginfo_range() + */ + if (!imapcommands_use_uid) { + /* find the msgUID's to use */ + lo = ud->mailbox.seq_list[fetch_start]; + hi = ud->mailbox.seq_list[fetch_end]; + + } else { + lo = fetch_start; + hi = fetch_end; } - cached_msg.file_dumped = 1; - } - - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - if (fi->bodyfetch.octetstart == -1) - { - mseek(cached_msg.memdump, 0, SEEK_SET); - - fprintf(ci->tx, "BODY[] {%llu}\r\n", cached_msg.dumpsize); - send_data(ci->tx, cached_msg.memdump, cached_msg.dumpsize); - } - else - { - mseek(cached_msg.memdump, fi->bodyfetch.octetstart, SEEK_SET); - - /** \todo this next statement is ugly because of the - casts to 'long long'. Probably, octetcnt should be - changed to be a u64_t instead of a long long, because - it should never be negative anyway */ - actual_cnt = - (fi->bodyfetch.octetcnt > - (((long long) cached_msg.dumpsize) - - fi->bodyfetch.octetstart)) ? - (((long long)cached_msg.dumpsize) - - fi->bodyfetch.octetstart) : - fi->bodyfetch.octetcnt; + /* (always retrieve uid) */ + result = + db_get_msginfo_range(lo, hi, ud->mailbox.uid, + getflags, getinternaldate, + getrfcsize, 1, &msginfo, + &nmatching); + + if (result == -1) { + list_freelist(&fetch_list.start); + fprintf(ci->tx, + "* BYE internal dbase error\r\n"); + return -1; + } - fprintf(ci->tx, "BODY[]<%llu> {%llu}\r\n", fi->bodyfetch.octetstart, - actual_cnt); + if (result == -2) { + list_freelist(&fetch_list.start); + fprintf(ci->tx, "* BYE out of memory\r\n"); + return -1; + } - send_data(ci->tx, cached_msg.memdump, actual_cnt); + for (i = 0; i < nmatching; i++) { + if (getrfcsize && msginfo[i].rfcsize == 0) { + /* parse the message to calc the size */ + result = + db_fetch_headers(msginfo[i]. + uid, + &headermsg); + if (result == -2) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + list_freelist(&fetch_list. + start); + my_free(msginfo); + return -1; + } + if (result == -3) { + fprintf(ci->tx, + "\r\n* BYE out of memory\r\n"); + list_freelist(&fetch_list. + start); + my_free(msginfo); + return -1; + } + + msginfo[i].rfcsize = + (headermsg.rfcheadersize + + headermsg.bodysize + + headermsg.bodylines); + + db_set_rfcsize(msginfo[i].rfcsize, + msginfo[i].uid, + ud->mailbox.uid); + db_free_msg(&headermsg); + } - } + if (binary_search + (ud->mailbox.seq_list, + ud->mailbox.exists, msginfo[i].uid, + &fn) == -1) { + /* this is probably some sync error: + * the msgUID belongs to this mailbox but was not found + * when building the mailbox info + * let's call it fatal and let the client re-connect :) + */ + fprintf(ci->tx, + "* BYE internal syncing error\r\n"); + + list_freelist(&fetch_list.start); + my_free(msginfo); + return -1; + } - if (fi->getBodyTotal) - setseen = 1; + fprintf(ci->tx, "* %u FETCH (", (fn + 1)); + + curr = list_getstart(&fetch_list); + isfirstfetchout = 1; + + while (curr) { + trace(TRACE_DEBUG, + "_ic_fetch(): no parsing, into fetch loop"); + + fi = (fetch_items_t *) curr->data; + + if (fi->getInternalDate) { + if (isfirstfetchout) + isfirstfetchout = + 0; + else + fprintf(ci->tx, + " "); + + fprintf(ci->tx, + "INTERNALDATE \"%s\"", + date_sql2imap + (msginfo[i]. + internaldate)); + } + + if (fi->getUID) { + if (isfirstfetchout) + isfirstfetchout = + 0; + else + fprintf(ci->tx, + " "); + + fprintf(ci->tx, "UID %llu", + msginfo[i].uid); + } + + if (fi->getSize) { + if (isfirstfetchout) + isfirstfetchout = + 0; + else + fprintf(ci->tx, + " "); + + fprintf(ci->tx, + "RFC822.SIZE %llu", + msginfo[i]. + rfcsize); + } + + if (fi->getFlags) { + isfirstout = 1; + + if (isfirstfetchout) + isfirstfetchout = + 0; + else + fprintf(ci->tx, + " "); + + fprintf(ci->tx, "FLAGS ("); + for (j = 0; + j < IMAP_NFLAGS; + j++) { + if (msginfo[i]. + flags[j]) { + fprintf + (ci-> + tx, + "%s%s", + isfirstout + ? "" : + " ", + imap_flag_desc_escaped + [j]); + if (isfirstout) + isfirstout + = + 0; + } + } + fprintf(ci->tx, ")"); + } + + curr = curr->nextnode; + } - } + fprintf(ci->tx, ")\r\n"); + } - if (fi->getRFC822Header) - { - /* here: msgparse_needed == 1 - * if this msg is in cache, retrieve it from there - * otherwise only_main_header_parsing == 1 so retrieve direct - * from the dbase - */ - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - if (cached_msg.num == thisnum) - { - mrewind(cached_msg.tmpdump); - tmpdumpsize = - rfcheader_dump(cached_msg.tmpdump, &cached_msg.msg.rfcheader, args, 0, 0); - - mseek(cached_msg.tmpdump, 0, SEEK_SET); - - fprintf(ci->tx, "RFC822.HEADER {%llu}\r\n",tmpdumpsize); - send_data(ci->tx, cached_msg.tmpdump, tmpdumpsize); - } - else - { - /* remember only_main_header_parsing == 1 here ! */ - - /* use cached_msg.tmpdump as temporary storage */ - mrewind(cached_msg.tmpdump); - tmpdumpsize = - rfcheader_dump(cached_msg.tmpdump, &headermsg.rfcheader, args, 0, 0); - - mseek(cached_msg.tmpdump, 0, SEEK_SET); - - fprintf(ci->tx, "RFC822.HEADER {%llu}\r\n",tmpdumpsize); - send_data(ci->tx, cached_msg.tmpdump, tmpdumpsize); - } + my_free(msginfo); } - - if (fi->getRFC822Text) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - mrewind(cached_msg.tmpdump); - tmpdumpsize = db_dump_range(cached_msg.tmpdump, cached_msg.msg.bodystart, - cached_msg.msg.bodyend, thisnum); + /* if there is no parsing at all, this loop is not needed */ + for (i = fetch_start; i <= fetch_end && !no_parsing_at_all; + i++) { + thisnum = + (imapcommands_use_uid ? i : ud->mailbox. + seq_list[i]); + insert_rfcsize = 0; + + if (imapcommands_use_uid) { + if (i > ud->mailbox.msguidnext - 1) { + /* passed the last one */ + fprintf(ci->tx, + "%s OK FETCH completed\r\n", + tag); + list_freelist(&fetch_list.start); + return 0; + } - mseek(cached_msg.tmpdump, 0, SEEK_SET); + /* check if the message with this UID belongs to this mailbox */ + if (binary_search + (ud->mailbox.seq_list, + ud->mailbox.exists, i, &fn) == -1) { + continue; + } - fprintf(ci->tx, "RFC822.TEXT {%llu}\r\n",tmpdumpsize); - send_data(ci->tx, cached_msg.tmpdump, tmpdumpsize); + fprintf(ci->tx, "* %u FETCH (", fn + 1); + + } else + fprintf(ci->tx, "* %llu FETCH (", i + 1); + + trace(TRACE_DEBUG, + "Fetching msgID %llu (fetch num %llu)", + thisnum, i + 1); + + curr = list_getstart(&fetch_list); + setseen = 0; + bad_response_send = 0; + + isfirstfetchout = 1; + + while (curr && !bad_response_send) { + fi = (fetch_items_t *) curr->data; + fflush(ci->tx); + + only_text_from_msgpart = 0; + + /* check RFC822.SIZE request */ + if (fi->getSize) { + /* ok, try to fetch size from dbase */ + if (db_get_rfcsize + (thisnum, ud->mailbox.uid, + &rfcsize) == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + list_freelist(&fetch_list. + start); + return -1; + } + + if (rfcsize == 0) { + /* field is empty in dbase, message needs + to be parsed */ + fi->msgparse_needed = 1; + only_main_header_parsing = + 0; + insert_rfcsize = 1; + } + } - setseen = 1; - } - if (fi->bodyfetch.itemtype >= 0) - { - mrewind(cached_msg.tmpdump); - - if (fi->bodyfetch.partspec[0]) - { - if (fi->bodyfetch.partspec[0] == '0') - { - fprintf(ci->tx,"\r\n%s BAD protocol error\r\n",tag); - trace(TRACE_DEBUG,"PROTOCOL ERROR"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return 1; - } + /* update cache */ + if (fi->msgparse_needed + && thisnum != cached_msg.num) { + if (only_main_header_parsing) { + /* don't update cache if only the main header is needed + * but do retrieve this main header + */ + + result = + db_get_main_header + (thisnum, + &headermsg.rfcheader); + + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + list_freelist + (&fetch_list. + start); + db_free_msg + (&headermsg); + return -1; + } + + if (result == -2) { + fprintf(ci->tx, + "\r\n* BYE out of memory\r\n"); + list_freelist + (&fetch_list. + start); + db_free_msg + (&headermsg); + return -1; + } + + } else { + /* parse message structure */ + if (cached_msg.msg_parsed) + db_free_msg + (&cached_msg. + msg); + + memset(&cached_msg.msg, 0, + sizeof(cached_msg. + msg)); + + cached_msg.msg_parsed = 0; + cached_msg.num = -1; + cached_msg.file_dumped = 0; + mreset(cached_msg.memdump); + + result = + db_fetch_headers + (thisnum, + &cached_msg.msg); + if (result == -2) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + list_freelist + (&fetch_list. + start); + db_free_msg + (&headermsg); + return -1; + } + if (result == -3) { + fprintf(ci->tx, + "\r\n* BYE out of memory\r\n"); + list_freelist + (&fetch_list. + start); + db_free_msg + (&headermsg); + return -1; + } + + cached_msg.msg_parsed = 1; + cached_msg.num = thisnum; + + rfcsize = + (cached_msg.msg. + rfcheadersize + + cached_msg.msg. + bodysize + + cached_msg.msg. + bodylines); + + if (insert_rfcsize) { + /* insert the rfc822 size into the dbase */ + if (db_set_rfcsize + (rfcsize, + thisnum, + ud->mailbox. + uid) == -1) { + fprintf + (ci-> + tx, + "\r\n* BYE internal dbase error\r\n"); + list_freelist + (&fetch_list. + start); + db_free_msg + (&headermsg); + return -1; + } + + insert_rfcsize = 0; + } + + } + } - msgpart = get_part_by_num(&cached_msg.msg, fi->bodyfetch.partspec); - - if (!msgpart) - { - /* if the partspec ends on "1" or "1." the msg body - * of the parent message is to be retrieved - */ - - partspeclen = strlen(fi->bodyfetch.partspec); - - if ((fi->bodyfetch.partspec[partspeclen-1] == '1' && - (partspeclen == 1 || fi->bodyfetch.partspec[partspeclen-2] == '.')) - || - ((fi->bodyfetch.partspec[partspeclen-1] == '.' && - fi->bodyfetch.partspec[partspeclen-2] == '1') && - (partspeclen == 2 || fi->bodyfetch.partspec[partspeclen-3] == '.')) - ) - { - /* ok find the parent of this message */ - /* start value of k is partspeclen-2 'cause we could - have partspec[partspeclen-1] == '.' right at the start - */ - - for (k = partspeclen-2; k>=0; k--) - if (fi->bodyfetch.partspec[k] == '.') - break; - - if (k>0) - { - fi->bodyfetch.partspec[k] = '\0'; - msgpart = get_part_by_num(&cached_msg.msg, - fi->bodyfetch.partspec); - fi->bodyfetch.partspec[k] = '.'; + if (fi->getInternalDate) { + result = + db_get_msgdate(ud->mailbox.uid, + thisnum, date); + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + list_freelist(&fetch_list. + start); + db_free_msg(&headermsg); + return -1; + } + + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + fprintf(ci->tx, + "INTERNALDATE \"%s\"", + date_sql2imap(date)); } - else - msgpart = &cached_msg.msg; - only_text_from_msgpart = 1; - } - } - else - { - only_text_from_msgpart = 0; - } - } - else - { - if (cached_msg.num == thisnum) - msgpart = &cached_msg.msg; - else - { - /* this will be only the case when only_main_header_parsing == 1 */ - msgpart = &headermsg; - } - } - - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - if (fi->bodyfetch.noseen) - fprintf(ci->tx, "BODY[%s", fi->bodyfetch.partspec); - else - { - fprintf(ci->tx, "BODY[%s", fi->bodyfetch.partspec); - setseen = 1; - } - - switch (fi->bodyfetch.itemtype) - { - case BFIT_TEXT_SILENT: - if (!msgpart) - fprintf(ci->tx, "] NIL "); - else - { - tmpdumpsize = 0; - - if (!only_text_from_msgpart) - tmpdumpsize = rfcheader_dump(cached_msg.tmpdump, &msgpart->rfcheader, - args, 0, 0); - - tmpdumpsize += - db_dump_range(cached_msg.tmpdump, msgpart->bodystart, msgpart->bodyend, - thisnum); - - if (fi->bodyfetch.octetstart >= 0) - { - cnt = tmpdumpsize - fi->bodyfetch.octetstart; - if (cnt<0) cnt = 0; - if (cnt > fi->bodyfetch.octetcnt) cnt = fi->bodyfetch.octetcnt; - - fprintf(ci->tx, "]<%llu> {%llu}\r\n", - fi->bodyfetch.octetstart, cnt); - - mseek(cached_msg.tmpdump, fi->bodyfetch.octetstart, SEEK_SET); - } - else - { - cnt = tmpdumpsize; - fprintf(ci->tx, "] {%llu}\r\n", tmpdumpsize); - mseek(cached_msg.tmpdump, 0, SEEK_SET); - } - - /* output data */ - send_data(ci->tx, cached_msg.tmpdump, cnt); + if (fi->getUID) { + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); - } - break; - - - case BFIT_TEXT: - /* dump body text */ - fprintf(ci->tx, "TEXT"); - if (!msgpart) - fprintf(ci->tx, "] NIL "); - else - { - tmpdumpsize = - db_dump_range(cached_msg.tmpdump, msgpart->bodystart, msgpart->bodyend, - thisnum); - - if (fi->bodyfetch.octetstart >= 0) - { - cnt = tmpdumpsize - fi->bodyfetch.octetstart; - if (cnt<0) cnt = 0; - if (cnt > fi->bodyfetch.octetcnt) cnt = fi->bodyfetch.octetcnt; - - fprintf(ci->tx, "]<%llu> {%llu}\r\n", - fi->bodyfetch.octetstart, cnt); - - mseek(cached_msg.tmpdump, fi->bodyfetch.octetstart, SEEK_SET); - } - else - { - cnt = tmpdumpsize; - fprintf(ci->tx, "] {%llu}\r\n", tmpdumpsize); - mseek(cached_msg.tmpdump, 0, SEEK_SET); - } - - /* output data */ - send_data(ci->tx, cached_msg.tmpdump, cnt); - } - break; - - case BFIT_HEADER: - fprintf(ci->tx, "HEADER"); - if (!msgpart || only_text_from_msgpart) - fprintf(ci->tx, "] NIL\r\n"); - else - { - tmpdumpsize = rfcheader_dump(cached_msg.tmpdump, &msgpart->rfcheader, - args, 0, 0); - - if (!tmpdumpsize) - { - fprintf(ci->tx, "] NIL\r\n"); - } - else - { - if (fi->bodyfetch.octetstart >= 0) - { - cnt = tmpdumpsize - fi->bodyfetch.octetstart; - if (cnt<0) cnt = 0; - if (cnt > fi->bodyfetch.octetcnt) cnt = fi->bodyfetch.octetcnt; - - fprintf(ci->tx, "]<%llu> {%llu}\r\n", - fi->bodyfetch.octetstart, cnt); - - mseek(cached_msg.tmpdump, fi->bodyfetch.octetstart, SEEK_SET); + fprintf(ci->tx, "UID %llu", + thisnum); + } + + if (fi->getMIME_IMB) { + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + fprintf(ci->tx, "BODYSTRUCTURE "); + result = + retrieve_structure(ci->tx, + &cached_msg. + msg, 1); + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE error fetching body structure\r\n"); + list_freelist(&fetch_list. + start); + db_free_msg(&headermsg); + return -1; + } } - else - { - cnt = tmpdumpsize; - fprintf(ci->tx, "] {%llu}\r\n", tmpdumpsize); - mseek(cached_msg.tmpdump, 0, SEEK_SET); + + if (fi->getMIME_IMB_noextension) { + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + fprintf(ci->tx, "BODY "); + result = + retrieve_structure(ci->tx, + &cached_msg. + msg, 0); + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE error fetching body\r\n"); + list_freelist(&fetch_list. + start); + db_free_msg(&headermsg); + return -1; + } } - /* output data */ - send_data(ci->tx, cached_msg.tmpdump, cnt); + if (fi->getEnvelope) { + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + fprintf(ci->tx, "ENVELOPE "); + result = + retrieve_envelope(ci->tx, + &cached_msg. + msg. + rfcheader); + + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE error fetching envelope structure\r\n"); + list_freelist(&fetch_list. + start); + db_free_msg(&headermsg); + return -1; + } + } - } - } - break; - - case BFIT_HEADER_FIELDS: - fprintf(ci->tx, "HEADER.FIELDS ("); - - isfirstout = 1; - for (k=0; k<fi->bodyfetch.argcnt; k++) - { - if (isfirstout) - { - fprintf(ci->tx, "%s",args[k + fi->bodyfetch.argstart]); - isfirstout = 0; - } - else - fprintf(ci->tx, " %s",args[k + fi->bodyfetch.argstart]); - } + if (fi->getRFC822 || fi->getRFC822Peek) { + if (cached_msg.file_dumped == 0 + || cached_msg.num != thisnum) { + mreset(cached_msg.memdump); + + cached_msg.dumpsize = + rfcheader_dump + (cached_msg.memdump, + &cached_msg.msg. + rfcheader, args, 0, + 0); + + cached_msg.dumpsize += + db_dump_range + (cached_msg.memdump, + cached_msg.msg. + bodystart, + cached_msg.msg. + bodyend, thisnum); + + cached_msg.file_dumped = 1; + + if (cached_msg.num != + thisnum) { + /* if there is a parsed msg in the cache it will be invalid now */ + if (cached_msg. + msg_parsed) { + cached_msg. + msg_parsed + = 0; + db_free_msg + (&cached_msg. + msg); + } + cached_msg.num = + thisnum; + } + } + + mseek(cached_msg.memdump, 0, + SEEK_SET); + + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + fprintf(ci->tx, + "RFC822 {%llu}\r\n", + cached_msg.dumpsize); + send_data(ci->tx, + cached_msg.memdump, + cached_msg.dumpsize); + + if (fi->getRFC822) + setseen = 1; - fprintf(ci->tx,")] "); - - if (!msgpart || only_text_from_msgpart) - fprintf(ci->tx, "NIL\r\n"); - else - { - tmpdumpsize = - rfcheader_dump(cached_msg.tmpdump, &msgpart->rfcheader, - &args[fi->bodyfetch.argstart], - fi->bodyfetch.argcnt, 1); - - if (!tmpdumpsize) - { - fprintf(ci->tx, "NIL\r\n"); - } - else - { - if (fi->bodyfetch.octetstart >= 0) - { - cnt = tmpdumpsize - fi->bodyfetch.octetstart; - if (cnt<0) cnt = 0; - if (cnt > fi->bodyfetch.octetcnt) cnt = fi->bodyfetch.octetcnt; - - fprintf(ci->tx, "<%llu> {%llu}\r\n", - fi->bodyfetch.octetstart, cnt); - - mseek(cached_msg.tmpdump, fi->bodyfetch.octetstart, SEEK_SET); } - else - { - cnt = tmpdumpsize; - fprintf(ci->tx, "{%llu}\r\n", tmpdumpsize); - mseek(cached_msg.tmpdump, 0, SEEK_SET); + + if (fi->getSize) { + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + fprintf(ci->tx, "RFC822.SIZE %llu", + rfcsize); } - /* output data */ - send_data(ci->tx, cached_msg.tmpdump, cnt); + if (fi->getBodyTotal + || fi->getBodyTotalPeek) { + if (cached_msg.file_dumped == 0 + || cached_msg.num != thisnum) { + cached_msg.dumpsize = + rfcheader_dump + (cached_msg.memdump, + &cached_msg.msg. + rfcheader, args, 0, + 0); + + cached_msg.dumpsize += + db_dump_range + (cached_msg.memdump, + cached_msg.msg. + bodystart, + cached_msg.msg. + bodyend, thisnum); + + + if (cached_msg.num != + thisnum) { + /* if there is a parsed msg in the cache it will be invalid now */ + if (cached_msg. + msg_parsed) { + cached_msg. + msg_parsed + = 0; + db_free_msg + (&cached_msg. + msg); + } + cached_msg.num = + thisnum; + } + + cached_msg.file_dumped = 1; + } + + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + if (fi->bodyfetch.octetstart == -1) { + mseek(cached_msg.memdump, + 0, SEEK_SET); + + fprintf(ci->tx, + "BODY[] {%llu}\r\n", + cached_msg. + dumpsize); + send_data(ci->tx, + cached_msg. + memdump, + cached_msg. + dumpsize); + } else { + mseek(cached_msg.memdump, + fi->bodyfetch. + octetstart, + SEEK_SET); - } - } - break; - case BFIT_HEADER_FIELDS_NOT: - fprintf(ci->tx, "HEADER.FIELDS.NOT ("); - - isfirstout = 1; - for (k=0; k<fi->bodyfetch.argcnt; k++) - { - if (isfirstout) - { - fprintf(ci->tx, "%s",args[k + fi->bodyfetch.argstart]); - isfirstout = 0; - } - else - fprintf(ci->tx, " %s",args[k + fi->bodyfetch.argstart]); - } + /** \todo this next statement is ugly because of the + casts to 'long long'. Probably, octetcnt should be + changed to be a u64_t instead of a long long, because + it should never be negative anyway */ + actual_cnt = + (fi->bodyfetch. + octetcnt > + (((long long) + cached_msg. + dumpsize) - + fi->bodyfetch. + octetstart)) + ? (((long long) + cached_msg. + dumpsize) + - + fi->bodyfetch. + octetstart) : fi-> + bodyfetch.octetcnt; + + fprintf(ci->tx, + "BODY[]<%llu> {%llu}\r\n", + fi->bodyfetch. + octetstart, + actual_cnt); + + send_data(ci->tx, + cached_msg. + memdump, + actual_cnt); + + } + + if (fi->getBodyTotal) + setseen = 1; - fprintf(ci->tx,")] "); - - if (!msgpart || only_text_from_msgpart) - fprintf(ci->tx, "NIL\r\n"); - else - { - tmpdumpsize = - rfcheader_dump(cached_msg.tmpdump, &msgpart->rfcheader, - &args[fi->bodyfetch.argstart], - fi->bodyfetch.argcnt, 0); - - if (!tmpdumpsize) - { - fprintf(ci->tx, "NIL\r\n"); - } - else - { - if (fi->bodyfetch.octetstart >= 0) - { - cnt = tmpdumpsize - fi->bodyfetch.octetstart; - if (cnt<0) cnt = 0; - if (cnt > fi->bodyfetch.octetcnt) cnt = fi->bodyfetch.octetcnt; - - fprintf(ci->tx, "<%llu> {%llu}\r\n", - fi->bodyfetch.octetstart, cnt); - - mseek(cached_msg.tmpdump, fi->bodyfetch.octetstart, SEEK_SET); - } - else - { - cnt = tmpdumpsize; - fprintf(ci->tx, "{%llu}\r\n", tmpdumpsize); - mseek(cached_msg.tmpdump, 0, SEEK_SET); } - /* output data */ - send_data(ci->tx, cached_msg.tmpdump, cnt); + if (fi->getRFC822Header) { + /* here: msgparse_needed == 1 + * if this msg is in cache, retrieve it from there + * otherwise only_main_header_parsing == 1 so retrieve direct + * from the dbase + */ + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + if (cached_msg.num == thisnum) { + mrewind(cached_msg. + tmpdump); + tmpdumpsize = + rfcheader_dump + (cached_msg.tmpdump, + &cached_msg.msg. + rfcheader, args, 0, + 0); + + mseek(cached_msg.tmpdump, + 0, SEEK_SET); + + fprintf(ci->tx, + "RFC822.HEADER {%llu}\r\n", + tmpdumpsize); + send_data(ci->tx, + cached_msg. + tmpdump, + tmpdumpsize); + } else { + /* remember only_main_header_parsing == 1 here ! */ + + /* use cached_msg.tmpdump as temporary storage */ + mrewind(cached_msg. + tmpdump); + tmpdumpsize = + rfcheader_dump + (cached_msg.tmpdump, + &headermsg.rfcheader, + args, 0, 0); + + mseek(cached_msg.tmpdump, + 0, SEEK_SET); + + fprintf(ci->tx, + "RFC822.HEADER {%llu}\r\n", + tmpdumpsize); + send_data(ci->tx, + cached_msg. + tmpdump, + tmpdumpsize); + } + } - } - } - break; - case BFIT_MIME: - fprintf(ci->tx, "MIME] "); - - if (!msgpart) - fprintf(ci->tx, "NIL\r\n"); - else - { - tmpdumpsize = mimeheader_dump(cached_msg.tmpdump, &msgpart->mimeheader); - - if (!tmpdumpsize) - { - fprintf(ci->tx, "NIL\r\n"); - } - else - { - if (fi->bodyfetch.octetstart >= 0) - { - cnt = tmpdumpsize - fi->bodyfetch.octetstart; - if (cnt<0) cnt = 0; - if (cnt > fi->bodyfetch.octetcnt) cnt = fi->bodyfetch.octetcnt; - - fprintf(ci->tx, "<%llu> {%llu}\r\n", - fi->bodyfetch.octetstart, cnt); - - mseek(cached_msg.tmpdump, fi->bodyfetch.octetstart, SEEK_SET); + if (fi->getRFC822Text) { + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + mrewind(cached_msg.tmpdump); + tmpdumpsize = + db_dump_range(cached_msg. + tmpdump, + cached_msg.msg. + bodystart, + cached_msg.msg. + bodyend, + thisnum); + + mseek(cached_msg.tmpdump, 0, + SEEK_SET); + + fprintf(ci->tx, + "RFC822.TEXT {%llu}\r\n", + tmpdumpsize); + send_data(ci->tx, + cached_msg.tmpdump, + tmpdumpsize); + + setseen = 1; } - else - { - cnt = tmpdumpsize; - fprintf(ci->tx, "{%llu}\r\n", tmpdumpsize); - mseek(cached_msg.tmpdump, 0, SEEK_SET); + + if (fi->bodyfetch.itemtype >= 0) { + mrewind(cached_msg.tmpdump); + + if (fi->bodyfetch.partspec[0]) { + if (fi->bodyfetch. + partspec[0] == '0') { + fprintf(ci->tx, + "\r\n%s BAD protocol error\r\n", + tag); + trace(TRACE_DEBUG, + "PROTOCOL ERROR"); + list_freelist + (&fetch_list. + start); + db_free_msg + (&headermsg); + return 1; + } + + msgpart = + get_part_by_num + (&cached_msg.msg, + fi->bodyfetch. + partspec); + + if (!msgpart) { + /* if the partspec ends on "1" or "1." the msg body + * of the parent message is to be retrieved + */ + + partspeclen = + strlen(fi-> + bodyfetch. + partspec); + + if ((fi->bodyfetch. + partspec + [partspeclen - + 1] == '1' + && + (partspeclen + == 1 + || fi-> + bodyfetch. + partspec + [partspeclen + - 2] == + '.')) + || + ((fi-> + bodyfetch. + partspec + [partspeclen + - 1] == '.' + && fi-> + bodyfetch. + partspec + [partspeclen + - 2] == '1') + && + (partspeclen + == 2 + || fi-> + bodyfetch. + partspec + [partspeclen + - 3] == + '.')) + ) { + /* ok find the parent of this message */ + /* start value of k is partspeclen-2 'cause we could + have partspec[partspeclen-1] == '.' right at the start + */ + + for (k = + partspeclen + - 2; + k >= + 0; + k--) + if (fi->bodyfetch.partspec[k] == '.') + break; + + if (k > 0) { + fi->bodyfetch.partspec[k] = '\0'; + msgpart + = + get_part_by_num + (&cached_msg. + msg, + fi-> + bodyfetch. + partspec); + fi->bodyfetch.partspec[k] = '.'; + } else + msgpart + = + &cached_msg. + msg; + + only_text_from_msgpart + = 1; + } + } else { + only_text_from_msgpart + = 0; + } + } else { + if (cached_msg.num == + thisnum) + msgpart = + &cached_msg. + msg; + else { + /* this will be only the case when only_main_header_parsing == 1 */ + msgpart = + &headermsg; + } + } + + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + if (fi->bodyfetch.noseen) + fprintf(ci->tx, "BODY[%s", + fi->bodyfetch. + partspec); + else { + fprintf(ci->tx, "BODY[%s", + fi->bodyfetch. + partspec); + setseen = 1; + } + + switch (fi->bodyfetch.itemtype) { + case BFIT_TEXT_SILENT: + if (!msgpart) + fprintf(ci->tx, + "] NIL "); + else { + tmpdumpsize = 0; + + if (!only_text_from_msgpart) + tmpdumpsize + = + rfcheader_dump + (cached_msg. + tmpdump, + &msgpart-> + rfcheader, + args, + 0, 0); + + tmpdumpsize += + db_dump_range + (cached_msg. + tmpdump, + msgpart-> + bodystart, + msgpart-> + bodyend, + thisnum); + + if (fi->bodyfetch. + octetstart >= + 0) { + cnt = + tmpdumpsize + - + fi-> + bodyfetch. + octetstart; + if (cnt < + 0) + cnt = 0; + if (cnt > + fi-> + bodyfetch. + octetcnt) + cnt = fi->bodyfetch.octetcnt; + + fprintf + (ci-> + tx, + "]<%llu> {%llu}\r\n", + fi-> + bodyfetch. + octetstart, + cnt); + + mseek + (cached_msg. + tmpdump, + fi-> + bodyfetch. + octetstart, + SEEK_SET); + } else { + cnt = + tmpdumpsize; + fprintf + (ci-> + tx, + "] {%llu}\r\n", + tmpdumpsize); + mseek + (cached_msg. + tmpdump, + 0, + SEEK_SET); + } + + /* output data */ + send_data(ci->tx, + cached_msg. + tmpdump, + cnt); + + } + break; + + + case BFIT_TEXT: + /* dump body text */ + fprintf(ci->tx, "TEXT"); + if (!msgpart) + fprintf(ci->tx, + "] NIL "); + else { + tmpdumpsize = + db_dump_range + (cached_msg. + tmpdump, + msgpart-> + bodystart, + msgpart-> + bodyend, + thisnum); + + if (fi->bodyfetch. + octetstart >= + 0) { + cnt = + tmpdumpsize + - + fi-> + bodyfetch. + octetstart; + if (cnt < + 0) + cnt = 0; + if (cnt > + fi-> + bodyfetch. + octetcnt) + cnt = fi->bodyfetch.octetcnt; + + fprintf + (ci-> + tx, + "]<%llu> {%llu}\r\n", + fi-> + bodyfetch. + octetstart, + cnt); + + mseek + (cached_msg. + tmpdump, + fi-> + bodyfetch. + octetstart, + SEEK_SET); + } else { + cnt = + tmpdumpsize; + fprintf + (ci-> + tx, + "] {%llu}\r\n", + tmpdumpsize); + mseek + (cached_msg. + tmpdump, + 0, + SEEK_SET); + } + + /* output data */ + send_data(ci->tx, + cached_msg. + tmpdump, + cnt); + } + break; + + case BFIT_HEADER: + fprintf(ci->tx, "HEADER"); + if (!msgpart + || + only_text_from_msgpart) + fprintf(ci->tx, + "] NIL\r\n"); + else { + tmpdumpsize = + rfcheader_dump + (cached_msg. + tmpdump, + &msgpart-> + rfcheader, + args, 0, 0); + + if (!tmpdumpsize) { + fprintf + (ci-> + tx, + "] NIL\r\n"); + } else { + if (fi-> + bodyfetch. + octetstart + >= 0) { + cnt = tmpdumpsize - fi->bodyfetch.octetstart; + if (cnt < 0) + cnt = 0; + if (cnt > fi->bodyfetch.octetcnt) + cnt = fi->bodyfetch.octetcnt; + + fprintf + (ci-> + tx, + "]<%llu> {%llu}\r\n", + fi-> + bodyfetch. + octetstart, + cnt); + + mseek + (cached_msg. + tmpdump, + fi-> + bodyfetch. + octetstart, + SEEK_SET); + } else { + cnt = tmpdumpsize; + fprintf + (ci-> + tx, + "] {%llu}\r\n", + tmpdumpsize); + mseek + (cached_msg. + tmpdump, + 0, + SEEK_SET); + } + + /* output data */ + send_data + (ci-> + tx, + cached_msg. + tmpdump, + cnt); + + } + } + break; + + case BFIT_HEADER_FIELDS: + fprintf(ci->tx, + "HEADER.FIELDS ("); + + isfirstout = 1; + for (k = 0; + k < + fi->bodyfetch.argcnt; + k++) { + if (isfirstout) { + fprintf + (ci-> + tx, + "%s", + args[k + + + fi-> + bodyfetch. + argstart]); + isfirstout + = 0; + } else + fprintf + (ci-> + tx, + " %s", + args[k + + + fi-> + bodyfetch. + argstart]); + } + + fprintf(ci->tx, ")] "); + + if (!msgpart + || + only_text_from_msgpart) + fprintf(ci->tx, + "NIL\r\n"); + else { + tmpdumpsize = + rfcheader_dump + (cached_msg. + tmpdump, + &msgpart-> + rfcheader, + &args[fi-> + bodyfetch. + argstart], + fi->bodyfetch. + argcnt, 1); + + if (!tmpdumpsize) { + fprintf + (ci-> + tx, + "NIL\r\n"); + } else { + if (fi-> + bodyfetch. + octetstart + >= 0) { + cnt = tmpdumpsize - fi->bodyfetch.octetstart; + if (cnt < 0) + cnt = 0; + if (cnt > fi->bodyfetch.octetcnt) + cnt = fi->bodyfetch.octetcnt; + + fprintf + (ci-> + tx, + "<%llu> {%llu}\r\n", + fi-> + bodyfetch. + octetstart, + cnt); + + mseek + (cached_msg. + tmpdump, + fi-> + bodyfetch. + octetstart, + SEEK_SET); + } else { + cnt = tmpdumpsize; + fprintf + (ci-> + tx, + "{%llu}\r\n", + tmpdumpsize); + mseek + (cached_msg. + tmpdump, + 0, + SEEK_SET); + } + + /* output data */ + send_data + (ci-> + tx, + cached_msg. + tmpdump, + cnt); + + } + } + break; + case BFIT_HEADER_FIELDS_NOT: + fprintf(ci->tx, + "HEADER.FIELDS.NOT ("); + + isfirstout = 1; + for (k = 0; + k < + fi->bodyfetch.argcnt; + k++) { + if (isfirstout) { + fprintf + (ci-> + tx, + "%s", + args[k + + + fi-> + bodyfetch. + argstart]); + isfirstout + = 0; + } else + fprintf + (ci-> + tx, + " %s", + args[k + + + fi-> + bodyfetch. + argstart]); + } + + fprintf(ci->tx, ")] "); + + if (!msgpart + || + only_text_from_msgpart) + fprintf(ci->tx, + "NIL\r\n"); + else { + tmpdumpsize = + rfcheader_dump + (cached_msg. + tmpdump, + &msgpart-> + rfcheader, + &args[fi-> + bodyfetch. + argstart], + fi->bodyfetch. + argcnt, 0); + + if (!tmpdumpsize) { + fprintf + (ci-> + tx, + "NIL\r\n"); + } else { + if (fi-> + bodyfetch. + octetstart + >= 0) { + cnt = tmpdumpsize - fi->bodyfetch.octetstart; + if (cnt < 0) + cnt = 0; + if (cnt > fi->bodyfetch.octetcnt) + cnt = fi->bodyfetch.octetcnt; + + fprintf + (ci-> + tx, + "<%llu> {%llu}\r\n", + fi-> + bodyfetch. + octetstart, + cnt); + + mseek + (cached_msg. + tmpdump, + fi-> + bodyfetch. + octetstart, + SEEK_SET); + } else { + cnt = tmpdumpsize; + fprintf + (ci-> + tx, + "{%llu}\r\n", + tmpdumpsize); + mseek + (cached_msg. + tmpdump, + 0, + SEEK_SET); + } + + /* output data */ + send_data + (ci-> + tx, + cached_msg. + tmpdump, + cnt); + + } + } + break; + case BFIT_MIME: + fprintf(ci->tx, "MIME] "); + + if (!msgpart) + fprintf(ci->tx, + "NIL\r\n"); + else { + tmpdumpsize = + mimeheader_dump + (cached_msg. + tmpdump, + &msgpart-> + mimeheader); + + if (!tmpdumpsize) { + fprintf + (ci-> + tx, + "NIL\r\n"); + } else { + if (fi-> + bodyfetch. + octetstart + >= 0) { + cnt = tmpdumpsize - fi->bodyfetch.octetstart; + if (cnt < 0) + cnt = 0; + if (cnt > fi->bodyfetch.octetcnt) + cnt = fi->bodyfetch.octetcnt; + + fprintf + (ci-> + tx, + "<%llu> {%llu}\r\n", + fi-> + bodyfetch. + octetstart, + cnt); + + mseek + (cached_msg. + tmpdump, + fi-> + bodyfetch. + octetstart, + SEEK_SET); + } else { + cnt = tmpdumpsize; + fprintf + (ci-> + tx, + "{%llu}\r\n", + tmpdumpsize); + mseek + (cached_msg. + tmpdump, + 0, + SEEK_SET); + } + + /* output data */ + send_data + (ci-> + tx, + cached_msg. + tmpdump, + cnt); + + } + } + + break; + default: + fprintf(ci->tx, + "\r\n* BYE internal server error\r\n"); + list_freelist(&fetch_list. + start); + db_free_msg(&headermsg); + return -1; + } } - /* output data */ - send_data(ci->tx, cached_msg.tmpdump, cnt); - - } - } - - break; - default: - fprintf(ci->tx, "\r\n* BYE internal server error\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } - } + /* set \Seen flag if necessary; note the absence of an error-check + * for db_get_msgflag()! + */ + if (setseen + && db_get_msgflag("seen", thisnum, + ud->mailbox.uid) != + 1) { + result = + db_set_msgflag(thisnum, + ud->mailbox.uid, + setSeenSet, + IMAPFA_ADD); + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + list_freelist(&fetch_list. + start); + db_free_msg(&headermsg); + return -1; + } + + fi->getFlags = 1; + fprintf(ci->tx, " "); + } - /* set \Seen flag if necessary; note the absence of an error-check - * for db_get_msgflag()! - */ - if (setseen && db_get_msgflag("seen", thisnum, ud->mailbox.uid) != 1) - { - result = db_set_msgflag(thisnum, ud->mailbox.uid, setSeenSet, IMAPFA_ADD); - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } - - fi->getFlags = 1; - fprintf(ci->tx," "); - } + /* FLAGS ? */ + if (fi->getFlags) { + if (isfirstfetchout) + isfirstfetchout = 0; + else + fprintf(ci->tx, " "); + + fprintf(ci->tx, "FLAGS ("); + + isfirstout = 1; + + result = + db_get_msgflag_all(thisnum, + ud->mailbox. + uid, + msgflags); + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + list_freelist(&fetch_list. + start); + db_free_msg(&headermsg); + return -1; + } + + for (j = 0; j < IMAP_NFLAGS; j++) { + if (msgflags[j]) { + if (isfirstout) { + fprintf + (ci-> + tx, + "\\%s", + imap_flag_desc + [j]); + isfirstout + = 0; + } else + fprintf + (ci-> + tx, + " \\%s", + imap_flag_desc + [j]); + } + } + fprintf(ci->tx, ")"); + } - /* FLAGS ? */ - if (fi->getFlags) - { - if (isfirstfetchout) - isfirstfetchout = 0; - else - fprintf(ci->tx, " "); - - fprintf(ci->tx,"FLAGS ("); - - isfirstout = 1; - - result = db_get_msgflag_all(thisnum, ud->mailbox.uid, msgflags); - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); - return -1; - } - - for (j=0; j<IMAP_NFLAGS; j++) - { - if (msgflags[j]) - { - if (isfirstout) - { - fprintf(ci->tx,"\\%s",imap_flag_desc[j]); - isfirstout = 0; - } - else - fprintf(ci->tx," \\%s",imap_flag_desc[j]); + curr = curr->nextnode; } - } - fprintf(ci->tx, ")"); - } - - curr = curr->nextnode; - } - if (!bad_response_send) - fprintf(ci->tx,")\r\n"); + if (!bad_response_send) + fprintf(ci->tx, ")\r\n"); + } } - } - mreset(cached_msg.tmpdump); - list_freelist(&fetch_list.start); - db_free_msg(&headermsg); + mreset(cached_msg.tmpdump); + list_freelist(&fetch_list.start); + db_free_msg(&headermsg); - fprintf(ci->tx,"%s OK %sFETCH completed\r\n", tag, imapcommands_use_uid ? "UID " : ""); - return 0; + fprintf(ci->tx, "%s OK %sFETCH completed\r\n", tag, + imapcommands_use_uid ? "UID " : ""); + return 0; } @@ -3213,296 +3798,332 @@ int _ic_fetch(char *tag, char **args, ClientInfo *ci) * * alter message-associated data in selected mailbox */ -int _ic_store(char *tag, char **args, ClientInfo *ci) +int _ic_store(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - char *endptr, *lastchar = NULL; - u64_t i,store_start,store_end; - unsigned fn=0; - int result,j,isfirstout=0; - int be_silent=0,action=IMAPFA_NONE; - int flaglist[IMAP_NFLAGS], msgflags[IMAP_NFLAGS]; - u64_t thisnum,lo,hi; - - memset(flaglist, 0, sizeof(int) * IMAP_NFLAGS); - - if (ud->state != IMAPCS_SELECTED) - { - fprintf(ci->tx,"%s BAD STORE command received in invalid state\r\n", tag); - return 1; - } - - if (!args[0] || !args[1] || !args[2]) - { - fprintf(ci->tx,"%s BAD missing argument(s) to STORE\r\n", tag); - return 1; - } - - /* multiple flags should be parenthesed */ - if (args[3] && strcmp(args[2],"(") != 0) - { - fprintf(ci->tx,"%s BAD invalid argument(s) to STORE\r\n", tag); - return 1; - } - - - /* retrieve action type */ - if (strcasecmp(args[1], "flags") == 0) - action = IMAPFA_REPLACE; - else if (strcasecmp(args[1], "flags.silent") == 0) - { - action = IMAPFA_REPLACE; - be_silent = 1; - } - else if (strcasecmp(args[1], "+flags") == 0) - action = IMAPFA_ADD; - else if (strcasecmp(args[1], "+flags.silent") == 0) - { - action = IMAPFA_ADD; - be_silent = 1; - } - else if (strcasecmp(args[1], "-flags") == 0) - action = IMAPFA_REMOVE; - else if (strcasecmp(args[1], "-flags.silent") == 0) - { - action = IMAPFA_REMOVE; - be_silent = 1; - } - - if (action == IMAPFA_NONE) - { - fprintf(ci->tx,"%s BAD invalid STORE action specified\r\n",tag); - return 1; - } - - /* now fetch flag list */ - i = (strcmp(args[2], "(") == 0) ? 3: 2; - - for ( ; args[i] && strcmp(args[i] ,")") != 0; i++) - { - for (j=0; j<IMAP_NFLAGS; j++) - if (strcasecmp(args[i],imap_flag_desc_escaped[j]) == 0) - { - flaglist[j] = 1; - break; - } - - if (j == IMAP_NFLAGS) - { - fprintf(ci->tx,"%s BAD invalid flag list to STORE command\r\n",tag); - return 1; - } - } - + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + char *endptr, *lastchar = NULL; + u64_t i, store_start, store_end; + unsigned fn = 0; + int result, j, isfirstout = 0; + int be_silent = 0, action = IMAPFA_NONE; + int flaglist[IMAP_NFLAGS], msgflags[IMAP_NFLAGS]; + u64_t thisnum, lo, hi; + + memset(flaglist, 0, sizeof(int) * IMAP_NFLAGS); + + if (ud->state != IMAPCS_SELECTED) { + fprintf(ci->tx, + "%s BAD STORE command received in invalid state\r\n", + tag); + return 1; + } + + if (!args[0] || !args[1] || !args[2]) { + fprintf(ci->tx, "%s BAD missing argument(s) to STORE\r\n", + tag); + return 1; + } + + /* multiple flags should be parenthesed */ + if (args[3] && strcmp(args[2], "(") != 0) { + fprintf(ci->tx, "%s BAD invalid argument(s) to STORE\r\n", + tag); + return 1; + } + + + /* retrieve action type */ + if (strcasecmp(args[1], "flags") == 0) + action = IMAPFA_REPLACE; + else if (strcasecmp(args[1], "flags.silent") == 0) { + action = IMAPFA_REPLACE; + be_silent = 1; + } else if (strcasecmp(args[1], "+flags") == 0) + action = IMAPFA_ADD; + else if (strcasecmp(args[1], "+flags.silent") == 0) { + action = IMAPFA_ADD; + be_silent = 1; + } else if (strcasecmp(args[1], "-flags") == 0) + action = IMAPFA_REMOVE; + else if (strcasecmp(args[1], "-flags.silent") == 0) { + action = IMAPFA_REMOVE; + be_silent = 1; + } + + if (action == IMAPFA_NONE) { + fprintf(ci->tx, + "%s BAD invalid STORE action specified\r\n", tag); + return 1; + } + + /* now fetch flag list */ + i = (strcmp(args[2], "(") == 0) ? 3 : 2; + + for (; args[i] && strcmp(args[i], ")") != 0; i++) { + for (j = 0; j < IMAP_NFLAGS; j++) + if (strcasecmp(args[i], imap_flag_desc_escaped[j]) + == 0) { + flaglist[j] = 1; + break; + } + + if (j == IMAP_NFLAGS) { + fprintf(ci->tx, + "%s BAD invalid flag list to STORE command\r\n", + tag); + return 1; + } + } + /** check ACL's for STORE */ - if (flaglist[IMAP_STORE_FLAG_SEEN] == 1) { - result = acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_SEEN); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error"); - return -1; /* fatal */ - } - if (result == 0) { - fprintf(ci->tx, "%s NO no right to store \\SEEN flag", tag); - return 1; - } - } - if (flaglist[IMAP_STORE_FLAG_DELETED] == 1) { - result = acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_DELETE); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error"); - return -1; /* fatal */ - } - if (result == 0) { - fprintf(ci->tx, "%s NO no right to store \\DELETED flag", tag); - return 1; - } - } - if (flaglist[IMAP_STORE_FLAG_ANSWERED] == 1 || - flaglist[IMAP_STORE_FLAG_FLAGGED] == 1 || - flaglist[IMAP_STORE_FLAG_DRAFT] == 1 || - flaglist[IMAP_STORE_FLAG_RECENT] == 1) { - result = acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_WRITE); - if (result < 0) { - fprintf(ci->tx, "*BYE internal database error"); - return -1; - } - if (result == 0) { - fprintf(ci->tx, "%s NO no right to store flags", tag); - return 1; - } - } - /* end of ACL checking. If we get here without returning, the user has - the right to store the flags */ - - /* set flags & show if needed */ - endptr = args[0]; - while (*endptr) - { - if (endptr != args[0]) - endptr++; /* skip delimiter */ - - store_start = strtoull(endptr, &endptr, 10); - - if (store_start == 0 || store_start > - (imapcommands_use_uid ? (ud->mailbox.msguidnext-1) : ud->mailbox.exists)) - { - fprintf(ci->tx, "%s BAD invalid message range specified\r\n",tag); - return 1; - } - - switch (*endptr) - { - case ':': - store_end = strtoull(++endptr, &lastchar, 10); - endptr = lastchar; - - if (*endptr == '*') - { - store_end = (imapcommands_use_uid ? - (ud->mailbox.msguidnext-1) : ud->mailbox.exists); - endptr++; - break; - } - - if (store_end == 0 || store_end > - (imapcommands_use_uid ? (ud->mailbox.msguidnext-1) : ud->mailbox.exists)) - { - fprintf(ci->tx, "%s BAD invalid message range specified\r\n",tag); - return 1; - } - - if (store_end < store_start) - { - i = store_start; - store_start = store_end; - store_end = i; - } - break; - - case ',': - case 0: - store_end = store_start; - break; - - default: - fprintf(ci->tx, "%s BAD invalid character in message range\r\n",tag); - return 1; - } - - if (!imapcommands_use_uid) - { - store_start--; - store_end--; - } - - if (store_start == store_end) - { - thisnum = (imapcommands_use_uid ? store_start : ud->mailbox.seq_list[store_start]); - - if (imapcommands_use_uid) - { - /* check if the message with this UID belongs to this mailbox */ - if (binary_search(ud->mailbox.seq_list, ud->mailbox.exists, - store_start, &fn) == -1) - continue; - } - - result = db_set_msgflag(thisnum, ud->mailbox.uid, flaglist, action); - - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - return -1; - } - - if (!be_silent) - { - result = db_get_msgflag_all(thisnum, ud->mailbox.uid, msgflags); - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - return -1; + if (flaglist[IMAP_STORE_FLAG_SEEN] == 1) { + result = + acl_has_right(ud->userid, ud->mailbox.uid, + ACL_RIGHT_SEEN); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error"); + return -1; /* fatal */ + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no right to store \\SEEN flag", + tag); + return 1; + } + } + if (flaglist[IMAP_STORE_FLAG_DELETED] == 1) { + result = + acl_has_right(ud->userid, ud->mailbox.uid, + ACL_RIGHT_DELETE); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error"); + return -1; /* fatal */ } - - fprintf(ci->tx, "* %llu FETCH (FLAGS (", - imapcommands_use_uid ? (u64_t)(fn+1) : store_start+1); - - for (j=0,isfirstout=1; j<IMAP_NFLAGS; j++) - { - if (msgflags[j]) - { - fprintf(ci->tx, "%s%s", isfirstout ? "" : " ",imap_flag_desc_escaped[j]); - if (isfirstout) isfirstout = 0; - } + if (result == 0) { + fprintf(ci->tx, + "%s NO no right to store \\DELETED flag", + tag); + return 1; + } + } + if (flaglist[IMAP_STORE_FLAG_ANSWERED] == 1 || + flaglist[IMAP_STORE_FLAG_FLAGGED] == 1 || + flaglist[IMAP_STORE_FLAG_DRAFT] == 1 || + flaglist[IMAP_STORE_FLAG_RECENT] == 1) { + result = + acl_has_right(ud->userid, ud->mailbox.uid, + ACL_RIGHT_WRITE); + if (result < 0) { + fprintf(ci->tx, "*BYE internal database error"); + return -1; } + if (result == 0) { + fprintf(ci->tx, "%s NO no right to store flags", + tag); + return 1; + } + } + /* end of ACL checking. If we get here without returning, the user has + the right to store the flags */ + + /* set flags & show if needed */ + endptr = args[0]; + while (*endptr) { + if (endptr != args[0]) + endptr++; /* skip delimiter */ + + store_start = strtoull(endptr, &endptr, 10); + + if (store_start == 0 || store_start > + (imapcommands_use_uid ? (ud->mailbox.msguidnext - 1) : + ud->mailbox.exists)) { + fprintf(ci->tx, + "%s BAD invalid message range specified\r\n", + tag); + return 1; + } + + switch (*endptr) { + case ':': + store_end = strtoull(++endptr, &lastchar, 10); + endptr = lastchar; + + if (*endptr == '*') { + store_end = (imapcommands_use_uid ? + (ud->mailbox.msguidnext - + 1) : ud->mailbox.exists); + endptr++; + break; + } + + if (store_end == 0 || store_end > + (imapcommands_use_uid + ? (ud->mailbox.msguidnext - + 1) : ud->mailbox.exists)) { + fprintf(ci->tx, + "%s BAD invalid message range specified\r\n", + tag); + return 1; + } + + if (store_end < store_start) { + i = store_start; + store_start = store_end; + store_end = i; + } + break; + + case ',': + case 0: + store_end = store_start; + break; + + default: + fprintf(ci->tx, + "%s BAD invalid character in message range\r\n", + tag); + return 1; + } + + if (!imapcommands_use_uid) { + store_start--; + store_end--; + } + + if (store_start == store_end) { + thisnum = + (imapcommands_use_uid ? store_start : ud-> + mailbox.seq_list[store_start]); + + if (imapcommands_use_uid) { + /* check if the message with this UID belongs to this mailbox */ + if (binary_search + (ud->mailbox.seq_list, + ud->mailbox.exists, store_start, + &fn) == -1) + continue; + } + + result = + db_set_msgflag(thisnum, ud->mailbox.uid, + flaglist, action); + + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + return -1; + } + + if (!be_silent) { + result = + db_get_msgflag_all(thisnum, + ud->mailbox.uid, + msgflags); + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + return -1; + } + + fprintf(ci->tx, "* %llu FETCH (FLAGS (", + imapcommands_use_uid ? (u64_t) (fn + + + 1) + : store_start + 1); + + for (j = 0, isfirstout = 1; + j < IMAP_NFLAGS; j++) { + if (msgflags[j]) { + fprintf(ci->tx, "%s%s", + isfirstout ? "" : + " ", + imap_flag_desc_escaped + [j]); + if (isfirstout) + isfirstout = 0; + } + } - fprintf(ci->tx,"))\r\n"); - } - } - else - { - if (!imapcommands_use_uid) - { - /* find the msgUID's to use */ - lo = ud->mailbox.seq_list[store_start]; - hi = ud->mailbox.seq_list[store_end]; - - } - else - { - lo = store_start; - hi = store_end; - } - - result = db_set_msgflag_range(lo, hi, ud->mailbox.uid, flaglist, action); - - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - return -1; - } - - if (!be_silent) - { - for (i=store_start; i<=store_end; i++) - { - thisnum = (imapcommands_use_uid ? i : ud->mailbox.seq_list[i]); - - if (imapcommands_use_uid) { - /* check if the message with this UID belongs - to this mailbox */ - if (binary_search(ud->mailbox.seq_list, - ud->mailbox.exists, i, &fn) == -1) - continue; - } - - result = db_get_msgflag_all(thisnum, ud->mailbox.uid, msgflags); - if (result == -1) - { - fprintf(ci->tx,"\r\n* BYE internal dbase error\r\n"); - return -1; - } - - fprintf(ci->tx, "* %llu FETCH (FLAGS (", - imapcommands_use_uid ? (u64_t)(fn+1) : i+1); - - for (j=0,isfirstout=1; j<IMAP_NFLAGS; j++) - { - if (msgflags[j]) - { - fprintf(ci->tx, "%s%s", isfirstout ? "" : " ",imap_flag_desc_escaped[j]); - if (isfirstout) isfirstout = 0; + fprintf(ci->tx, "))\r\n"); + } + } else { + if (!imapcommands_use_uid) { + /* find the msgUID's to use */ + lo = ud->mailbox.seq_list[store_start]; + hi = ud->mailbox.seq_list[store_end]; + + } else { + lo = store_start; + hi = store_end; } - } - fprintf(ci->tx,"))\r\n"); + result = + db_set_msgflag_range(lo, hi, ud->mailbox.uid, + flaglist, action); + + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + return -1; + } + + if (!be_silent) { + for (i = store_start; i <= store_end; i++) { + thisnum = + (imapcommands_use_uid ? i : + ud->mailbox.seq_list[i]); + + if (imapcommands_use_uid) { + /* check if the message with this UID belongs + to this mailbox */ + if (binary_search + (ud->mailbox.seq_list, + ud->mailbox.exists, i, + &fn) == -1) + continue; + } + + result = + db_get_msgflag_all(thisnum, + ud->mailbox. + uid, + msgflags); + if (result == -1) { + fprintf(ci->tx, + "\r\n* BYE internal dbase error\r\n"); + return -1; + } + + fprintf(ci->tx, + "* %llu FETCH (FLAGS (", + imapcommands_use_uid + ? (u64_t) (fn + 1) : i + + 1); + + for (j = 0, isfirstout = 1; + j < IMAP_NFLAGS; j++) { + if (msgflags[j]) { + fprintf(ci->tx, + "%s%s", + isfirstout + ? "" : " ", + imap_flag_desc_escaped + [j]); + if (isfirstout) + isfirstout + = 0; + } + } + + fprintf(ci->tx, "))\r\n"); + } + } } - } } - } - fprintf(ci->tx,"%s OK %sSTORE completed\r\n", tag, imapcommands_use_uid ? "UID ":""); - return 0; + fprintf(ci->tx, "%s OK %sSTORE completed\r\n", tag, + imapcommands_use_uid ? "UID " : ""); + return 0; } @@ -3511,141 +4132,155 @@ int _ic_store(char *tag, char **args, ClientInfo *ci) * * copy a message to another mailbox */ -int _ic_copy(char *tag, char **args, ClientInfo *ci) +int _ic_copy(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - u64_t i,copy_start,copy_end; - unsigned fn; - u64_t destmboxid,thisnum; - int result; - u64_t new_msgid; - char *endptr, *lastchar = NULL; - - if (!check_state_and_args("COPY", tag, args, 2, IMAPCS_SELECTED, ci)) - return 1; /* error, return */ - - /* check if destination mailbox exists */ - if (db_findmailbox(args[1], ud->userid, &destmboxid) == -1) { - fprintf(ci->tx, "* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - if (destmboxid == 0) { - /* error: cannot select mailbox */ - fprintf(ci->tx, "%s NO [TRYCREATE] specified mailbox does not exist\r\n",tag); - return 1; - } - - // check if user has right to COPY from source mailbox - result = acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_READ); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; /* fatal */ - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to copy from mailbox\r\n", tag); - return 1; - } - // check if user has right to COPY to destination mailbox - result = acl_has_right(ud->userid, destmboxid, ACL_RIGHT_INSERT); - if (result < 0) { - fprintf(ci->tx, "* BYE internal database error\r\n"); - return -1; /* fatal */ - } - if (result == 0) { - fprintf(ci->tx, "%s NO no permission to copy to mailbox\r\n", tag); - return 1; - } - - /* ok copy msgs */ - endptr = args[0]; - while (*endptr) - { - if (endptr != args[0]) - endptr++; /* skip delimiter */ - - copy_start = strtoull(endptr, &lastchar, 10); - endptr = lastchar; - - if (copy_start == 0 || copy_start > - (imapcommands_use_uid ? (ud->mailbox.msguidnext-1) : ud->mailbox.exists)) - { - fprintf(ci->tx, "%s BAD invalid message range specified\r\n",tag); - return 1; - } - - switch (*endptr) - { - case ':': - copy_end = strtoull(++endptr, &lastchar, 10); - endptr = lastchar; - - if (*endptr == '*') - { - copy_end = (imapcommands_use_uid ? - (ud->mailbox.msguidnext-1) : ud->mailbox.exists); - endptr++; - break; - } - - if (copy_end == 0 || copy_end > - (imapcommands_use_uid ? (ud->mailbox.msguidnext-1) : ud->mailbox.exists)) - { - fprintf(ci->tx, "%s BAD invalid message range specified\r\n",tag); - return 1; - } - - if (copy_end < copy_start) - { - i = copy_start; - copy_start = copy_end; - copy_end = i; - } - break; - - case ',': - case 0: - copy_end = copy_start; - break; - - default: - fprintf(ci->tx, "%s BAD invalid character in message range\r\n",tag); - return 1; - } - - if (!imapcommands_use_uid) - { - copy_start--; - copy_end--; - } - - for (i=copy_start; i<=copy_end; i++) - { - thisnum = (imapcommands_use_uid ? i : ud->mailbox.seq_list[i]); - - if (imapcommands_use_uid) - { - /* check if the message with this UID belongs to this mailbox */ - if (binary_search(ud->mailbox.seq_list, ud->mailbox.exists, - i, &fn) == -1) - continue; - } - - result = db_copymsg(thisnum, destmboxid, ud->userid, &new_msgid); - if (result == -1) - { - fprintf(ci->tx,"* BYE internal dbase error\r\n"); - return -1; - } - if (result == -2) - { - fprintf(ci->tx,"%s NO quotum would exceed\r\n", tag); - return 1; - } - } - } - - fprintf(ci->tx,"%s OK %sCOPY completed\r\n", tag, imapcommands_use_uid?"UID ":""); - return 0; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + u64_t i, copy_start, copy_end; + unsigned fn; + u64_t destmboxid, thisnum; + int result; + u64_t new_msgid; + char *endptr, *lastchar = NULL; + + if (!check_state_and_args + ("COPY", tag, args, 2, IMAPCS_SELECTED, ci)) + return 1; /* error, return */ + + /* check if destination mailbox exists */ + if (db_findmailbox(args[1], ud->userid, &destmboxid) == -1) { + fprintf(ci->tx, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + if (destmboxid == 0) { + /* error: cannot select mailbox */ + fprintf(ci->tx, + "%s NO [TRYCREATE] specified mailbox does not exist\r\n", + tag); + return 1; + } + // check if user has right to COPY from source mailbox + result = + acl_has_right(ud->userid, ud->mailbox.uid, ACL_RIGHT_READ); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; /* fatal */ + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to copy from mailbox\r\n", + tag); + return 1; + } + // check if user has right to COPY to destination mailbox + result = acl_has_right(ud->userid, destmboxid, ACL_RIGHT_INSERT); + if (result < 0) { + fprintf(ci->tx, "* BYE internal database error\r\n"); + return -1; /* fatal */ + } + if (result == 0) { + fprintf(ci->tx, + "%s NO no permission to copy to mailbox\r\n", tag); + return 1; + } + + /* ok copy msgs */ + endptr = args[0]; + while (*endptr) { + if (endptr != args[0]) + endptr++; /* skip delimiter */ + + copy_start = strtoull(endptr, &lastchar, 10); + endptr = lastchar; + + if (copy_start == 0 || copy_start > + (imapcommands_use_uid ? (ud->mailbox.msguidnext - 1) : + ud->mailbox.exists)) { + fprintf(ci->tx, + "%s BAD invalid message range specified\r\n", + tag); + return 1; + } + + switch (*endptr) { + case ':': + copy_end = strtoull(++endptr, &lastchar, 10); + endptr = lastchar; + + if (*endptr == '*') { + copy_end = (imapcommands_use_uid ? + (ud->mailbox.msguidnext - + 1) : ud->mailbox.exists); + endptr++; + break; + } + + if (copy_end == 0 || copy_end > + (imapcommands_use_uid + ? (ud->mailbox.msguidnext - + 1) : ud->mailbox.exists)) { + fprintf(ci->tx, + "%s BAD invalid message range specified\r\n", + tag); + return 1; + } + + if (copy_end < copy_start) { + i = copy_start; + copy_start = copy_end; + copy_end = i; + } + break; + + case ',': + case 0: + copy_end = copy_start; + break; + + default: + fprintf(ci->tx, + "%s BAD invalid character in message range\r\n", + tag); + return 1; + } + + if (!imapcommands_use_uid) { + copy_start--; + copy_end--; + } + + for (i = copy_start; i <= copy_end; i++) { + thisnum = + (imapcommands_use_uid ? i : ud->mailbox. + seq_list[i]); + + if (imapcommands_use_uid) { + /* check if the message with this UID belongs to this mailbox */ + if (binary_search + (ud->mailbox.seq_list, + ud->mailbox.exists, i, &fn) == -1) + continue; + } + + result = + db_copymsg(thisnum, destmboxid, ud->userid, + &new_msgid); + if (result == -1) { + fprintf(ci->tx, + "* BYE internal dbase error\r\n"); + return -1; + } + if (result == -2) { + fprintf(ci->tx, + "%s NO quotum would exceed\r\n", + tag); + return 1; + } + } + } + + fprintf(ci->tx, "%s OK %sCOPY completed\r\n", tag, + imapcommands_use_uid ? "UID " : ""); + return 0; } @@ -3654,67 +4289,70 @@ int _ic_copy(char *tag, char **args, ClientInfo *ci) * * fetch/store/copy/search message UID's */ -int _ic_uid(char *tag, char **args, ClientInfo *ci) +int _ic_uid(char *tag, char **args, ClientInfo * ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - int result; - - if (ud->state != IMAPCS_SELECTED) - { - fprintf(ci->tx,"%s BAD UID command received in invalid state\r\n",tag); - return 1; - } - - if (!args[0]) - { - fprintf(ci->tx,"%s BAD missing argument(s) to UID\r\n",tag); - return 1; - } - - imapcommands_use_uid = 1; /* set global var to make clear we will be using UID's */ - /* ACL rights for UID are handled by the other functions called below */ - if (strcasecmp(args[0], "fetch") == 0) - result = _ic_fetch(tag, &args[1], ci); - else if (strcasecmp(args[0], "copy") == 0) - result = _ic_copy(tag, &args[1], ci); - else if (strcasecmp(args[0], "store") == 0) - result = _ic_store(tag, &args[1], ci); - else if (strcasecmp(args[0], "search") == 0) - result = _ic_search(tag, &args[1], ci); - else - { - fprintf(ci->tx,"%s BAD invalid UID command\r\n",tag); - result = 1; - } - - imapcommands_use_uid = 0; - - return result; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + int result; + + if (ud->state != IMAPCS_SELECTED) { + fprintf(ci->tx, + "%s BAD UID command received in invalid state\r\n", + tag); + return 1; + } + + if (!args[0]) { + fprintf(ci->tx, "%s BAD missing argument(s) to UID\r\n", + tag); + return 1; + } + + imapcommands_use_uid = 1; /* set global var to make clear we will be using UID's */ + /* ACL rights for UID are handled by the other functions called below */ + if (strcasecmp(args[0], "fetch") == 0) + result = _ic_fetch(tag, &args[1], ci); + else if (strcasecmp(args[0], "copy") == 0) + result = _ic_copy(tag, &args[1], ci); + else if (strcasecmp(args[0], "store") == 0) + result = _ic_store(tag, &args[1], ci); + else if (strcasecmp(args[0], "search") == 0) + result = _ic_search(tag, &args[1], ci); + else { + fprintf(ci->tx, "%s BAD invalid UID command\r\n", tag); + result = 1; + } + + imapcommands_use_uid = 0; + + return result; } /* Helper function for _ic_getquotaroot() and _ic_getquota(). * Send all resource limits in `quota'. */ -void send_quota(quota_t *quota, ClientInfo *ci) { - int r; - u64_t usage, limit; - char *name; - - for (r=0; r<quota->n_resources; r++) { - if (quota->resource[r].limit > 0) { - switch (quota->resource[r].type) { - case RT_STORAGE: - name = "STORAGE"; - usage = quota->resource[r].usage/1024; - limit = quota->resource[r].limit/1024; - break; - default: continue; - } - fprintf(ci->tx, "* QUOTA \"%s\" (%s %llu %llu)\r\n", - quota->root, name, usage, limit); +void send_quota(quota_t * quota, ClientInfo * ci) +{ + int r; + u64_t usage, limit; + char *name; + + for (r = 0; r < quota->n_resources; r++) { + if (quota->resource[r].limit > 0) { + switch (quota->resource[r].type) { + case RT_STORAGE: + name = "STORAGE"; + usage = quota->resource[r].usage / 1024; + limit = quota->resource[r].limit / 1024; + break; + default: + continue; + } + fprintf(ci->tx, + "* QUOTA \"%s\" (%s %llu %llu)\r\n", + quota->root, name, usage, limit); + } } - } } /* @@ -3722,33 +4360,35 @@ void send_quota(quota_t *quota, ClientInfo *ci) { * * get quota root and send quota */ -int _ic_getquotaroot(char *tag, char **args, ClientInfo *ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - quota_t *quota; - char *root, *errormsg; - - if (!check_state_and_args("GETQUOTAROOT", tag, args, 1, - IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - root = quota_get_quotaroot(ud->userid, args[0], &errormsg); - if (root == NULL) { - fprintf(ci->tx, "%s NO %s\r\n", tag, errormsg); - return 1; - } - - quota = quota_get_quota(ud->userid, root, &errormsg); - if (quota == NULL) { - fprintf(ci->tx, "%s NO %s\r\n", tag, errormsg); - return 1; - } - - fprintf(ci->tx, "* QUOTAROOT \"%s\" \"%s\"\r\n", args[0], quota->root); - send_quota(quota, ci); - quota_free(quota); - - fprintf(ci->tx, "%s OK GETQUOTAROOT completed\r\n", tag); - return 0; +int _ic_getquotaroot(char *tag, char **args, ClientInfo * ci) +{ + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + quota_t *quota; + char *root, *errormsg; + + if (!check_state_and_args("GETQUOTAROOT", tag, args, 1, + IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + root = quota_get_quotaroot(ud->userid, args[0], &errormsg); + if (root == NULL) { + fprintf(ci->tx, "%s NO %s\r\n", tag, errormsg); + return 1; + } + + quota = quota_get_quota(ud->userid, root, &errormsg); + if (quota == NULL) { + fprintf(ci->tx, "%s NO %s\r\n", tag, errormsg); + return 1; + } + + fprintf(ci->tx, "* QUOTAROOT \"%s\" \"%s\"\r\n", args[0], + quota->root); + send_quota(quota, ci); + quota_free(quota); + + fprintf(ci->tx, "%s OK GETQUOTAROOT completed\r\n", tag); + return 0; } /* @@ -3756,37 +4396,37 @@ int _ic_getquotaroot(char *tag, char **args, ClientInfo *ci) { * * get quota */ -int _ic_getquota(char *tag, char **args, ClientInfo *ci) { - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - quota_t *quota; - char *errormsg; - - if (!check_state_and_args("GETQUOTA", tag, args, 1, - IMAPCS_AUTHENTICATED, ci)) - return 1; /* error, return */ - - quota = quota_get_quota(ud->userid, args[0], &errormsg); - if (quota == NULL) { - fprintf(ci->tx, "%s NO %s\r\n", tag, errormsg); - return 1; - } - - send_quota(quota, ci); - quota_free(quota); - - fprintf(ci->tx, "%s OK GETQUOTA completed\r\n", tag); - return 0; +int _ic_getquota(char *tag, char **args, ClientInfo * ci) +{ + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + quota_t *quota; + char *errormsg; + + if (!check_state_and_args("GETQUOTA", tag, args, 1, + IMAPCS_AUTHENTICATED, ci)) + return 1; /* error, return */ + + quota = quota_get_quota(ud->userid, args[0], &errormsg); + if (quota == NULL) { + fprintf(ci->tx, "%s NO %s\r\n", tag, errormsg); + return 1; + } + + send_quota(quota, ci); + quota_free(quota); + + fprintf(ci->tx, "%s OK GETQUOTA completed\r\n", tag); + return 0; } /* returns -1 on error, 0 if user or mailbox not found and 1 otherwise */ static int imap_acl_pre_administer(const char *mailboxname, - const char *username, - u64_t executing_userid, - u64_t *mboxid, - u64_t *target_userid) + const char *username, + u64_t executing_userid, + u64_t * mboxid, u64_t * target_userid) { int result; - result = db_findmailbox(mailboxname, executing_userid, mboxid); + result = db_findmailbox(mailboxname, executing_userid, mboxid); if (result < 1) return result; @@ -3797,14 +4437,14 @@ static int imap_acl_pre_administer(const char *mailboxname, return 1; } -int _ic_setacl(char *tag, char **args, ClientInfo *ci) +int _ic_setacl(char *tag, char **args, ClientInfo * ci) { /* SETACL mailboxname identifier mod_rights */ - imap_userdata_t *ud = (imap_userdata_t*) ci->userData; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; int result; u64_t mboxid; u64_t targetuserid; - + if (!check_state_and_args("SETACL", tag, args, 3, IMAPCS_AUTHENTICATED, ci)) return 1; @@ -3819,12 +4459,10 @@ int _ic_setacl(char *tag, char **args, ClientInfo *ci) tag); return 1; } - // has the rights to 'administer' this mailbox? if (acl_has_right(ud->userid, mboxid, ACL_RIGHT_ADMINISTER) != 1) { fprintf(ci->tx, "%s NO SETACL failure: can't set acl, " - "you don't have the proper rights\r\n", - tag); + "you don't have the proper rights\r\n", tag); return 1; } // set the new acl @@ -3838,13 +4476,13 @@ int _ic_setacl(char *tag, char **args, ClientInfo *ci) } -int _ic_deleteacl(char *tag, char **args, ClientInfo *ci) +int _ic_deleteacl(char *tag, char **args, ClientInfo * ci) { // DELETEACL mailboxname identifier - imap_userdata_t *ud = (imap_userdata_t*) ci->userData; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; u64_t mboxid; u64_t targetuserid; - + if (!check_state_and_args("DELETEACL", tag, args, 2, IMAPCS_AUTHENTICATED, ci)) return 1; @@ -3854,7 +4492,6 @@ int _ic_deleteacl(char *tag, char **args, ClientInfo *ci) fprintf(ci->tx, "* BYE internal dbase error\r\n"); return -1; } - // has the rights to 'administer' this mailbox? if (acl_has_right(ud->userid, mboxid, ACL_RIGHT_ADMINISTER) != 1) { fprintf(ci->tx, "%s NO DELETEACL failure: can't delete " @@ -3862,7 +4499,7 @@ int _ic_deleteacl(char *tag, char **args, ClientInfo *ci) return 1; } // set the new acl - if (acl_delete_acl(targetuserid,mboxid) < 0) { + if (acl_delete_acl(targetuserid, mboxid) < 0) { fprintf(ci->tx, "* BYE internal database error\r\n"); return -1; } @@ -3871,10 +4508,10 @@ int _ic_deleteacl(char *tag, char **args, ClientInfo *ci) return 0; } -int _ic_getacl(char *tag, char **args, ClientInfo *ci) +int _ic_getacl(char *tag, char **args, ClientInfo * ci) { /* GETACL mailboxname */ - imap_userdata_t *ud = (imap_userdata_t*) ci->userData; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; int result; u64_t mboxid; char *acl_string; @@ -3892,29 +4529,28 @@ int _ic_getacl(char *tag, char **args, ClientInfo *ci) tag); return 1; } - // get acl string (string of identifier-rights pairs) if (!(acl_string = acl_get_acl(mboxid))) { fprintf(ci->tx, "* BYE internal database error\r\n"); return -1; } - + fprintf(ci->tx, "* ACL \"%s\" %s\r\n", args[0], acl_string); - my_free(acl_string); + my_free(acl_string); fprintf(ci->tx, "%s OK GETACL completed\r\n", tag); return 0; } - -int _ic_listrights(char *tag, char **args, ClientInfo *ci) + +int _ic_listrights(char *tag, char **args, ClientInfo * ci) { /* LISTRIGHTS mailboxname identifier */ - imap_userdata_t *ud = (imap_userdata_t*) ci->userData; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; int result; u64_t mboxid; u64_t targetuserid; const char *listrights_string; - + if (!check_state_and_args("LISTRIGHTS", tag, args, 2, IMAPCS_AUTHENTICATED, ci)) return 1; @@ -3925,14 +4561,15 @@ int _ic_listrights(char *tag, char **args, ClientInfo *ci) fprintf(ci->tx, "* BYE internal database error\r\n"); return -1; } else if (result == 0) { - fprintf(ci->tx, "%s, NO LISTRIGHTS failure: can't set acl\r\n", + fprintf(ci->tx, + "%s, NO LISTRIGHTS failure: can't set acl\r\n", tag); return 1; } - // has the rights to 'administer' this mailbox? if (acl_has_right(ud->userid, mboxid, ACL_RIGHT_ADMINISTER) != 1) { - fprintf(ci->tx, "%s NO LISTRIGHTS failure: can't set acl\r\n", + fprintf(ci->tx, + "%s NO LISTRIGHTS failure: can't set acl\r\n", tag); return 1; } @@ -3948,10 +4585,10 @@ int _ic_listrights(char *tag, char **args, ClientInfo *ci) return 0; } -int _ic_myrights(char *tag, char **args, ClientInfo *ci) +int _ic_myrights(char *tag, char **args, ClientInfo * ci) { /* MYRIGHTS mailboxname */ - imap_userdata_t *ud = (imap_userdata_t*) ci->userData; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; int result; u64_t mboxid; char *myrights_string; @@ -3959,41 +4596,41 @@ int _ic_myrights(char *tag, char **args, ClientInfo *ci) if (!check_state_and_args("LISTRIGHTS", tag, args, 1, IMAPCS_AUTHENTICATED, ci)) return 1; - + result = db_findmailbox(args[0], ud->userid, &mboxid); if (result == -1) { fprintf(ci->tx, "* BYE internal database error\r\n"); return -1; } else if (result == 0) { - fprintf(ci->tx, "%s, NO MYRIGHTS failure: unknown mailbox\r\n", + fprintf(ci->tx, + "%s, NO MYRIGHTS failure: unknown mailbox\r\n", tag); return 1; } - + if (!(myrights_string = acl_myrights(ud->userid, mboxid))) { fprintf(ci->tx, "* BYE internal database error\r\n"); return -1; } - - fprintf(ci->tx, "* MYRIGHTS \"%s\" %s\r\n", args[0], myrights_string); + + fprintf(ci->tx, "* MYRIGHTS \"%s\" %s\r\n", args[0], + myrights_string); my_free(myrights_string); fprintf(ci->tx, "%s OK MYRIGHTS complete\r\n", tag); return 0; } -int _ic_namespace(char *tag, char **args, ClientInfo *ci) +int _ic_namespace(char *tag, char **args, ClientInfo * ci) { /* NAMESPACE command */ if (!check_state_and_args("NAMESPACE", tag, args, 0, IMAPCS_AUTHENTICATED, ci)) return 1; - + fprintf(ci->tx, "* NAMESPACE ((\"\" \"%s\")) ((\"%s\" \"%s\")) " - "((\"%s\" \"%s\"))\r\n", + "((\"%s\" \"%s\"))\r\n", MAILBOX_SEPERATOR, NAMESPACE_USER, MAILBOX_SEPERATOR, NAMESPACE_PUBLIC, MAILBOX_SEPERATOR); fprintf(ci->tx, "%s OK NAMESPACE complete\r\n", tag); return 0; } - - diff --git a/imapcommands.h b/imapcommands.h index ce422e8a..7d1b023f 100644 --- a/imapcommands.h +++ b/imapcommands.h @@ -35,65 +35,65 @@ #include "imap4.h" /* any-state commands */ -int _ic_capability(char *tag, char **args, ClientInfo *ci); -int _ic_noop(char *tag, char **args, ClientInfo *ci); -int _ic_logout(char *tag, char **args, ClientInfo *ci); +int _ic_capability(char *tag, char **args, ClientInfo * ci); +int _ic_noop(char *tag, char **args, ClientInfo * ci); +int _ic_logout(char *tag, char **args, ClientInfo * ci); /* non-auth state commands */ -int _ic_login(char *tag, char **args, ClientInfo *ci); -int _ic_authenticate(char *tag, char **args, ClientInfo *ci); +int _ic_login(char *tag, char **args, ClientInfo * ci); +int _ic_authenticate(char *tag, char **args, ClientInfo * ci); /* auth state commands */ -int _ic_select(char *tag, char **args, ClientInfo *ci); -int _ic_examine(char *tag, char **args, ClientInfo *ci); -int _ic_create(char *tag, char **args, ClientInfo *ci); -int _ic_delete(char *tag, char **args, ClientInfo *ci); -int _ic_rename(char *tag, char **args, ClientInfo *ci); -int _ic_subscribe(char *tag, char **args, ClientInfo *ci); -int _ic_unsubscribe(char *tag, char **args, ClientInfo *ci); -int _ic_list(char *tag, char **args, ClientInfo *ci); -int _ic_lsub(char *tag, char **args, ClientInfo *ci); -int _ic_status(char *tag, char **args, ClientInfo *ci); -int _ic_append(char *tag, char **args, ClientInfo *ci); +int _ic_select(char *tag, char **args, ClientInfo * ci); +int _ic_examine(char *tag, char **args, ClientInfo * ci); +int _ic_create(char *tag, char **args, ClientInfo * ci); +int _ic_delete(char *tag, char **args, ClientInfo * ci); +int _ic_rename(char *tag, char **args, ClientInfo * ci); +int _ic_subscribe(char *tag, char **args, ClientInfo * ci); +int _ic_unsubscribe(char *tag, char **args, ClientInfo * ci); +int _ic_list(char *tag, char **args, ClientInfo * ci); +int _ic_lsub(char *tag, char **args, ClientInfo * ci); +int _ic_status(char *tag, char **args, ClientInfo * ci); +int _ic_append(char *tag, char **args, ClientInfo * ci); /* selected-state commands */ -int _ic_check(char *tag, char **args, ClientInfo *ci); -int _ic_close(char *tag, char **args, ClientInfo *ci); -int _ic_expunge(char *tag, char **args, ClientInfo *ci); -int _ic_search(char *tag, char **args, ClientInfo *ci); -int _ic_fetch(char *tag, char **args, ClientInfo *ci); -int _ic_store(char *tag, char **args, ClientInfo *ci); -int _ic_copy(char *tag, char **args, ClientInfo *ci); -int _ic_uid(char *tag, char **args, ClientInfo *ci); +int _ic_check(char *tag, char **args, ClientInfo * ci); +int _ic_close(char *tag, char **args, ClientInfo * ci); +int _ic_expunge(char *tag, char **args, ClientInfo * ci); +int _ic_search(char *tag, char **args, ClientInfo * ci); +int _ic_fetch(char *tag, char **args, ClientInfo * ci); +int _ic_store(char *tag, char **args, ClientInfo * ci); +int _ic_copy(char *tag, char **args, ClientInfo * ci); +int _ic_uid(char *tag, char **args, ClientInfo * ci); /* quota commands */ -int _ic_getquotaroot(char *tag, char **args, ClientInfo *ci); -int _ic_getquota(char *tag, char **args, ClientInfo *ci); +int _ic_getquotaroot(char *tag, char **args, ClientInfo * ci); +int _ic_getquota(char *tag, char **args, ClientInfo * ci); /* acl commands */ /** * \brief SETACL command */ -int _ic_setacl(char *tag, char **args, ClientInfo *ci); +int _ic_setacl(char *tag, char **args, ClientInfo * ci); /** * DELETEACL command */ -int _ic_deleteacl(char *tag, char **args, ClientInfo *ci); +int _ic_deleteacl(char *tag, char **args, ClientInfo * ci); /** * GETACL command */ -int _ic_getacl(char *tag, char **args, ClientInfo *ci); +int _ic_getacl(char *tag, char **args, ClientInfo * ci); /** * LISTRIGHTS command */ -int _ic_listrights(char *tag, char **args, ClientInfo *ci); +int _ic_listrights(char *tag, char **args, ClientInfo * ci); /** * MYRIGHTS command */ -int _ic_myrights(char *tag, char **args, ClientInfo *ci); +int _ic_myrights(char *tag, char **args, ClientInfo * ci); /** * NAMESPACE command */ -int _ic_namespace(char *tag, char **args, ClientInfo *ci); +int _ic_namespace(char *tag, char **args, ClientInfo * ci); #endif @@ -52,10 +52,10 @@ char *configFile = DEFAULT_CONFIG_FILE; /* set up database login data */ extern db_param_t _db_params; -static void SetConfigItems(serverConfig_t *config, struct list *items); +static void SetConfigItems(serverConfig_t * config, struct list *items); static void Daemonize(void); static int SetMainSigHandler(void); -static void MainSigHandler(int sig, siginfo_t *info, void *data); +static void MainSigHandler(int sig, siginfo_t * info, void *data); int imap_before_smtp = 0; @@ -69,253 +69,279 @@ int main(int argc, char *argv[], char **envp) int main(int argc, char *argv[]) #endif { - serverConfig_t config; - struct list imapItems, sysItems; - int result, status; - pid_t pid; - - openlog(PNAME, LOG_PID, LOG_MAIL); - - if (argc >= 2 && argv[1]) - { - if (strcmp(argv[1],"-v") == 0) - { - printf ("\n*** DBMAIL: dbmail-imap version $Revision$ %s\n",COPYRIGHT); - return 0; + serverConfig_t config; + struct list imapItems, sysItems; + int result, status; + pid_t pid; + + openlog(PNAME, LOG_PID, LOG_MAIL); + + if (argc >= 2 && argv[1]) { + if (strcmp(argv[1], "-v") == 0) { + printf + ("\n*** DBMAIL: dbmail-imap version $Revision$ %s\n", + COPYRIGHT); + return 0; + } else if (argv[2] && (strcmp(argv[1], "-f") == 0)) { + configFile = argv[2]; + } } - else if (argv[2] && (strcmp(argv[1],"-f") == 0)) - { - configFile = argv[2]; - } - } - - SetMainSigHandler(); - Daemonize(); - result = 0; - - do - { - mainStop = 0; - mainRestart = 0; - - trace(TRACE_DEBUG, "main(): reading config"); -#ifdef PROC_TITLES - init_set_proc_title(argc, argv, envp, PNAME); - set_proc_title("%s", "Idle"); -#endif - ReadConfig("IMAP", configFile, &imapItems); - ReadConfig("DBMAIL", configFile, &sysItems); - SetConfigItems(&config, &imapItems); - SetTraceLevel(&imapItems); - GetDBParams(&_db_params, &sysItems); - - config.ClientHandler = IMAPClientHandler; - config.timeoutMsg = IMAP_TIMEOUT_MSG; - - CreateSocket(&config); - trace(TRACE_ERROR, "main(): socket created, starting server"); - - switch ( (pid = fork()) ) - { - case -1: - close(config.listenSocket); - trace(TRACE_FATAL, "main(): fork failed [%s]", strerror(errno)); - - case 0: - /* child process */ - drop_privileges(config.serverUser, config.serverGroup); - result = StartServer(&config); - trace(TRACE_INFO, "main(): server done, exit."); - exit(result); - - default: - /* parent process, wait for child to exit */ - while (waitpid(pid, &status, WNOHANG|WUNTRACED) == 0) - { - if (mainStop) - kill(pid, SIGTERM); - - if (mainRestart) - kill(pid, SIGHUP); - - sleep(2); - } - - if (WIFEXITED(status)) - { - /* child process terminated neatly */ - result = WEXITSTATUS(status); - trace(TRACE_DEBUG, "main(): server has exited, exit status [%d]", result); - } - else - { - /* child stopped or signaled, don't like */ - /* make sure it is dead */ - trace(TRACE_DEBUG, "main(): server has not exited normally. Killing.."); - - kill(pid, SIGKILL); - result = 0; - } - } + SetMainSigHandler(); + Daemonize(); + result = 0; - list_freelist(&imapItems.start); - list_freelist(&sysItems.start); - close(config.listenSocket); - - } while (result == 1 && !mainStop) ; /* 1 means reread-config and restart */ + do { + mainStop = 0; + mainRestart = 0; + + trace(TRACE_DEBUG, "main(): reading config"); +#ifdef PROC_TITLES + init_set_proc_title(argc, argv, envp, PNAME); + set_proc_title("%s", "Idle"); +#endif - trace(TRACE_INFO, "main(): exit"); - return 0; + ReadConfig("IMAP", configFile, &imapItems); + ReadConfig("DBMAIL", configFile, &sysItems); + SetConfigItems(&config, &imapItems); + SetTraceLevel(&imapItems); + GetDBParams(&_db_params, &sysItems); + + config.ClientHandler = IMAPClientHandler; + config.timeoutMsg = IMAP_TIMEOUT_MSG; + + CreateSocket(&config); + trace(TRACE_ERROR, + "main(): socket created, starting server"); + + switch ((pid = fork())) { + case -1: + close(config.listenSocket); + trace(TRACE_FATAL, "main(): fork failed [%s]", + strerror(errno)); + + case 0: + /* child process */ + drop_privileges(config.serverUser, + config.serverGroup); + result = StartServer(&config); + trace(TRACE_INFO, "main(): server done, exit."); + exit(result); + + default: + /* parent process, wait for child to exit */ + while (waitpid(pid, &status, WNOHANG | WUNTRACED) + == 0) { + if (mainStop) + kill(pid, SIGTERM); + + if (mainRestart) + kill(pid, SIGHUP); + + sleep(2); + } + + if (WIFEXITED(status)) { + /* child process terminated neatly */ + result = WEXITSTATUS(status); + trace(TRACE_DEBUG, + "main(): server has exited, exit status [%d]", + result); + } else { + /* child stopped or signaled, don't like */ + /* make sure it is dead */ + trace(TRACE_DEBUG, + "main(): server has not exited normally. Killing.."); + + kill(pid, SIGKILL); + result = 0; + } + } + + list_freelist(&imapItems.start); + list_freelist(&sysItems.start); + close(config.listenSocket); + + } while (result == 1 && !mainStop); /* 1 means reread-config and restart */ + + trace(TRACE_INFO, "main(): exit"); + return 0; } -void MainSigHandler(int sig, siginfo_t *info UNUSED, void *data UNUSED) +void MainSigHandler(int sig, siginfo_t * info UNUSED, void *data UNUSED) { - trace(TRACE_DEBUG, "MainSigHandler(): got signal [%d]", sig); + trace(TRACE_DEBUG, "MainSigHandler(): got signal [%d]", sig); - if (sig == SIGHUP) - mainRestart = 1; - else - mainStop = 1; + if (sig == SIGHUP) + mainRestart = 1; + else + mainStop = 1; } void Daemonize() { - if (fork()) - exit(0); - setsid(); + if (fork()) + exit(0); + setsid(); - if (fork()) - exit(0); -} + if (fork()) + exit(0); +} int SetMainSigHandler() { - struct sigaction act; + struct sigaction act; - /* init & install signal handlers */ - memset(&act, 0, sizeof(act)); + /* init & install signal handlers */ + memset(&act, 0, sizeof(act)); - act.sa_sigaction = MainSigHandler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; + act.sa_sigaction = MainSigHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; - sigaction(SIGINT, &act, 0); - sigaction(SIGQUIT, &act, 0); + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); - sigaction(SIGTERM, &act, 0); - sigaction(SIGHUP, &act, 0); + sigaction(SIGTERM, &act, 0); + sigaction(SIGHUP, &act, 0); - return 0; + return 0; } -void SetConfigItems(serverConfig_t *config, struct list *items) +void SetConfigItems(serverConfig_t * config, struct list *items) { - field_t val; - - /* read items: NCHILDREN */ - GetConfigValue("NCHILDREN", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for NCHILDREN in config file"); + field_t val; + + /* read items: NCHILDREN */ + GetConfigValue("NCHILDREN", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for NCHILDREN in config file"); + + if ((config->nChildren = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for NCHILDREN is invalid: [%d]", + config->nChildren); + + trace(TRACE_DEBUG, + "SetConfigItems(): server will create [%d] children", + config->nChildren); + + + /* read items: MAXCONNECTS */ + GetConfigValue("MAXCONNECTS", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for MAXCONNECTS in config file"); - if ( (config->nChildren = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for NCHILDREN is invalid: [%d]", config->nChildren); + if ((config->childMaxConnect = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", + config->childMaxConnect); - trace(TRACE_DEBUG, "SetConfigItems(): server will create [%d] children", config->nChildren); + trace(TRACE_DEBUG, + "SetConfigItems(): children will make max. [%d] connections", + config->childMaxConnect); - /* read items: MAXCONNECTS */ - GetConfigValue("MAXCONNECTS", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for MAXCONNECTS in config file"); + /* read items: TIMEOUT */ + GetConfigValue("TIMEOUT", items, val); + if (strlen(val) == 0) { + trace(TRACE_DEBUG, + "SetConfigItems(): no value for TIMEOUT in config file"); + config->timeout = 0; + } else if ((config->timeout = atoi(val)) <= 30) + trace(TRACE_FATAL, + "SetConfigItems(): value for TIMEOUT is invalid: [%d]", + config->timeout); - if ( (config->childMaxConnect = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", config->childMaxConnect); + trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", + config->timeout); - trace(TRACE_DEBUG, "SetConfigItems(): children will make max. [%d] connections", config->childMaxConnect); - - /* read items: TIMEOUT */ - GetConfigValue("TIMEOUT", items, val); - if (strlen(val) == 0) - { - trace(TRACE_DEBUG, "SetConfigItems(): no value for TIMEOUT in config file"); - config->timeout = 0; - } - else if ( (config->timeout = atoi(val)) <= 30) - trace(TRACE_FATAL, "SetConfigItems(): value for TIMEOUT is invalid: [%d]", config->timeout); + /* read items: PORT */ + GetConfigValue("PORT", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for PORT in config file"); - trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", config->timeout); - + if ((config->port = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for PORT is invalid: [%d]", + config->port); - /* read items: PORT */ - GetConfigValue("PORT", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for PORT in config file"); + trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", + config->port); - if ( (config->port = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for PORT is invalid: [%d]", config->port); - trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", config->port); - + /* read items: BINDIP */ + GetConfigValue("BINDIP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for BINDIP in config file"); - /* read items: BINDIP */ - GetConfigValue("BINDIP", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for BINDIP in config file"); + strncpy(config->ip, val, IPLEN); + config->ip[IPLEN - 1] = '\0'; - strncpy(config->ip, val, IPLEN); - config->ip[IPLEN-1] = '\0'; + trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", + config->ip); - trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", config->ip); + /* read items: RESOLVE_IP */ + GetConfigValue("RESOLVE_IP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, + "SetConfigItems(): no value for RESOLVE_IP in config file"); - /* read items: RESOLVE_IP */ - GetConfigValue("RESOLVE_IP", items, val); - if (strlen(val) == 0) - trace(TRACE_DEBUG, "SetConfigItems(): no value for RESOLVE_IP in config file"); + config->resolveIP = (strcasecmp(val, "yes") == 0); - config->resolveIP = (strcasecmp(val, "yes") == 0); + trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", + config->resolveIP ? "" : "not "); - trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", config->resolveIP ? "" : "not "); + /* read items: IMAP-BEFORE-SMTP */ + GetConfigValue("IMAP_BEFORE_SMTP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, + "SetConfigItems(): no value for IMAP_BEFORE_SMTP in config file"); - /* read items: IMAP-BEFORE-SMTP */ - GetConfigValue("IMAP_BEFORE_SMTP", items, val); - if (strlen(val) == 0) - trace(TRACE_DEBUG, "SetConfigItems(): no value for IMAP_BEFORE_SMTP in config file"); + imap_before_smtp = (strcasecmp(val, "yes") == 0); - imap_before_smtp = (strcasecmp(val, "yes") == 0); + trace(TRACE_DEBUG, "SetConfigItems(): %s IMAP-before-SMTP", + imap_before_smtp ? "Enabling" : "Disabling"); - trace(TRACE_DEBUG, "SetConfigItems(): %s IMAP-before-SMTP", - imap_before_smtp ? "Enabling" : "Disabling"); + /* read items: EFFECTIVE-USER */ + GetConfigValue("EFFECTIVE_USER", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for EFFECTIVE_USER in config file"); - /* read items: EFFECTIVE-USER */ - GetConfigValue("EFFECTIVE_USER", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_USER in config file"); + strncpy(config->serverUser, val, FIELDSIZE); + config->serverUser[FIELDSIZE - 1] = '\0'; - strncpy(config->serverUser, val, FIELDSIZE); - config->serverUser[FIELDSIZE-1] = '\0'; + trace(TRACE_DEBUG, + "SetConfigItems(): effective user shall be [%s]", + config->serverUser); - trace(TRACE_DEBUG, "SetConfigItems(): effective user shall be [%s]", config->serverUser); + /* read items: EFFECTIVE-GROUP */ + GetConfigValue("EFFECTIVE_GROUP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for EFFECTIVE_GROUP in config file"); - /* read items: EFFECTIVE-GROUP */ - GetConfigValue("EFFECTIVE_GROUP", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_GROUP in config file"); + strncpy(config->serverGroup, val, FIELDSIZE); + config->serverGroup[FIELDSIZE - 1] = '\0'; - strncpy(config->serverGroup, val, FIELDSIZE); - config->serverGroup[FIELDSIZE-1] = '\0'; + trace(TRACE_DEBUG, + "SetConfigItems(): effective group shall be [%s]", + config->serverGroup); - trace(TRACE_DEBUG, "SetConfigItems(): effective group shall be [%s]", config->serverGroup); - } @@ -62,7 +62,8 @@ extern const char AcceptedMailboxnameChars[]; extern const char *month_desc[]; -char base64encodestring[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +char base64encodestring[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* returned by date_sql2imap() */ char _imapdate[IMAP_INTERNALDATE_LEN] = "03-Nov-1979 00:00:00"; @@ -70,19 +71,16 @@ char _imapdate[IMAP_INTERNALDATE_LEN] = "03-Nov-1979 00:00:00"; /* returned by date_imap2sql() */ char _sqldate[] = "1979-11-03 00:00:00"; -const int month_len[]= -{ - 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +const int month_len[] = { + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - -const char *item_desc[] = -{ - "TEXT", "HEADER", "MIME", "HEADER.FIELDS", "HEADER.FIELDS.NOT" + +const char *item_desc[] = { + "TEXT", "HEADER", "MIME", "HEADER.FIELDS", "HEADER.FIELDS.NOT" }; -const char *envelope_items[] = -{ - "from", "sender", "reply-to", "to", "cc", "bcc", NULL +const char *envelope_items[] = { + "from", "sender", "reply-to", "to", "cc", "bcc", NULL }; /* @@ -95,221 +93,221 @@ const char *envelope_items[] = * * returns -1 on error, 0 on success */ -int retrieve_structure(FILE *outstream, mime_message_t *msg, int show_extension_data) +int retrieve_structure(FILE * outstream, mime_message_t * msg, + int show_extension_data) { - struct mime_record *mr; - struct element *curr; - struct list *header_to_use; - mime_message_t rfcmsg; - char *subtype,*extension,*newline; - int is_mime_multipart = 0, is_rfc_multipart = 0; - int rfc822 = 0; - - fprintf(outstream,"("); - - mime_findfield("content-type", &msg->mimeheader, &mr); - is_mime_multipart = (mr && strncasecmp(mr->value,"multipart", strlen("multipart")) == 0 && - !msg->message_has_errors); - - mime_findfield("content-type", &msg->rfcheader, &mr); - is_rfc_multipart = (mr && strncasecmp(mr->value,"multipart", strlen("multipart")) == 0 && - !msg->message_has_errors); - - /* eddy */ - if (mr && strncasecmp(mr->value, "message/rfc822", strlen("message/rfc822")) == 0) - { - rfc822 = 1; - } - - - if (rfc822 || (!is_rfc_multipart && !is_mime_multipart) ) - { - /* show basic fields: - * content-type, content-subtype, (parameter list), - * content-id, content-description, content-transfer-encoding, - * size - */ - - if (msg->mimeheader.start == NULL) - header_to_use = &msg->rfcheader; /* we're dealing with a single-part RFC msg here */ - else - header_to_use = &msg->mimeheader; /* we're dealing with a pure-MIME header here */ - - mime_findfield("content-type", header_to_use, &mr); - if (mr && strlen(mr->value) > 0) - show_mime_parameter_list(outstream, mr, 1, 0); - else - fprintf(outstream, "\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\")"); /* default */ - - mime_findfield("content-id", header_to_use, &mr); - if (mr && strlen(mr->value) > 0) - { - fprintf(outstream, " "); - quoted_string_out(outstream, mr->value); - } - else - fprintf(outstream, " NIL"); - - mime_findfield("content-description", header_to_use, &mr); - if (mr && strlen(mr->value) > 0) - { - fprintf(outstream, " "); - quoted_string_out(outstream, mr->value); - } - else - fprintf(outstream, " NIL"); - - mime_findfield("content-transfer-encoding", header_to_use, &mr); - if (mr && strlen(mr->value) > 0) - { - fprintf(outstream, " "); - quoted_string_out(outstream, mr->value); - } - else - fprintf(outstream, " \"7BIT\""); - - /* now output size */ - /* add msg->bodylines because \n is dumped as \r\n */ - if (msg->mimeheader.start && msg->rfcheader.start) - fprintf(outstream, " %llu ", msg->bodysize + msg->mimerfclines + msg->rfcheadersize - - msg->rfcheaderlines); - else - fprintf(outstream, " %llu ", msg->bodysize + msg->bodylines); - - - /* now check special cases, first case: message/rfc822 */ - mime_findfield("content-type", header_to_use, &mr); - if (mr && strncasecmp(mr->value, "message/rfc822", strlen("message/rfc822")) == 0 && - header_to_use != &msg->rfcheader) - { - /* msg/rfc822 found; extra items to be displayed: - * (a) body envelope of rfc822 msg - * (b) body structure of rfc822 msg - * (c) msg size (lines) - */ - - if (retrieve_envelope(outstream, &msg->rfcheader) == -1) - return -1; - - fprintf(outstream, " "); - - memmove(&rfcmsg, msg, sizeof(rfcmsg)); - rfcmsg.mimeheader.start = NULL; /* forget MIME-part */ - - if (retrieve_structure(outstream, &rfcmsg, show_extension_data) == -1) - return -1; - - /* output # of lines */ - fprintf(outstream, " %llu", msg->bodylines); - } - /* now check second special case: text - * NOTE: if 'content-type' is absent, TEXT is assumed - */ - if ((mr && strncasecmp(mr->value, "text", strlen("text")) == 0) || !mr) - { - /* output # of lines */ - if (msg->mimeheader.start && msg->rfcheader.start) - fprintf(outstream, "%llu", msg->mimerfclines); - else - fprintf(outstream, "%llu", msg->bodylines); + struct mime_record *mr; + struct element *curr; + struct list *header_to_use; + mime_message_t rfcmsg; + char *subtype, *extension, *newline; + int is_mime_multipart = 0, is_rfc_multipart = 0; + int rfc822 = 0; + + fprintf(outstream, "("); + + mime_findfield("content-type", &msg->mimeheader, &mr); + is_mime_multipart = (mr + && strncasecmp(mr->value, "multipart", + strlen("multipart")) == 0 + && !msg->message_has_errors); + + mime_findfield("content-type", &msg->rfcheader, &mr); + is_rfc_multipart = (mr + && strncasecmp(mr->value, "multipart", + strlen("multipart")) == 0 + && !msg->message_has_errors); + + /* eddy */ + if (mr + && strncasecmp(mr->value, "message/rfc822", + strlen("message/rfc822")) == 0) { + rfc822 = 1; } - if (show_extension_data) - { - mime_findfield("content-md5", header_to_use, &mr); - if (mr && strlen(mr->value) > 0) - { - fprintf(outstream, " "); - quoted_string_out(outstream, mr->value); - } - else - fprintf(outstream, " NIL"); - - mime_findfield("content-disposition", header_to_use, &mr); - if (mr && strlen(mr->value) > 0) - { - fprintf(outstream, " ("); - show_mime_parameter_list(outstream, mr, 0, 0); - fprintf(outstream, ")"); - } - else - fprintf(outstream, " NIL"); - - mime_findfield("content-language", header_to_use, &mr); - if (mr && strlen(mr->value) > 0) - { - fprintf(outstream, " "); - quoted_string_out(outstream, mr->value); - } - else - fprintf(outstream, " NIL"); - } - } - else - { - /* check for a multipart message */ - if (is_rfc_multipart || is_mime_multipart) - { - curr = list_getstart(&msg->children); - while (curr) - { - if (retrieve_structure(outstream, (mime_message_t*)curr->data, - show_extension_data) == -1) - return -1; - curr = curr->nextnode; - } - - /* show multipart subtype */ - if (is_mime_multipart) - mime_findfield("content-type", &msg->mimeheader, &mr); - else - mime_findfield("content-type", &msg->rfcheader, &mr); - - subtype = strchr(mr->value, '/'); - extension = strchr(subtype, ';'); - - if (!subtype) - fprintf(outstream, " NIL"); - else - { - if (!extension) - { - newline = strchr(subtype, '\n'); - if (!newline) - return -1; - - *newline = 0; - fprintf(outstream, " "); - quoted_string_out(outstream, subtype+1); - *newline = '\n'; + if (rfc822 || (!is_rfc_multipart && !is_mime_multipart)) { + /* show basic fields: + * content-type, content-subtype, (parameter list), + * content-id, content-description, content-transfer-encoding, + * size + */ + + if (msg->mimeheader.start == NULL) + header_to_use = &msg->rfcheader; /* we're dealing with a single-part RFC msg here */ + else + header_to_use = &msg->mimeheader; /* we're dealing with a pure-MIME header here */ + + mime_findfield("content-type", header_to_use, &mr); + if (mr && strlen(mr->value) > 0) + show_mime_parameter_list(outstream, mr, 1, 0); + else + fprintf(outstream, "\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\")"); /* default */ + + mime_findfield("content-id", header_to_use, &mr); + if (mr && strlen(mr->value) > 0) { + fprintf(outstream, " "); + quoted_string_out(outstream, mr->value); + } else + fprintf(outstream, " NIL"); + + mime_findfield("content-description", header_to_use, &mr); + if (mr && strlen(mr->value) > 0) { + fprintf(outstream, " "); + quoted_string_out(outstream, mr->value); + } else + fprintf(outstream, " NIL"); + + mime_findfield("content-transfer-encoding", header_to_use, + &mr); + if (mr && strlen(mr->value) > 0) { + fprintf(outstream, " "); + quoted_string_out(outstream, mr->value); + } else + fprintf(outstream, " \"7BIT\""); + + /* now output size */ + /* add msg->bodylines because \n is dumped as \r\n */ + if (msg->mimeheader.start && msg->rfcheader.start) + fprintf(outstream, " %llu ", + msg->bodysize + msg->mimerfclines + + msg->rfcheadersize - msg->rfcheaderlines); + else + fprintf(outstream, " %llu ", + msg->bodysize + msg->bodylines); + + + /* now check special cases, first case: message/rfc822 */ + mime_findfield("content-type", header_to_use, &mr); + if (mr + && strncasecmp(mr->value, "message/rfc822", + strlen("message/rfc822")) == 0 + && header_to_use != &msg->rfcheader) { + /* msg/rfc822 found; extra items to be displayed: + * (a) body envelope of rfc822 msg + * (b) body structure of rfc822 msg + * (c) msg size (lines) + */ + + if (retrieve_envelope(outstream, &msg->rfcheader) + == -1) + return -1; + + fprintf(outstream, " "); + + memmove(&rfcmsg, msg, sizeof(rfcmsg)); + rfcmsg.mimeheader.start = NULL; /* forget MIME-part */ + + if (retrieve_structure + (outstream, &rfcmsg, + show_extension_data) == -1) + return -1; + + /* output # of lines */ + fprintf(outstream, " %llu", msg->bodylines); } - else - { - *extension = 0; - fprintf(outstream, " "); - quoted_string_out(outstream, subtype+1); - *extension = ';'; + /* now check second special case: text + * NOTE: if 'content-type' is absent, TEXT is assumed + */ + if ((mr + && strncasecmp(mr->value, "text", + strlen("text")) == 0) || !mr) { + /* output # of lines */ + if (msg->mimeheader.start && msg->rfcheader.start) + fprintf(outstream, "%llu", + msg->mimerfclines); + else + fprintf(outstream, "%llu", msg->bodylines); } - } - /* show extension data (after subtype) */ - if (extension && show_extension_data) - { - show_mime_parameter_list(outstream, mr, 0, 1); + if (show_extension_data) { + mime_findfield("content-md5", header_to_use, &mr); + if (mr && strlen(mr->value) > 0) { + fprintf(outstream, " "); + quoted_string_out(outstream, mr->value); + } else + fprintf(outstream, " NIL"); + + mime_findfield("content-disposition", + header_to_use, &mr); + if (mr && strlen(mr->value) > 0) { + fprintf(outstream, " ("); + show_mime_parameter_list(outstream, mr, 0, + 0); + fprintf(outstream, ")"); + } else + fprintf(outstream, " NIL"); + + mime_findfield("content-language", header_to_use, + &mr); + if (mr && strlen(mr->value) > 0) { + fprintf(outstream, " "); + quoted_string_out(outstream, mr->value); + } else + fprintf(outstream, " NIL"); + } + } else { + /* check for a multipart message */ + if (is_rfc_multipart || is_mime_multipart) { + curr = list_getstart(&msg->children); + while (curr) { + if (retrieve_structure + (outstream, + (mime_message_t *) curr->data, + show_extension_data) == -1) + return -1; - /* FIXME: should give body-disposition & body-language here */ - fprintf(outstream, " NIL NIL"); - } - } - else - { - /* ??? */ + curr = curr->nextnode; + } + + /* show multipart subtype */ + if (is_mime_multipart) + mime_findfield("content-type", + &msg->mimeheader, &mr); + else + mime_findfield("content-type", + &msg->rfcheader, &mr); + + subtype = strchr(mr->value, '/'); + extension = strchr(subtype, ';'); + + if (!subtype) + fprintf(outstream, " NIL"); + else { + if (!extension) { + newline = strchr(subtype, '\n'); + if (!newline) + return -1; + + *newline = 0; + fprintf(outstream, " "); + quoted_string_out(outstream, + subtype + 1); + *newline = '\n'; + } else { + *extension = 0; + fprintf(outstream, " "); + quoted_string_out(outstream, + subtype + 1); + *extension = ';'; + } + } + + /* show extension data (after subtype) */ + if (extension && show_extension_data) { + show_mime_parameter_list(outstream, mr, 0, + 1); + + /* FIXME: should give body-disposition & body-language here */ + fprintf(outstream, " NIL NIL"); + } + } else { + /* ??? */ + } } - } - fprintf(outstream,")"); + fprintf(outstream, ")"); - return 0; + return 0; } @@ -320,84 +318,74 @@ int retrieve_structure(FILE *outstream, mime_message_t *msg, int show_extension_ * * returns -1 on error, 0 on success */ -int retrieve_envelope(FILE *outstream, struct list *rfcheader) +int retrieve_envelope(FILE * outstream, struct list *rfcheader) { - struct mime_record *mr; - int idx; - - fprintf(outstream,"("); - - mime_findfield("date", rfcheader, &mr); - if (mr && strlen(mr->value) > 0) - { - quoted_string_out(outstream, mr->value); - fprintf(outstream, " "); - } - else - fprintf(outstream, "NIL "); - - mime_findfield("subject", rfcheader, &mr); - if (mr && strlen(mr->value) > 0) - { - quoted_string_out(outstream, mr->value); - fprintf(outstream, " "); - } - else - fprintf(outstream, "NIL "); - - /* now from, sender, reply-to, to, cc, bcc, in-reply-to fields; - * note that multiple mailaddresses are separated by ',' - */ - - for (idx=0; envelope_items[idx]; idx++) - { - mime_findfield(envelope_items[idx], rfcheader, &mr); - if (mr && strlen(mr->value) > 0) - { - show_address_list(outstream, mr); + struct mime_record *mr; + int idx; + + fprintf(outstream, "("); + + mime_findfield("date", rfcheader, &mr); + if (mr && strlen(mr->value) > 0) { + quoted_string_out(outstream, mr->value); + fprintf(outstream, " "); + } else + fprintf(outstream, "NIL "); + + mime_findfield("subject", rfcheader, &mr); + if (mr && strlen(mr->value) > 0) { + quoted_string_out(outstream, mr->value); + fprintf(outstream, " "); + } else + fprintf(outstream, "NIL "); + + /* now from, sender, reply-to, to, cc, bcc, in-reply-to fields; + * note that multiple mailaddresses are separated by ',' + */ + + for (idx = 0; envelope_items[idx]; idx++) { + mime_findfield(envelope_items[idx], rfcheader, &mr); + if (mr && strlen(mr->value) > 0) { + show_address_list(outstream, mr); + } else if (strcasecmp(envelope_items[idx], "reply-to") == + 0) { + /* default this field */ + mime_findfield("from", rfcheader, &mr); + if (mr && strlen(mr->value) > 0) + show_address_list(outstream, mr); + else /* no from field ??? */ + fprintf(outstream, + "((NIL NIL \"nobody\" \"nowhere.nirgendwo\"))"); + } else if (strcasecmp(envelope_items[idx], "sender") == 0) { + /* default this field */ + mime_findfield("from", rfcheader, &mr); + if (mr && strlen(mr->value) > 0) + show_address_list(outstream, mr); + else /* no from field ??? */ + fprintf(outstream, + "((NIL NIL \"nobody\" \"nowhere.nirgendwo\"))"); + } else + fprintf(outstream, "NIL"); + + fprintf(outstream, " "); } - else if (strcasecmp(envelope_items[idx], "reply-to") == 0) - { - /* default this field */ - mime_findfield("from", rfcheader, &mr); - if (mr && strlen(mr->value) > 0) - show_address_list(outstream, mr); - else /* no from field ??? */ - fprintf(outstream, "((NIL NIL \"nobody\" \"nowhere.nirgendwo\"))"); - } - else if (strcasecmp(envelope_items[idx], "sender") == 0) - { - /* default this field */ - mime_findfield("from", rfcheader, &mr); - if (mr && strlen(mr->value) > 0) - show_address_list(outstream, mr); - else /* no from field ??? */ - fprintf(outstream, "((NIL NIL \"nobody\" \"nowhere.nirgendwo\"))"); - } - else - fprintf(outstream, "NIL"); - - fprintf(outstream, " "); - } - - mime_findfield("in-reply-to", rfcheader, &mr); - if (mr && strlen(mr->value) > 0) - { - quoted_string_out(outstream, mr->value); - fprintf(outstream, " "); - } - else - fprintf(outstream, "NIL "); - - mime_findfield("message-id", rfcheader, &mr); - if (mr && strlen(mr->value) > 0) - quoted_string_out(outstream, mr->value); - else - fprintf(outstream, "NIL"); - - fprintf(outstream,")"); - - return 0; + + mime_findfield("in-reply-to", rfcheader, &mr); + if (mr && strlen(mr->value) > 0) { + quoted_string_out(outstream, mr->value); + fprintf(outstream, " "); + } else + fprintf(outstream, "NIL "); + + mime_findfield("message-id", rfcheader, &mr); + if (mr && strlen(mr->value) > 0) + quoted_string_out(outstream, mr->value); + else + fprintf(outstream, "NIL"); + + fprintf(outstream, ")"); + + return 0; } @@ -406,109 +394,107 @@ int retrieve_envelope(FILE *outstream, struct list *rfcheader) * * gives an address list, output to outstream */ -int show_address_list(FILE *outstream, struct mime_record *mr) +int show_address_list(FILE * outstream, struct mime_record *mr) { - int delimiter,i,inquote,start,has_split; - char savechar; - - fprintf(outstream,"("); - - /* find ',' to split up multiple addresses */ - delimiter = 0; - - do - { - fprintf(outstream,"("); - - start = delimiter; - - for (inquote=0; mr->value[delimiter] && !(mr->value[delimiter] == ',' && !inquote); - delimiter++) - if (mr->value[delimiter] == '\"') inquote ^= 1; - - if (mr->value[delimiter]) - mr->value[delimiter] = 0; /* replace ',' by NULL-termination */ - else - delimiter = -1; /* this will be the last one */ - - /* the address currently being processed is now contained within - * &mr->value[start] 'till first '\0' - */ - - /* possibilities for the mail address: - * (1) name <user@domain> - * (2) <user@domain> - * (3) user@domain - * scan for '<' to determine which case we should be dealing with; - */ - - for (i=start, inquote=0; mr->value[i] && !(mr->value[i] == '<' && !inquote); i++) - if (mr->value[i] == '\"') inquote ^= 1; - - if (mr->value[i]) - { - if (i > start+2) - { - /* name is contained in &mr->value[start] untill &mr->value[i-2] */ - /* name might contain quotes */ - savechar = mr->value[i-1]; - mr->value[i-1] = '\0'; /* terminate string */ - - quoted_string_out(outstream, &mr->value[start]); - - mr->value[i-1] = savechar; - - } - else - fprintf(outstream, "NIL"); - - start = i+1; /* skip to after '<' */ - } - else - fprintf(outstream, "NIL"); - - fprintf(outstream, " NIL "); /* source route ?? smtp at-domain-list ?? */ - - /* now display user domainname; &mr->value[start] is starting point */ - fprintf(outstream, "\""); - - /* - * added a check for whitespace within the address (not good) - */ - for (i=start, has_split=0; mr->value[i] && mr->value[i] != '>' && !isspace(mr->value[i]); - i++) - { - if (mr->value[i] == '@') - { - fprintf(outstream,"\" \""); - has_split = 1; - } - else - { - if (mr->value[i] == '"') - fprintf(outstream, "\\"); - fprintf(outstream,"%c",mr->value[i]); - } - } + int delimiter, i, inquote, start, has_split; + char savechar; + + fprintf(outstream, "("); + + /* find ',' to split up multiple addresses */ + delimiter = 0; + + do { + fprintf(outstream, "("); + + start = delimiter; + + for (inquote = 0; + mr->value[delimiter] && !(mr->value[delimiter] == ',' + && !inquote); delimiter++) + if (mr->value[delimiter] == '\"') + inquote ^= 1; + + if (mr->value[delimiter]) + mr->value[delimiter] = 0; /* replace ',' by NULL-termination */ + else + delimiter = -1; /* this will be the last one */ + + /* the address currently being processed is now contained within + * &mr->value[start] 'till first '\0' + */ + + /* possibilities for the mail address: + * (1) name <user@domain> + * (2) <user@domain> + * (3) user@domain + * scan for '<' to determine which case we should be dealing with; + */ + + for (i = start, inquote = 0; + mr->value[i] && !(mr->value[i] == '<' && !inquote); + i++) + if (mr->value[i] == '\"') + inquote ^= 1; + + if (mr->value[i]) { + if (i > start + 2) { + /* name is contained in &mr->value[start] untill &mr->value[i-2] */ + /* name might contain quotes */ + savechar = mr->value[i - 1]; + mr->value[i - 1] = '\0'; /* terminate string */ + + quoted_string_out(outstream, + &mr->value[start]); + + mr->value[i - 1] = savechar; + + } else + fprintf(outstream, "NIL"); + + start = i + 1; /* skip to after '<' */ + } else + fprintf(outstream, "NIL"); + + fprintf(outstream, " NIL "); /* source route ?? smtp at-domain-list ?? */ + + /* now display user domainname; &mr->value[start] is starting point */ + fprintf(outstream, "\""); + + /* + * added a check for whitespace within the address (not good) + */ + for (i = start, has_split = 0; + mr->value[i] && mr->value[i] != '>' + && !isspace(mr->value[i]); i++) { + if (mr->value[i] == '@') { + fprintf(outstream, "\" \""); + has_split = 1; + } else { + if (mr->value[i] == '"') + fprintf(outstream, "\\"); + fprintf(outstream, "%c", mr->value[i]); + } + } - if (!has_split) - fprintf(outstream,"\" \"\""); /* '@' did not occur */ - else - fprintf(outstream, "\""); - - if (delimiter > 0) - { - mr->value[delimiter++] = ','; /* restore & prepare for next iteration */ - while (isspace(mr->value[delimiter])) delimiter++; - } + if (!has_split) + fprintf(outstream, "\" \"\""); /* '@' did not occur */ + else + fprintf(outstream, "\""); - fprintf(outstream, ")"); + if (delimiter > 0) { + mr->value[delimiter++] = ','; /* restore & prepare for next iteration */ + while (isspace(mr->value[delimiter])) + delimiter++; + } + + fprintf(outstream, ")"); + + } while (delimiter > 0); - } while (delimiter > 0) ; - - fprintf(outstream,")"); + fprintf(outstream, ")"); - return 0; + return 0; } @@ -521,140 +507,149 @@ int show_address_list(FILE *outstream, struct mime_record *mr) * if force_subtype != 0 'NIL' will be outputted if no subtype is specified * if only_extension != 0 only extension data (after first ';') will be shown */ -int show_mime_parameter_list(FILE *outstream, struct mime_record *mr, +int show_mime_parameter_list(FILE * outstream, struct mime_record *mr, int force_subtype, int only_extension) { - int idx,delimiter,start,end; - - /* find first delimiter */ - for (delimiter = 0; mr->value[delimiter] && mr->value[delimiter] != ';'; delimiter++) ; - - /* are there non-whitespace chars after the delimiter? */ - /* looking for the case where the mime type ends with a ";" */ - /* if it is of type "text" it must have a default character set generated */ - end = strlen(mr->value); - for (start = delimiter+1; (isspace(mr->value[start])==0 && start<=end) ; start++ ); - end = start - delimiter - 1; - start = 0; - if ( end && strstr(mr->value,"text") ) start++; - - if (mr->value[delimiter]) - mr->value[delimiter] = 0; - else - delimiter = -1; - - if (!only_extension) - { - /* find main type in value */ - for (idx = 0; mr->value[idx] && mr->value[idx] != '/'; idx++) ; - - if (mr->value[idx] && (idx<delimiter || delimiter == -1)) - { - mr->value[idx] = 0; - - quoted_string_out(outstream, mr->value); - fprintf(outstream, " "); - quoted_string_out(outstream, &mr->value[idx+1]); - - mr->value[idx] = '/'; - } - else - { - quoted_string_out(outstream, mr->value); - fprintf(outstream," %s", force_subtype ? "NIL" : ""); + int idx, delimiter, start, end; + + /* find first delimiter */ + for (delimiter = 0; + mr->value[delimiter] && mr->value[delimiter] != ';'; + delimiter++); + + /* are there non-whitespace chars after the delimiter? */ + /* looking for the case where the mime type ends with a ";" */ + /* if it is of type "text" it must have a default character set generated */ + end = strlen(mr->value); + for (start = delimiter + 1; + (isspace(mr->value[start]) == 0 && start <= end); start++); + end = start - delimiter - 1; + start = 0; + if (end && strstr(mr->value, "text")) + start++; + + if (mr->value[delimiter]) + mr->value[delimiter] = 0; + else + delimiter = -1; + + if (!only_extension) { + /* find main type in value */ + for (idx = 0; mr->value[idx] && mr->value[idx] != '/'; + idx++); + + if (mr->value[idx] && (idx < delimiter || delimiter == -1)) { + mr->value[idx] = 0; + + quoted_string_out(outstream, mr->value); + fprintf(outstream, " "); + quoted_string_out(outstream, &mr->value[idx + 1]); + + mr->value[idx] = '/'; + } else { + quoted_string_out(outstream, mr->value); + fprintf(outstream, " %s", + force_subtype ? "NIL" : ""); + } } - } - - if (delimiter >= 0) - { - /* extra parameters specified */ - mr->value[delimiter] = ';'; - idx=delimiter; - - fprintf(outstream," ("); - - if ( start ) fprintf(outstream,"\"CHARSET\" \"US-ASCII\""); - /* extra params: <name>=<val> [; <name>=<val> [; ...etc...]] - * note that both name and val may or may not be enclosed by - * either single or double quotation marks - */ - - do - { - /* skip whitespace */ - for (idx++; isspace(mr->value[idx]); idx++) ; - - if (!mr->value[idx]) break; /* ?? */ - - /* check if quotation marks are specified */ - if (mr->value[idx] == '\"' || mr->value[idx] == '\'') - { - start = ++idx; - while (mr->value[idx] && mr->value[idx] != mr->value[start-1]) idx++; - - if (!mr->value[idx] || mr->value[idx+1] != '=') /* ?? no end quote */ - break; - end = idx; - idx+=2; /* skip to after '=' */ - } - else - { - start = idx; - while (mr->value[idx] && mr->value[idx] != '=') idx++; - - if (!mr->value[idx]) /* ?? no value specified */ - break; - - end = idx; - idx++; /* skip to after '=' */ - } + if (delimiter >= 0) { + /* extra parameters specified */ + mr->value[delimiter] = ';'; + idx = delimiter; + + fprintf(outstream, " ("); + + if (start) + fprintf(outstream, "\"CHARSET\" \"US-ASCII\""); + /* extra params: <name>=<val> [; <name>=<val> [; ...etc...]] + * note that both name and val may or may not be enclosed by + * either single or double quotation marks + */ + + do { + /* skip whitespace */ + for (idx++; isspace(mr->value[idx]); idx++); + + if (!mr->value[idx]) + break; /* ?? */ + + /* check if quotation marks are specified */ + if (mr->value[idx] == '\"' + || mr->value[idx] == '\'') { + start = ++idx; + while (mr->value[idx] + && mr->value[idx] != + mr->value[start - 1]) + idx++; + + if (!mr->value[idx] || mr->value[idx + 1] != '=') /* ?? no end quote */ + break; + + end = idx; + idx += 2; /* skip to after '=' */ + } else { + start = idx; + while (mr->value[idx] + && mr->value[idx] != '=') + idx++; + + if (!mr->value[idx]) /* ?? no value specified */ + break; + + end = idx; + idx++; /* skip to after '=' */ + } - fprintf(outstream,"\"%.*s\" ", (end-start), &mr->value[start]); + fprintf(outstream, "\"%.*s\" ", (end - start), + &mr->value[start]); - /* now process the value; practically same procedure */ + /* now process the value; practically same procedure */ - if (mr->value[idx] == '\"' || mr->value[idx] == '\'') - { - start = ++idx; - while (mr->value[idx] && mr->value[idx] != mr->value[start-1]) idx++; - - if (!mr->value[idx]) /* ?? no end quote */ - break; + if (mr->value[idx] == '\"' + || mr->value[idx] == '\'') { + start = ++idx; + while (mr->value[idx] + && mr->value[idx] != + mr->value[start - 1]) + idx++; + + if (!mr->value[idx]) /* ?? no end quote */ + break; - end = idx; - idx++; - } - else - { - start = idx; - - while (mr->value[idx] && !isspace(mr->value[idx]) && - mr->value[idx] != ';') idx++; - - end = idx; - } - - fprintf(outstream,"\"%.*s\"", (end-start), &mr->value[start]); - - /* check for more name/val pairs */ - while (mr->value[idx] && mr->value[idx] != ';') idx++; - - if (mr->value[idx]) - fprintf(outstream," "); - - } while (mr->value[idx]); - - fprintf(outstream,")"); - - } - else - { - fprintf(outstream," NIL"); - } - - return 0; + end = idx; + idx++; + } else { + start = idx; + + while (mr->value[idx] + && !isspace(mr->value[idx]) + && mr->value[idx] != ';') + idx++; + + end = idx; + } + + fprintf(outstream, "\"%.*s\"", (end - start), + &mr->value[start]); + + /* check for more name/val pairs */ + while (mr->value[idx] && mr->value[idx] != ';') + idx++; + + if (mr->value[idx]) + fprintf(outstream, " "); + + } while (mr->value[idx]); + + fprintf(outstream, ")"); + + } else { + fprintf(outstream, " NIL"); + } + + return 0; } @@ -665,27 +660,28 @@ int show_mime_parameter_list(FILE *outstream, struct mime_record *mr, * 'part' is assumed to be valid! (i.e '1.2.3.44') * returns NULL if there is no such part */ -mime_message_t* get_part_by_num(mime_message_t *msg, const char *part) +mime_message_t *get_part_by_num(mime_message_t * msg, const char *part) { - int nextpart,j; - char *endptr; - struct element *curr; + int nextpart, j; + char *endptr; + struct element *curr; - if (part == NULL || strlen(part) == 0 || msg == NULL) - return msg; + if (part == NULL || strlen(part) == 0 || msg == NULL) + return msg; - nextpart = strtoul(part, &endptr, 10); /* strtoul() stops at '.' */ + nextpart = strtoul(part, &endptr, 10); /* strtoul() stops at '.' */ - for (j=1, curr=list_getstart(&msg->children); j<nextpart && curr; j++, curr = curr->nextnode); + for (j = 1, curr = list_getstart(&msg->children); + j < nextpart && curr; j++, curr = curr->nextnode); - if (!curr) - return NULL; + if (!curr) + return NULL; - if (*endptr) - return get_part_by_num((mime_message_t*)curr->data, &endptr[1]); /* skip dot in part */ + if (*endptr) + return get_part_by_num((mime_message_t *) curr->data, &endptr[1]); /* skip dot in part */ - return (mime_message_t*)curr->data; -} + return (mime_message_t *) curr->data; +} /* @@ -701,41 +697,41 @@ mime_message_t* get_part_by_num(mime_message_t *msg, const char *part) * * returns number of bytes written to outmem */ -u64_t rfcheader_dump(MEM *outmem, struct list *rfcheader, char **fieldnames, int nfields, - int equal_type) +u64_t rfcheader_dump(MEM * outmem, struct list * rfcheader, + char **fieldnames, int nfields, int equal_type) { - struct mime_record *mr; - struct element *curr; - u64_t size = 0; - - curr = list_getstart(rfcheader); - if (rfcheader == NULL || curr == NULL) - { - /*size += fprintf(outstream, "NIL\r\n");*/ - return 0; - } - - curr = list_getstart(rfcheader); - while (curr) - { - mr = (struct mime_record*)curr->data; - - if (haystack_find(nfields, fieldnames, mr->field) == equal_type) - { - /* ok output this field */ - size += mwrite(mr->field, strlen(mr->field), outmem); - size += mwrite(": ", 2, outmem); - size += mwrite(mr->value, strlen(mr->value), outmem); - size += mwrite("\r\n", 2, outmem); + struct mime_record *mr; + struct element *curr; + u64_t size = 0; + + curr = list_getstart(rfcheader); + if (rfcheader == NULL || curr == NULL) { + /*size += fprintf(outstream, "NIL\r\n"); */ + return 0; + } + + curr = list_getstart(rfcheader); + while (curr) { + mr = (struct mime_record *) curr->data; + + if (haystack_find(nfields, fieldnames, mr->field) == + equal_type) { + /* ok output this field */ + size += + mwrite(mr->field, strlen(mr->field), outmem); + size += mwrite(": ", 2, outmem); + size += + mwrite(mr->value, strlen(mr->value), outmem); + size += mwrite("\r\n", 2, outmem); + } + + curr = curr->nextnode; } + size += mwrite("\r\n", 2, outmem); + + return size; +} - curr = curr->nextnode; - } - size += mwrite("\r\n", 2, outmem); - - return size; -} - /* * mimeheader_dump() @@ -743,32 +739,30 @@ u64_t rfcheader_dump(MEM *outmem, struct list *rfcheader, char **fieldnames, int * dumps mime-header fields belonging to mimeheader * */ -u64_t mimeheader_dump(MEM *outmem, struct list *mimeheader) +u64_t mimeheader_dump(MEM * outmem, struct list * mimeheader) { - struct mime_record *mr; - struct element *curr; - u64_t size = 0; - - curr = list_getstart(mimeheader); - if (mimeheader == NULL || curr == NULL) - { - /*size = fprintf(outstream, "NIL\r\n");*/ - return 0; - } - - while (curr) - { - mr = (struct mime_record*)curr->data; - size += mwrite(mr->field, strlen(mr->field), outmem); - size += mwrite(": ", 2, outmem); - size += mwrite(mr->value, strlen(mr->value), outmem); - size += mwrite("\r\n", 2, outmem); - curr = curr->nextnode; - } - size += mwrite("\r\n", 2, outmem); - - return size; -} + struct mime_record *mr; + struct element *curr; + u64_t size = 0; + + curr = list_getstart(mimeheader); + if (mimeheader == NULL || curr == NULL) { + /*size = fprintf(outstream, "NIL\r\n"); */ + return 0; + } + + while (curr) { + mr = (struct mime_record *) curr->data; + size += mwrite(mr->field, strlen(mr->field), outmem); + size += mwrite(": ", 2, outmem); + size += mwrite(mr->value, strlen(mr->value), outmem); + size += mwrite("\r\n", 2, outmem); + curr = curr->nextnode; + } + size += mwrite("\r\n", 2, outmem); + + return size; +} /* @@ -776,13 +770,13 @@ u64_t mimeheader_dump(MEM *outmem, struct list *mimeheader) */ int haystack_find(int haystacklen, char **haystack, const char *needle) { - int i; + int i; - for (i=0; i<haystacklen; i++) - if (strcasecmp(haystack[i], needle) == 0) - return 1; + for (i = 0; i < haystacklen; i++) + if (strcasecmp(haystack[i], needle) == 0) + return 1; - return 0; + return 0; } @@ -794,336 +788,308 @@ int haystack_find(int haystacklen, char **haystack, const char *needle) * arglist is supposed to be formatted according to build_args_array() * */ -int next_fetch_item(char **args, int idx, fetch_items_t *fi) +int next_fetch_item(char **args, int idx, fetch_items_t * fi) { - int invalidargs,indigit,ispeek,shouldclose,delimpos; - unsigned int j = 0; - - memset(fi, 0, sizeof(fetch_items_t)); /* init */ - fi->bodyfetch.itemtype = -1; /* expect no body fetches (a priori) */ - invalidargs = 0; - - if (!args[idx]) - return -1; /* no more */ - - if (args[idx][0] == '(') - idx++; - - if (!args[idx]) - return -2; /* error */ - - if (strcasecmp(args[idx], "flags") == 0) - fi->getFlags = 1; - else if (strcasecmp(args[idx], "internaldate") == 0) - fi->getInternalDate = 1; - else if (strcasecmp(args[idx], "uid") == 0) - fi->getUID = 1; - else if (strcasecmp(args[idx], "rfc822") == 0) - { - fi->getRFC822 = 1; - fi->msgparse_needed = 1; - } - else if (strcasecmp(args[idx], "rfc822.peek") == 0) - { - fi->getRFC822Peek = 1; - fi->msgparse_needed = 1; - } - else if (strcasecmp(args[idx], "rfc822.header") == 0) - { - fi->getRFC822Header = 1; - fi->msgparse_needed = 1; - } - else if (strcasecmp(args[idx], "rfc822.size") == 0) - { - fi->getSize = 1; -/* fi->msgparse_needed = 1;*/ /* after first calc, it will be in the dbase */ - } - else if (strcasecmp(args[idx], "rfc822.text") == 0) - { - fi->getRFC822Text = 1; - fi->msgparse_needed = 1; - } - else if (strcasecmp(args[idx], "body") == 0 || strcasecmp(args[idx],"body.peek") == 0) - { - fi->msgparse_needed = 1; - - if (!args[idx+1] || strcmp(args[idx+1],"[") != 0) - { - if (strcasecmp(args[idx],"body.peek") == 0) - return -2; /* error DONE */ - else - fi->getMIME_IMB_noextension = 1; /* just BODY specified */ - } - else - { - /* determine wheter or not to set the seen flag */ - ispeek = (strcasecmp(args[idx],"body.peek") == 0); - - /* now read the argument list to body */ - idx++; /* now pointing at '[' (not the last arg, parentheses are matched) */ - idx++; /* now pointing at what should be the item type */ - - if (strcmp(args[idx], "]") == 0) - { - /* specified body[] or body.peek[] */ - if (ispeek) - fi->getBodyTotalPeek = 1; - else - fi->getBodyTotal = 1; - - /* check if octet start/cnt is specified */ - if (args[idx+1] && args[idx+1][0] == '<') - { - idx++; /* advance */ - - /* check argument */ - if (args[idx][strlen(args[idx]) - 1 ] != '>') - return -2; /* error DONE */ - - delimpos = -1; - for (j=1; j < strlen(args[idx])-1; j++) - { - if (args[idx][j] == '.') - { - if (delimpos != -1) - { - invalidargs = 1; - break; - } - delimpos = j; + int invalidargs, indigit, ispeek, shouldclose, delimpos; + unsigned int j = 0; + + memset(fi, 0, sizeof(fetch_items_t)); /* init */ + fi->bodyfetch.itemtype = -1; /* expect no body fetches (a priori) */ + invalidargs = 0; + + if (!args[idx]) + return -1; /* no more */ + + if (args[idx][0] == '(') + idx++; + + if (!args[idx]) + return -2; /* error */ + + if (strcasecmp(args[idx], "flags") == 0) + fi->getFlags = 1; + else if (strcasecmp(args[idx], "internaldate") == 0) + fi->getInternalDate = 1; + else if (strcasecmp(args[idx], "uid") == 0) + fi->getUID = 1; + else if (strcasecmp(args[idx], "rfc822") == 0) { + fi->getRFC822 = 1; + fi->msgparse_needed = 1; + } else if (strcasecmp(args[idx], "rfc822.peek") == 0) { + fi->getRFC822Peek = 1; + fi->msgparse_needed = 1; + } else if (strcasecmp(args[idx], "rfc822.header") == 0) { + fi->getRFC822Header = 1; + fi->msgparse_needed = 1; + } else if (strcasecmp(args[idx], "rfc822.size") == 0) { + fi->getSize = 1; +/* fi->msgparse_needed = 1;*//* after first calc, it will be in the dbase */ + } else if (strcasecmp(args[idx], "rfc822.text") == 0) { + fi->getRFC822Text = 1; + fi->msgparse_needed = 1; + } else if (strcasecmp(args[idx], "body") == 0 + || strcasecmp(args[idx], "body.peek") == 0) { + fi->msgparse_needed = 1; + + if (!args[idx + 1] || strcmp(args[idx + 1], "[") != 0) { + if (strcasecmp(args[idx], "body.peek") == 0) + return -2; /* error DONE */ + else + fi->getMIME_IMB_noextension = 1; /* just BODY specified */ + } else { + /* determine wheter or not to set the seen flag */ + ispeek = (strcasecmp(args[idx], "body.peek") == 0); + + /* now read the argument list to body */ + idx++; /* now pointing at '[' (not the last arg, parentheses are matched) */ + idx++; /* now pointing at what should be the item type */ + + if (strcmp(args[idx], "]") == 0) { + /* specified body[] or body.peek[] */ + if (ispeek) + fi->getBodyTotalPeek = 1; + else + fi->getBodyTotal = 1; + + /* check if octet start/cnt is specified */ + if (args[idx + 1] + && args[idx + 1][0] == '<') { + idx++; /* advance */ + + /* check argument */ + if (args[idx] + [strlen(args[idx]) - 1] != '>') + return -2; /* error DONE */ + + delimpos = -1; + for (j = 1; + j < strlen(args[idx]) - 1; + j++) { + if (args[idx][j] == '.') { + if (delimpos != -1) { + invalidargs + = 1; + break; + } + delimpos = j; + } else + if (!isdigit + (args[idx][j])) { + invalidargs = 1; + break; + } + } + + if (invalidargs || delimpos == -1 + || delimpos == 1 + || delimpos == + (int) (strlen(args[idx]) - 2)) + return -2; /* no delimiter found or at first/last pos OR invalid args DONE */ + + /* read the numbers */ + args[idx][strlen(args[idx]) - 1] = + '\0'; + args[idx][delimpos] = '\0'; + fi->bodyfetch.octetstart = + strtoll(&args[idx][1], NULL, + 10); + fi->bodyfetch.octetcnt = + strtoll(&args[idx] + [delimpos + 1], NULL, + 10); + + /* restore argument */ + args[idx][delimpos] = '.'; + args[idx][strlen(args[idx]) - 1] = + '>'; + } else { + fi->bodyfetch.octetstart = -1; + fi->bodyfetch.octetcnt = -1; + } + + return idx + 1; /* DONE */ } - else if (!isdigit(args[idx][j])) - { - invalidargs = 1; - break; + + if (ispeek) + fi->bodyfetch.noseen = 1; + + /* check for a partspecifier */ + /* first check if there is a partspecifier (numbers & dots) */ + indigit = 0; + + for (j = 0; args[idx][j]; j++) { + if (isdigit(args[idx][j])) { + indigit = 1; + continue; + } else if (args[idx][j] == '.') { + if (!indigit) { + /* error, single dot specified */ + invalidargs = 1; + break; + } + + indigit = 0; + continue; + } else + break; /* other char found */ } - } - - if (invalidargs || delimpos == -1 || delimpos == 1 || - delimpos == (int) (strlen(args[idx])-2) ) - return -2; /* no delimiter found or at first/last pos OR invalid args DONE */ - - /* read the numbers */ - args[idx][strlen(args[idx]) - 1] = '\0'; - args[idx][delimpos] = '\0'; - fi->bodyfetch.octetstart = strtoll(&args[idx][1], NULL, 10); - fi->bodyfetch.octetcnt = strtoll(&args[idx][delimpos+1], NULL, 10); - - /* restore argument */ - args[idx][delimpos] = '.'; - args[idx][strlen(args[idx]) - 1] = '>'; - } - else - { - fi->bodyfetch.octetstart = -1; - fi->bodyfetch.octetcnt = -1; - } - - return idx+1; /* DONE */ - } - - if (ispeek) - fi->bodyfetch.noseen = 1; - - /* check for a partspecifier */ - /* first check if there is a partspecifier (numbers & dots) */ - indigit = 0; - - for (j=0; args[idx][j]; j++) - { - if (isdigit(args[idx][j])) - { - indigit = 1; - continue; - } - else if (args[idx][j] == '.') - { - if (!indigit) - { - /* error, single dot specified */ - invalidargs = 1; - break; - } - - indigit = 0; - continue; - } - else - break; /* other char found */ - } - - if (invalidargs) - return -2; /* error DONE */ - - if (j > 0) - { - if (indigit && args[idx][j]) - return -2; /* error DONE */ - - /* partspecifier present, save it */ - if (j >= IMAP_MAX_PARTSPEC_LEN) - return -2; /* error DONE */ - - strncpy(fi->bodyfetch.partspec, args[idx], j); - } - - fi->bodyfetch.partspec[j] = '\0'; - - - shouldclose = 0; - if (strcasecmp(&args[idx][j], "text") == 0) - { - fi->bodyfetch.itemtype = BFIT_TEXT; - shouldclose = 1; - } - else if (strcasecmp(&args[idx][j], "header") == 0) - { - fi->bodyfetch.itemtype = BFIT_HEADER; - shouldclose = 1; - } - else if (strcasecmp(&args[idx][j], "mime") == 0) - { - if (j == 0) - return -2; /* error DONE */ - - fi->bodyfetch.itemtype = BFIT_MIME; - shouldclose = 1; - } - else if (strcasecmp(&args[idx][j], "header.fields") == 0) - fi->bodyfetch.itemtype = BFIT_HEADER_FIELDS; - else if (strcasecmp(&args[idx][j], "header.fields.not") == 0) - fi->bodyfetch.itemtype = BFIT_HEADER_FIELDS_NOT; - else if (args[idx][j] == '\0') - { - fi->bodyfetch.itemtype = BFIT_TEXT_SILENT; - shouldclose = 1; - } - else - return -2; /* error DONE */ - - if (shouldclose) - { - if (strcmp(args[idx+1],"]") != 0) - return -2; /* error DONE */ - } - else - { - idx++; /* should be at '(' now */ - if (strcmp(args[idx],"(") != 0) - return -2; /* error DONE */ - - idx++; /* at first item of field list now, remember idx */ - fi->bodyfetch.argstart = idx; - - /* walk on untill list terminates (and it does 'cause parentheses are matched) */ - while (strcmp(args[idx],")") != 0) - idx++; - fi->bodyfetch.argcnt = idx - fi->bodyfetch.argstart; - - if (fi->bodyfetch.argcnt == 0 || strcmp(args[idx+1],"]") != 0) - return -2; /* error DONE */ - } - - idx++; /* points to ']' now */ - - /* check if octet start/cnt is specified */ - if (args[idx+1] && args[idx+1][0] == '<') - { - idx++; /* advance */ - - /* check argument */ - if (args[idx][strlen(args[idx]) - 1 ] != '>') - return -2; /* error DONE */ - - delimpos = -1; - for (j=1; j < strlen(args[idx])-1; j++) - { - if (args[idx][j] == '.') - { - if (delimpos != -1) - { - invalidargs = 1; - break; + if (invalidargs) + return -2; /* error DONE */ + + if (j > 0) { + if (indigit && args[idx][j]) + return -2; /* error DONE */ + + /* partspecifier present, save it */ + if (j >= IMAP_MAX_PARTSPEC_LEN) + return -2; /* error DONE */ + + strncpy(fi->bodyfetch.partspec, args[idx], + j); + } + + fi->bodyfetch.partspec[j] = '\0'; + + + shouldclose = 0; + if (strcasecmp(&args[idx][j], "text") == 0) { + fi->bodyfetch.itemtype = BFIT_TEXT; + shouldclose = 1; + } else if (strcasecmp(&args[idx][j], "header") == + 0) { + fi->bodyfetch.itemtype = BFIT_HEADER; + shouldclose = 1; + } else if (strcasecmp(&args[idx][j], "mime") == 0) { + if (j == 0) + return -2; /* error DONE */ + + fi->bodyfetch.itemtype = BFIT_MIME; + shouldclose = 1; + } else + if (strcasecmp(&args[idx][j], "header.fields") + == 0) + fi->bodyfetch.itemtype = + BFIT_HEADER_FIELDS; + else if (strcasecmp + (&args[idx][j], "header.fields.not") == 0) + fi->bodyfetch.itemtype = + BFIT_HEADER_FIELDS_NOT; + else if (args[idx][j] == '\0') { + fi->bodyfetch.itemtype = BFIT_TEXT_SILENT; + shouldclose = 1; + } else + return -2; /* error DONE */ + + if (shouldclose) { + if (strcmp(args[idx + 1], "]") != 0) + return -2; /* error DONE */ + } else { + idx++; /* should be at '(' now */ + if (strcmp(args[idx], "(") != 0) + return -2; /* error DONE */ + + idx++; /* at first item of field list now, remember idx */ + fi->bodyfetch.argstart = idx; + + /* walk on untill list terminates (and it does 'cause parentheses are matched) */ + while (strcmp(args[idx], ")") != 0) + idx++; + + fi->bodyfetch.argcnt = + idx - fi->bodyfetch.argstart; + + if (fi->bodyfetch.argcnt == 0 + || strcmp(args[idx + 1], "]") != 0) + return -2; /* error DONE */ } - delimpos = j; - } - else if (!isdigit(args[idx][j])) - { - invalidargs = 1; - break; - } + + idx++; /* points to ']' now */ + + /* check if octet start/cnt is specified */ + if (args[idx + 1] && args[idx + 1][0] == '<') { + idx++; /* advance */ + + /* check argument */ + if (args[idx][strlen(args[idx]) - 1] != + '>') + return -2; /* error DONE */ + + delimpos = -1; + for (j = 1; j < strlen(args[idx]) - 1; j++) { + if (args[idx][j] == '.') { + if (delimpos != -1) { + invalidargs = 1; + break; + } + delimpos = j; + } else if (!isdigit(args[idx][j])) { + invalidargs = 1; + break; + } + } + + if (invalidargs || delimpos == -1 || + delimpos == 1 + || delimpos == + (int) (strlen(args[idx]) - 2)) + return -2; /* no delimiter found or at first/last pos OR invalid args DONE */ + + /* read the numbers */ + args[idx][strlen(args[idx]) - 1] = '\0'; + args[idx][delimpos] = '\0'; + fi->bodyfetch.octetstart = + strtoll(&args[idx][1], NULL, 10); + fi->bodyfetch.octetcnt = + strtoll(&args[idx][delimpos + 1], NULL, + 10); + + /* restore argument */ + args[idx][delimpos] = '.'; + args[idx][strlen(args[idx]) - 1] = '>'; + } else { + fi->bodyfetch.octetstart = -1; + fi->bodyfetch.octetcnt = -1; + } + /* ok all done for body item */ } - - if (invalidargs || delimpos == -1 || - delimpos == 1 || delimpos == (int) (strlen(args[idx])-2) ) - return -2; /* no delimiter found or at first/last pos OR invalid args DONE */ - - /* read the numbers */ - args[idx][strlen(args[idx]) - 1] = '\0'; - args[idx][delimpos] = '\0'; - fi->bodyfetch.octetstart = strtoll(&args[idx][1], NULL, 10); - fi->bodyfetch.octetcnt = strtoll(&args[idx][delimpos+1], NULL, 10); - - /* restore argument */ - args[idx][delimpos] = '.'; - args[idx][strlen(args[idx]) - 1] = '>'; - } - else - { - fi->bodyfetch.octetstart = -1; - fi->bodyfetch.octetcnt = -1; - } - /* ok all done for body item */ - } - } - else if (strcasecmp(args[idx], "all") == 0) - { - fi->getFlags = 1; - fi->getInternalDate = 1; - fi->getSize = 1; - fi->getEnvelope = 1; - fi->msgparse_needed = 1; - } - else if (strcasecmp(args[idx], "fast") == 0) - { - fi->getFlags = 1; - fi->getInternalDate = 1; - fi->getSize = 1; -/* fi->msgparse_needed = 1; */ /* size will be in dbase after first calc */ - } - else if (strcasecmp(args[idx], "full") == 0) - { - fi->getFlags = 1; - fi->getInternalDate = 1; - fi->getSize = 1; - fi->getEnvelope = 1; - fi->getMIME_IMB = 1; - fi->msgparse_needed = 1; - } - else if (strcasecmp(args[idx], "bodystructure") == 0) - { - fi->getMIME_IMB = 1; - fi->msgparse_needed = 1; - } - else if (strcasecmp(args[idx], "envelope") == 0) - { - fi->getEnvelope = 1; - fi->msgparse_needed = 1; - } - else if (strcmp(args[idx], ")") == 0) - { - /* only allowed if last arg here */ - if (args[idx+1]) - return -2; /* DONE */ - else - return -1; - } - else - return -2; /* DONE */ - - trace(TRACE_DEBUG,"next_fetch_item(): args[idx = %d] = %s (returning %d)\n",idx,args[idx],idx+1); - return idx+1; + } else if (strcasecmp(args[idx], "all") == 0) { + fi->getFlags = 1; + fi->getInternalDate = 1; + fi->getSize = 1; + fi->getEnvelope = 1; + fi->msgparse_needed = 1; + } else if (strcasecmp(args[idx], "fast") == 0) { + fi->getFlags = 1; + fi->getInternalDate = 1; + fi->getSize = 1; +/* fi->msgparse_needed = 1; *//* size will be in dbase after first calc */ + } else if (strcasecmp(args[idx], "full") == 0) { + fi->getFlags = 1; + fi->getInternalDate = 1; + fi->getSize = 1; + fi->getEnvelope = 1; + fi->getMIME_IMB = 1; + fi->msgparse_needed = 1; + } else if (strcasecmp(args[idx], "bodystructure") == 0) { + fi->getMIME_IMB = 1; + fi->msgparse_needed = 1; + } else if (strcasecmp(args[idx], "envelope") == 0) { + fi->getEnvelope = 1; + fi->msgparse_needed = 1; + } else if (strcmp(args[idx], ")") == 0) { + /* only allowed if last arg here */ + if (args[idx + 1]) + return -2; /* DONE */ + else + return -1; + } else + return -2; /* DONE */ + + trace(TRACE_DEBUG, + "next_fetch_item(): args[idx = %d] = %s (returning %d)\n", + idx, args[idx], idx + 1); + return idx + 1; } @@ -1135,53 +1101,48 @@ int next_fetch_item(char **args, int idx, fetch_items_t *fi) */ char **give_chunks(const char *str, char delimiter) { - int cnt,i; - char **array,*cpy,*tmp; - - cpy = (char*)my_malloc(sizeof(char) * (strlen(str) + 1)); - if (!cpy ) - { - trace(TRACE_ERROR, "give_chunks(): out of memory\n"); - return NULL; - } - - strcpy(cpy,str); - tmp = cpy; /* save start of cpy */ - - for (i=0,cnt=0; str[i]; i++) - if (str[i] == delimiter) - { - cnt++; - cpy[i] = '\0'; - } - - cnt++; /* add last part */ - - /* alloc mem */ - cnt++; /* for NULL termination */ - array = (char**)my_malloc(sizeof(char*) * cnt); - - if (!array) - { - trace(TRACE_ERROR, "give_chunks(): out of memory\n"); - my_free(cpy); - return NULL; - } - - for (i=0,cnt=0; str[i]; i++) - { - if (str[i] == delimiter) - { - array[cnt++] = cpy; /* save this address */ - cpy = &tmp[i+1]; /* let cpy point to next string */ + int cnt, i; + char **array, *cpy, *tmp; + + cpy = (char *) my_malloc(sizeof(char) * (strlen(str) + 1)); + if (!cpy) { + trace(TRACE_ERROR, "give_chunks(): out of memory\n"); + return NULL; } - } - /* copy last part */ - array[cnt++] = cpy; + strcpy(cpy, str); + tmp = cpy; /* save start of cpy */ + + for (i = 0, cnt = 0; str[i]; i++) + if (str[i] == delimiter) { + cnt++; + cpy[i] = '\0'; + } + + cnt++; /* add last part */ + + /* alloc mem */ + cnt++; /* for NULL termination */ + array = (char **) my_malloc(sizeof(char *) * cnt); + + if (!array) { + trace(TRACE_ERROR, "give_chunks(): out of memory\n"); + my_free(cpy); + return NULL; + } - array[cnt] = NULL; - return array; + for (i = 0, cnt = 0; str[i]; i++) { + if (str[i] == delimiter) { + array[cnt++] = cpy; /* save this address */ + cpy = &tmp[i + 1]; /* let cpy point to next string */ + } + } + + /* copy last part */ + array[cnt++] = cpy; + + array[cnt] = NULL; + return array; } @@ -1192,13 +1153,13 @@ char **give_chunks(const char *str, char delimiter) */ void free_chunks(char **chunks) { - if (!chunks) - return; + if (!chunks) + return; - if (chunks[0]) - my_free(chunks[0]); /* the entire array will be freed now */ + if (chunks[0]) + my_free(chunks[0]); /* the entire array will be freed now */ - my_free(chunks); /* free ptrs to strings */ + my_free(chunks); /* free ptrs to strings */ } @@ -1212,48 +1173,48 @@ void free_chunks(char **chunks) * * returns 1 on succes, 0 on failure */ -int check_state_and_args(const char *command, const char *tag, char **args, - int nargs, int state, ClientInfo *ci) +int check_state_and_args(const char *command, const char *tag, char **args, + int nargs, int state, ClientInfo * ci) { - int i; - imap_userdata_t *ud = (imap_userdata_t*)ci->userData; - - /* check state */ - if (state != -1) - { - if (ud->state != state) - { - if (!(state == IMAPCS_AUTHENTICATED && ud->state == IMAPCS_SELECTED)) - { - fprintf(ci->tx,"%s BAD %s command received in invalid state\r\n", tag, command); - return 0; - } + int i; + imap_userdata_t *ud = (imap_userdata_t *) ci->userData; + + /* check state */ + if (state != -1) { + if (ud->state != state) { + if (! + (state == IMAPCS_AUTHENTICATED + && ud->state == IMAPCS_SELECTED)) { + fprintf(ci->tx, + "%s BAD %s command received in invalid state\r\n", + tag, command); + return 0; + } + } } - } - - /* check args */ - for (i=0; i<nargs; i++) - { - if (!args[i]) - { - /* error: need more args */ - fprintf(ci->tx,"%s BAD missing argument%s to %s\r\n", tag, - (nargs == 1) ? "" : "(s)", command); - return 0; + + /* check args */ + for (i = 0; i < nargs; i++) { + if (!args[i]) { + /* error: need more args */ + fprintf(ci->tx, + "%s BAD missing argument%s to %s\r\n", tag, + (nargs == 1) ? "" : "(s)", command); + return 0; + } } - } - for (i=0; args[i]; i++) ; + for (i = 0; args[i]; i++); - if (i > nargs) - { - /* error: too many args */ - fprintf(ci->tx,"%s BAD too many arguments to %s\r\n",tag, command); - return 0; - } + if (i > nargs) { + /* error: too many args */ + fprintf(ci->tx, "%s BAD too many arguments to %s\r\n", tag, + command); + return 0; + } - /* succes */ - return 1; + /* succes */ + return 1; } @@ -1284,7 +1245,7 @@ int check_state_and_args(const char *command, const char *tag, char **args, */ /* local defines */ -#define NORMPAR 1 +#define NORMPAR 1 #define SQUAREPAR 2 #define NOPAR 0 @@ -1292,474 +1253,457 @@ char *the_args[MAX_ARGS]; char **build_args_array(const char *s) { - int nargs=0,inquote=0,i,quotestart=0; - int nnorm=0,nsquare=0,paridx=0,slen=0,argstart=0; - char parlist[MAX_LINESIZE]; - - if (!s) - return NULL; - - /* check for empty string */ - if (!(*s)) - { - the_args[0] = NULL; - return the_args; - } - - /* find the arguments */ - paridx = 0; - parlist[paridx] = NOPAR; - - inquote = 0; - slen = strlen(s); - - for (i=0,nargs=0; i<slen && nargs < MAX_ARGS-1; i++) - { - /* check quotes */ - if (s[i] == '"' && ((i > 0 && s[i-1] != '\\') || i == 0)) - { - if (inquote) - { - /* quotation end, treat quoted string as argument */ - if (!(the_args[nargs] = (char*)my_malloc(sizeof(char) * (i-quotestart)) )) - { - /* out of mem */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; - } - - trace(TRACE_ERROR, - "IMAPD: Not enough memory while building up argument array."); - return NULL; - } - - memcpy(the_args[nargs], &s[quotestart+1], i-quotestart-1); - the_args[nargs][i-quotestart -1] = '\0'; - - nargs++; - inquote = 0; - } - else - { - inquote = 1; - quotestart = i; - } - - continue; + int nargs = 0, inquote = 0, i, quotestart = 0; + int nnorm = 0, nsquare = 0, paridx = 0, slen = 0, argstart = 0; + char parlist[MAX_LINESIZE]; + + if (!s) + return NULL; + + /* check for empty string */ + if (!(*s)) { + the_args[0] = NULL; + return the_args; } - if (inquote) - continue; - - /* check for (, ), [ or ] in string */ - if (s[i] == '(' || s[i] == ')' || s[i] == '[' || s[i] == ']') - { - /* check parenthese structure */ - if (s[i] == ')') - { - if (paridx < 0 || parlist[paridx] != NORMPAR) - paridx = -1; - else - { - nnorm--; - paridx--; - } - } - else if (s[i] == ']') - { - if (paridx < 0 || parlist[paridx] != SQUAREPAR) - paridx = -1; - else - { - paridx--; - nsquare--; + /* find the arguments */ + paridx = 0; + parlist[paridx] = NOPAR; + + inquote = 0; + slen = strlen(s); + + for (i = 0, nargs = 0; i < slen && nargs < MAX_ARGS - 1; i++) { + /* check quotes */ + if (s[i] == '"' && ((i > 0 && s[i - 1] != '\\') || i == 0)) { + if (inquote) { + /* quotation end, treat quoted string as argument */ + if (! + (the_args[nargs] = + (char *) my_malloc(sizeof(char) * + (i - + quotestart)))) { + /* out of mem */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + + trace(TRACE_ERROR, + "IMAPD: Not enough memory while building up argument array."); + return NULL; + } + + memcpy(the_args[nargs], &s[quotestart + 1], + i - quotestart - 1); + the_args[nargs][i - quotestart - 1] = '\0'; + + nargs++; + inquote = 0; + } else { + inquote = 1; + quotestart = i; + } + + continue; } - } - else if (s[i] == '(') - { - parlist[++paridx] = NORMPAR; - nnorm++; - } - else /* s[i] == '[' */ - { - parlist[++paridx] = SQUAREPAR; - nsquare++; - } - - if (paridx < 0) - { - /* error in parenthesis structure */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; + + if (inquote) + continue; + + /* check for (, ), [ or ] in string */ + if (s[i] == '(' || s[i] == ')' || s[i] == '[' + || s[i] == ']') { + /* check parenthese structure */ + if (s[i] == ')') { + if (paridx < 0 + || parlist[paridx] != NORMPAR) + paridx = -1; + else { + nnorm--; + paridx--; + } + } else if (s[i] == ']') { + if (paridx < 0 + || parlist[paridx] != SQUAREPAR) + paridx = -1; + else { + paridx--; + nsquare--; + } + } else if (s[i] == '(') { + parlist[++paridx] = NORMPAR; + nnorm++; + } else { /* s[i] == '[' */ + + parlist[++paridx] = SQUAREPAR; + nsquare++; + } + + if (paridx < 0) { + /* error in parenthesis structure */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + return NULL; + } + + /* add this parenthesis to the arg list and continue */ + if (! + (the_args[nargs] = + (char *) my_malloc(sizeof(" ")))) { + /* out of mem */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + + trace(TRACE_ERROR, + "IMAPD: Not enough memory while building up argument array."); + return NULL; + } + the_args[nargs][0] = s[i]; + the_args[nargs][1] = '\0'; + + nargs++; + continue; } - return NULL; - } - - /* add this parenthesis to the arg list and continue */ - if (!(the_args[nargs] = (char*)my_malloc( sizeof(" ") )) ) - { - /* out of mem */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; + + if (s[i] == ' ') + continue; + + /* at an argument start now, walk on until next delimiter + * and save argument + */ + + for (argstart = i; i < slen && !strchr(" []()", s[i]); i++) + if (s[i] == '"') { + if (s[i - 1] == '\\') + continue; + else + break; + } + + if (! + (the_args[nargs] = + (char *) my_malloc(sizeof(char) * + (i - argstart + 1)))) { + /* out of mem */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + + trace(TRACE_ERROR, + "IMAPD: Not enough memory while building up argument array."); + return NULL; } - - trace(TRACE_ERROR, - "IMAPD: Not enough memory while building up argument array."); - return NULL; - } - the_args[nargs][0] = s[i]; - the_args[nargs][1] = '\0'; - - nargs++; - continue; - } - - if (s[i] == ' ') - continue; - - /* at an argument start now, walk on until next delimiter - * and save argument - */ - - for (argstart = i; i<slen && !strchr(" []()",s[i]); i++) - if (s[i] == '"') - { - if (s[i-1] == '\\') continue; - else break; - } - - if (!(the_args[nargs] = (char*)my_malloc(sizeof(char) * (i-argstart +1)) )) - { - /* out of mem */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; - } - - trace(TRACE_ERROR, - "IMAPD: Not enough memory while building up argument array."); - return NULL; + + memcpy(the_args[nargs], &s[argstart], i - argstart); + the_args[nargs][i - argstart] = '\0'; + + nargs++; + i--; /* walked one too far */ } - - memcpy(the_args[nargs], &s[argstart], i-argstart); - the_args[nargs][i-argstart] = '\0'; - - nargs++; - i--; /* walked one too far */ - } - - if (paridx != 0) - { - /* error in parenthesis structure */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; + + if (paridx != 0) { + /* error in parenthesis structure */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + return NULL; } - return NULL; - } - the_args[nargs] = NULL; /* terminate */ + the_args[nargs] = NULL; /* terminate */ - /* dump args (debug) */ - for (i=0; the_args[i]; i++) - { - trace(TRACE_DEBUG, "arg[%d]: '%s'\n",i,the_args[i]); - } + /* dump args (debug) */ + for (i = 0; the_args[i]; i++) { + trace(TRACE_DEBUG, "arg[%d]: '%s'\n", i, the_args[i]); + } - return the_args; + return the_args; } /* * as build_args_array(), but reads strings on cmd line specified by {##}\0 * (\r\n had been removed from string) */ -char **build_args_array_ext(const char *originalString, clientinfo_t *ci) +char **build_args_array_ext(const char *originalString, clientinfo_t * ci) { - int nargs=0,inquote=0, quotestart=0; - int nnorm=0,nsquare=0,paridx=0,argstart=0; - unsigned int i; - char parlist[MAX_LINESIZE]; - char s[MAX_LINESIZE]; - char *tmp, *lastchar; - int quotedSize, cnt, dataidx; - - /* this is done for the possible extra lines to be read from the client: - * the line is read into currline; s will always point to the line currently - * being processed - */ - strncpy(s, originalString, MAX_LINESIZE); - - if (!s) - return NULL; - - /* check for empty string */ - if (!(*s)) - { - the_args[0] = NULL; - return the_args; - } - - /* find the arguments */ - paridx = 0; - parlist[paridx] = NOPAR; - - inquote = 0; - - for (i=0,nargs=0; s[i] && nargs < MAX_ARGS-1; i++) - { - /* check quotes */ - if (s[i] == '"' && ((i > 0 && s[i-1] != '\\') || i == 0)) - { - if (inquote) - { - /* quotation end, treat quoted string as argument */ - if (!(the_args[nargs] = (char*)my_malloc(sizeof(char) * (i-quotestart)) )) - { - /* out of mem */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; - } - - trace(TRACE_ERROR, - "IMAPD: Not enough memory while building up argument array."); - return NULL; - } - - memcpy(the_args[nargs], &s[quotestart+1], i-quotestart-1); - the_args[nargs][i-quotestart -1] = '\0'; - - nargs++; - inquote = 0; - } - else - { - inquote = 1; - quotestart = i; - } - - continue; + int nargs = 0, inquote = 0, quotestart = 0; + int nnorm = 0, nsquare = 0, paridx = 0, argstart = 0; + unsigned int i; + char parlist[MAX_LINESIZE]; + char s[MAX_LINESIZE]; + char *tmp, *lastchar; + int quotedSize, cnt, dataidx; + + /* this is done for the possible extra lines to be read from the client: + * the line is read into currline; s will always point to the line currently + * being processed + */ + strncpy(s, originalString, MAX_LINESIZE); + + if (!s) + return NULL; + + /* check for empty string */ + if (!(*s)) { + the_args[0] = NULL; + return the_args; } - if (inquote) - continue; - - /* check for (, ), [ or ] in string */ - if (s[i] == '(' || s[i] == ')' || s[i] == '[' || s[i] == ']') - { - /* check parenthese structure */ - if (s[i] == ')') - { - if (paridx < 0 || parlist[paridx] != NORMPAR) - paridx = -1; - else - { - nnorm--; - paridx--; - } - } - else if (s[i] == ']') - { - if (paridx < 0 || parlist[paridx] != SQUAREPAR) - paridx = -1; - else - { - paridx--; - nsquare--; - } - } - else if (s[i] == '(') - { - parlist[++paridx] = NORMPAR; - nnorm++; - } - else /* s[i] == '[' */ - { - parlist[++paridx] = SQUAREPAR; - nsquare++; - } - - if (paridx < 0) - { - /* error in parenthesis structure */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; - } - return NULL; - } - - /* add this parenthesis to the arg list and continue */ - if (!(the_args[nargs] = (char*)my_malloc( sizeof(" ") )) ) - { - /* out of mem */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; - } - - trace(TRACE_ERROR, - "IMAPD: Not enough memory while building up argument array."); - return NULL; - } - the_args[nargs][0] = s[i]; - the_args[nargs][1] = '\0'; - - nargs++; - continue; - } - - if (s[i] == ' ') - continue; - - /* check for {number}\0 */ - if (s[i] == '{') - { - quotedSize = strtoul(&s[i+1], &lastchar, 10); - - /* only continue if the number is followed by '}\0' */ - if (*lastchar == '}' && *(lastchar+1) == '\0') - { - /* allocate space for this argument (could be a message when used with APPEND) */ - if (!(the_args[nargs] = (char*)my_malloc(sizeof(char) * (quotedSize+1)) )) - { - /* out of mem */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; - } - - trace(TRACE_ERROR, - "build_args_array_ext(): out of memory allocating [%u] bytes for extra string", quotedSize+1); - return NULL; - } - - fprintf(ci->tx, "+ OK gimme that string\r\n"); - alarm(ci->timeout); /* dont wait forever */ - for (cnt=0, dataidx=0; cnt<quotedSize; cnt++) - { - the_args[nargs][dataidx] = fgetc(ci->rx); - - if (the_args[nargs][dataidx] != '\r') - dataidx++; /* only store if it is not \r */ + /* find the arguments */ + paridx = 0; + parlist[paridx] = NOPAR; + + inquote = 0; + + for (i = 0, nargs = 0; s[i] && nargs < MAX_ARGS - 1; i++) { + /* check quotes */ + if (s[i] == '"' && ((i > 0 && s[i - 1] != '\\') || i == 0)) { + if (inquote) { + /* quotation end, treat quoted string as argument */ + if (! + (the_args[nargs] = + (char *) my_malloc(sizeof(char) * + (i - + quotestart)))) { + /* out of mem */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + + trace(TRACE_ERROR, + "IMAPD: Not enough memory while building up argument array."); + return NULL; + } + + memcpy(the_args[nargs], &s[quotestart + 1], + i - quotestart - 1); + the_args[nargs][i - quotestart - 1] = '\0'; + + nargs++; + inquote = 0; + } else { + inquote = 1; + quotestart = i; + } + + continue; } - - alarm(0); - the_args[nargs][dataidx] = '\0'; /* terminate string */ - nargs++; - - if (!ci->rx || !ci->tx || ferror(ci->rx) || ferror(ci->tx)) - { - /* timeout occurred or connection has gone away */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; - } - - trace(TRACE_ERROR, "build_args_array_ext(): timeout occurred"); - return NULL; + + if (inquote) + continue; + + /* check for (, ), [ or ] in string */ + if (s[i] == '(' || s[i] == ')' || s[i] == '[' + || s[i] == ']') { + /* check parenthese structure */ + if (s[i] == ')') { + if (paridx < 0 + || parlist[paridx] != NORMPAR) + paridx = -1; + else { + nnorm--; + paridx--; + } + } else if (s[i] == ']') { + if (paridx < 0 + || parlist[paridx] != SQUAREPAR) + paridx = -1; + else { + paridx--; + nsquare--; + } + } else if (s[i] == '(') { + parlist[++paridx] = NORMPAR; + nnorm++; + } else { /* s[i] == '[' */ + + parlist[++paridx] = SQUAREPAR; + nsquare++; + } + + if (paridx < 0) { + /* error in parenthesis structure */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + return NULL; + } + + /* add this parenthesis to the arg list and continue */ + if (! + (the_args[nargs] = + (char *) my_malloc(sizeof(" ")))) { + /* out of mem */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + + trace(TRACE_ERROR, + "IMAPD: Not enough memory while building up argument array."); + return NULL; + } + the_args[nargs][0] = s[i]; + the_args[nargs][1] = '\0'; + + nargs++; + continue; } - /* now read the rest of this line */ - alarm(ci->timeout); - fgets(s, MAX_LINESIZE, ci->rx); - alarm(0); - - if (!ci->rx || !ci->tx || ferror(ci->rx) || ferror(ci->tx)) - { - /* timeout occurred */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; - } - - trace(TRACE_ERROR, "build_args_array_ext(): timeout occurred"); - return NULL; + if (s[i] == ' ') + continue; + + /* check for {number}\0 */ + if (s[i] == '{') { + quotedSize = strtoul(&s[i + 1], &lastchar, 10); + + /* only continue if the number is followed by '}\0' */ + if (*lastchar == '}' && *(lastchar + 1) == '\0') { + /* allocate space for this argument (could be a message when used with APPEND) */ + if (! + (the_args[nargs] = + (char *) my_malloc(sizeof(char) * + (quotedSize + + 1)))) { + /* out of mem */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + + trace(TRACE_ERROR, + "build_args_array_ext(): out of memory allocating [%u] bytes for extra string", + quotedSize + 1); + return NULL; + } + + fprintf(ci->tx, + "+ OK gimme that string\r\n"); + alarm(ci->timeout); /* dont wait forever */ + for (cnt = 0, dataidx = 0; + cnt < quotedSize; cnt++) { + the_args[nargs][dataidx] = + fgetc(ci->rx); + + if (the_args[nargs][dataidx] != + '\r') + dataidx++; /* only store if it is not \r */ + } + + alarm(0); + the_args[nargs][dataidx] = '\0'; /* terminate string */ + nargs++; + + if (!ci->rx || !ci->tx || ferror(ci->rx) + || ferror(ci->tx)) { + /* timeout occurred or connection has gone away */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + + trace(TRACE_ERROR, + "build_args_array_ext(): timeout occurred"); + return NULL; + } + + /* now read the rest of this line */ + alarm(ci->timeout); + fgets(s, MAX_LINESIZE, ci->rx); + alarm(0); + + if (!ci->rx || !ci->tx || ferror(ci->rx) + || ferror(ci->tx)) { + /* timeout occurred */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + + trace(TRACE_ERROR, + "build_args_array_ext(): timeout occurred"); + return NULL; + } + + /* remove trailing \r\n */ + tmp = &s[strlen(s)]; + tmp--; /* go before trailing \0; watch this with empty strings! */ + while (tmp >= s + && (*tmp == '\r' || *tmp == '\n')) { + *tmp = '\0'; + tmp--; + } + + trace(TRACE_DEBUG, + "build_args_array_ext(): got extra line [%s]", + s); + + /* start over! */ + i = 0; + continue; + } } - /* remove trailing \r\n */ - tmp = &s[strlen(s)]; - tmp--; /* go before trailing \0; watch this with empty strings! */ - while (tmp >= s && (*tmp == '\r' || *tmp == '\n')) - { - *tmp = '\0'; - tmp--; + /* at an argument start now, walk on until next delimiter + * and save argument + */ + + for (argstart = i; i < strlen(s) && !strchr(" []()", s[i]); + i++) + if (s[i] == '"') { + if (s[i - 1] == '\\') + continue; + else + break; + } + + if (! + (the_args[nargs] = + (char *) my_malloc(sizeof(char) * + (i - argstart + 1)))) { + /* out of mem */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + + trace(TRACE_ERROR, + "IMAPD: Not enough memory while building up argument array."); + return NULL; } - trace(TRACE_DEBUG, "build_args_array_ext(): got extra line [%s]", s); + memcpy(the_args[nargs], &s[argstart], i - argstart); + the_args[nargs][i - argstart] = '\0'; - /* start over! */ - i = 0; - continue; - } + nargs++; + i--; /* walked one too far */ } - /* at an argument start now, walk on until next delimiter - * and save argument - */ - - for (argstart = i; i<strlen(s) && !strchr(" []()",s[i]); i++) - if (s[i] == '"') - { - if (s[i-1] == '\\') continue; - else break; - } - - if (!(the_args[nargs] = (char*)my_malloc(sizeof(char) * (i-argstart +1)) )) - { - /* out of mem */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; - } - - trace(TRACE_ERROR, - "IMAPD: Not enough memory while building up argument array."); - return NULL; - } - - memcpy(the_args[nargs], &s[argstart], i-argstart); - the_args[nargs][i-argstart] = '\0'; - - nargs++; - i--; /* walked one too far */ - } - - if (paridx != 0) - { - /* error in parenthesis structure */ - while (--nargs >= 0) - { - my_free(the_args[nargs]); - the_args[nargs] = NULL; + if (paridx != 0) { + /* error in parenthesis structure */ + while (--nargs >= 0) { + my_free(the_args[nargs]); + the_args[nargs] = NULL; + } + return NULL; } - return NULL; - } - the_args[nargs] = NULL; /* terminate */ + the_args[nargs] = NULL; /* terminate */ - /* dump args (debug) */ - for (i=0; the_args[i]; i++) - { - trace(TRACE_DEBUG, "arg[%d]: '%s'\n",i,the_args[i]); - } + /* dump args (debug) */ + for (i = 0; the_args[i]; i++) { + trace(TRACE_DEBUG, "arg[%d]: '%s'\n", i, the_args[i]); + } - return the_args; + return the_args; } #undef NOPAR @@ -1775,69 +1719,64 @@ char **build_args_array_ext(const char *originalString, clientinfo_t *ci) */ void clarify_data(char *str) { - int startidx,inquote,endidx; - unsigned int i; - - - /* remove leading spaces */ - for (i=0; str[i] == ' '; i++) ; - memmove(str, &str[i], sizeof(char) * (strlen(&str[i])+1)); /* add one for \0 */ - - /* remove CR/LF */ - endidx = strlen(str)-1; - if (endidx >= 0 && (str[endidx] == '\n' ||str[endidx] == '\r')) - endidx--; - - if (endidx >= 0 && (str[endidx] == '\n' ||str[endidx] == '\r')) - endidx--; - - - if (endidx == 0) - { - /* only 1 char left and it is not a space */ - str[1] = '\0'; - return; - } - - /* remove trailing spaces */ - for (i=endidx; i>0 && str[i] == ' '; i--) ; - if (i == 0) - { - /* empty string remains */ - *str = '\0'; - return; - } - - str[i+1] = '\0'; - - /* scan for multiple spaces */ - inquote = 0; - for (i=0; i < strlen(str); i++) - { - if (str[i] == '"') - { - if ((i > 0 && str[i-1]!='\\') || i == 0) - { - /* toggle in-quote flag */ - inquote ^= 1; - } + int startidx, inquote, endidx; + unsigned int i; + + + /* remove leading spaces */ + for (i = 0; str[i] == ' '; i++); + memmove(str, &str[i], sizeof(char) * (strlen(&str[i]) + 1)); /* add one for \0 */ + + /* remove CR/LF */ + endidx = strlen(str) - 1; + if (endidx >= 0 && (str[endidx] == '\n' || str[endidx] == '\r')) + endidx--; + + if (endidx >= 0 && (str[endidx] == '\n' || str[endidx] == '\r')) + endidx--; + + + if (endidx == 0) { + /* only 1 char left and it is not a space */ + str[1] = '\0'; + return; + } + + /* remove trailing spaces */ + for (i = endidx; i > 0 && str[i] == ' '; i--); + if (i == 0) { + /* empty string remains */ + *str = '\0'; + return; } - if (str[i] == ' ' && !inquote) - { - for (startidx = i; str[i] == ' '; i++); - - if (i-startidx > 1) - { - /* multiple non-quoted spaces found --> remove 'm */ - memmove(&str[startidx+1], &str[i], sizeof(char) * (strlen(&str[i])+1)); - /* update i */ - i = startidx+1; - } + str[i + 1] = '\0'; + + /* scan for multiple spaces */ + inquote = 0; + for (i = 0; i < strlen(str); i++) { + if (str[i] == '"') { + if ((i > 0 && str[i - 1] != '\\') || i == 0) { + /* toggle in-quote flag */ + inquote ^= 1; + } + } + + if (str[i] == ' ' && !inquote) { + for (startidx = i; str[i] == ' '; i++); + + if (i - startidx > 1) { + /* multiple non-quoted spaces found --> remove 'm */ + memmove(&str[startidx + 1], &str[i], + sizeof(char) * (strlen(&str[i]) + + 1)); + /* update i */ + i = startidx + 1; + } + } } - } -} - +} + /* * is_textplain() @@ -1846,23 +1785,25 @@ void clarify_data(char *str) */ int is_textplain(struct list *hdr) { - struct mime_record *mr; - int i,len; + struct mime_record *mr; + int i, len; - if (!hdr) - return 0; + if (!hdr) + return 0; - mime_findfield("content-type", hdr, &mr); + mime_findfield("content-type", hdr, &mr); - if (!mr) - return 0; + if (!mr) + return 0; - len = strlen(mr->value); - for (i=0; len - i >= (int) sizeof("text/plain"); i++) - if (strncasecmp(&mr->value[i], "text/plain", sizeof("text/plain")-1) == 0) - return 1; - - return 0; + len = strlen(mr->value); + for (i = 0; len - i >= (int) sizeof("text/plain"); i++) + if (strncasecmp + (&mr->value[i], "text/plain", + sizeof("text/plain") - 1) == 0) + return 1; + + return 0; } @@ -1877,39 +1818,38 @@ int is_textplain(struct list *hdr) */ char *date_sql2imap(const char *sqldate) { - int mon; + int mon; - if (strlen(sqldate) != strlen("yyyy-mm-dd hh:mm:ss")) - { - strcpy(_imapdate, "03-Nov-1979 00:00:00"); - return _imapdate; - } + if (strlen(sqldate) != strlen("yyyy-mm-dd hh:mm:ss")) { + strcpy(_imapdate, "03-Nov-1979 00:00:00"); + return _imapdate; + } - /* copy day */ - _imapdate[0] = sqldate[8]; - _imapdate[1] = sqldate[9]; + /* copy day */ + _imapdate[0] = sqldate[8]; + _imapdate[1] = sqldate[9]; - /* find out which month */ - mon = strtoul(&sqldate[5], NULL, 10) - 1; - if (mon < 0 || mon > 11) - mon = 0; + /* find out which month */ + mon = strtoul(&sqldate[5], NULL, 10) - 1; + if (mon < 0 || mon > 11) + mon = 0; - /* copy month */ - _imapdate[3] = month_desc[mon][0]; - _imapdate[4] = month_desc[mon][1]; - _imapdate[5] = month_desc[mon][2]; + /* copy month */ + _imapdate[3] = month_desc[mon][0]; + _imapdate[4] = month_desc[mon][1]; + _imapdate[5] = month_desc[mon][2]; - /* copy year */ - _imapdate[7] = sqldate[0]; - _imapdate[8] = sqldate[1]; - _imapdate[9] = sqldate[2]; - _imapdate[10] = sqldate[3]; + /* copy year */ + _imapdate[7] = sqldate[0]; + _imapdate[8] = sqldate[1]; + _imapdate[9] = sqldate[2]; + _imapdate[10] = sqldate[3]; - /* copy time */ - strcpy(&_imapdate[11], &sqldate[10]); + /* copy time */ + strcpy(&_imapdate[11], &sqldate[10]); - return _imapdate; -} + return _imapdate; +} /* @@ -1926,49 +1866,49 @@ char *date_sql2imap(const char *sqldate) */ char *date_imap2sql(const char *imapdate) { - int i,j; - char sub[4]; + int i, j; + char sub[4]; + + if (strlen(imapdate) != strlen("dd-mon-yyyy") + && strlen(imapdate) != strlen("d-mon-yyyy")) + return NULL; - if (strlen(imapdate) != strlen("dd-mon-yyyy") && strlen(imapdate) != strlen("d-mon-yyyy")) - return NULL; + j = (strlen(imapdate) == strlen("d-mon-yyyy")) ? 1 : 0; - j = (strlen(imapdate) == strlen("d-mon-yyyy")) ? 1 : 0; + /* copy year */ + _sqldate[0] = imapdate[7 - j]; + _sqldate[1] = imapdate[8 - j]; + _sqldate[2] = imapdate[9 - j]; + _sqldate[3] = imapdate[10 - j]; - /* copy year */ - _sqldate[0] = imapdate[7-j]; - _sqldate[1] = imapdate[8-j]; - _sqldate[2] = imapdate[9-j]; - _sqldate[3] = imapdate[10-j]; + _sqldate[4] = '-'; - _sqldate[4] = '-'; + /* copy month */ + strncpy(sub, &imapdate[3 - j], 3); + sub[3] = 0; - /* copy month */ - strncpy(sub, &imapdate[3-j], 3); - sub[3] = 0; + for (i = 0; i < 12; i++) { + if (strcasecmp(month_desc[i], sub) == 0) + break; + } - for (i=0; i<12; i++) - { - if (strcasecmp(month_desc[i], sub) == 0) - break; - } - - if (i>=12) - return NULL; + if (i >= 12) + return NULL; - i++; /* make i in [1,12] */ - _sqldate[5] = (i<10) ? '0' : '1'; - _sqldate[6] = (i<10) ? (i+'0') : ((i-10) + '0'); + i++; /* make i in [1,12] */ + _sqldate[5] = (i < 10) ? '0' : '1'; + _sqldate[6] = (i < 10) ? (i + '0') : ((i - 10) + '0'); - _sqldate[7] = '-'; - - /* copy day */ - _sqldate[8] = j ? '0' : imapdate[0]; - _sqldate[9] = imapdate[1-j]; - - _sqldate[10] = 0; /* terminate */ + _sqldate[7] = '-'; - return _sqldate; -} + /* copy day */ + _sqldate[8] = j ? '0' : imapdate[0]; + _sqldate[9] = imapdate[1 - j]; + + _sqldate[10] = 0; /* terminate */ + + return _sqldate; +} /* @@ -1976,11 +1916,11 @@ char *date_imap2sql(const char *imapdate) */ unsigned stridx(const char *s, char ch) { - unsigned i; + unsigned i; - for (i=0; s[i] && s[i] != ch; i++) ; + for (i = 0; s[i] && s[i] != ch; i++); - return i; + return i; } @@ -1992,17 +1932,15 @@ unsigned stridx(const char *s, char ch) */ int checkchars(const char *s) { - int i; - - for (i=0; s[i]; i++) - { - if (!strchr(AcceptedChars, s[i])) - { - /* wrong char found */ - return 0; + int i; + + for (i = 0; s[i]; i++) { + if (!strchr(AcceptedChars, s[i])) { + /* wrong char found */ + return 0; + } } - } - return 1; + return 1; } @@ -2014,17 +1952,15 @@ int checkchars(const char *s) */ int checktag(const char *s) { - int i; - - for (i=0; s[i]; i++) - { - if (!strchr(AcceptedTagChars, s[i])) - { - /* wrong char found */ - return 0; + int i; + + for (i = 0; s[i]; i++) { + if (!strchr(AcceptedTagChars, s[i])) { + /* wrong char found */ + return 0; + } } - } - return 1; + return 1; } @@ -2036,39 +1972,36 @@ int checktag(const char *s) */ int checkmailboxname(const char *s) { - int i; - - if (strlen(s) == 0) - return 0; /* empty name is not valid */ - - if (strlen(s) >= IMAP_MAX_MAILBOX_NAMELEN) - return 0; /* a too large string is not valid */ - - /* check for invalid characters */ - for (i=0; s[i]; i++) - { - if (!strchr(AcceptedMailboxnameChars, s[i])) - { - /* dirty hack to allow namespaces to function */ - if (i == 0 && s[0] == '#') - continue; - /* wrong char found */ - return 0; + int i; + + if (strlen(s) == 0) + return 0; /* empty name is not valid */ + + if (strlen(s) >= IMAP_MAX_MAILBOX_NAMELEN) + return 0; /* a too large string is not valid */ + + /* check for invalid characters */ + for (i = 0; s[i]; i++) { + if (!strchr(AcceptedMailboxnameChars, s[i])) { + /* dirty hack to allow namespaces to function */ + if (i == 0 && s[0] == '#') + continue; + /* wrong char found */ + return 0; + } } - } - /* check for double '/' */ - for (i=1; s[i]; i++) - { - if (s[i] == '/' && s[i-1] == '/') - return 0; - } + /* check for double '/' */ + for (i = 1; s[i]; i++) { + if (s[i] == '/' && s[i - 1] == '/') + return 0; + } - /* check if the name consists of a single '/' */ - if (strlen(s) == 1 && s[0] == '/') - return 0; + /* check if the name consists of a single '/' */ + if (strlen(s) == 1 && s[0] == '/') + return 0; - return 1; + return 1; } @@ -2082,36 +2015,37 @@ int checkmailboxname(const char *s) */ int check_date(const char *date) { - char sub[4]; - int days,i,j; + char sub[4]; + int days, i, j; - if (strlen(date) != strlen("01-Jan-1970") && strlen(date) != strlen("1-Jan-1970")) - return 0; + if (strlen(date) != strlen("01-Jan-1970") + && strlen(date) != strlen("1-Jan-1970")) + return 0; - j = (strlen(date) == strlen("1-Jan-1970")) ? 1 : 0; - - if (date[2-j] != '-' || date[6-j] != '-') - return 0; + j = (strlen(date) == strlen("1-Jan-1970")) ? 1 : 0; - days = strtoul(date, NULL, 10); - strncpy(sub, &date[3-j], 3); - sub[3] = 0; + if (date[2 - j] != '-' || date[6 - j] != '-') + return 0; - for (i=0; i<12; i++) - { - if (strcasecmp(month_desc[i], sub) == 0) - break; - } + days = strtoul(date, NULL, 10); + strncpy(sub, &date[3 - j], 3); + sub[3] = 0; - if (i >= 12 || days > month_len[i]) - return 0; + for (i = 0; i < 12; i++) { + if (strcasecmp(month_desc[i], sub) == 0) + break; + } + + if (i >= 12 || days > month_len[i]) + return 0; - for (i=7; i<11; i++) - if (!isdigit(date[i-j])) return 0; + for (i = 7; i < 11; i++) + if (!isdigit(date[i - j])) + return 0; - return 1; + return 1; } - + /* @@ -2121,77 +2055,74 @@ int check_date(const char *date) */ int check_msg_set(const char *s) { - int i,indigit; - - if (!s || !isdigit(s[0])) - return 0; - - for (i=1,indigit=1; s[i]; i++) - { - if (isdigit(s[i])) - indigit = 1; - else if (s[i] == ',') - { - if (!indigit && s[i-1] != '*') - return 0; - - indigit = 0; - } - else if (s[i] == ':') - { - if (!indigit) - return 0; - - indigit = 0; - } - else if (s[i] == '*') - { - if (s[i-1] != ':') - return 0; + int i, indigit; + + if (!s || !isdigit(s[0])) + return 0; + + for (i = 1, indigit = 1; s[i]; i++) { + if (isdigit(s[i])) + indigit = 1; + else if (s[i] == ',') { + if (!indigit && s[i - 1] != '*') + return 0; + + indigit = 0; + } else if (s[i] == ':') { + if (!indigit) + return 0; + + indigit = 0; + } else if (s[i] == '*') { + if (s[i - 1] != ':') + return 0; + } } - } - return 1; + return 1; } - + /* * base64encode() * * encodes a string using base64 encoding */ -void base64encode(char *in,char *out) +void base64encode(char *in, char *out) { - for ( ; strlen(in) >= 3; in+=3) - { - *out++ = base64encodestring[ (in[0] & 0xFC) >> 2U]; - *out++ = base64encodestring[ ((in[0] & 0x03) << 4U) | ((in[1] & 0xF0) >> 4U) ]; - *out++ = base64encodestring[ ((in[1] & 0x0F) << 2U) | ((in[2] & 0xC0) >> 6U) ]; - *out++ = base64encodestring[ (in[2] & 0x3F) ]; - } - - if (strlen(in) == 2) - { - /* 16 bits left to encode */ - *out++ = base64encodestring[ (in[0] & 0xFC) >> 2U]; - *out++ = base64encodestring[ ((in[0] & 0x03) << 4U) | ((in[1] & 0xF0) >> 4U) ]; - *out++ = base64encodestring[ ((in[1] & 0x0F) << 2U) ]; - *out++ = '='; - - return; - } - - if (strlen(in) == 1) - { - /* 8 bits left to encode */ - *out++ = base64encodestring[ (in[0] & 0xFC) >> 2U]; - *out++ = base64encodestring[ ((in[0] & 0x03) << 4U) ]; - *out++ = '='; - *out++ = '='; - - return; - } -} + for (; strlen(in) >= 3; in += 3) { + *out++ = base64encodestring[(in[0] & 0xFC) >> 2U]; + *out++ = + base64encodestring[((in[0] & 0x03) << 4U) | + ((in[1] & 0xF0) >> 4U)]; + *out++ = + base64encodestring[((in[1] & 0x0F) << 2U) | + ((in[2] & 0xC0) >> 6U)]; + *out++ = base64encodestring[(in[2] & 0x3F)]; + } + + if (strlen(in) == 2) { + /* 16 bits left to encode */ + *out++ = base64encodestring[(in[0] & 0xFC) >> 2U]; + *out++ = + base64encodestring[((in[0] & 0x03) << 4U) | + ((in[1] & 0xF0) >> 4U)]; + *out++ = base64encodestring[((in[1] & 0x0F) << 2U)]; + *out++ = '='; + + return; + } + + if (strlen(in) == 1) { + /* 8 bits left to encode */ + *out++ = base64encodestring[(in[0] & 0xFC) >> 2U]; + *out++ = base64encodestring[((in[0] & 0x03) << 4U)]; + *out++ = '='; + *out++ = '='; + + return; + } +} /* @@ -2199,22 +2130,21 @@ void base64encode(char *in,char *out) * * decodes a base64 encoded string */ -void base64decode(char *in,char *out) +void base64decode(char *in, char *out) { - for ( ; strlen(in) >= 4; in+=4) - { - *out++ = (stridx(base64encodestring, in[0]) << 2U) - | ((stridx(base64encodestring, in[1]) & 0x30) >> 4U); + for (; strlen(in) >= 4; in += 4) { + *out++ = (stridx(base64encodestring, in[0]) << 2U) + | ((stridx(base64encodestring, in[1]) & 0x30) >> 4U); - *out++ = ((stridx(base64encodestring, in[1]) & 0x0F) << 4U) - | ((stridx(base64encodestring, in[2]) & 0x3C) >> 2U); + *out++ = ((stridx(base64encodestring, in[1]) & 0x0F) << 4U) + | ((stridx(base64encodestring, in[2]) & 0x3C) >> 2U); - *out++ = ((stridx(base64encodestring, in[2]) & 0x03) << 6U) - | (stridx(base64encodestring, in[3]) & 0x3F); - } + *out++ = ((stridx(base64encodestring, in[2]) & 0x03) << 6U) + | (stridx(base64encodestring, in[3]) & 0x3F); + } - *out = 0; -} + *out = 0; +} /* @@ -2225,36 +2155,35 @@ void base64decode(char *in,char *out) * * returns -1 if not found. key_idx will hold key if found */ -int binary_search(const u64_t *array, unsigned arraysize, u64_t key, +int binary_search(const u64_t * array, unsigned arraysize, u64_t key, unsigned int *key_idx) { - unsigned low, high, mid = 1; - - assert(key_idx != NULL); - *key_idx = 0; - if (arraysize == 0) - return -1; - - low = 0; - high = arraysize-1; - - while (low <= high) { - mid = (high + low) / (unsigned) 2; - if (array[mid] < key) - low = mid + 1; - else if (array[mid] > key) { - if (mid > 0) - high = mid - 1; - else - break; - } - else { - *key_idx = mid; - return 1; - } - } - - return -1; /* not found */ + unsigned low, high, mid = 1; + + assert(key_idx != NULL); + *key_idx = 0; + if (arraysize == 0) + return -1; + + low = 0; + high = arraysize - 1; + + while (low <= high) { + mid = (high + low) / (unsigned) 2; + if (array[mid] < key) + low = mid + 1; + else if (array[mid] > key) { + if (mid > 0) + high = mid - 1; + else + break; + } else { + *key_idx = mid; + return 1; + } + } + + return -1; /* not found */ } /* @@ -2266,28 +2195,29 @@ int binary_search(const u64_t *array, unsigned arraysize, u64_t key, * * returns the number of bytes outputted. */ -int quoted_string_out(FILE *outstream, const char *s) +int quoted_string_out(FILE * outstream, const char *s) { - int i,cnt; - - // check wheter we must use literal string - for (i = 0; s[i]; i++) - { - if (!(s[i] & 0xe0) || (s[i] & 0x80) || (s[i] == '"') || (s[i] == '\\')) - { - cnt = fprintf(outstream, "{"); - cnt += fprintf(outstream, "%lu", (unsigned long) strlen(s)); - cnt += fprintf(outstream, "}\r\n"); - cnt += fprintf(outstream, "%s", s); - return cnt; + int i, cnt; + + // check wheter we must use literal string + for (i = 0; s[i]; i++) { + if (!(s[i] & 0xe0) || (s[i] & 0x80) || (s[i] == '"') + || (s[i] == '\\')) { + cnt = fprintf(outstream, "{"); + cnt += + fprintf(outstream, "%lu", + (unsigned long) strlen(s)); + cnt += fprintf(outstream, "}\r\n"); + cnt += fprintf(outstream, "%s", s); + return cnt; + } } - } - cnt = fprintf(outstream, "\""); - cnt += fprintf(outstream, "%s", s); - cnt += fprintf(outstream, "\""); + cnt = fprintf(outstream, "\""); + cnt += fprintf(outstream, "%s", s); + cnt += fprintf(outstream, "\""); - return cnt; + return cnt; } @@ -2297,25 +2227,23 @@ int quoted_string_out(FILE *outstream, const char *s) * sends cnt bytes from a MEM structure to a FILE stream * uses a simple buffering system */ -void send_data(FILE *to, MEM *from, int cnt) +void send_data(FILE * to, MEM * from, int cnt) { - char buf[SEND_BUF_SIZE]; + char buf[SEND_BUF_SIZE]; - for (cnt -= SEND_BUF_SIZE; cnt >= 0; cnt -= SEND_BUF_SIZE) - { - mread(buf, SEND_BUF_SIZE, from); - fwrite(buf, SEND_BUF_SIZE, 1, to); - } + for (cnt -= SEND_BUF_SIZE; cnt >= 0; cnt -= SEND_BUF_SIZE) { + mread(buf, SEND_BUF_SIZE, from); + fwrite(buf, SEND_BUF_SIZE, 1, to); + } - if (cnt < 0) - { - mread(buf, cnt+SEND_BUF_SIZE, from); - fwrite(buf, cnt+SEND_BUF_SIZE, 1, to); - } + if (cnt < 0) { + mread(buf, cnt + SEND_BUF_SIZE, from); + fwrite(buf, cnt + SEND_BUF_SIZE, 1, to); + } - fflush(to); + fflush(to); } - + /* @@ -2328,441 +2256,374 @@ void send_data(FILE *to, MEM *from, int cnt) */ int build_imap_search(char **search_keys, struct list *sl, int *idx) { - search_key_t key; - int result; - - if (!search_keys || !search_keys[*idx]) - return 0; - - memset(&key, 0, sizeof(key)); - - if (strcasecmp(search_keys[*idx], "all") == 0) - { - key.type = IST_SET; - strcpy(key.search, "1:*"); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "uid") == 0) - { - key.type = IST_SET_UID; - if (!search_keys[*idx+1]) - return -1; - - (*idx)++; - - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - if (!check_msg_set(key.search)) - return -1; - - (*idx)++; - } - - /* - * FLAG search keys - */ - - else if (strcasecmp(search_keys[*idx], "answered") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "answered_flag=1", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "deleted") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "deleted_flag=1", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "flagged") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "flagged_flag=1", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "recent") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "recent_flag=1", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "seen") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "seen_flag=1", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "keyword") == 0) - { - /* no results from this one */ - if (!search_keys[(*idx)+1]) /* there should follow an argument */ - return -1; - - (*idx)++; - - key.type = IST_SET; - strcpy(key.search, "0"); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "draft") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "draft_flag=1", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "new") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "(seen_flag=0 AND recent_flag=1)", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "old") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "recent_flag=0", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "unanswered") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "answered_flag=0", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "undeleted") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "deleted_flag=0", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "unflagged") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "flagged_flag=0", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "unseen") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "seen_flag=0", MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "unkeyword") == 0) - { - /* matches every msg */ - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - - key.type = IST_SET; - strcpy(key.search, "1:*"); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "undraft") == 0) - { - key.type = IST_FLAG; - strncpy(key.search, "draft_flag=0", MAX_SEARCH_LEN); - (*idx)++; - } - - /* - * HEADER search keys - */ - - else if (strcasecmp(search_keys[*idx], "bcc") == 0) - { - key.type = IST_HDR; - strncpy(key.hdrfld, "bcc", MIME_FIELD_MAX); - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "cc") == 0) - { - key.type = IST_HDR; - strncpy(key.hdrfld, "cc", MIME_FIELD_MAX); - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "from") == 0) - { - key.type = IST_HDR; - strncpy(key.hdrfld, "from", MIME_FIELD_MAX); - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "to") == 0) - { - key.type = IST_HDR; - strncpy(key.hdrfld, "to", MIME_FIELD_MAX); - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "subject") == 0) - { - key.type = IST_HDR; - strncpy(key.hdrfld, "subject", MIME_FIELD_MAX); - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "header") == 0) - { - key.type = IST_HDR; - if (!search_keys[(*idx)+1] || !search_keys[(*idx)+2]) - return -1; - - strncpy(key.hdrfld, search_keys[(*idx)+1], MIME_FIELD_MAX); - strncpy(key.search, search_keys[(*idx)+2], MAX_SEARCH_LEN); - - (*idx) += 3; - } - else if (strcasecmp(search_keys[*idx], "sentbefore") == 0) - { - key.type = IST_HDRDATE_BEFORE; - strncpy(key.hdrfld, "date", MIME_FIELD_MAX); - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "senton") == 0) - { - key.type = IST_HDRDATE_ON; - strncpy(key.hdrfld, "date", MIME_FIELD_MAX); - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "sentsince") == 0) - { - key.type = IST_HDRDATE_SINCE; - strncpy(key.hdrfld, "date", MIME_FIELD_MAX); - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - - /* - * INTERNALDATE keys - */ - - else if (strcasecmp(search_keys[*idx], "before") == 0) - { - key.type = IST_IDATE; - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - if (!check_date(search_keys[*idx])) - return -1; - - strncpy(key.search, "internal_date<'", MAX_SEARCH_LEN); - strncat(key.search, date_imap2sql(search_keys[*idx]), - MAX_SEARCH_LEN - sizeof("internal_date<''")); - strcat(key.search, "'"); - - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "on") == 0) - { - key.type = IST_IDATE; - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - if (!check_date(search_keys[*idx])) - return -1; - - strncpy(key.search, "internal_date LIKE '", MAX_SEARCH_LEN); - strncat(key.search, date_imap2sql(search_keys[*idx]), - MAX_SEARCH_LEN - sizeof("internal_date LIKE 'x'")); - strcat(key.search, "%'"); - - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "since") == 0) - { - key.type = IST_IDATE; - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - if (!check_date(search_keys[*idx])) - return -1; - - strncpy(key.search, "internal_date>'", MAX_SEARCH_LEN); - strncat(key.search, date_imap2sql(search_keys[*idx]), - MAX_SEARCH_LEN - sizeof("internal_date>''")); - strcat(key.search, "'"); - - (*idx)++; - } - - /* - * DATA-keys - */ - - else if (strcasecmp(search_keys[*idx], "body") == 0) - { - key.type = IST_DATA_BODY; - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "text") == 0) - { - key.type = IST_DATA_TEXT; - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); - (*idx)++; - } - - /* - * SIZE keys - */ - - else if (strcasecmp(search_keys[*idx], "larger") == 0) - { - key.type = IST_SIZE_LARGER; - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - key.size = strtoull(search_keys[(*idx)], NULL, 10); - (*idx)++; - } - else if (strcasecmp(search_keys[*idx], "smaller") == 0) - { - key.type = IST_SIZE_SMALLER; - if (!search_keys[(*idx)+1]) - return -1; - - (*idx)++; - key.size = strtoull(search_keys[(*idx)], NULL, 10); - (*idx)++; - } - - /* - * NOT, OR, () - */ - else if (strcasecmp(search_keys[*idx], "not") == 0) - { - key.type = IST_SUBSEARCH_NOT; - - (*idx)++; - if ((result = build_imap_search(search_keys, &key.sub_search, idx)) < 0) - { - list_freelist(&key.sub_search.start); - return result; + search_key_t key; + int result; + + if (!search_keys || !search_keys[*idx]) + return 0; + + memset(&key, 0, sizeof(key)); + + if (strcasecmp(search_keys[*idx], "all") == 0) { + key.type = IST_SET; + strcpy(key.search, "1:*"); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "uid") == 0) { + key.type = IST_SET_UID; + if (!search_keys[*idx + 1]) + return -1; + + (*idx)++; + + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + if (!check_msg_set(key.search)) + return -1; + + (*idx)++; } - /* a NOT should be unary */ - if (key.sub_search.total_nodes != 1) - { - free_searchlist(&key.sub_search); - return -1; + /* + * FLAG search keys + */ + + else if (strcasecmp(search_keys[*idx], "answered") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "answered_flag=1", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "deleted") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "deleted_flag=1", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "flagged") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "flagged_flag=1", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "recent") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "recent_flag=1", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "seen") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "seen_flag=1", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "keyword") == 0) { + /* no results from this one */ + if (!search_keys[(*idx) + 1]) /* there should follow an argument */ + return -1; + + (*idx)++; + + key.type = IST_SET; + strcpy(key.search, "0"); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "draft") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "draft_flag=1", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "new") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "(seen_flag=0 AND recent_flag=1)", + MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "old") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "recent_flag=0", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "unanswered") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "answered_flag=0", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "undeleted") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "deleted_flag=0", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "unflagged") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "flagged_flag=0", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "unseen") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "seen_flag=0", MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "unkeyword") == 0) { + /* matches every msg */ + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + + key.type = IST_SET; + strcpy(key.search, "1:*"); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "undraft") == 0) { + key.type = IST_FLAG; + strncpy(key.search, "draft_flag=0", MAX_SEARCH_LEN); + (*idx)++; } - } - else if (strcasecmp(search_keys[*idx], "or") == 0) - { - key.type = IST_SUBSEARCH_OR; - - (*idx)++; - if ((result = build_imap_search(search_keys, &key.sub_search, idx)) < 0) - { - list_freelist(&key.sub_search.start); - return result; + + /* + * HEADER search keys + */ + + else if (strcasecmp(search_keys[*idx], "bcc") == 0) { + key.type = IST_HDR; + strncpy(key.hdrfld, "bcc", MIME_FIELD_MAX); + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "cc") == 0) { + key.type = IST_HDR; + strncpy(key.hdrfld, "cc", MIME_FIELD_MAX); + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "from") == 0) { + key.type = IST_HDR; + strncpy(key.hdrfld, "from", MIME_FIELD_MAX); + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "to") == 0) { + key.type = IST_HDR; + strncpy(key.hdrfld, "to", MIME_FIELD_MAX); + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "subject") == 0) { + key.type = IST_HDR; + strncpy(key.hdrfld, "subject", MIME_FIELD_MAX); + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "header") == 0) { + key.type = IST_HDR; + if (!search_keys[(*idx) + 1] || !search_keys[(*idx) + 2]) + return -1; + + strncpy(key.hdrfld, search_keys[(*idx) + 1], + MIME_FIELD_MAX); + strncpy(key.search, search_keys[(*idx) + 2], + MAX_SEARCH_LEN); + + (*idx) += 3; + } else if (strcasecmp(search_keys[*idx], "sentbefore") == 0) { + key.type = IST_HDRDATE_BEFORE; + strncpy(key.hdrfld, "date", MIME_FIELD_MAX); + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "senton") == 0) { + key.type = IST_HDRDATE_ON; + strncpy(key.hdrfld, "date", MIME_FIELD_MAX); + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "sentsince") == 0) { + key.type = IST_HDRDATE_SINCE; + strncpy(key.hdrfld, "date", MIME_FIELD_MAX); + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; } - if ((result = build_imap_search(search_keys, &key.sub_search, idx)) < 0) - { - list_freelist(&key.sub_search.start); - return result; + /* + * INTERNALDATE keys + */ + + else if (strcasecmp(search_keys[*idx], "before") == 0) { + key.type = IST_IDATE; + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + if (!check_date(search_keys[*idx])) + return -1; + + strncpy(key.search, "internal_date<'", MAX_SEARCH_LEN); + strncat(key.search, date_imap2sql(search_keys[*idx]), + MAX_SEARCH_LEN - sizeof("internal_date<''")); + strcat(key.search, "'"); + + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "on") == 0) { + key.type = IST_IDATE; + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + if (!check_date(search_keys[*idx])) + return -1; + + strncpy(key.search, "internal_date LIKE '", + MAX_SEARCH_LEN); + strncat(key.search, date_imap2sql(search_keys[*idx]), + MAX_SEARCH_LEN - sizeof("internal_date LIKE 'x'")); + strcat(key.search, "%'"); + + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "since") == 0) { + key.type = IST_IDATE; + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + if (!check_date(search_keys[*idx])) + return -1; + + strncpy(key.search, "internal_date>'", MAX_SEARCH_LEN); + strncat(key.search, date_imap2sql(search_keys[*idx]), + MAX_SEARCH_LEN - sizeof("internal_date>''")); + strcat(key.search, "'"); + + (*idx)++; } - /* an OR should be binary */ - if (key.sub_search.total_nodes != 2) - { - free_searchlist(&key.sub_search); - return -1; + /* + * DATA-keys + */ + + else if (strcasecmp(search_keys[*idx], "body") == 0) { + key.type = IST_DATA_BODY; + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "text") == 0) { + key.type = IST_DATA_TEXT; + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + strncpy(key.search, search_keys[(*idx)], MAX_SEARCH_LEN); + (*idx)++; } - } - else if (strcasecmp(search_keys[*idx], "(") == 0) - { - key.type = IST_SUBSEARCH_AND; + /* + * SIZE keys + */ + + else if (strcasecmp(search_keys[*idx], "larger") == 0) { + key.type = IST_SIZE_LARGER; + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + key.size = strtoull(search_keys[(*idx)], NULL, 10); + (*idx)++; + } else if (strcasecmp(search_keys[*idx], "smaller") == 0) { + key.type = IST_SIZE_SMALLER; + if (!search_keys[(*idx) + 1]) + return -1; + + (*idx)++; + key.size = strtoull(search_keys[(*idx)], NULL, 10); + (*idx)++; + } - (*idx)++; - while ((result = build_imap_search(search_keys, &key.sub_search, idx)) == 0 - && search_keys[*idx]) ; + /* + * NOT, OR, () + */ + else if (strcasecmp(search_keys[*idx], "not") == 0) { + key.type = IST_SUBSEARCH_NOT; + + (*idx)++; + if ((result = + build_imap_search(search_keys, &key.sub_search, + idx)) < 0) { + list_freelist(&key.sub_search.start); + return result; + } - if (result < 0) - { - /* error */ - list_freelist(&key.sub_search.start); - return result; - } + /* a NOT should be unary */ + if (key.sub_search.total_nodes != 1) { + free_searchlist(&key.sub_search); + return -1; + } + } else if (strcasecmp(search_keys[*idx], "or") == 0) { + key.type = IST_SUBSEARCH_OR; + + (*idx)++; + if ((result = + build_imap_search(search_keys, &key.sub_search, + idx)) < 0) { + list_freelist(&key.sub_search.start); + return result; + } + + if ((result = + build_imap_search(search_keys, &key.sub_search, + idx)) < 0) { + list_freelist(&key.sub_search.start); + return result; + } + + /* an OR should be binary */ + if (key.sub_search.total_nodes != 2) { + free_searchlist(&key.sub_search); + return -1; + } - if (result == 0) - { - /* no ')' encountered (should not happen, parentheses are matched at the command line) */ - free_searchlist(&key.sub_search); - return -1; + } else if (strcasecmp(search_keys[*idx], "(") == 0) { + key.type = IST_SUBSEARCH_AND; + + (*idx)++; + while ((result = + build_imap_search(search_keys, &key.sub_search, + idx)) == 0 && search_keys[*idx]); + + if (result < 0) { + /* error */ + list_freelist(&key.sub_search.start); + return result; + } + + if (result == 0) { + /* no ')' encountered (should not happen, parentheses are matched at the command line) */ + free_searchlist(&key.sub_search); + return -1; + } + } else if (strcasecmp(search_keys[*idx], ")") == 0) { + (*idx)++; + return 1; + } else if (check_msg_set(search_keys[*idx])) { + key.type = IST_SET; + strncpy(key.search, search_keys[*idx], MAX_SEARCH_LEN); + (*idx)++; + } else { + /* unknown search key */ + return -1; } - } - else if (strcasecmp(search_keys[*idx], ")") == 0) - { - (*idx)++; - return 1; - } - else if (check_msg_set(search_keys[*idx])) - { - key.type = IST_SET; - strncpy(key.search, search_keys[*idx], MAX_SEARCH_LEN); - (*idx)++; - } - else - { - /* unknown search key */ - return -1; - } - - if (!list_nodeadd(sl, &key, sizeof(key))) - return -2; - - return 0; + + if (!list_nodeadd(sl, &key, sizeof(key))) + return -2; + + return 0; } @@ -2772,105 +2633,103 @@ int build_imap_search(char **search_keys, struct list *sl, int *idx) * returns 0 on succes, -1 on dbase error, -2 on memory error, 1 if result set is too small * (new mail has been added to mailbox while searching, mailbox data out of sync) */ -int perform_imap_search(int *rset, int setlen, search_key_t *sk, mailbox_t *mb) +int perform_imap_search(int *rset, int setlen, search_key_t * sk, + mailbox_t * mb) { - search_key_t *subsk; - struct element *el; - int result,*newset = NULL,i; - int subtype = IST_SUBSEARCH_OR; - - if (!rset) - return -2; /* stupidity */ - - if (!sk) - return 0; /* no search */ - - newset = (int*)my_malloc(sizeof(int) * setlen); - if (!newset) - return -2; - - switch (sk->type) - { - case IST_SET: - build_set(rset, setlen, sk->search); - break; - - case IST_SET_UID: - build_uid_set(rset, setlen, sk->search, mb); - break; - - case IST_FLAG: - result = db_search(rset, setlen, sk->search, mb, sk->type); - if (result != 0) - { - my_free(newset); - return result; - } - break; - - case IST_HDR: - case IST_HDRDATE_BEFORE: - case IST_HDRDATE_ON: - case IST_HDRDATE_SINCE: - case IST_DATA_BODY: - case IST_DATA_TEXT: - case IST_SIZE_LARGER: - case IST_SIZE_SMALLER: - /* these all have in common that a message should be parsed before - matching is possible - */ - result = db_search_parsed(rset, setlen, sk, mb); - break; - - case IST_IDATE: - result = db_search(rset, setlen, sk->search, mb, sk->type); - if (result != 0) - { - my_free(newset); - return result; - } - break; - - case IST_SUBSEARCH_NOT: - case IST_SUBSEARCH_AND: - subtype = IST_SUBSEARCH_AND; - - case IST_SUBSEARCH_OR: - el = list_getstart(&sk->sub_search); - while (el) - { - subsk = (search_key_t*)el->data; - - if (subsk->type == IST_SUBSEARCH_OR) - memset(newset, 0, sizeof(int)*setlen); - else if (subsk->type == IST_SUBSEARCH_AND || subsk->type == IST_SUBSEARCH_NOT) - for (i=0; i<setlen; i++) - newset[i] = 1; - - result = perform_imap_search(newset, setlen, subsk, mb); - if (result < 0 || result == 1) - { - my_free(newset); - return result; - } - - combine_sets(rset, newset, setlen, subtype); - - el = el->nextnode; - } + search_key_t *subsk; + struct element *el; + int result, *newset = NULL, i; + int subtype = IST_SUBSEARCH_OR; + + if (!rset) + return -2; /* stupidity */ + + if (!sk) + return 0; /* no search */ + + newset = (int *) my_malloc(sizeof(int) * setlen); + if (!newset) + return -2; + + switch (sk->type) { + case IST_SET: + build_set(rset, setlen, sk->search); + break; - if (sk->type == IST_SUBSEARCH_NOT) - invert_set(rset, setlen); + case IST_SET_UID: + build_uid_set(rset, setlen, sk->search, mb); + break; + + case IST_FLAG: + result = db_search(rset, setlen, sk->search, mb, sk->type); + if (result != 0) { + my_free(newset); + return result; + } + break; + + case IST_HDR: + case IST_HDRDATE_BEFORE: + case IST_HDRDATE_ON: + case IST_HDRDATE_SINCE: + case IST_DATA_BODY: + case IST_DATA_TEXT: + case IST_SIZE_LARGER: + case IST_SIZE_SMALLER: + /* these all have in common that a message should be parsed before + matching is possible + */ + result = db_search_parsed(rset, setlen, sk, mb); + break; - break; + case IST_IDATE: + result = db_search(rset, setlen, sk->search, mb, sk->type); + if (result != 0) { + my_free(newset); + return result; + } + break; + + case IST_SUBSEARCH_NOT: + case IST_SUBSEARCH_AND: + subtype = IST_SUBSEARCH_AND; + + case IST_SUBSEARCH_OR: + el = list_getstart(&sk->sub_search); + while (el) { + subsk = (search_key_t *) el->data; + + if (subsk->type == IST_SUBSEARCH_OR) + memset(newset, 0, sizeof(int) * setlen); + else if (subsk->type == IST_SUBSEARCH_AND + || subsk->type == IST_SUBSEARCH_NOT) + for (i = 0; i < setlen; i++) + newset[i] = 1; + + result = + perform_imap_search(newset, setlen, subsk, mb); + if (result < 0 || result == 1) { + my_free(newset); + return result; + } + + combine_sets(rset, newset, setlen, subtype); - default: - my_free(newset); - return -2; /* ??? */ - } - - my_free(newset); - return 0; + el = el->nextnode; + } + + if (sk->type == IST_SUBSEARCH_NOT) + invert_set(rset, setlen); + + break; + + default: + my_free(newset); + return -2; /* ??? */ + } + + my_free(newset); + return 0; } @@ -2880,60 +2739,56 @@ int perform_imap_search(int *rset, int setlen, search_key_t *sk, mailbox_t *mb) */ void free_searchlist(struct list *sl) { - search_key_t *sk; - struct element *el; - - if (!sl) - return; - - el = list_getstart(sl); - - while (el) - { - sk = (search_key_t*)el->data; - - free_searchlist(&sk->sub_search); - list_freelist(&sk->sub_search.start); - - el = el->nextnode; - } - - list_freelist(&sl->start); - return; + search_key_t *sk; + struct element *el; + + if (!sl) + return; + + el = list_getstart(sl); + + while (el) { + sk = (search_key_t *) el->data; + + free_searchlist(&sk->sub_search); + list_freelist(&sk->sub_search.start); + + el = el->nextnode; + } + + list_freelist(&sl->start); + return; } void invert_set(int *set, int setlen) { - int i; + int i; - if (!set) - return; + if (!set) + return; - for (i=0; i<setlen; i++) - set[i] = !set[i]; + for (i = 0; i < setlen; i++) + set[i] = !set[i]; } void combine_sets(int *dest, int *sec, int setlen, int type) { - int i; - - if (!dest || !sec) - return; - - if (type == IST_SUBSEARCH_AND) - { - for (i=0; i<setlen; i++) - dest[i] = (sec[i] && dest[i]); - } - else if (type == IST_SUBSEARCH_OR) - { - for (i=0; i<setlen; i++) - dest[i] = (sec[i] || dest[i]); - } + int i; + + if (!dest || !sec) + return; + + if (type == IST_SUBSEARCH_AND) { + for (i = 0; i < setlen; i++) + dest[i] = (sec[i] && dest[i]); + } else if (type == IST_SUBSEARCH_OR) { + for (i = 0; i < setlen; i++) + dest[i] = (sec[i] || dest[i]); + } } - + /* * build_set() @@ -2943,77 +2798,66 @@ void combine_sets(int *dest, int *sec, int setlen, int type) */ void build_set(int *set, unsigned int setlen, char *cset) { - unsigned int i; - u64_t num,num2; - char *sep=NULL; - - if (!set) - return; - - memset(set, 0, setlen * sizeof(int)); - - if (!cset) - return; - - do - { - num = strtoull(cset, &sep, 10); - - if (num <= setlen && num > 0) - { - if (!*sep) - set[num-1] = 1; - else if (*sep == ',') - { - set[num-1] = 1; - cset = sep+1; - } - else - { - /* sep == ':' here */ - sep++; - if (*sep == '*') - { - for (i=num-1; i<setlen; i++) - set[i] = 1; - - cset = sep+1; - } - else - { - cset = sep; - num2 = strtoull(cset, &sep, 10); - - if (num2 > setlen) num2 = setlen; - if (num2 > 0) - { - /* NOTE: here: num2 > 0, num > 0 */ - if (num2 < num) - { - /* swap! */ - i = num; - num = num2; - num2 = i; + unsigned int i; + u64_t num, num2; + char *sep = NULL; + + if (!set) + return; + + memset(set, 0, setlen * sizeof(int)); + + if (!cset) + return; + + do { + num = strtoull(cset, &sep, 10); + + if (num <= setlen && num > 0) { + if (!*sep) + set[num - 1] = 1; + else if (*sep == ',') { + set[num - 1] = 1; + cset = sep + 1; + } else { + /* sep == ':' here */ + sep++; + if (*sep == '*') { + for (i = num - 1; i < setlen; i++) + set[i] = 1; + + cset = sep + 1; + } else { + cset = sep; + num2 = strtoull(cset, &sep, 10); + + if (num2 > setlen) + num2 = setlen; + if (num2 > 0) { + /* NOTE: here: num2 > 0, num > 0 */ + if (num2 < num) { + /* swap! */ + i = num; + num = num2; + num2 = i; + } + + for (i = num - 1; i < num2; + i++) + set[i] = 1; + } + if (*sep) + cset = sep + 1; + } + } + } else { + /* invalid num, skip it */ + if (*sep) { + cset = sep + 1; + sep++; } - - for (i=num-1; i<num2; i++) - set[i] = 1; - } - if (*sep) - cset = sep+1; } - } - } - else - { - /* invalid num, skip it */ - if (*sep) - { - cset = sep+1; - sep++; - } - } - } while (sep && *sep && cset && *cset); + } while (sep && *sep && cset && *cset); } @@ -3022,188 +2866,193 @@ void build_set(int *set, unsigned int setlen, char *cset) * * as build_set() but takes uid's instead of MSN's */ -void build_uid_set(int *set, unsigned int setlen, char *cset, mailbox_t *mb) +void build_uid_set(int *set, unsigned int setlen, char *cset, + mailbox_t * mb) { - unsigned int i, msn, msn2; - int result; - int num2found = 0; - u64_t num,num2; - char *sep=NULL; - - if (!set) - return; - - memset(set, 0, setlen * sizeof(int)); - - if (!cset || setlen == 0) - return; - - do - { - num = strtoull(cset, &sep, 10); - result = binary_search(mb->seq_list, mb->exists, num, &msn); - - if (result < 0 && num < mb->seq_list[mb->exists-1]) - { - /* ok this num is not a UID, but if a range is specified (i.e. 1:*) - * it is valid -> check *sep - */ - if (*sep == ':') - { - for (msn=0; mb->seq_list[msn] < num; msn++) ; - if (msn >= mb->exists) - msn = mb->exists-1; - } - } - - if (result >= 0) - { - if (!*sep) - set[msn] = 1; - else if (*sep == ',') - { - set[msn] = 1; - cset = sep+1; - } - else - { - /* sep == ':' here */ - sep++; - if (*sep == '*') - { - for (i=msn; i<setlen; i++) - set[i] = 1; - - cset = sep+1; + unsigned int i, msn, msn2; + int result; + int num2found = 0; + u64_t num, num2; + char *sep = NULL; + + if (!set) + return; + + memset(set, 0, setlen * sizeof(int)); + + if (!cset || setlen == 0) + return; + + do { + num = strtoull(cset, &sep, 10); + result = + binary_search(mb->seq_list, mb->exists, num, &msn); + + if (result < 0 && num < mb->seq_list[mb->exists - 1]) { + /* ok this num is not a UID, but if a range is specified (i.e. 1:*) + * it is valid -> check *sep + */ + if (*sep == ':') { + for (msn = 0; mb->seq_list[msn] < num; + msn++); + if (msn >= mb->exists) + msn = mb->exists - 1; + } } - else - { - /* fetch second number */ - cset = sep; - num2 = strtoull(cset, &sep, 10); - result = binary_search(mb->seq_list, mb->exists, - num2, &msn2); - - if (result < 0) - { - /* in a range: (like 1:1000) so this number doesnt need to exist; - * find the closest match below this UID value - */ - if (mb->exists == 0) - num2found = 0; - else { - for (msn2 = mb->exists - 1;; msn2--) { - if (msn2 == 0 && mb->seq_list[msn2] > num2) { - num2found = 0; - break; - } else if (mb->seq_list[msn2] <= num2) { - /* found! */ - num2found = 1; - break; + + if (result >= 0) { + if (!*sep) + set[msn] = 1; + else if (*sep == ',') { + set[msn] = 1; + cset = sep + 1; + } else { + /* sep == ':' here */ + sep++; + if (*sep == '*') { + for (i = msn; i < setlen; i++) + set[i] = 1; + + cset = sep + 1; + } else { + /* fetch second number */ + cset = sep; + num2 = strtoull(cset, &sep, 10); + result = + binary_search(mb->seq_list, + mb->exists, num2, + &msn2); + + if (result < 0) { + /* in a range: (like 1:1000) so this number doesnt need to exist; + * find the closest match below this UID value + */ + if (mb->exists == 0) + num2found = 0; + else { + for (msn2 = + mb->exists - + 1;; msn2--) { + if (msn2 == + 0 + && mb-> + seq_list + [msn2] + > num2) { + num2found + = + 0; + break; + } else + if + (mb-> + seq_list + [msn2] + <= + num2) + { + /* found! */ + num2found + = + 1; + break; + } + } + } + + } else + num2found = 1; + + if (num2found == 1) { + if (msn2 < msn) { + /* swap! */ + i = msn; + msn = msn2; + msn2 = i; + } + + for (i = msn; i <= msn2; + i++) + set[i] = 1; + } + + if (*sep) + cset = sep + 1; } - } - } - - } else - num2found = 1; - - if (num2found == 1) - { - if (msn2 < msn) - { - /* swap! */ - i = msn; - msn = msn2; - msn2 = i; } - - for (i=msn; i<=msn2; i++) - set[i] = 1; - } - - if (*sep) - cset = sep+1; + } else { + /* invalid num, skip it */ + if (*sep) { + cset = sep + 1; + sep++; + } } - } - } - else - { - /* invalid num, skip it */ - if (*sep) - { - cset = sep+1; - sep++; - } - } - } while (sep && *sep && cset && *cset); + } while (sep && *sep && cset && *cset); } -void dumpsearch(search_key_t *sk, int level) +void dumpsearch(search_key_t * sk, int level) { - char *spaces = (char*)my_malloc(level*3 +1); - struct element *el; - search_key_t *subsk; - - if (!spaces) - return; - - memset(spaces, ' ',level*3); - spaces[level*3] = 0; - - if (!sk) - { - trace(TRACE_DEBUG,"%s(null)\n",spaces); - my_free(spaces); - return; - } - - switch (sk->type) - { - case IST_SUBSEARCH_NOT: - trace(TRACE_DEBUG,"%sNOT\n",spaces); - - el = list_getstart(&sk->sub_search); - if (el) - subsk = (search_key_t*)el->data; - else - subsk = NULL; - - dumpsearch(subsk, level+1); - break; - - case IST_SUBSEARCH_AND: - trace(TRACE_DEBUG,"%sAND\n",spaces); - el = list_getstart(&sk->sub_search); - - while (el) - { - subsk = (search_key_t*)el->data; - dumpsearch(subsk, level+1); - - el = el->nextnode; - } - break; - - case IST_SUBSEARCH_OR: - trace(TRACE_DEBUG,"%sOR\n",spaces); - el = list_getstart(&sk->sub_search); - - while (el) - { - subsk = (search_key_t*)el->data; - dumpsearch(subsk, level+1); - - el = el->nextnode; + char *spaces = (char *) my_malloc(level * 3 + 1); + struct element *el; + search_key_t *subsk; + + if (!spaces) + return; + + memset(spaces, ' ', level * 3); + spaces[level * 3] = 0; + + if (!sk) { + trace(TRACE_DEBUG, "%s(null)\n", spaces); + my_free(spaces); + return; } - break; - default: - trace(TRACE_DEBUG,"%s[type %d] \"%s\"\n",spaces,sk->type,sk->search); - } + switch (sk->type) { + case IST_SUBSEARCH_NOT: + trace(TRACE_DEBUG, "%sNOT\n", spaces); - my_free(spaces); - return; + el = list_getstart(&sk->sub_search); + if (el) + subsk = (search_key_t *) el->data; + else + subsk = NULL; + + dumpsearch(subsk, level + 1); + break; + + case IST_SUBSEARCH_AND: + trace(TRACE_DEBUG, "%sAND\n", spaces); + el = list_getstart(&sk->sub_search); + + while (el) { + subsk = (search_key_t *) el->data; + dumpsearch(subsk, level + 1); + + el = el->nextnode; + } + break; + + case IST_SUBSEARCH_OR: + trace(TRACE_DEBUG, "%sOR\n", spaces); + el = list_getstart(&sk->sub_search); + + while (el) { + subsk = (search_key_t *) el->data; + dumpsearch(subsk, level + 1); + + el = el->nextnode; + } + break; + + default: + trace(TRACE_DEBUG, "%s[type %d] \"%s\"\n", spaces, + sk->type, sk->search); + } + + my_free(spaces); + return; } @@ -3212,15 +3061,15 @@ void dumpsearch(search_key_t *sk, int level) */ void close_cache() { - if (cached_msg.msg_parsed) - db_free_msg(&cached_msg.msg); + if (cached_msg.msg_parsed) + db_free_msg(&cached_msg.msg); - cached_msg.num = -1; - cached_msg.msg_parsed = 0; - memset(&cached_msg.msg, 0, sizeof(cached_msg.msg)); + cached_msg.num = -1; + cached_msg.msg_parsed = 0; + memset(&cached_msg.msg, 0, sizeof(cached_msg.msg)); - mclose(&cached_msg.memdump); - mclose(&cached_msg.tmpdump); + mclose(&cached_msg.memdump); + mclose(&cached_msg.tmpdump); } /* @@ -3228,22 +3077,21 @@ void close_cache() */ int init_cache() { - cached_msg.num = -1; - cached_msg.msg_parsed = 0; - memset(&cached_msg.msg, 0, sizeof(cached_msg.msg)); - - cached_msg.memdump = mopen(); - if (!cached_msg.memdump) - return -1; - - cached_msg.tmpdump = mopen(); - if (!cached_msg.tmpdump) - { - mclose(&cached_msg.memdump); - return -1; - } - - cached_msg.file_dumped = 0; - cached_msg.dumpsize = 0; - return 0; + cached_msg.num = -1; + cached_msg.msg_parsed = 0; + memset(&cached_msg.msg, 0, sizeof(cached_msg.msg)); + + cached_msg.memdump = mopen(); + if (!cached_msg.memdump) + return -1; + + cached_msg.tmpdump = mopen(); + if (!cached_msg.tmpdump) { + mclose(&cached_msg.memdump); + return -1; + } + + cached_msg.file_dumped = 0; + cached_msg.dumpsize = 0; + return 0; } @@ -39,24 +39,24 @@ #include "clientinfo.h" #include <stdio.h> -int retrieve_structure(FILE *outstream, mime_message_t *msg, int show_extension_data); -int retrieve_envelope(FILE *outstream, struct list *rfcheader); -int show_address_list(FILE *outstream, struct mime_record *mr); -int show_mime_parameter_list(FILE *outstream, struct mime_record *mr, - int force_subtype, - int only_extension); +int retrieve_structure(FILE * outstream, mime_message_t * msg, + int show_extension_data); +int retrieve_envelope(FILE * outstream, struct list *rfcheader); +int show_address_list(FILE * outstream, struct mime_record *mr); +int show_mime_parameter_list(FILE * outstream, struct mime_record *mr, + int force_subtype, int only_extension); -mime_message_t* get_part_by_num(mime_message_t *msg, const char *part); +mime_message_t *get_part_by_num(mime_message_t * msg, const char *part); -u64_t rfcheader_dump(MEM *outmem, struct list *rfcheader, char **fieldnames, int nfields, - int equal_type); -u64_t mimeheader_dump(MEM *outmem, struct list *mimeheader); +u64_t rfcheader_dump(MEM * outmem, struct list *rfcheader, + char **fieldnames, int nfields, int equal_type); +u64_t mimeheader_dump(MEM * outmem, struct list *mimeheader); int haystack_find(int haystacklen, char **haystack, const char *needle); -int check_state_and_args(const char *command, const char *tag, char **args, - int nargs, int state, ClientInfo *ci); -int next_fetch_item(char **args, int idx, fetch_items_t *fi); +int check_state_and_args(const char *command, const char *tag, char **args, + int nargs, int state, ClientInfo * ci); +int next_fetch_item(char **args, int idx, fetch_items_t * fi); int is_textplain(struct list *hdr); char *date_sql2imap(const char *sqldate); @@ -70,28 +70,30 @@ int check_msg_set(const char *s); int check_date(const char *date); void clarify_data(char *str); char **build_args_array(const char *s); -char **build_args_array_ext(const char *originalString, clientinfo_t *ci); +char **build_args_array_ext(const char *originalString, clientinfo_t * ci); -void base64encode(char *in,char *out); -void base64decode(char *in,char *out); -int binary_search(const u64_t *array, unsigned arraysize, u64_t key, - unsigned int *key_idx); +void base64encode(char *in, char *out); +void base64decode(char *in, char *out); +int binary_search(const u64_t * array, unsigned arraysize, u64_t key, + unsigned int *key_idx); char **give_chunks(const char *str, char delimiter); void free_chunks(char **chunks); -int quoted_string_out(FILE *outstream, const char *s); -void send_data(FILE *to, MEM *from, int cnt); +int quoted_string_out(FILE * outstream, const char *s); +void send_data(FILE * to, MEM * from, int cnt); int build_imap_search(char **search_keys, struct list *sl, int *idx); -int perform_imap_search(int *rset, int setlen, search_key_t *sk, mailbox_t *mb); +int perform_imap_search(int *rset, int setlen, search_key_t * sk, + mailbox_t * mb); void free_searchlist(struct list *sl); void invert_set(int *set, int setlen); void combine_sets(int *dest, int *sec, int setlen, int type); void build_set(int *set, unsigned int setlen, char *cset); -void build_uid_set(int *set, unsigned int setlen, char *cset, mailbox_t *mb); -void dumpsearch(search_key_t *sk, int level); +void build_uid_set(int *set, unsigned int setlen, char *cset, + mailbox_t * mb); +void dumpsearch(search_key_t * sk, int level); int init_cache(void); void close_cache(void); @@ -34,8 +34,8 @@ void list_init(struct list *tlist) { - tlist->start=NULL; - tlist->total_nodes=0; + tlist->start = NULL; + tlist->total_nodes = 0; } @@ -46,17 +46,17 @@ void list_init(struct list *tlist) */ void list_freelist(struct element **start) { - /* check if list exists */ - if (!(*start)) - return; - - /* free rest of list */ - list_freelist(&(*start)->nextnode); - - /* free this item */ - my_free((*start)->data); - my_free(*start); - *start = NULL; + /* check if list exists */ + if (!(*start)) + return; + + /* free rest of list */ + list_freelist(&(*start)->nextnode); + + /* free this item */ + my_free((*start)->data); + my_free(*start); + *start = NULL; } @@ -65,25 +65,25 @@ void list_freelist(struct element **start) * * reverse the order of a linked list */ -struct element* dbmail_list_reverse(struct element *start) +struct element *dbmail_list_reverse(struct element *start) { - struct element *newstart; + struct element *newstart; - if (!start) - return NULL; /* nothing there */ + if (!start) + return NULL; /* nothing there */ - if (!start->nextnode) - return start; /* nothing to reverse */ + if (!start->nextnode) + return start; /* nothing to reverse */ - newstart = dbmail_list_reverse(start->nextnode); /* reverse rest of list */ - start->nextnode->nextnode = start; + newstart = dbmail_list_reverse(start->nextnode); /* reverse rest of list */ + start->nextnode->nextnode = start; - start->nextnode = NULL; /* terminate list */ + start->nextnode = NULL; /* terminate list */ - return newstart; + return newstart; } - + /* * list_nodeadd() * @@ -95,41 +95,41 @@ struct element* dbmail_list_reverse(struct element *start) struct element *list_nodeadd(struct list *tlist, const void *data, size_t dsize) { - struct element *p; - - if (!tlist) - return NULL; /* cannot add to non-existing list */ - - p=tlist->start; - - tlist->start=(struct element *)my_malloc(sizeof(struct element)); - - /* allocating memory */ + struct element *p; + + if (!tlist) + return NULL; /* cannot add to non-existing list */ + + p = tlist->start; + + tlist->start = + (struct element *) my_malloc(sizeof(struct element)); + + /* allocating memory */ #ifdef USE_EXIT_ON_ERROR - memtst(tlist->start==NULL); - memtst((tlist->start->data=(void *)my_malloc(dsize))==NULL); + memtst(tlist->start == NULL); + memtst((tlist->start->data = (void *) my_malloc(dsize)) == NULL); #else - if (!tlist->start) - return NULL; - - tlist->start->data=(void *)my_malloc(dsize); - if (!tlist->start->data) - { - my_free(tlist->start); - tlist->start = NULL; - return NULL; - } + if (!tlist->start) + return NULL; + + tlist->start->data = (void *) my_malloc(dsize); + if (!tlist->start->data) { + my_free(tlist->start); + tlist->start = NULL; + return NULL; + } #endif - - /* copy data */ - tlist->start->data = memcpy(tlist->start->data,data,dsize); - tlist->start->dsize = dsize; - tlist->start->nextnode=p; + /* copy data */ + tlist->start->data = memcpy(tlist->start->data, data, dsize); + tlist->start->dsize = dsize; + + tlist->start->nextnode = p; /* updating node count */ - tlist->total_nodes++; - return tlist->start; + tlist->total_nodes++; + return tlist->start; } @@ -141,18 +141,18 @@ struct element *list_nodeadd(struct list *tlist, const void *data, */ struct element *list_nodepop(struct list *list) { - struct element *ret; + struct element *ret; + + if (!list || !list->start) + return NULL; - if (!list || !list->start) - return NULL; + ret = list->start; - ret = list->start; + list->start = list->start->nextnode; - list->start = list->start->nextnode; - - return ret; + return ret; } - + /* @@ -162,75 +162,71 @@ struct element *list_nodepop(struct list *list) * * returns */ -struct element *list_nodedel(struct list *tlist,void *data) +struct element *list_nodedel(struct list *tlist, void *data) { - struct element *temp; - struct element *item; - item=NULL; - - if (!tlist) - return NULL; - - temp=tlist->start; - - /* checking if lists exist else return NULL*/ - if (temp==NULL) return NULL; - - while (temp!=NULL) /* walk the list */ - { - if (temp->data==data) - { - if (item==NULL) - { - tlist->start=temp->nextnode; - my_free(temp->data); - my_free((struct element *)temp); - break; - } - else - { - item->nextnode=temp->nextnode; - my_free(temp->data); /* freeing memory */ - my_free((struct element *)temp); - break; - } - /* updating node count */ - tlist->total_nodes--; - } - item=temp; - temp=temp->nextnode; - } - - return NULL; + struct element *temp; + struct element *item; + item = NULL; + + if (!tlist) + return NULL; + + temp = tlist->start; + + /* checking if lists exist else return NULL */ + if (temp == NULL) + return NULL; + + while (temp != NULL) { /* walk the list */ + if (temp->data == data) { + if (item == NULL) { + tlist->start = temp->nextnode; + my_free(temp->data); + my_free((struct element *) temp); + break; + } else { + item->nextnode = temp->nextnode; + my_free(temp->data); /* freeing memory */ + my_free((struct element *) temp); + break; + } + /* updating node count */ + tlist->total_nodes--; + } + item = temp; + temp = temp->nextnode; + } + + return NULL; } struct element *list_getstart(struct list *tlist) { - return (tlist) ? tlist->start : NULL; + return (tlist) ? tlist->start : NULL; } long list_totalnodes(struct list *tlist) { - return (tlist) ? tlist->total_nodes : -1; /* a NULL ptr doesnt even have zero nodes (?) */ + return (tlist) ? tlist->total_nodes : -1; /* a NULL ptr doesnt even have zero nodes (?) */ } void list_showlist(struct list *tlist) { - struct element *temp; - - if (!tlist) - { - trace(TRACE_MESSAGE,"list_showlist(): NULL ptr received\n"); - return; - } - - temp=tlist->start; - while (temp!=NULL) - { - trace (TRACE_MESSAGE,"list_showlist():item found [%s]\n",(char *)temp->data); - temp=temp->nextnode; - } -} + struct element *temp; + + if (!tlist) { + trace(TRACE_MESSAGE, + "list_showlist(): NULL ptr received\n"); + return; + } + + temp = tlist->start; + while (temp != NULL) { + trace(TRACE_MESSAGE, "list_showlist():item found [%s]\n", + (char *) temp->data); + temp = temp->nextnode; + } +} @@ -34,23 +34,21 @@ /* * list data types */ -struct element -{ - void *data; - size_t dsize; - struct element *nextnode; +struct element { + void *data; + size_t dsize; + struct element *nextnode; }; -struct list -{ - struct element *start; - long total_nodes; +struct list { + struct element *start; + long total_nodes; }; struct element *list_nodeadd(struct list *tlist, const void *data, - size_t dsize); + size_t dsize); struct element *list_nodedel(struct list *tlist, void *data); struct element *list_nodepop(struct list *list); @@ -64,6 +62,6 @@ void list_init(struct list *tlist); * export a function with the name list_reverse(). Nice of them, * but a pretty "strange" way to pollute the global namespace */ -struct element* dbmail_list_reverse(struct element *start); +struct element *dbmail_list_reverse(struct element *start); -#endif +#endif @@ -42,639 +42,668 @@ struct list rcpt; char *envelopefrom = NULL; /* allowed lmtp commands */ -const char * const commands [] = -{ - "LHLO", "QUIT", "RSET", "DATA", "MAIL", - "VRFY", "EXPN", "HELP", "NOOP", "RCPT" +const char *const commands[] = { + "LHLO", "QUIT", "RSET", "DATA", "MAIL", + "VRFY", "EXPN", "HELP", "NOOP", "RCPT" }; const char validchars[] = -"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -"_.!@#$%^&*()-+=~[]{}<>:;\\/ "; + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "_.!@#$%^&*()-+=~[]{}<>:;\\/ "; char myhostname[64]; -int lmtp_reset(PopSession_t *session) - { - /* Free the lists and reinitialize - * but only if they were previously - * initialized by LMTP_LHLO... */ - if( session->state == LHLO ) - { - list_freelist( &rcpt.start ); - list_init( &rcpt ); - } - - if( envelopefrom != NULL ) - { - my_free( envelopefrom ); - } - envelopefrom = NULL; - - session->state = LHLO; - - return 1; - } - - -int lmtp_handle_connection(clientinfo_t *ci) +int lmtp_reset(PopSession_t * session) { - /* - Handles connection and calls - lmtp command handler - */ - - int done = 1; /* loop state */ - char *buffer = NULL; /* connection buffer */ - int cnt; /* counter */ - - PopSession_t session; /* current connection session */ - - /* setting Session variables */ - session.error_count = 0; - - session.username = NULL; - session.password = NULL; - - session.SessionResult = 0; - - /* reset counters */ - session.totalsize = 0; - session.virtual_totalsize = 0; - session.totalmessages = 0; - session.virtual_totalmessages = 0; - - - /* getting hostname */ - gethostname(myhostname,64); - myhostname[63] = 0; /* make sure string is terminated */ - - buffer=(char *)my_malloc(INCOMING_BUFFER_SIZE*sizeof(char)); - - if (!buffer) - { - trace(TRACE_MESSAGE,"lmtp_handle_connection(): Could not allocate buffer"); - return 0; - } - - if (ci->tx) - { - /* sending greeting */ - fprintf(ci->tx,"220 %s DBMail LMTP service ready to rock\r\n", - myhostname); - fflush(ci->tx); - } - else - { - trace(TRACE_MESSAGE,"lmtp_handle_connection(): TX stream is null!"); - return 0; - } - - lmtp_reset(&session); - while (done > 0) - { - /* set the timeout counter */ - alarm(ci->timeout); - - /* clear the buffer */ - memset(buffer, 0, INCOMING_BUFFER_SIZE); - - for (cnt=0; cnt < INCOMING_BUFFER_SIZE-1; cnt++) - { - do - { - clearerr(ci->rx); - fread(&buffer[cnt], 1, 1, ci->rx); - - /* leave, an alarm has occured during fread */ - if (!ci->rx) return 0; - } while (ferror(ci->rx) && errno == EINTR); - - if (buffer[cnt] == '\n' || feof(ci->rx) || ferror(ci->rx)) - { - buffer[cnt+1] = '\0'; - break; - } - } - - if (feof(ci->rx) || ferror(ci->rx)) - { - /* check client eof */ - done = -1; - } - else - { - /* reset function handle timeout */ - alarm(0); - /* handle lmtp commands */ - done = lmtp(ci->tx, ci->rx, buffer, ci->ip, &session); - } - fflush(ci->tx); - } - - /* memory cleanup */ - lmtp_reset(&session); - my_free(buffer); - buffer = NULL; - - /* reset timers */ - alarm(0); - __debug_dumpallocs(); - - return 0; + /* Free the lists and reinitialize + * but only if they were previously + * initialized by LMTP_LHLO... */ + if (session->state == LHLO) { + list_freelist(&rcpt.start); + list_init(&rcpt); + } + + if (envelopefrom != NULL) { + my_free(envelopefrom); + } + envelopefrom = NULL; + + session->state = LHLO; + + return 1; } -int lmtp_error(PopSession_t *session, void *stream, const char *formatstring, ...) - __attribute__((format(printf, 3, 4))); -int lmtp_error(PopSession_t *session, void *stream, const char *formatstring, ...) +int lmtp_handle_connection(clientinfo_t * ci) { - va_list argp; - - if (session->error_count>=MAX_ERRORS) - { - trace(TRACE_MESSAGE,"lmtp_error(): too many errors (MAX_ERRORS is %d)",MAX_ERRORS); - fprintf((FILE *)stream, "500 Too many errors, closing connection.\r\n"); - session->SessionResult = 2; /* possible flood */ - lmtp_reset(session); - return -3; - } - else - { - va_start(argp, formatstring); - vfprintf((FILE *)stream, formatstring, argp); - va_end(argp); - } - - trace(TRACE_DEBUG,"lmtp_error(): an invalid command was issued"); - session->error_count++; - return 1; + /* + Handles connection and calls + lmtp command handler + */ + + int done = 1; /* loop state */ + char *buffer = NULL; /* connection buffer */ + int cnt; /* counter */ + + PopSession_t session; /* current connection session */ + + /* setting Session variables */ + session.error_count = 0; + + session.username = NULL; + session.password = NULL; + + session.SessionResult = 0; + + /* reset counters */ + session.totalsize = 0; + session.virtual_totalsize = 0; + session.totalmessages = 0; + session.virtual_totalmessages = 0; + + + /* getting hostname */ + gethostname(myhostname, 64); + myhostname[63] = 0; /* make sure string is terminated */ + + buffer = (char *) my_malloc(INCOMING_BUFFER_SIZE * sizeof(char)); + + if (!buffer) { + trace(TRACE_MESSAGE, + "lmtp_handle_connection(): Could not allocate buffer"); + return 0; + } + + if (ci->tx) { + /* sending greeting */ + fprintf(ci->tx, + "220 %s DBMail LMTP service ready to rock\r\n", + myhostname); + fflush(ci->tx); + } else { + trace(TRACE_MESSAGE, + "lmtp_handle_connection(): TX stream is null!"); + return 0; + } + + lmtp_reset(&session); + while (done > 0) { + /* set the timeout counter */ + alarm(ci->timeout); + + /* clear the buffer */ + memset(buffer, 0, INCOMING_BUFFER_SIZE); + + for (cnt = 0; cnt < INCOMING_BUFFER_SIZE - 1; cnt++) { + do { + clearerr(ci->rx); + fread(&buffer[cnt], 1, 1, ci->rx); + + /* leave, an alarm has occured during fread */ + if (!ci->rx) + return 0; + } while (ferror(ci->rx) && errno == EINTR); + + if (buffer[cnt] == '\n' || feof(ci->rx) + || ferror(ci->rx)) { + buffer[cnt + 1] = '\0'; + break; + } + } + + if (feof(ci->rx) || ferror(ci->rx)) { + /* check client eof */ + done = -1; + } else { + /* reset function handle timeout */ + alarm(0); + /* handle lmtp commands */ + done = + lmtp(ci->tx, ci->rx, buffer, ci->ip, &session); + } + fflush(ci->tx); + } + + /* memory cleanup */ + lmtp_reset(&session); + my_free(buffer); + buffer = NULL; + + /* reset timers */ + alarm(0); + __debug_dumpallocs(); + + return 0; } -int lmtp(void *stream, void *instream, char *buffer, char *client_ip UNUSED, PopSession_t *session) +int lmtp_error(PopSession_t * session, void *stream, + const char *formatstring, ...) + __attribute__ ((format(printf, 3, 4))); +int lmtp_error(PopSession_t * session, void *stream, + const char *formatstring, ...) { - /* returns values: - * 0 to quit - * -1 on failure - * 1 on success */ - char *command, *value; - int cmdtype; - int indx=0; - - /* buffer overflow attempt */ - if (strlen(buffer) > MAX_IN_BUFFER) - { - trace(TRACE_DEBUG, "lmtp(): buffer overflow attempt"); - return -3; - } - - /* check for command issued */ - while (strchr(validchars, buffer[indx])) - indx++; - - /* end buffer */ - buffer[indx]='\0'; - - trace(TRACE_DEBUG,"lmtp(): incoming buffer: [%s]",buffer); - - command = buffer; - - value = strstr(command," "); /* look for the separator */ - - if (value!=NULL) - { - *value = '\0'; /* set a \0 on the command end */ - value++; /* skip space */ - - if (strlen(value) == 0) - { - value=NULL; /* no value specified */ - } - else - { - trace(TRACE_DEBUG,"lmtp(): command issued :cmd [%s], value [%s]\n",command, value); - } - } - - for (cmdtype = LMTP_STRT; cmdtype < LMTP_END; cmdtype ++) - if (strcasecmp(command, commands[cmdtype]) == 0) break; - - trace(TRACE_DEBUG,"lmtp(): command looked up as commandtype %d", cmdtype); - - /* commands that are allowed to have no arguments */ - if ((value==NULL) && - !( - (cmdtype==LMTP_LHLO) || (cmdtype==LMTP_DATA) || - (cmdtype==LMTP_RSET) || (cmdtype==LMTP_QUIT) || - (cmdtype==LMTP_NOOP) || (cmdtype==LMTP_HELP) - )) - { - trace(TRACE_ERROR, "ARGUMENT %d", cmdtype); - return lmtp_error(session, stream, "500 This command requires an argument.\r\n"); - } - - switch (cmdtype) - { - case LMTP_QUIT : - { - fprintf((FILE *)stream, "221 %s BYE\r\n", myhostname); - lmtp_reset(session); - return 0; /* return 0 to cause the connection to close */ - } - case LMTP_NOOP : - { - fprintf((FILE *)stream, "250 OK\r\n"); - return 1; - } - case LMTP_RSET : - { - fprintf((FILE *)stream, "250 OK\r\n"); - lmtp_reset(session); - return 1; - } - case LMTP_LHLO : - { - /* Reply wth our hostname and a list of features. - * The RFC requires a couple of SMTP extensions - * with a MUST statement, so just hardcode them. - * */ - fprintf((FILE *)stream, - "250-%s\r\n" - "250-PIPELINING\r\n" - "250-ENHANCEDSTATUSCODES\r\n" - /* This is a SHOULD implement: - * "250-8BITMIME\r\n" - * Might as well do these, too: - * "250-CHUNKING\r\n" - * "250-BINARYMIME\r\n" - * */ - "250 SIZE\r\n", myhostname ); - /* Free the recipients list and reinitialize it */ - // list_freelist( &rcpt.start ); - list_init( &rcpt ); - - session->state = LHLO; - return 1; - } - case LMTP_HELP : - { - int helpcmd; - - if (value == NULL) - helpcmd = LMTP_END; - else - for (helpcmd = LMTP_STRT; helpcmd < LMTP_END; helpcmd++) - if (strcasecmp(value, commands[helpcmd]) == 0) break; - - trace(TRACE_DEBUG,"lmtp(): LMTP_HELP requested for commandtype %d", helpcmd); - - if( (helpcmd==LMTP_LHLO) || (helpcmd==LMTP_DATA) || - (helpcmd==LMTP_RSET) || (helpcmd==LMTP_QUIT) || - (helpcmd==LMTP_NOOP) || (helpcmd==LMTP_HELP) ) - { - fprintf((FILE *)stream, "%s", LMTP_HELP_TEXT[helpcmd]); - } - else - { - fprintf((FILE *)stream, "%s", LMTP_HELP_TEXT[LMTP_END]); - } - - return 1; - } - case LMTP_VRFY : - { - /* RFC 2821 says this SHOULD be implemented... - * and the goal is to say if the given address - * is a valid delivery address at this server. */ - fprintf((FILE *)stream, "502 Command not implemented\r\n" ); - return 1; - } - case LMTP_EXPN: - { - /* RFC 2821 says this SHOULD be implemented... - * and the goal is to return the membership - * of the specified mailing list. */ - fprintf((FILE *)stream, "502 Command not implemented\r\n" ); - return 1; - } - case LMTP_MAIL: - { - /* We need to LHLO first because the client - * needs to know what extensions we support. - * */ - if (session->state != LHLO) - { - fprintf((FILE *)stream, "550 Command out of sequence.\r\n"); - } - else if (envelopefrom != NULL) - { - fprintf((FILE *)stream, "500 Sender already received. Use RSET to clear.\r\n"); - } - else - { - /* First look for an email address. - * Don't bother verifying or whatever, - * just find something between angle brackets! - * */ - int goodtogo=1; - size_t tmplen = 0, tmppos = 0; - char *tmpaddr = NULL, *tmpbody = NULL; - - find_bounded(value, '<', '>', &tmpaddr, &tmplen, &tmppos); - - /* Second look for a BODY keyword. - * See if it has an argument, and if we - * support that feature. Don't give an OK - * if we can't handle it yet, like 8BIT! - * */ - - /* Find the '=' following the address - * then advance one character past it - * (but only if there's more string!) - * */ - tmpbody = strstr(value+tmppos, "="); - if (tmpbody != NULL) - if (strlen(tmpbody)) - tmpbody++; - - /* This is all a bit nested now... */ - if (tmplen < 1 && tmpaddr == NULL) - { - fprintf((FILE *)stream,"500 No address found.\r\n" ); - goodtogo = 0; - } - else if (tmpbody != NULL) - { - /* See RFC 3030 for the best - * description of this stuff. - * */ - if (strlen(tmpbody) < 4) - { - /* Caught */ - } - else if (0 == strcasecmp(tmpbody, "7BIT")) - { - /* Sure fine go ahead. */ - goodtogo = 1; // Not that it wasn't 1 already ;-) - } - /* 8BITMIME corresponds to RFC 1652, - * BINARYMIME corresponds to RFC 3030. - * */ - else if (strlen(tmpbody) < 8) - { - /* Caught */ - } - else if (0 == strcasecmp(tmpbody, "8BITMIME")) - { - /* We can't do this yet. */ - /* session->state = BIT8; - * */ - fprintf((FILE *)stream,"500 Please use 7BIT MIME only.\r\n"); - goodtogo = 0; - } - else if (strlen(tmpbody) < 10) - { - /* Caught */ - } - else if (0 == strcasecmp(tmpbody, "BINARYMIME")) - { - /* We can't do this yet. */ - /* session->state = BDAT; - * */ - fprintf((FILE *)stream,"500 Please use 7BIT MIME only.\r\n" ); - goodtogo = 0; - } - } - - if (goodtogo) - { - /* Sure fine go ahead. */ - envelopefrom = tmpaddr; - fprintf((FILE *)stream,"250 Sender <%s> OK\r\n", envelopefrom ); - } - else - { - if (tmpaddr != NULL) - my_free(tmpaddr); - } - } - return 1; - } - case LMTP_RCPT : - { - if (session->state != LHLO) - { - fprintf((FILE *)stream, "550 Command out of sequence.\r\n"); - } - else - { - size_t tmplen = 0, tmppos = 0; - char *tmpaddr = NULL; - - find_bounded(value, '<', '>', &tmpaddr, &tmplen, &tmppos); - - if (tmplen < 1) - { - fprintf((FILE *)stream,"500 No address found.\r\n" ); - } - else - { - /* Note that this is not a pointer, but really is on the stack! - * Because list_nodeadd() memcpy's the structure, we don't need - * it to live any longer than the duration of this stack frame. */ - deliver_to_user_t dsnuser; - - dsnuser_init(&dsnuser); - - /* find_bounded() allocated tmpaddr for us, and that's ok - * since dsnuser_free() will free it for us later on. */ - dsnuser.address = tmpaddr; - - /* Queue up the potential recipients. We can use one call to - * dsnuser_resolve_list() to look them up. This should not - * be a problem because the client is required to pipeline - * the commands, i.e. not wait for a reply to each command. */ - list_nodeadd(&rcpt, &dsnuser, sizeof(deliver_to_user_t)); - } - } - return 1; - } - /* Here's where it gets really exciting! */ - case LMTP_DATA: - { - // if (session->state != DATA || session->state != BIT8) - if (session->state != LHLO) - { - fprintf((FILE *)stream, "550 Command out of sequence\r\n" ); - } - else if (list_totalnodes(&rcpt) < 1) - { - fprintf((FILE *)stream, "503 No valid recipients\r\n" ); - } - else - { - int has_recipients = 0; - struct element *element; - - /* The replies MUST be in the order received */ - rcpt.start = dbmail_list_reverse(rcpt.start); - - /* Resolve the addresses into deliverable / non-deliverable form. */ - if (dsnuser_resolve_list(&rcpt) == -1) - { - trace(TRACE_ERROR, "main(): dsnuser_resolve_list failed"); - fprintf((FILE *)stream, "430 Temporary failure in recipient lookup\r\n" ); - return 1; - } - - for(element = list_getstart(&rcpt); - element != NULL; element = element->nextnode) - { - deliver_to_user_t *dsnuser = (deliver_to_user_t *)element->data; - - /* Class 2 means the address was deliverable in some way. */ - switch (dsnuser->dsn.class) - { - case DSN_CLASS_OK: - fprintf((FILE *)stream, "250 Recipient <%s> OK\r\n", - dsnuser->address); - has_recipients = 1; - break; - default: - fprintf((FILE *)stream, "550 Recipient <%s> FAIL\r\n", - dsnuser->address); - /* Remove the failed user from the potential recipients list - * so that we do not report a failed delivery later on. */ - list_nodedel(&rcpt, dsnuser); - break; - } - } - - /* Now we have a list of recipients! */ - /* Let the client know if they should continue... */ - - if (has_recipients && envelopefrom != NULL) - { - trace(TRACE_DEBUG,"main(): requesting sender to begin message."); - fprintf((FILE *)stream, "354 Start mail input; end with <CRLF>.<CRLF>\r\n" ); - } - else - { - if (!has_recipients) - { - trace(TRACE_DEBUG,"main(): no valid recipients found, cancel message."); - fprintf((FILE *)stream, "503 No valid recipients\r\n" ); - } - if (!envelopefrom) - { - trace(TRACE_DEBUG,"main(): envelopefrom is empty, cancel message."); - fprintf((FILE *)stream, "554 No valid sender.\r\n" ); - } - return 1; - } - - /* Anonymous Block */ - { - char *header = NULL; - u64_t headersize=0, headerrfcsize=0; - u64_t dummyidx=0,dummysize=0; - struct list fromlist, headerfields; - struct element *element; - - list_init(&mimelist); - list_init(&fromlist); - list_init(&headerfields); - - /* if (envelopefrom != NULL) */ - /* We know this to be true from the 354 code, above. */ - list_nodeadd(&fromlist, envelopefrom, strlen(envelopefrom)); - - if (!read_header((FILE *)instream, &headerrfcsize, &headersize, &header)) - { - trace(TRACE_ERROR,"main(): fatal error from read_header()"); - discard_client_input((FILE*) instream); - fprintf((FILE *)stream, "500 Error reading header.\r\n" ); - return 1; - } - - if (header != NULL) - { - trace(TRACE_ERROR,"main(): size of read_header() header " - "is [%llu]", headersize); - if (headersize > READ_BLOCK_SIZE) { - trace(TRACE_ERROR, "main(): header is too " - "big"); - discard_client_input((FILE *)instream); - fprintf((FILE*)stream, "500 Error reading header, " - "header too big.\r\n"); - return 1; - } - } - else - { - trace(TRACE_ERROR,"main(): read_header() returned a null header [%s]", header); - discard_client_input((FILE*) instream); - fprintf((FILE *)stream, "500 Error reading header.\r\n" ); - return 1; - } - - - /* Parse the list and scan for field and content */ - if (mime_readheader(header, &dummyidx, &mimelist, &dummysize) < 0) - { - trace(TRACE_ERROR,"main(): fatal error from mime_readheader()"); - discard_client_input((FILE*) instream); - fprintf((FILE *)stream, "500 Error reading header.\r\n" ); - return 1; - } - - if (insert_messages((FILE *)instream, - header, headersize, headerrfcsize, - &headerfields, &rcpt, &fromlist) == -1) - { - fprintf((FILE *)stream, "503 Message not received\r\n"); - } - else - { - /* The DATA command itself it not given a reply except - * that of the status of each of the remaining recipients. */ - - for (element = list_getstart(&rcpt); - element != NULL; element = element->nextnode) - { - deliver_to_user_t *dsnuser = (deliver_to_user_t *)element->data; - - switch (dsnuser->dsn.class) - { - case DSN_CLASS_OK: - fprintf((FILE *)stream, "250 Recipient <%s> OK\r\n", - dsnuser->address); - break; - case DSN_CLASS_TEMP: - fprintf((FILE *)stream, "450 Recipient <%s> TEMP FAIL\r\n", - dsnuser->address); - break; - case DSN_CLASS_FAIL: - default: - fprintf((FILE *)stream, "550 Recipient <%s> PERM FAIL\r\n", - dsnuser->address); - break; - } - } - } - if (header != NULL) - my_free(header); - } - } - return 1; - } - default : - { - return lmtp_error(session, stream,"500 What are you trying to say here?\r\n"); - } - } - return 1; + va_list argp; + + if (session->error_count >= MAX_ERRORS) { + trace(TRACE_MESSAGE, + "lmtp_error(): too many errors (MAX_ERRORS is %d)", + MAX_ERRORS); + fprintf((FILE *) stream, + "500 Too many errors, closing connection.\r\n"); + session->SessionResult = 2; /* possible flood */ + lmtp_reset(session); + return -3; + } else { + va_start(argp, formatstring); + vfprintf((FILE *) stream, formatstring, argp); + va_end(argp); + } + + trace(TRACE_DEBUG, "lmtp_error(): an invalid command was issued"); + session->error_count++; + return 1; } + +int lmtp(void *stream, void *instream, char *buffer, + char *client_ip UNUSED, PopSession_t * session) +{ + /* returns values: + * 0 to quit + * -1 on failure + * 1 on success */ + char *command, *value; + int cmdtype; + int indx = 0; + + /* buffer overflow attempt */ + if (strlen(buffer) > MAX_IN_BUFFER) { + trace(TRACE_DEBUG, "lmtp(): buffer overflow attempt"); + return -3; + } + + /* check for command issued */ + while (strchr(validchars, buffer[indx])) + indx++; + + /* end buffer */ + buffer[indx] = '\0'; + + trace(TRACE_DEBUG, "lmtp(): incoming buffer: [%s]", buffer); + + command = buffer; + + value = strstr(command, " "); /* look for the separator */ + + if (value != NULL) { + *value = '\0'; /* set a \0 on the command end */ + value++; /* skip space */ + + if (strlen(value) == 0) { + value = NULL; /* no value specified */ + } else { + trace(TRACE_DEBUG, + "lmtp(): command issued :cmd [%s], value [%s]\n", + command, value); + } + } + + for (cmdtype = LMTP_STRT; cmdtype < LMTP_END; cmdtype++) + if (strcasecmp(command, commands[cmdtype]) == 0) + break; + + trace(TRACE_DEBUG, "lmtp(): command looked up as commandtype %d", + cmdtype); + + /* commands that are allowed to have no arguments */ + if ((value == NULL) && + !((cmdtype == LMTP_LHLO) || (cmdtype == LMTP_DATA) || + (cmdtype == LMTP_RSET) || (cmdtype == LMTP_QUIT) || + (cmdtype == LMTP_NOOP) || (cmdtype == LMTP_HELP) + )) { + trace(TRACE_ERROR, "ARGUMENT %d", cmdtype); + return lmtp_error(session, stream, + "500 This command requires an argument.\r\n"); + } + + switch (cmdtype) { + case LMTP_QUIT: + { + fprintf((FILE *) stream, "221 %s BYE\r\n", + myhostname); + lmtp_reset(session); + return 0; /* return 0 to cause the connection to close */ + } + case LMTP_NOOP: + { + fprintf((FILE *) stream, "250 OK\r\n"); + return 1; + } + case LMTP_RSET: + { + fprintf((FILE *) stream, "250 OK\r\n"); + lmtp_reset(session); + return 1; + } + case LMTP_LHLO: + { + /* Reply wth our hostname and a list of features. + * The RFC requires a couple of SMTP extensions + * with a MUST statement, so just hardcode them. + * */ + fprintf((FILE *) stream, + "250-%s\r\n" + "250-PIPELINING\r\n" + "250-ENHANCEDSTATUSCODES\r\n" + /* This is a SHOULD implement: + * "250-8BITMIME\r\n" + * Might as well do these, too: + * "250-CHUNKING\r\n" + * "250-BINARYMIME\r\n" + * */ + "250 SIZE\r\n", myhostname); + /* Free the recipients list and reinitialize it */ + // list_freelist( &rcpt.start ); + list_init(&rcpt); + + session->state = LHLO; + return 1; + } + case LMTP_HELP: + { + int helpcmd; + + if (value == NULL) + helpcmd = LMTP_END; + else + for (helpcmd = LMTP_STRT; + helpcmd < LMTP_END; helpcmd++) + if (strcasecmp + (value, + commands[helpcmd]) == 0) + break; + + trace(TRACE_DEBUG, + "lmtp(): LMTP_HELP requested for commandtype %d", + helpcmd); + + if ((helpcmd == LMTP_LHLO) + || (helpcmd == LMTP_DATA) + || (helpcmd == LMTP_RSET) + || (helpcmd == LMTP_QUIT) + || (helpcmd == LMTP_NOOP) + || (helpcmd == LMTP_HELP)) { + fprintf((FILE *) stream, "%s", + LMTP_HELP_TEXT[helpcmd]); + } else { + fprintf((FILE *) stream, "%s", + LMTP_HELP_TEXT[LMTP_END]); + } + + return 1; + } + case LMTP_VRFY: + { + /* RFC 2821 says this SHOULD be implemented... + * and the goal is to say if the given address + * is a valid delivery address at this server. */ + fprintf((FILE *) stream, + "502 Command not implemented\r\n"); + return 1; + } + case LMTP_EXPN: + { + /* RFC 2821 says this SHOULD be implemented... + * and the goal is to return the membership + * of the specified mailing list. */ + fprintf((FILE *) stream, + "502 Command not implemented\r\n"); + return 1; + } + case LMTP_MAIL: + { + /* We need to LHLO first because the client + * needs to know what extensions we support. + * */ + if (session->state != LHLO) { + fprintf((FILE *) stream, + "550 Command out of sequence.\r\n"); + } else if (envelopefrom != NULL) { + fprintf((FILE *) stream, + "500 Sender already received. Use RSET to clear.\r\n"); + } else { + /* First look for an email address. + * Don't bother verifying or whatever, + * just find something between angle brackets! + * */ + int goodtogo = 1; + size_t tmplen = 0, tmppos = 0; + char *tmpaddr = NULL, *tmpbody = NULL; + + find_bounded(value, '<', '>', &tmpaddr, + &tmplen, &tmppos); + + /* Second look for a BODY keyword. + * See if it has an argument, and if we + * support that feature. Don't give an OK + * if we can't handle it yet, like 8BIT! + * */ + + /* Find the '=' following the address + * then advance one character past it + * (but only if there's more string!) + * */ + tmpbody = strstr(value + tmppos, "="); + if (tmpbody != NULL) + if (strlen(tmpbody)) + tmpbody++; + + /* This is all a bit nested now... */ + if (tmplen < 1 && tmpaddr == NULL) { + fprintf((FILE *) stream, + "500 No address found.\r\n"); + goodtogo = 0; + } else if (tmpbody != NULL) { + /* See RFC 3030 for the best + * description of this stuff. + * */ + if (strlen(tmpbody) < 4) { + /* Caught */ + } else if (0 == + strcasecmp(tmpbody, + "7BIT")) { + /* Sure fine go ahead. */ + goodtogo = 1; // Not that it wasn't 1 already ;-) + } + /* 8BITMIME corresponds to RFC 1652, + * BINARYMIME corresponds to RFC 3030. + * */ + else if (strlen(tmpbody) < 8) { + /* Caught */ + } else if (0 == + strcasecmp(tmpbody, + "8BITMIME")) + { + /* We can't do this yet. */ + /* session->state = BIT8; + * */ + fprintf((FILE *) stream, + "500 Please use 7BIT MIME only.\r\n"); + goodtogo = 0; + } else if (strlen(tmpbody) < 10) { + /* Caught */ + } else if (0 == + strcasecmp(tmpbody, + "BINARYMIME")) + { + /* We can't do this yet. */ + /* session->state = BDAT; + * */ + fprintf((FILE *) stream, + "500 Please use 7BIT MIME only.\r\n"); + goodtogo = 0; + } + } + + if (goodtogo) { + /* Sure fine go ahead. */ + envelopefrom = tmpaddr; + fprintf((FILE *) stream, + "250 Sender <%s> OK\r\n", + envelopefrom); + } else { + if (tmpaddr != NULL) + my_free(tmpaddr); + } + } + return 1; + } + case LMTP_RCPT: + { + if (session->state != LHLO) { + fprintf((FILE *) stream, + "550 Command out of sequence.\r\n"); + } else { + size_t tmplen = 0, tmppos = 0; + char *tmpaddr = NULL; + + find_bounded(value, '<', '>', &tmpaddr, + &tmplen, &tmppos); + + if (tmplen < 1) { + fprintf((FILE *) stream, + "500 No address found.\r\n"); + } else { + /* Note that this is not a pointer, but really is on the stack! + * Because list_nodeadd() memcpy's the structure, we don't need + * it to live any longer than the duration of this stack frame. */ + deliver_to_user_t dsnuser; + + dsnuser_init(&dsnuser); + + /* find_bounded() allocated tmpaddr for us, and that's ok + * since dsnuser_free() will free it for us later on. */ + dsnuser.address = tmpaddr; + + /* Queue up the potential recipients. We can use one call to + * dsnuser_resolve_list() to look them up. This should not + * be a problem because the client is required to pipeline + * the commands, i.e. not wait for a reply to each command. */ + list_nodeadd(&rcpt, &dsnuser, + sizeof + (deliver_to_user_t)); + } + } + return 1; + } + /* Here's where it gets really exciting! */ + case LMTP_DATA: + { + // if (session->state != DATA || session->state != BIT8) + if (session->state != LHLO) { + fprintf((FILE *) stream, + "550 Command out of sequence\r\n"); + } else if (list_totalnodes(&rcpt) < 1) { + fprintf((FILE *) stream, + "503 No valid recipients\r\n"); + } else { + int has_recipients = 0; + struct element *element; + + /* The replies MUST be in the order received */ + rcpt.start = + dbmail_list_reverse(rcpt.start); + + /* Resolve the addresses into deliverable / non-deliverable form. */ + if (dsnuser_resolve_list(&rcpt) == -1) { + trace(TRACE_ERROR, + "main(): dsnuser_resolve_list failed"); + fprintf((FILE *) stream, + "430 Temporary failure in recipient lookup\r\n"); + return 1; + } + + for (element = list_getstart(&rcpt); + element != NULL; + element = element->nextnode) { + deliver_to_user_t *dsnuser = + (deliver_to_user_t *) element-> + data; + + /* Class 2 means the address was deliverable in some way. */ + switch (dsnuser->dsn.class) { + case DSN_CLASS_OK: + fprintf((FILE *) stream, + "250 Recipient <%s> OK\r\n", + dsnuser->address); + has_recipients = 1; + break; + default: + fprintf((FILE *) stream, + "550 Recipient <%s> FAIL\r\n", + dsnuser->address); + /* Remove the failed user from the potential recipients list + * so that we do not report a failed delivery later on. */ + list_nodedel(&rcpt, + dsnuser); + break; + } + } + + /* Now we have a list of recipients! */ + /* Let the client know if they should continue... */ + + if (has_recipients && envelopefrom != NULL) { + trace(TRACE_DEBUG, + "main(): requesting sender to begin message."); + fprintf((FILE *) stream, + "354 Start mail input; end with <CRLF>.<CRLF>\r\n"); + } else { + if (!has_recipients) { + trace(TRACE_DEBUG, + "main(): no valid recipients found, cancel message."); + fprintf((FILE *) stream, + "503 No valid recipients\r\n"); + } + if (!envelopefrom) { + trace(TRACE_DEBUG, + "main(): envelopefrom is empty, cancel message."); + fprintf((FILE *) stream, + "554 No valid sender.\r\n"); + } + return 1; + } + + /* Anonymous Block */ + { + char *header = NULL; + u64_t headersize = + 0, headerrfcsize = 0; + u64_t dummyidx = 0, dummysize = 0; + struct list fromlist, headerfields; + struct element *element; + + list_init(&mimelist); + list_init(&fromlist); + list_init(&headerfields); + + /* if (envelopefrom != NULL) */ + /* We know this to be true from the 354 code, above. */ + list_nodeadd(&fromlist, + envelopefrom, + strlen(envelopefrom)); + + if (!read_header + ((FILE *) instream, + &headerrfcsize, &headersize, + &header)) { + trace(TRACE_ERROR, + "main(): fatal error from read_header()"); + discard_client_input((FILE + *) + instream); + fprintf((FILE *) stream, + "500 Error reading header.\r\n"); + return 1; + } + + if (header != NULL) { + trace(TRACE_ERROR, + "main(): size of read_header() header " + "is [%llu]", + headersize); + if (headersize > + READ_BLOCK_SIZE) { + trace(TRACE_ERROR, + "main(): header is too " + "big"); + discard_client_input + ((FILE *) + instream); + fprintf((FILE *) + stream, + "500 Error reading header, " + "header too big.\r\n"); + return 1; + } + } else { + trace(TRACE_ERROR, + "main(): read_header() returned a null header [%s]", + header); + discard_client_input((FILE + *) + instream); + fprintf((FILE *) stream, + "500 Error reading header.\r\n"); + return 1; + } + + + /* Parse the list and scan for field and content */ + if (mime_readheader + (header, &dummyidx, &mimelist, + &dummysize) < 0) { + trace(TRACE_ERROR, + "main(): fatal error from mime_readheader()"); + discard_client_input((FILE + *) + instream); + fprintf((FILE *) stream, + "500 Error reading header.\r\n"); + return 1; + } + + if (insert_messages + ((FILE *) instream, header, + headersize, headerrfcsize, + &headerfields, &rcpt, + &fromlist) == -1) { + fprintf((FILE *) stream, + "503 Message not received\r\n"); + } else { + /* The DATA command itself it not given a reply except + * that of the status of each of the remaining recipients. */ + + for (element = + list_getstart(&rcpt); + element != NULL; + element = + element->nextnode) { + deliver_to_user_t + * dsnuser = + (deliver_to_user_t + *) element-> + data; + + switch (dsnuser-> + dsn. + class) { + case DSN_CLASS_OK: + fprintf((FILE *) stream, "250 Recipient <%s> OK\r\n", dsnuser->address); + break; + case DSN_CLASS_TEMP: + fprintf((FILE *) stream, "450 Recipient <%s> TEMP FAIL\r\n", dsnuser->address); + break; + case DSN_CLASS_FAIL: + default: + fprintf((FILE *) stream, "550 Recipient <%s> PERM FAIL\r\n", dsnuser->address); + break; + } + } + } + if (header != NULL) + my_free(header); + } + } + return 1; + } + default: + { + return lmtp_error(session, stream, + "500 What are you trying to say here?\r\n"); + } + } + return 1; +} @@ -38,7 +38,7 @@ /* processes */ #define MAXCHILDREN 5 -#define DEFAULT_CHILDREN 5 +#define DEFAULT_CHILDREN 5 #define LMTP_DEF_MAXCONNECT 1500 @@ -57,21 +57,22 @@ const char *commands [] = "VRFY", "EXPN", "HELP", "NOOP", "RCPT" }; */ -#define LMTP_STRT 0 /* lower bound of array - 0 */ +#define LMTP_STRT 0 /* lower bound of array - 0 */ #define LMTP_LHLO 0 #define LMTP_QUIT 1 #define LMTP_RSET 2 -#define LMTP_DATA 3 +#define LMTP_DATA 3 #define LMTP_MAIL 4 #define LMTP_VRFY 5 #define LMTP_EXPN 6 #define LMTP_HELP 7 #define LMTP_NOOP 8 #define LMTP_RCPT 9 -#define LMTP_END 10 /* upper bound of array + 1 */ +#define LMTP_END 10 /* upper bound of array + 1 */ -int lmtp(void *stream, void *instream, char *buffer, char *client_ip, PopSession_t *session); -int lmtp_handle_connection(clientinfo_t *ci); +int lmtp(void *stream, void *instream, char *buffer, char *client_ip, + PopSession_t * session); +int lmtp_handle_connection(clientinfo_t * ci); /* * Enhanced Status Codes @@ -140,66 +141,66 @@ int lmtp_handle_connection(clientinfo_t *ci); */ /* Help */ -static const char * const LMTP_HELP_TEXT[] = { +static const char *const LMTP_HELP_TEXT[] = { /* LMTP_LHLO 0 */ - "214-The LHLO command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The LHLO command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_QUIT 1 */ , - "214-The QUIT command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The QUIT command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_RSET 2 */ , - "214-The RSET command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The RSET command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_DATA 3 */ , - "214-The DATA command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The DATA command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_MAIL 4 */ , - "214-The MAIL command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The MAIL command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_VRFY 5 */ , - "214-The VRFY command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The VRFY command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_EXPN 6 */ , - "214-The EXPN command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The EXPN command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_HELP 7 */ , - "214-The HELP command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The HELP command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_NOOP 8 */ , - "214-The NOOP command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The NOOP command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_RCPT 9 */ , - "214-The RCPT command begins a client/server\r\n" - "214-dialogue. The commands MAIL, RCPT and DATA\r\n" - "214-may only be issued after a successful LHLO.\r\n" - "214 Syntax: LHLO [your hostname]\r\n" + "214-The RCPT command begins a client/server\r\n" + "214-dialogue. The commands MAIL, RCPT and DATA\r\n" + "214-may only be issued after a successful LHLO.\r\n" + "214 Syntax: LHLO [your hostname]\r\n" /* LMTP_END 10 */ , - "214-This is DBMail-LMTP.\r\n" - "214-The following commands are supported:\r\n" - "214-LHLO, RSET, NOOP, QUIT, HELP.\r\n" - "214-VRFY, EXPN, MAIL, RCPT, DATA.\r\n" - "214-For more information about a command:\r\n" - "214 Use HELP <command>.\r\n" + "214-This is DBMail-LMTP.\r\n" + "214-The following commands are supported:\r\n" + "214-LHLO, RSET, NOOP, QUIT, HELP.\r\n" + "214-VRFY, EXPN, MAIL, RCPT, DATA.\r\n" + "214-For more information about a command:\r\n" + "214 Use HELP <command>.\r\n" /* For good measure... */ , - NULL + NULL }; #endif @@ -42,10 +42,10 @@ char *configFile = DEFAULT_CONFIG_FILE; /* set up database login data */ extern db_param_t _db_params; -void SetConfigItems(serverConfig_t *config, struct list *items); +void SetConfigItems(serverConfig_t * config, struct list *items); void Daemonize(void); int SetMainSigHandler(void); -void MainSigHandler(int sig, siginfo_t *info, void *data); +void MainSigHandler(int sig, siginfo_t * info, void *data); int lmtp_before_smtp = 0; int mainRestart = 0; @@ -58,256 +58,282 @@ char *timeout_setting; #ifdef PROC_TITLES int main(int argc, char *argv[], char **envp) #else - int main(int argc, char *argv[]) +int main(int argc, char *argv[]) #endif { - serverConfig_t config; - int result, status; - pid_t pid; - - openlog(PNAME, LOG_PID, LOG_MAIL); - - if (argc >= 2 && (argv[1])) - { - if (strcmp (argv[1],"-v") == 0) - { - printf ("\n*** DBMAIL: dbmail-lmtpd version $Revision$ %s\n\n",COPYRIGHT); - return 0; - } - else - if (strcmp(argv[1],"-f")==0 && (argv[2])) - configFile = argv[2]; - } - - SetMainSigHandler(); - Daemonize(); - result = 0; - - do - { - mainStop = 0; - mainRestart = 0; - - trace(TRACE_DEBUG, "main(): reading config"); -#ifdef PROC_TITLES - init_set_proc_title(argc, argv, envp, PNAME); - set_proc_title("%s", "Idle"); -#endif - - /* We need smtp config for bounce.c and forward.c */ - ReadConfig("SMTP", configFile, &smtpItems); - ReadConfig("LMTP", configFile, &lmtpItems); - ReadConfig("DBMAIL", configFile, &sysItems); - SetConfigItems(&config, &lmtpItems); - SetTraceLevel(&lmtpItems); - GetDBParams(&_db_params, &sysItems); - - config.ClientHandler = lmtp_handle_connection; - config.timeoutMsg = LMTP_TIMEOUT_MSG; - - CreateSocket(&config); - trace(TRACE_DEBUG, "main(): socket created, starting server"); - - switch ( (pid = fork()) ) - { - case -1: - close(config.listenSocket); - trace(TRACE_FATAL, "main(): fork failed [%s]", strerror(errno)); - - case 0: - /* child process */ - drop_privileges(config.serverUser, config.serverGroup); - result = StartServer(&config); - - trace(TRACE_INFO, "main(): server done, exit."); - exit(result); - - default: - /* parent process, wait for child to exit */ - while (waitpid(pid, &status, WNOHANG|WUNTRACED) == 0) - { - if (mainStop) - kill(pid, SIGTERM); - - if (mainRestart) - kill(pid, SIGHUP); - - sleep(2); - } - - if (WIFEXITED(status)) - { - /* child process terminated neatly */ - result = WEXITSTATUS(status); - trace(TRACE_DEBUG, "main(): server has exited, exit status [%d]", result); - } - else - { - /* child stopped or signaled, don't like */ - /* make sure it is dead */ - trace(TRACE_DEBUG, "main(): server has not exited normally. Killing.."); - - kill(pid, SIGKILL); - result = 0; - } + serverConfig_t config; + int result, status; + pid_t pid; + + openlog(PNAME, LOG_PID, LOG_MAIL); + + if (argc >= 2 && (argv[1])) { + if (strcmp(argv[1], "-v") == 0) { + printf + ("\n*** DBMAIL: dbmail-lmtpd version $Revision$ %s\n\n", + COPYRIGHT); + return 0; + } else if (strcmp(argv[1], "-f") == 0 && (argv[2])) + configFile = argv[2]; } - list_freelist(&smtpItems.start); - list_freelist(&lmtpItems.start); - list_freelist(&sysItems.start); - close(config.listenSocket); + SetMainSigHandler(); + Daemonize(); + result = 0; - } while (result == 1 && !mainStop) ; /* 1 means reread-config and restart */ + do { + mainStop = 0; + mainRestart = 0; + + trace(TRACE_DEBUG, "main(): reading config"); +#ifdef PROC_TITLES + init_set_proc_title(argc, argv, envp, PNAME); + set_proc_title("%s", "Idle"); +#endif - trace(TRACE_INFO, "main(): exit"); - return 0; + /* We need smtp config for bounce.c and forward.c */ + ReadConfig("SMTP", configFile, &smtpItems); + ReadConfig("LMTP", configFile, &lmtpItems); + ReadConfig("DBMAIL", configFile, &sysItems); + SetConfigItems(&config, &lmtpItems); + SetTraceLevel(&lmtpItems); + GetDBParams(&_db_params, &sysItems); + + config.ClientHandler = lmtp_handle_connection; + config.timeoutMsg = LMTP_TIMEOUT_MSG; + + CreateSocket(&config); + trace(TRACE_DEBUG, + "main(): socket created, starting server"); + + switch ((pid = fork())) { + case -1: + close(config.listenSocket); + trace(TRACE_FATAL, "main(): fork failed [%s]", + strerror(errno)); + + case 0: + /* child process */ + drop_privileges(config.serverUser, + config.serverGroup); + result = StartServer(&config); + + trace(TRACE_INFO, "main(): server done, exit."); + exit(result); + + default: + /* parent process, wait for child to exit */ + while (waitpid(pid, &status, WNOHANG | WUNTRACED) + == 0) { + if (mainStop) + kill(pid, SIGTERM); + + if (mainRestart) + kill(pid, SIGHUP); + + sleep(2); + } + + if (WIFEXITED(status)) { + /* child process terminated neatly */ + result = WEXITSTATUS(status); + trace(TRACE_DEBUG, + "main(): server has exited, exit status [%d]", + result); + } else { + /* child stopped or signaled, don't like */ + /* make sure it is dead */ + trace(TRACE_DEBUG, + "main(): server has not exited normally. Killing.."); + + kill(pid, SIGKILL); + result = 0; + } + } + + list_freelist(&smtpItems.start); + list_freelist(&lmtpItems.start); + list_freelist(&sysItems.start); + close(config.listenSocket); + + } while (result == 1 && !mainStop); /* 1 means reread-config and restart */ + + trace(TRACE_INFO, "main(): exit"); + return 0; } -void MainSigHandler(int sig, siginfo_t *info UNUSED, void *data UNUSED) +void MainSigHandler(int sig, siginfo_t * info UNUSED, void *data UNUSED) { - trace(TRACE_DEBUG, "MainSigHandler(): got signal [%d]", sig); + trace(TRACE_DEBUG, "MainSigHandler(): got signal [%d]", sig); - if (sig == SIGHUP) - mainRestart = 1; - else - mainStop = 1; + if (sig == SIGHUP) + mainRestart = 1; + else + mainStop = 1; } void Daemonize() { - if (fork()) - exit(0); - setsid(); + if (fork()) + exit(0); + setsid(); - if (fork()) - exit(0); + if (fork()) + exit(0); } int SetMainSigHandler() { - struct sigaction act; + struct sigaction act; - /* init & install signal handlers */ - memset(&act, 0, sizeof(act)); + /* init & install signal handlers */ + memset(&act, 0, sizeof(act)); - act.sa_sigaction = MainSigHandler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; + act.sa_sigaction = MainSigHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; - sigaction(SIGINT, &act, 0); - sigaction(SIGQUIT, &act, 0); - sigaction(SIGTERM, &act, 0); - sigaction(SIGHUP, &act, 0); + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); + sigaction(SIGTERM, &act, 0); + sigaction(SIGHUP, &act, 0); - return 0; + return 0; } -void SetConfigItems(serverConfig_t *config, struct list *items) +void SetConfigItems(serverConfig_t * config, struct list *items) { - field_t val; + field_t val; - /* read items: NCHILDREN */ - GetConfigValue("NCHILDREN", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for NCHILDREN in config file"); + /* read items: NCHILDREN */ + GetConfigValue("NCHILDREN", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for NCHILDREN in config file"); - if ( (config->nChildren = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for NCHILDREN is invalid: [%d]", config->nChildren); + if ((config->nChildren = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for NCHILDREN is invalid: [%d]", + config->nChildren); - trace(TRACE_DEBUG, "SetConfigItems(): server will create [%d] children", config->nChildren); + trace(TRACE_DEBUG, + "SetConfigItems(): server will create [%d] children", + config->nChildren); - /* read items: MAXCONNECTS */ - GetConfigValue("MAXCONNECTS", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for MAXCONNECTS in config file"); + /* read items: MAXCONNECTS */ + GetConfigValue("MAXCONNECTS", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for MAXCONNECTS in config file"); - if ( (config->childMaxConnect = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", config->childMaxConnect); + if ((config->childMaxConnect = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", + config->childMaxConnect); - trace(TRACE_DEBUG, "SetConfigItems(): children will make max. [%d] connections", config->childMaxConnect); + trace(TRACE_DEBUG, + "SetConfigItems(): children will make max. [%d] connections", + config->childMaxConnect); - /* read items: TIMEOUT */ - GetConfigValue("TIMEOUT", items, val); - if (strlen(val) == 0) - { - trace(TRACE_DEBUG, "SetConfigItems(): no value for TIMEOUT in config file"); - config->timeout = 0; - } - else if ( (config->timeout = atoi(val)) <= 30) - trace(TRACE_FATAL, "SetConfigItems(): value for TIMEOUT is invalid: [%d]", config->timeout); + /* read items: TIMEOUT */ + GetConfigValue("TIMEOUT", items, val); + if (strlen(val) == 0) { + trace(TRACE_DEBUG, + "SetConfigItems(): no value for TIMEOUT in config file"); + config->timeout = 0; + } else if ((config->timeout = atoi(val)) <= 30) + trace(TRACE_FATAL, + "SetConfigItems(): value for TIMEOUT is invalid: [%d]", + config->timeout); - trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", config->timeout); + trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", + config->timeout); - /* read items: PORT */ - GetConfigValue("PORT", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for PORT in config file"); + /* read items: PORT */ + GetConfigValue("PORT", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for PORT in config file"); - if ( (config->port = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for PORT is invalid: [%d]", config->port); + if ((config->port = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for PORT is invalid: [%d]", + config->port); - trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", config->port); + trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", + config->port); - /* read items: BINDIP */ - GetConfigValue("BINDIP", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for BINDIP in config file"); + /* read items: BINDIP */ + GetConfigValue("BINDIP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for BINDIP in config file"); - strncpy(config->ip, val, IPLEN); - config->ip[IPLEN-1] = '\0'; + strncpy(config->ip, val, IPLEN); + config->ip[IPLEN - 1] = '\0'; - trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", config->ip); + trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", + config->ip); - /* read items: RESOLVE_IP */ - GetConfigValue("RESOLVE_IP", items, val); - if (strlen(val) == 0) - trace(TRACE_DEBUG, "SetConfigItems(): no value for RESOLVE_IP in config file"); + /* read items: RESOLVE_IP */ + GetConfigValue("RESOLVE_IP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, + "SetConfigItems(): no value for RESOLVE_IP in config file"); - config->resolveIP = (strcasecmp(val, "yes") == 0); + config->resolveIP = (strcasecmp(val, "yes") == 0); - trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", config->resolveIP ? "" : "not "); + trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", + config->resolveIP ? "" : "not "); - /* read items: IMAP-BEFORE-SMTP */ - GetConfigValue("LMTP_BEFORE_SMTP", items, val); - if (strlen(val) == 0) - trace(TRACE_DEBUG, "SetConfigItems(): no value for LMTP_BEFORE_SMTP in config file"); + /* read items: IMAP-BEFORE-SMTP */ + GetConfigValue("LMTP_BEFORE_SMTP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, + "SetConfigItems(): no value for LMTP_BEFORE_SMTP in config file"); - lmtp_before_smtp = (strcasecmp(val, "yes") == 0); + lmtp_before_smtp = (strcasecmp(val, "yes") == 0); - trace(TRACE_DEBUG, "SetConfigItems(): %s LMTP-before-SMTP", - lmtp_before_smtp ? "Enabling" : "Disabling"); + trace(TRACE_DEBUG, "SetConfigItems(): %s LMTP-before-SMTP", + lmtp_before_smtp ? "Enabling" : "Disabling"); - /* read items: EFFECTIVE-USER */ - GetConfigValue("EFFECTIVE_USER", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_USER in config file"); + /* read items: EFFECTIVE-USER */ + GetConfigValue("EFFECTIVE_USER", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for EFFECTIVE_USER in config file"); - strncpy(config->serverUser, val, FIELDSIZE); - config->serverUser[FIELDSIZE-1] = '\0'; + strncpy(config->serverUser, val, FIELDSIZE); + config->serverUser[FIELDSIZE - 1] = '\0'; - trace(TRACE_DEBUG, "SetConfigItems(): effective user shall be [%s]", config->serverUser); + trace(TRACE_DEBUG, + "SetConfigItems(): effective user shall be [%s]", + config->serverUser); - /* read items: EFFECTIVE-GROUP */ - GetConfigValue("EFFECTIVE_GROUP", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_GROUP in config file"); + /* read items: EFFECTIVE-GROUP */ + GetConfigValue("EFFECTIVE_GROUP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for EFFECTIVE_GROUP in config file"); - strncpy(config->serverGroup, val, FIELDSIZE); - config->serverGroup[FIELDSIZE-1] = '\0'; + strncpy(config->serverGroup, val, FIELDSIZE); + config->serverGroup[FIELDSIZE - 1] = '\0'; - trace(TRACE_DEBUG, "SetConfigItems(): effective group shall be [%s]", config->serverGroup); + trace(TRACE_DEBUG, + "SetConfigItems(): effective group shall be [%s]", + config->serverGroup); @@ -49,17 +49,17 @@ /* syslog */ #define PNAME "dbmail/smtp" -struct list returnpath; /* returnpath (should aways be just 1 hop) */ -struct list mimelist; /* raw unformatted mimefields and values */ -struct list dsnusers; /* list of deliver_to_user_t structs */ -struct list users; /* list of email addresses in message */ +struct list returnpath; /* returnpath (should aways be just 1 hop) */ +struct list mimelist; /* raw unformatted mimefields and values */ +struct list dsnusers; /* list of deliver_to_user_t structs */ +struct list users; /* list of email addresses in message */ struct element *tmp; -struct list sysItems, smtpItems; /* config item lists */ +struct list sysItems, smtpItems; /* config item lists */ char *configFile = DEFAULT_CONFIG_FILE; -extern db_param_t _db_params; /* set up database login data */ +extern db_param_t _db_params; /* set up database login data */ deliver_to_user_t dsnuser; @@ -70,282 +70,286 @@ u64_t headersize, headerrfcsize; void print_usage(const char *progname) { - printf("\n*** DBMAIL: dbmail-smtp version $Revision$ %s\n", - COPYRIGHT); - printf("\nUsage: %s -n [headerfield] for normal deliveries (default: \"deliver-to\")\n", - progname); - printf(" %s -m \"mailbox\" -u [username] for delivery to mailbox (name)\n", - progname); - printf(" %s -d [addresses] for delivery without using scanner\n", - progname); - printf(" %s -u [usernames] for direct delivery to users\n\n", - progname); + printf("\n*** DBMAIL: dbmail-smtp version $Revision$ %s\n", + COPYRIGHT); + printf + ("\nUsage: %s -n [headerfield] for normal deliveries (default: \"deliver-to\")\n", + progname); + printf + (" %s -m \"mailbox\" -u [username] for delivery to mailbox (name)\n", + progname); + printf + (" %s -d [addresses] for delivery without using scanner\n", + progname); + printf + (" %s -u [usernames] for direct delivery to users\n\n", + progname); } -int main(int argc, char *argv[]) +int main(int argc, char *argv[]) { - int exitcode = 0; - int c, c_prev = 0, usage_error = 0; - u64_t dummyidx = 0, dummysize = 0; - - - openlog(PNAME, LOG_PID, LOG_MAIL); - - ReadConfig("DBMAIL", configFile, &sysItems); - ReadConfig("SMTP", configFile, &smtpItems); - SetTraceLevel(&smtpItems); - GetDBParams(&_db_params, &sysItems); - - list_init(&users); - list_init(&dsnusers); - list_init(&mimelist); - list_init(&returnpath); - - /* Check for commandline options. - * The initial '-' means that arguments which are not associated - * with an immediately preceding option are return with option - * value '1'. We will use this to allow for multiple values to - * follow after each of the supported options. */ - while ((c = getopt(argc, argv, "-n::m:u:d:f:")) != EOF) - { - /* Received an n-th value following the last option, - * so recall the last known option to be used in the switch. */ - if (c == '1') - c = c_prev; - c_prev = c; - /* Do something with this option. */ - switch (c) - { - case 'n': - trace(TRACE_INFO, "main(): using NORMAL_DELIVERY"); - - if (optarg) - { - if (deliver_to_header) - { - printf("Only one header field may be specified.\n"); - usage_error = 1; - } - else - deliver_to_header = optarg; - } - else - deliver_to_header = "deliver-to"; - - break; - case 'm': - trace(TRACE_INFO, "main(): using SPECIAL_DELIVERY to mailbox"); - - if (deliver_to_mailbox) - { - printf("Only one header field may be specified.\n"); - usage_error = 1; - } - else - deliver_to_mailbox = optarg; - - break; - case 'f': - trace(TRACE_INFO, "main(): using RETURN_PATH for bounces"); - - /* Add argument onto the returnpath list. */ - if (list_nodeadd(&returnpath, optarg, strlen(optarg) + 1) == 0) - { - trace(TRACE_ERROR, "main(): list_nodeadd reports out of memory" - " while adding to returnpath"); - exitcode = EX_TEMPFAIL; - goto freeall; - } - - break; - case 'u': - trace(TRACE_INFO, "main(): using SPECIAL_DELIVERY to usernames"); - - dsnuser_init(&dsnuser); - dsnuser.address = strdup(optarg); - - /* Add argument onto the users list. */ - if (list_nodeadd(&dsnusers, &dsnuser, sizeof(deliver_to_user_t)) == 0) - { - trace(TRACE_ERROR, "main(): list_nodeadd reports out of memory" - " while adding usernames"); - exitcode = EX_TEMPFAIL; - goto freeall; - } - - break; - case 'd': - trace(TRACE_INFO, "main(): using SPECIAL_DELIVERY to email addresses"); - - dsnuser_init(&dsnuser); - dsnuser.address = strdup(optarg); - - /* Add argument onto the users list. */ - if (list_nodeadd(&dsnusers, &dsnuser, sizeof(deliver_to_user_t)) == 0) - { - trace(TRACE_ERROR, "main(): list_nodeadd reports out of memory" - " while adding email addresses"); - exitcode = EX_TEMPFAIL; - goto freeall; - } - - break; - default: - usage_error = 1; - break; - } - - /* At the end of each round of options, check - * to see if there were any errors worth stopping for. */ - if (usage_error) - { - print_usage(argv[0]); - trace(TRACE_DEBUG, "main(): usage error; setting EX_USAGE and aborting"); - exitcode = EX_USAGE; - goto freeall; - } - } - - /* ...or if there weren't any command line arguments at all. */ - if (argc < 2) - { - print_usage(argv[0]); - trace(TRACE_DEBUG, "main(): no arguments; setting EX_USAGE and aborting"); - exitcode = EX_USAGE; - goto freeall; - } - - if (db_connect() != 0) - { - trace(TRACE_ERROR, "main(): database connection failed"); - exitcode = EX_TEMPFAIL; - goto freeall; - } - - if (auth_connect() != 0) - { - trace(TRACE_ERROR, "main(): authentication connection failed"); - exitcode = EX_TEMPFAIL; - goto freeall; - } - - /* first we need to read the header */ - if (!read_header(stdin, &headerrfcsize, &headersize, &header)) - { - trace(TRACE_ERROR, "main(): read_header failed to read a header"); - exitcode = EX_TEMPFAIL; - goto freeall; - } - - if (headersize > READ_BLOCK_SIZE) { - trace(TRACE_ERROR, "%s,%s: failed to read header because header is " - "too big (bigger than READ_BLOCK_SIZE (%llu))", - __FILE__, __FUNCTION__, (u64_t)READ_BLOCK_SIZE); - exitcode = EX_DATAERR; - goto freeall; - } - - /* parse the list and scan for field and content */ - if (mime_readheader(header, &dummyidx, &mimelist, &dummysize) < 0) - { - trace(TRACE_ERROR, "main(): mime_readheader failed to read a header list"); - exitcode = EX_TEMPFAIL; - goto freeall; - } - - /* parse returnpath from header */ - if (returnpath.total_nodes == 0) - mail_adr_list("Return-Path", &returnpath, &mimelist); - if (returnpath.total_nodes == 0) - mail_adr_list("From", &returnpath, &mimelist); - if (returnpath.total_nodes == 0) - trace(TRACE_DEBUG, "main(): no return path found."); - - /* If the NORMAL delivery mode has been selected... */ - if (deliver_to_header != NULL) - { - /* parse for destination addresses */ - trace(TRACE_DEBUG, "main(): scanning for [%s]", - deliver_to_header); - if (mail_adr_list(deliver_to_header, &users, &mimelist) !=0) - { - trace(TRACE_STOP, "main(): scanner found no email addresses (scanned for %s)", - deliver_to_header); - exitcode = EX_TEMPFAIL; - goto freeall; - } - - /* Loop through the users list, moving the entries into the dsnusers list. */ - for(tmp = list_getstart(&users); tmp != NULL; tmp = tmp->nextnode) - { - deliver_to_user_t dsnuser; - - dsnuser_init(&dsnuser); - dsnuser.address = strdup((char *)tmp->data); - - list_nodeadd(&dsnusers, &dsnuser, sizeof(deliver_to_user_t)); - } - } - - if (dsnuser_resolve_list(&dsnusers) == -1) - { - trace(TRACE_ERROR, "main(): dsnuser_resolve_list failed"); - /* Most likely a random failure... */ - exitcode = EX_TEMPFAIL; - goto freeall; - } - - /* inserting messages into the database */ - if (insert_messages(stdin, - header, headersize, headerrfcsize, - &mimelist, &dsnusers, &returnpath) == -1) - { - trace(TRACE_ERROR, "main(): insert_messages failed"); - /* Most likely a random failure... */ - exitcode = EX_TEMPFAIL; - } - -freeall: /* Goto's here! */ - - /* If there wasn't already an EX_TEMPFAIL from insert_messages(), - * then see if one of the status flags was marked with an error. */ - if (!exitcode) - { - /* Get one reasonable error code for everyone. */ - switch (dsnuser_worstcase_list(&dsnusers)) - { - case DSN_CLASS_OK: - exitcode = EX_OK; - break; - case DSN_CLASS_TEMP: - exitcode = EX_TEMPFAIL; - break; - case DSN_CLASS_FAIL: - exitcode = EX_NOUSER; - break; - } - } - - trace(TRACE_DEBUG, "main(): freeing dsnuser list"); - dsnuser_free_list(&dsnusers); - - trace(TRACE_DEBUG, "main(): freeing all other lists"); - list_freelist(&sysItems.start); - list_freelist(&smtpItems.start); - list_freelist(&mimelist.start); - list_freelist(&returnpath.start); - list_freelist(&users.start); - - trace(TRACE_DEBUG, "main(): freeing memory blocks"); - if (header != NULL) - my_free(header); - - trace(TRACE_DEBUG, "main(): they're all free. we're done."); - - db_disconnect(); - auth_disconnect(); - - trace(TRACE_DEBUG, "main(): exit code is [%d].", exitcode); - return exitcode; + int exitcode = 0; + int c, c_prev = 0, usage_error = 0; + u64_t dummyidx = 0, dummysize = 0; + + + openlog(PNAME, LOG_PID, LOG_MAIL); + + ReadConfig("DBMAIL", configFile, &sysItems); + ReadConfig("SMTP", configFile, &smtpItems); + SetTraceLevel(&smtpItems); + GetDBParams(&_db_params, &sysItems); + + list_init(&users); + list_init(&dsnusers); + list_init(&mimelist); + list_init(&returnpath); + + /* Check for commandline options. + * The initial '-' means that arguments which are not associated + * with an immediately preceding option are return with option + * value '1'. We will use this to allow for multiple values to + * follow after each of the supported options. */ + while ((c = getopt(argc, argv, "-n::m:u:d:f:")) != EOF) { + /* Received an n-th value following the last option, + * so recall the last known option to be used in the switch. */ + if (c == '1') + c = c_prev; + c_prev = c; + /* Do something with this option. */ + switch (c) { + case 'n': + trace(TRACE_INFO, "main(): using NORMAL_DELIVERY"); + + if (optarg) { + if (deliver_to_header) { + printf + ("Only one header field may be specified.\n"); + usage_error = 1; + } else + deliver_to_header = optarg; + } else + deliver_to_header = "deliver-to"; + + break; + case 'm': + trace(TRACE_INFO, + "main(): using SPECIAL_DELIVERY to mailbox"); + + if (deliver_to_mailbox) { + printf + ("Only one header field may be specified.\n"); + usage_error = 1; + } else + deliver_to_mailbox = optarg; + + break; + case 'f': + trace(TRACE_INFO, + "main(): using RETURN_PATH for bounces"); + + /* Add argument onto the returnpath list. */ + if (list_nodeadd + (&returnpath, optarg, + strlen(optarg) + 1) == 0) { + trace(TRACE_ERROR, + "main(): list_nodeadd reports out of memory" + " while adding to returnpath"); + exitcode = EX_TEMPFAIL; + goto freeall; + } + + break; + case 'u': + trace(TRACE_INFO, + "main(): using SPECIAL_DELIVERY to usernames"); + + dsnuser_init(&dsnuser); + dsnuser.address = strdup(optarg); + + /* Add argument onto the users list. */ + if (list_nodeadd + (&dsnusers, &dsnuser, + sizeof(deliver_to_user_t)) == 0) { + trace(TRACE_ERROR, + "main(): list_nodeadd reports out of memory" + " while adding usernames"); + exitcode = EX_TEMPFAIL; + goto freeall; + } + + break; + case 'd': + trace(TRACE_INFO, + "main(): using SPECIAL_DELIVERY to email addresses"); + + dsnuser_init(&dsnuser); + dsnuser.address = strdup(optarg); + + /* Add argument onto the users list. */ + if (list_nodeadd + (&dsnusers, &dsnuser, + sizeof(deliver_to_user_t)) == 0) { + trace(TRACE_ERROR, + "main(): list_nodeadd reports out of memory" + " while adding email addresses"); + exitcode = EX_TEMPFAIL; + goto freeall; + } + + break; + default: + usage_error = 1; + break; + } + + /* At the end of each round of options, check + * to see if there were any errors worth stopping for. */ + if (usage_error) { + print_usage(argv[0]); + trace(TRACE_DEBUG, + "main(): usage error; setting EX_USAGE and aborting"); + exitcode = EX_USAGE; + goto freeall; + } + } + + /* ...or if there weren't any command line arguments at all. */ + if (argc < 2) { + print_usage(argv[0]); + trace(TRACE_DEBUG, + "main(): no arguments; setting EX_USAGE and aborting"); + exitcode = EX_USAGE; + goto freeall; + } + + if (db_connect() != 0) { + trace(TRACE_ERROR, "main(): database connection failed"); + exitcode = EX_TEMPFAIL; + goto freeall; + } + + if (auth_connect() != 0) { + trace(TRACE_ERROR, + "main(): authentication connection failed"); + exitcode = EX_TEMPFAIL; + goto freeall; + } + + /* first we need to read the header */ + if (!read_header(stdin, &headerrfcsize, &headersize, &header)) { + trace(TRACE_ERROR, + "main(): read_header failed to read a header"); + exitcode = EX_TEMPFAIL; + goto freeall; + } + + if (headersize > READ_BLOCK_SIZE) { + trace(TRACE_ERROR, + "%s,%s: failed to read header because header is " + "too big (bigger than READ_BLOCK_SIZE (%llu))", + __FILE__, __FUNCTION__, (u64_t) READ_BLOCK_SIZE); + exitcode = EX_DATAERR; + goto freeall; + } + + /* parse the list and scan for field and content */ + if (mime_readheader(header, &dummyidx, &mimelist, &dummysize) < 0) { + trace(TRACE_ERROR, + "main(): mime_readheader failed to read a header list"); + exitcode = EX_TEMPFAIL; + goto freeall; + } + + /* parse returnpath from header */ + if (returnpath.total_nodes == 0) + mail_adr_list("Return-Path", &returnpath, &mimelist); + if (returnpath.total_nodes == 0) + mail_adr_list("From", &returnpath, &mimelist); + if (returnpath.total_nodes == 0) + trace(TRACE_DEBUG, "main(): no return path found."); + + /* If the NORMAL delivery mode has been selected... */ + if (deliver_to_header != NULL) { + /* parse for destination addresses */ + trace(TRACE_DEBUG, "main(): scanning for [%s]", + deliver_to_header); + if (mail_adr_list(deliver_to_header, &users, &mimelist) != + 0) { + trace(TRACE_STOP, + "main(): scanner found no email addresses (scanned for %s)", + deliver_to_header); + exitcode = EX_TEMPFAIL; + goto freeall; + } + + /* Loop through the users list, moving the entries into the dsnusers list. */ + for (tmp = list_getstart(&users); tmp != NULL; + tmp = tmp->nextnode) { + deliver_to_user_t dsnuser; + + dsnuser_init(&dsnuser); + dsnuser.address = strdup((char *) tmp->data); + + list_nodeadd(&dsnusers, &dsnuser, + sizeof(deliver_to_user_t)); + } + } + + if (dsnuser_resolve_list(&dsnusers) == -1) { + trace(TRACE_ERROR, "main(): dsnuser_resolve_list failed"); + /* Most likely a random failure... */ + exitcode = EX_TEMPFAIL; + goto freeall; + } + + /* inserting messages into the database */ + if (insert_messages(stdin, + header, headersize, headerrfcsize, + &mimelist, &dsnusers, &returnpath) == -1) { + trace(TRACE_ERROR, "main(): insert_messages failed"); + /* Most likely a random failure... */ + exitcode = EX_TEMPFAIL; + } + + freeall: /* Goto's here! */ + + /* If there wasn't already an EX_TEMPFAIL from insert_messages(), + * then see if one of the status flags was marked with an error. */ + if (!exitcode) { + /* Get one reasonable error code for everyone. */ + switch (dsnuser_worstcase_list(&dsnusers)) { + case DSN_CLASS_OK: + exitcode = EX_OK; + break; + case DSN_CLASS_TEMP: + exitcode = EX_TEMPFAIL; + break; + case DSN_CLASS_FAIL: + exitcode = EX_NOUSER; + break; + } + } + + trace(TRACE_DEBUG, "main(): freeing dsnuser list"); + dsnuser_free_list(&dsnusers); + + trace(TRACE_DEBUG, "main(): freeing all other lists"); + list_freelist(&sysItems.start); + list_freelist(&smtpItems.start); + list_freelist(&mimelist.start); + list_freelist(&returnpath.start); + list_freelist(&users.start); + + trace(TRACE_DEBUG, "main(): freeing memory blocks"); + if (header != NULL) + my_free(header); + + trace(TRACE_DEBUG, "main(): they're all free. we're done."); + + db_disconnect(); + auth_disconnect(); + + trace(TRACE_DEBUG, "main(): exit code is [%d].", exitcode); + return exitcode; } - diff --git a/maintenance.c b/maintenance.c index 7dea9168..a2cdbf07 100644 --- a/maintenance.c +++ b/maintenance.c @@ -53,441 +53,453 @@ static void find_time(char *timestr, const char *timespec); int main(int argc, char *argv[]) { - int should_fix = 0, check_integrity = 0, check_iplog = 0; - int check_null_messages=0; - int show_help=0, purge_deleted=0, set_deleted=0; - int vacuum_db = 0; - int do_nothing=1; - struct list sysItems; - - time_t start,stop; - - char timespec[LEN],timestr[LEN]; - int opt; - struct list lostlist; - struct element *el; - u64_t id; - - u64_t deleted_messages; - u64_t messages_set_to_delete; - - openlog(PNAME, LOG_PID, LOG_MAIL); - - ReadConfig("DBMAIL", configFile, &sysItems); - SetTraceLevel(&sysItems); - GetDBParams(&_db_params, &sysItems); - - setvbuf(stdout,0,_IONBF,0); - printf ("*** dbmail-maintenance ***\n"); - - /* get options */ - opterr = 0; /* suppress error message from getopt() */ - while ((opt = getopt(argc, argv, "cfvinl:phd")) != -1) - { - switch (opt) - { - case 'c': - vacuum_db = 1; - do_nothing = 0; - break; + int should_fix = 0, check_integrity = 0, check_iplog = 0; + int check_null_messages = 0; + int show_help = 0, purge_deleted = 0, set_deleted = 0; + int vacuum_db = 0; + int do_nothing = 1; + struct list sysItems; + + time_t start, stop; + + char timespec[LEN], timestr[LEN]; + int opt; + struct list lostlist; + struct element *el; + u64_t id; + + u64_t deleted_messages; + u64_t messages_set_to_delete; + + openlog(PNAME, LOG_PID, LOG_MAIL); + + ReadConfig("DBMAIL", configFile, &sysItems); + SetTraceLevel(&sysItems); + GetDBParams(&_db_params, &sysItems); + + setvbuf(stdout, 0, _IONBF, 0); + printf("*** dbmail-maintenance ***\n"); + + /* get options */ + opterr = 0; /* suppress error message from getopt() */ + while ((opt = getopt(argc, argv, "cfvinl:phd")) != -1) { + switch (opt) { + case 'c': + vacuum_db = 1; + do_nothing = 0; + break; + + case 'h': + show_help = 1; + do_nothing = 0; + break; + + case 'p': + purge_deleted = 1; + do_nothing = 0; + break; + + case 'd': + set_deleted = 1; + do_nothing = 0; + break; + + case 'f': + check_integrity = 1; + should_fix = 1; + do_nothing = 0; + break; + + case 'i': + check_integrity = 1; + do_nothing = 0; + break; + + case 'n': + check_null_messages = 1; + do_nothing = 0; + break; + + case 'v': + printf + ("\n*** DBMAIL: dbmail-maintenance version $Revision$ %s\n", + COPYRIGHT); + return 0; + + + case 'l': + check_iplog = 1; + do_nothing = 0; + if (optarg) + strncpy(timespec, optarg, LEN); + else + timespec[0] = 0; + + timespec[LEN] = 0; + break; + + default: + /*printf("unrecognized option [%c], continuing...\n",optopt); */ + break; + } + } - case 'h': - show_help = 1; - do_nothing = 0; - break; - - case 'p': - purge_deleted = 1; - do_nothing = 0; - break; - - case 'd': - set_deleted = 1; - do_nothing = 0; - break; - - case 'f': - check_integrity = 1; - should_fix = 1; - do_nothing = 0; - break; - - case 'i': - check_integrity = 1; - do_nothing = 0; - break; - - case 'n': - check_null_messages = 1; - do_nothing = 0; - break; - - case 'v': - printf ("\n*** DBMAIL: dbmail-maintenance version $Revision$ %s\n",COPYRIGHT); + if (show_help) { + printf("\ndbmail maintenance utility\n\n"); + printf + ("Performs maintenance tasks on the dbmail-databases\n"); + printf("Use: dbmail-maintenance -[cfiphdl]\n"); + printf("See the man page for more info\n\n"); return 0; + } - case 'l': - check_iplog = 1; - do_nothing = 0; - if (optarg) - strncpy(timespec, optarg, LEN); - else - timespec[0] = 0; - - timespec[LEN] = 0; - break; + if (do_nothing) { + printf("Ok. Nothing requested, nothing done. " + "Try adding a command-line option to perform maintenance.\n"); + return 0; + } - default: - /*printf("unrecognized option [%c], continuing...\n",optopt);*/ - break; + printf("Opening connection to database... "); + if (db_connect() != 0) { + printf("Failed. An error occured. Please check log.\n"); + return -1; } - } - - if (show_help) - { - printf("\ndbmail maintenance utility\n\n"); - printf("Performs maintenance tasks on the dbmail-databases\n"); - printf("Use: dbmail-maintenance -[cfiphdl]\n"); - printf("See the man page for more info\n\n"); - return 0; - } - - - if (do_nothing) - { - printf("Ok. Nothing requested, nothing done. " - "Try adding a command-line option to perform maintenance.\n"); - return 0; - } - - printf ("Opening connection to database... "); - if (db_connect() != 0) - { - printf ("Failed. An error occured. Please check log.\n"); - return -1; - } - - printf ("Opening connection to authentication... "); - if (auth_connect() != 0) - { - printf ("Failed. An error occured. Please check log.\n"); - return -1; - } - - printf ("Ok. Connected\n"); - - if (purge_deleted) - { - printf ("Deleting messages with DELETE status... "); - if (db_deleted_purge(&deleted_messages) < 0) { - printf ("Failed. An error occured. Please check log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; - } - printf ("Ok. [%llu] messages deleted.\n",deleted_messages); - } - - - if (set_deleted) - { - printf ("Setting DELETE status for deleted messages... "); - if (db_set_deleted(&messages_set_to_delete) == -1) { - printf ("Failed. An error occured. Please check log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; - } - printf ("Ok. [%llu] messages set for deletion.\n",messages_set_to_delete); - printf("Re-calculating used quota for all users... "); - if (db_calculate_quotum_all() < 0) { - printf("Failed. An error occured. Please check log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; - } - printf("Ok. Used quota updated for all users.\n"); - } - - if (check_null_messages) - { - printf ("Now checking DBMAIL for NULL messages.. "); - time(&start); - - if (db_icheck_null_messages(&lostlist) < 0) - { - printf ("Failed. An error occured. Please check log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; + + printf("Opening connection to authentication... "); + if (auth_connect() != 0) { + printf("Failed. An error occured. Please check log.\n"); + return -1; } - - if (lostlist.total_nodes > 0) - { - printf ("Ok. Found [%ld] null messages:\n", lostlist.total_nodes); - - el = lostlist.start; - while (el) - { - id = *((u64_t*)el->data); - if (db_set_message_status(id, 6) < 0) - printf("Warning: could not set message status #%llu. Check log.\n", id); - else - printf("%llu (status update to 6)\n", id); - - el = el->nextnode; - } - - list_freelist(&lostlist.start); - - printf ("\n"); + + printf("Ok. Connected\n"); + + if (purge_deleted) { + printf("Deleting messages with DELETE status... "); + if (db_deleted_purge(&deleted_messages) < 0) { + printf + ("Failed. An error occured. Please check log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; + } + printf("Ok. [%llu] messages deleted.\n", deleted_messages); } - else - printf ("Ok. Found 0 NULL messages.\n"); - - time(&stop); - printf("--- checking NULL messages took %g seconds\n", difftime(stop, start)); - printf("Now checking DBMAIL for NULL physmessages.."); - time(&start); - if (db_icheck_null_physmessages(&lostlist) < 0) { - printf("Failed, an error occured. Please check log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; - } - - if (lostlist.total_nodes > 0) { - printf("found %ld physmessages without messageblocks\n", - lostlist.total_nodes); - el = lostlist.start; - while(el) { - id = *((u64_t*)el->data); - if (db_delete_physmessage(id) < 0) - printf("Warning: couldn't delete physmessage"); - else - printf("deleted physmessage [%llu]\n", id); - el = el->nextnode; - } - list_freelist(&lostlist.start); - printf("\n"); - } else - printf("found 0 physmessages without messageblks"); - - time(&stop); - fprintf(stderr, "--- checking NULL physmessages took %g seconds\n", - difftime(stop,start)); - } - - if (check_integrity) - { - printf ("Now checking DBMAIL messageblocks integrity.. "); - time(&start); - - /* this is what we do: - * First we're checking for loose messageblocks - * Secondly we're chekcing for loose messages - * Third we're checking for loose mailboxes - */ - - /* first part */ - if (db_icheck_messageblks(&lostlist) < 0) - { - printf ("Failed. An error occured. Please check log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; + + + if (set_deleted) { + printf("Setting DELETE status for deleted messages... "); + if (db_set_deleted(&messages_set_to_delete) == -1) { + printf + ("Failed. An error occured. Please check log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; + } + printf("Ok. [%llu] messages set for deletion.\n", + messages_set_to_delete); + printf("Re-calculating used quota for all users... "); + if (db_calculate_quotum_all() < 0) { + printf + ("Failed. An error occured. Please check log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; + } + printf("Ok. Used quota updated for all users.\n"); } - - if (lostlist.total_nodes > 0) - { - printf ("Ok. Found [%ld] unconnected messageblks:\n", lostlist.total_nodes); - - el = lostlist.start; - while (el) - { - id = *((u64_t*)el->data); - if (should_fix == 0) - printf("%llu ", id); - else - { - if (db_delete_messageblk(id) < 0) - printf("Warning: could not delete messageblock #%llu. Check log.\n", id); - else - printf("%llu (removed from dbase)\n",id); + + if (check_null_messages) { + printf("Now checking DBMAIL for NULL messages.. "); + time(&start); + + if (db_icheck_null_messages(&lostlist) < 0) { + printf + ("Failed. An error occured. Please check log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; } - el = el->nextnode; - } - - list_freelist(&lostlist.start); - - printf ("\n"); - if (should_fix == 0) - { - printf("Try running dbmail-maintenance with the '-f' option " - "in order to fix these problems\n\n"); - } - } - else - printf ("Ok. Found 0 unconnected messageblks.\n"); - - - time(&stop); - printf("--- checking block integrity took %g seconds\n", - difftime(stop, start)); - fprintf(stderr, "--- checking block integrity took %g seconds\n", - difftime(stop,start)); - - /* second part */ - start = stop; - printf ("Now checking DBMAIL message integrity.. "); - - if (db_icheck_messages(&lostlist) < 0) - { - printf ("Failed. An error occured. Please check log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; + if (lostlist.total_nodes > 0) { + printf("Ok. Found [%ld] null messages:\n", + lostlist.total_nodes); + + el = lostlist.start; + while (el) { + id = *((u64_t *) el->data); + if (db_set_message_status(id, 6) < 0) + printf + ("Warning: could not set message status #%llu. Check log.\n", + id); + else + printf + ("%llu (status update to 6)\n", + id); + + el = el->nextnode; + } + + list_freelist(&lostlist.start); + + printf("\n"); + } else + printf("Ok. Found 0 NULL messages.\n"); + + time(&stop); + printf("--- checking NULL messages took %g seconds\n", + difftime(stop, start)); + printf("Now checking DBMAIL for NULL physmessages.."); + time(&start); + if (db_icheck_null_physmessages(&lostlist) < 0) { + printf + ("Failed, an error occured. Please check log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; + } + + if (lostlist.total_nodes > 0) { + printf + ("found %ld physmessages without messageblocks\n", + lostlist.total_nodes); + el = lostlist.start; + while (el) { + id = *((u64_t *) el->data); + if (db_delete_physmessage(id) < 0) + printf + ("Warning: couldn't delete physmessage"); + else + printf + ("deleted physmessage [%llu]\n", + id); + el = el->nextnode; + } + list_freelist(&lostlist.start); + printf("\n"); + } else + printf("found 0 physmessages without messageblks"); + + time(&stop); + fprintf(stderr, + "--- checking NULL physmessages took %g seconds\n", + difftime(stop, start)); } - - if (lostlist.total_nodes > 0) - { - printf ("Ok. Found [%ld] unconnected messages:\n", lostlist.total_nodes); - - el = lostlist.start; - while (el) - { - id = *((u64_t*)el->data); - - if (should_fix == 0) - printf("%llu ", id); - else - { - if (db_delete_message(id) < 0) - printf("Warning: could not delete message #%llu. Check log.\n", id); - else - printf("%llu (removed from dbase)\n", id); + + if (check_integrity) { + printf("Now checking DBMAIL messageblocks integrity.. "); + time(&start); + + /* this is what we do: + * First we're checking for loose messageblocks + * Secondly we're chekcing for loose messages + * Third we're checking for loose mailboxes + */ + + /* first part */ + if (db_icheck_messageblks(&lostlist) < 0) { + printf + ("Failed. An error occured. Please check log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; + } + + if (lostlist.total_nodes > 0) { + printf + ("Ok. Found [%ld] unconnected messageblks:\n", + lostlist.total_nodes); + + el = lostlist.start; + while (el) { + id = *((u64_t *) el->data); + if (should_fix == 0) + printf("%llu ", id); + else { + if (db_delete_messageblk(id) < 0) + printf + ("Warning: could not delete messageblock #%llu. Check log.\n", + id); + else + printf + ("%llu (removed from dbase)\n", + id); + } + + el = el->nextnode; + } + + list_freelist(&lostlist.start); + + printf("\n"); + if (should_fix == 0) { + printf + ("Try running dbmail-maintenance with the '-f' option " + "in order to fix these problems\n\n"); + } + } else + printf("Ok. Found 0 unconnected messageblks.\n"); + + + time(&stop); + printf("--- checking block integrity took %g seconds\n", + difftime(stop, start)); + fprintf(stderr, + "--- checking block integrity took %g seconds\n", + difftime(stop, start)); + + /* second part */ + start = stop; + printf("Now checking DBMAIL message integrity.. "); + + if (db_icheck_messages(&lostlist) < 0) { + printf + ("Failed. An error occured. Please check log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; } - el = el->nextnode; - } - - printf ("\n"); - if (should_fix == 0) - { - printf("Try running dbmail-maintenance with the '-f' option " - "in order to fix these problems\n\n"); - } - list_freelist(&lostlist.start); + if (lostlist.total_nodes > 0) { + printf("Ok. Found [%ld] unconnected messages:\n", + lostlist.total_nodes); + + el = lostlist.start; + while (el) { + id = *((u64_t *) el->data); + + if (should_fix == 0) + printf("%llu ", id); + else { + if (db_delete_message(id) < 0) + printf + ("Warning: could not delete message #%llu. Check log.\n", + id); + else + printf + ("%llu (removed from dbase)\n", + id); + } + + el = el->nextnode; + } + + printf("\n"); + if (should_fix == 0) { + printf + ("Try running dbmail-maintenance with the '-f' option " + "in order to fix these problems\n\n"); + } + list_freelist(&lostlist.start); + + } else + printf("Ok. Found 0 unconnected messages.\n"); + + time(&stop); + printf("--- checking message integrity took %g seconds\n", + difftime(stop, start)); + fprintf(stderr, + "--- checking message integrity took %g seconds\n", + difftime(stop, start)); + + + /* third part */ + printf("Now checking DBMAIL mailbox integrity.. "); + start = stop; + + if (db_icheck_mailboxes(&lostlist) < 0) { + printf + ("Failed. An error occured. Please check log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; + } + if (lostlist.total_nodes) { + printf("Ok. Found [%ld] unconnected mailboxes:\n", + lostlist.total_nodes); + + el = lostlist.start; + while (el) { + id = *((u64_t *) el->data); + + if (should_fix == 0) + printf("%llu ", id); + else { + if (db_delete_mailbox(id, 0, 0) < + 0) + printf + ("Warning: could not delete mailbox #%llu. Check log.\n", + id); + else + printf + ("%llu (removed from dbase)\n", + id); + } + + el = el->nextnode; + } + + printf("\n"); + if (should_fix == 0) { + printf + ("Try running dbmail-maintenance with the '-f' option " + "in order to fix these problems\n\n"); + } + + list_freelist(&lostlist.start); + } else + printf("Ok. Found 0 unconnected mailboxes.\n"); + + time(&stop); + printf("--- checking mailbox integrity took %g seconds\n", + difftime(stop, start)); + fprintf(stderr, + "--- checking mailbox integrity took %g seconds\n", + difftime(stop, start)); } - else - printf ("Ok. Found 0 unconnected messages.\n"); - - time(&stop); - printf("--- checking message integrity took %g seconds\n", - difftime(stop, start)); - fprintf(stderr, "--- checking message integrity took %g seconds\n", - difftime(stop, start)); - - - /* third part */ - printf ("Now checking DBMAIL mailbox integrity.. "); - start = stop; - - if (db_icheck_mailboxes(&lostlist) < 0) - { - printf ("Failed. An error occured. Please check log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; - } - - if (lostlist.total_nodes) - { - printf ("Ok. Found [%ld] unconnected mailboxes:\n", lostlist.total_nodes); - - el = lostlist.start; - while (el) - { - id = *((u64_t*)el->data); - - if (should_fix == 0) - printf("%llu ", id); - else - { - if (db_delete_mailbox(id, 0, 0) < 0) - printf("Warning: could not delete mailbox #%llu. Check log.\n", id); - else - printf("%llu (removed from dbase)\n",id); + + if (check_iplog) { + find_time(timestr, timespec); + printf("Cleaning up IP log... "); + + if (timestr[0] == 0) { + printf("Failed. Invalid argument [%s] specified\n", + timespec); + db_disconnect(); + auth_disconnect(); + return -1; } - el = el->nextnode; - } - - printf ("\n"); - if (should_fix == 0) - { - printf("Try running dbmail-maintenance with the '-f' option " - "in order to fix these problems\n\n"); - } - - list_freelist(&lostlist.start); - } - else - printf ("Ok. Found 0 unconnected mailboxes.\n"); - - time(&stop); - printf("--- checking mailbox integrity took %g seconds\n", - difftime(stop, start)); - fprintf(stderr, "--- checking mailbox integrity took %g seconds\n", - difftime(stop, start)); - } - - if (check_iplog) - { - find_time(timestr, timespec); - printf("Cleaning up IP log... "); - - if (timestr[0] == 0) - { - printf("Failed. Invalid argument [%s] specified\n",timespec); - db_disconnect(); - auth_disconnect(); - return -1; - } + if (db_cleanup_iplog(timestr) < 0) { + printf("Failed. Please check the log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; + } - if (db_cleanup_iplog(timestr) < 0) - { - printf("Failed. Please check the log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; + printf("Ok. All entries before [%s] have been removed.\n", + timestr); } - - printf("Ok. All entries before [%s] have been removed.\n",timestr); - } - - if (vacuum_db) - { - printf("Cleaning up database structure... "); fflush(stdout); - if (db_cleanup() < 0) - { - printf("Failed. Please check the log.\n"); - db_disconnect(); - auth_disconnect(); - return -1; + + if (vacuum_db) { + printf("Cleaning up database structure... "); + fflush(stdout); + if (db_cleanup() < 0) { + printf("Failed. Please check the log.\n"); + db_disconnect(); + auth_disconnect(); + return -1; + } + + printf("Ok. Database cleaned up.\n"); } - - printf("Ok. Database cleaned up.\n"); - } - - printf ("Maintenance done.\n\n"); - - db_disconnect(); - auth_disconnect(); - return 0; + + printf("Maintenance done.\n\n"); + + db_disconnect(); + auth_disconnect(); + return 0; } /* @@ -500,79 +512,71 @@ int main(int argc, char *argv[]) */ void find_time(char *timestr, const char *timespec) { - time_t td; - struct tm tm; - int min=-1,hour=-1; - long tmp; - char *end; - - time(&td); /* get time */ - - timestr[0] = 0; - if (!timespec) - return; - - /* find first num */ - tmp = strtol(timespec, &end, 10); - if (!end) - return; - - if (tmp < 0) - return; - - switch (*end) - { - case 'h': - case 'H': - hour = tmp; - break; - - case 'm': - case 'M': - hour = 0; - min = tmp; - if (end[1]) /* should end here */ - return; + time_t td; + struct tm tm; + int min = -1, hour = -1; + long tmp; + char *end; + + time(&td); /* get time */ - break; + timestr[0] = 0; + if (!timespec) + return; - default: - return; - } + /* find first num */ + tmp = strtol(timespec, &end, 10); + if (!end) + return; + if (tmp < 0) + return; - /* find second num */ - if (timespec[end-timespec+1]) - { - tmp = strtol(×pec[end-timespec+1], &end, 10); - if (end) - { - if ((*end != 'm' && *end != 'M') || end[1]) - return; + switch (*end) { + case 'h': + case 'H': + hour = tmp; + break; - if (tmp < 0) - return; + case 'm': + case 'M': + hour = 0; + min = tmp; + if (end[1]) /* should end here */ + return; - if (min >= 0) /* already specified minutes */ - return; + break; - min = tmp; + default: + return; } - } - if (min < 0) - min = 0; - /* adjust time */ - td -= (hour * 3600L + min * 60L); - - tm = *localtime(&td); /* get components */ - strftime(timestr, LEN, "%Y-%m-%d %H:%M:%S", &tm); + /* find second num */ + if (timespec[end - timespec + 1]) { + tmp = strtol(×pec[end - timespec + 1], &end, 10); + if (end) { + if ((*end != 'm' && *end != 'M') || end[1]) + return; - return; -} + if (tmp < 0) + return; + if (min >= 0) /* already specified minutes */ + return; + min = tmp; + } + } + + if (min < 0) + min = 0; + /* adjust time */ + td -= (hour * 3600L + min * 60L); + tm = *localtime(&td); /* get components */ + strftime(timestr, LEN, "%Y-%m-%d %H:%M:%S", &tm); + return; +} diff --git a/maintenance.h b/maintenance.h index fdeb9dee..ba2c76e5 100644 --- a/maintenance.h +++ b/maintenance.h @@ -31,4 +31,3 @@ #define PNAME "dbmail/maintenance" #endif - diff --git a/mbox2dbmail.c b/mbox2dbmail.c index 61ccd59e..89659236 100644 --- a/mbox2dbmail.c +++ b/mbox2dbmail.c @@ -42,87 +42,73 @@ const char *mbox_delimiter_pattern = "^From .*@.* "; int main(int argc, char *argv[]) { - regex_t preg; - int result; - int in_msg; - char line[MAX_LINESIZE],cmdstr[MAX_LINESIZE]; - FILE *smtp = 0; - unsigned long long uid; - - if ((result = regcomp(&preg, mbox_delimiter_pattern, REG_NOSUB)) != 0) - { - fprintf(stderr,"Regex compilation failed.\n"); - return 1; - } - - if (argc >= 2) - { - /* user ID specified as an argument */ - snprintf(cmdstr, MAX_LINESIZE, "%s %s", SMTP_INJECTOR, argv[1]); - } - else - { - /* first line should be user ID */ - if (fgets(line, MAX_LINESIZE, stdin) == 0) - { - fprintf(stderr, "Error reading from stdin\n"); - return -1; + regex_t preg; + int result; + int in_msg; + char line[MAX_LINESIZE], cmdstr[MAX_LINESIZE]; + FILE *smtp = 0; + unsigned long long uid; + + if ((result = + regcomp(&preg, mbox_delimiter_pattern, REG_NOSUB)) != 0) { + fprintf(stderr, "Regex compilation failed.\n"); + return 1; } - - uid = strtoull(line, NULL, 10); - snprintf(cmdstr, MAX_LINESIZE, "%s %llu", SMTP_INJECTOR, uid); - } - in_msg = 0; - - while (!feof(stdin) && !ferror(stdin)) - { - if (fgets(line, MAX_LINESIZE, stdin) == 0) - break; - - /* check if this is a mbox delimiter */ - if (regexec(&preg, line, 0, NULL, 0) == 0) - { - if (!in_msg) - { - /* ok start of a new msg */ - /* this code will only be reached if it concerns the first msg */ - if ((smtp = popen(cmdstr, "w")) == 0) - { - perror("Error opening pipe"); - break; - } - - in_msg = 1; - } - else - { - /* close current pipe */ - pclose(smtp); - - /* open new pipe */ - if ((smtp = popen(cmdstr, "w")) == 0) - { - perror("Error opening pipe"); - break; + + if (argc >= 2) { + /* user ID specified as an argument */ + snprintf(cmdstr, MAX_LINESIZE, "%s %s", SMTP_INJECTOR, + argv[1]); + } else { + /* first line should be user ID */ + if (fgets(line, MAX_LINESIZE, stdin) == 0) { + fprintf(stderr, "Error reading from stdin\n"); + return -1; } - } + + uid = strtoull(line, NULL, 10); + snprintf(cmdstr, MAX_LINESIZE, "%s %llu", SMTP_INJECTOR, + uid); } - else - { - /* write data to pipe */ - if (smtp) - fputs(line, smtp); - else - { - fprintf(stderr,"Tried to write to an unopened pipe!\n"); - return 1; - } + in_msg = 0; + + while (!feof(stdin) && !ferror(stdin)) { + if (fgets(line, MAX_LINESIZE, stdin) == 0) + break; + + /* check if this is a mbox delimiter */ + if (regexec(&preg, line, 0, NULL, 0) == 0) { + if (!in_msg) { + /* ok start of a new msg */ + /* this code will only be reached if it concerns the first msg */ + if ((smtp = popen(cmdstr, "w")) == 0) { + perror("Error opening pipe"); + break; + } + + in_msg = 1; + } else { + /* close current pipe */ + pclose(smtp); + + /* open new pipe */ + if ((smtp = popen(cmdstr, "w")) == 0) { + perror("Error opening pipe"); + break; + } + } + } else { + /* write data to pipe */ + if (smtp) + fputs(line, smtp); + else { + fprintf(stderr, + "Tried to write to an unopened pipe!\n"); + return 1; + } + } } - } - return 0; + return 0; } - - - @@ -62,13 +62,13 @@ void byteReverse(unsigned char *buf, unsigned longs); */ void byteReverse(unsigned char *buf, unsigned longs) { - uint32 t; - do { - t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(uint32 *) buf = t; - buf += 4; - } while (--longs); + uint32 t; + do { + t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32 *) buf = t; + buf += 4; + } while (--longs); } #endif @@ -77,112 +77,111 @@ void byteReverse(unsigned char *buf, unsigned longs) * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ -void -gdm_md5_init (struct GdmMD5Context *ctx) +void gdm_md5_init(struct GdmMD5Context *ctx) { - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; - ctx->bits[0] = 0; - ctx->bits[1] = 0; + ctx->bits[0] = 0; + ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ -void -gdm_md5_update (struct GdmMD5Context *ctx, unsigned char const *buf, unsigned len) +void +gdm_md5_update(struct GdmMD5Context *ctx, unsigned char const *buf, + unsigned len) { - uint32 t; + uint32 t; - /* Update bitcount */ + /* Update bitcount */ - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - /* Handle any leading odd-sized chunks */ + /* Handle any leading odd-sized chunks */ - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; - t = 64 - t; - if (len < t) { - memcpy (p, buf, len); - return; + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + gdm_md5_transform(ctx->buf, (uint32 *) ctx->in); + buf += t; + len -= t; } - memcpy (p, buf, t); - byteReverse (ctx->in, 16); - gdm_md5_transform (ctx->buf, (uint32 *) ctx->in); - buf += t; - len -= t; - } - - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy (ctx->in, buf, 64); - byteReverse (ctx->in, 16); - gdm_md5_transform (ctx->buf, (uint32 *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + gdm_md5_transform(ctx->buf, (uint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ -void -gdm_md5_final (unsigned char digest[16], struct GdmMD5Context *ctx) +void gdm_md5_final(unsigned char digest[16], struct GdmMD5Context *ctx) { - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset (p, 0, count); - byteReverse (ctx->in, 16); - gdm_md5_transform (ctx->buf, (uint32 *) ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32 *) ctx->in)[14] = ctx->bits[0]; - ((uint32 *) ctx->in)[15] = ctx->bits[1]; - - gdm_md5_transform (ctx->buf, (uint32 *) ctx->in); - byteReverse ((unsigned char *) ctx->buf, 4); - memcpy (digest, ctx->buf, 16); - memset (ctx, 0, sizeof(ctx)); /* In case it's sensitive */ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + gdm_md5_transform(ctx->buf, (uint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *) ctx->in)[14] = ctx->bits[0]; + ((uint32 *) ctx->in)[15] = ctx->bits[1]; + + gdm_md5_transform(ctx->buf, (uint32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } @@ -202,89 +201,85 @@ gdm_md5_final (unsigned char digest[16], struct GdmMD5Context *ctx) * reflect the addition of 16 longwords of new data. GdmMD5Update blocks * the data and converts bytes into longwords for this routine. */ -void -gdm_md5_transform (uint32 buf[4], uint32 const in[16]) +void gdm_md5_transform(uint32 buf[4], uint32 const in[16]) { - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - gdm_md5_step(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - gdm_md5_step(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - gdm_md5_step(F1, c, d, a, b, in[2] + 0x242070db, 17); - gdm_md5_step(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - gdm_md5_step(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - gdm_md5_step(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - gdm_md5_step(F1, c, d, a, b, in[6] + 0xa8304613, 17); - gdm_md5_step(F1, b, c, d, a, in[7] + 0xfd469501, 22); - gdm_md5_step(F1, a, b, c, d, in[8] + 0x698098d8, 7); - gdm_md5_step(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - gdm_md5_step(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - gdm_md5_step(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - gdm_md5_step(F1, a, b, c, d, in[12] + 0x6b901122, 7); - gdm_md5_step(F1, d, a, b, c, in[13] + 0xfd987193, 12); - gdm_md5_step(F1, c, d, a, b, in[14] + 0xa679438e, 17); - gdm_md5_step(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - gdm_md5_step(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - gdm_md5_step(F2, d, a, b, c, in[6] + 0xc040b340, 9); - gdm_md5_step(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - gdm_md5_step(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - gdm_md5_step(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - gdm_md5_step(F2, d, a, b, c, in[10] + 0x02441453, 9); - gdm_md5_step(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - gdm_md5_step(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - gdm_md5_step(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - gdm_md5_step(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - gdm_md5_step(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - gdm_md5_step(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - gdm_md5_step(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - gdm_md5_step(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - gdm_md5_step(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - gdm_md5_step(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - gdm_md5_step(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - gdm_md5_step(F3, d, a, b, c, in[8] + 0x8771f681, 11); - gdm_md5_step(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - gdm_md5_step(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - gdm_md5_step(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - gdm_md5_step(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - gdm_md5_step(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - gdm_md5_step(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - gdm_md5_step(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - gdm_md5_step(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - gdm_md5_step(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - gdm_md5_step(F3, b, c, d, a, in[6] + 0x04881d05, 23); - gdm_md5_step(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - gdm_md5_step(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - gdm_md5_step(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - gdm_md5_step(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - gdm_md5_step(F4, a, b, c, d, in[0] + 0xf4292244, 6); - gdm_md5_step(F4, d, a, b, c, in[7] + 0x432aff97, 10); - gdm_md5_step(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - gdm_md5_step(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - gdm_md5_step(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - gdm_md5_step(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - gdm_md5_step(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - gdm_md5_step(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - gdm_md5_step(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - gdm_md5_step(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - gdm_md5_step(F4, c, d, a, b, in[6] + 0xa3014314, 15); - gdm_md5_step(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - gdm_md5_step(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - gdm_md5_step(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - gdm_md5_step(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - gdm_md5_step(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + gdm_md5_step(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + gdm_md5_step(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + gdm_md5_step(F1, c, d, a, b, in[2] + 0x242070db, 17); + gdm_md5_step(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + gdm_md5_step(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + gdm_md5_step(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + gdm_md5_step(F1, c, d, a, b, in[6] + 0xa8304613, 17); + gdm_md5_step(F1, b, c, d, a, in[7] + 0xfd469501, 22); + gdm_md5_step(F1, a, b, c, d, in[8] + 0x698098d8, 7); + gdm_md5_step(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + gdm_md5_step(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + gdm_md5_step(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + gdm_md5_step(F1, a, b, c, d, in[12] + 0x6b901122, 7); + gdm_md5_step(F1, d, a, b, c, in[13] + 0xfd987193, 12); + gdm_md5_step(F1, c, d, a, b, in[14] + 0xa679438e, 17); + gdm_md5_step(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + gdm_md5_step(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + gdm_md5_step(F2, d, a, b, c, in[6] + 0xc040b340, 9); + gdm_md5_step(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + gdm_md5_step(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + gdm_md5_step(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + gdm_md5_step(F2, d, a, b, c, in[10] + 0x02441453, 9); + gdm_md5_step(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + gdm_md5_step(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + gdm_md5_step(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + gdm_md5_step(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + gdm_md5_step(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + gdm_md5_step(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + gdm_md5_step(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + gdm_md5_step(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + gdm_md5_step(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + gdm_md5_step(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + gdm_md5_step(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + gdm_md5_step(F3, d, a, b, c, in[8] + 0x8771f681, 11); + gdm_md5_step(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + gdm_md5_step(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + gdm_md5_step(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + gdm_md5_step(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + gdm_md5_step(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + gdm_md5_step(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + gdm_md5_step(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + gdm_md5_step(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + gdm_md5_step(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + gdm_md5_step(F3, b, c, d, a, in[6] + 0x04881d05, 23); + gdm_md5_step(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + gdm_md5_step(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + gdm_md5_step(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + gdm_md5_step(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + gdm_md5_step(F4, a, b, c, d, in[0] + 0xf4292244, 6); + gdm_md5_step(F4, d, a, b, c, in[7] + 0x432aff97, 10); + gdm_md5_step(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + gdm_md5_step(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + gdm_md5_step(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + gdm_md5_step(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + gdm_md5_step(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + gdm_md5_step(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + gdm_md5_step(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + gdm_md5_step(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + gdm_md5_step(F4, c, d, a, b, in[6] + 0xa3014314, 15); + gdm_md5_step(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + gdm_md5_step(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + gdm_md5_step(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + gdm_md5_step(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + gdm_md5_step(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; } - - - @@ -34,15 +34,16 @@ struct GdmMD5Context { unsigned char in[64]; }; -void gdm_md5_init (struct GdmMD5Context *context); -void gdm_md5_update (struct GdmMD5Context *context, unsigned char const *buf, - unsigned len); -void gdm_md5_final (unsigned char digest[16], struct GdmMD5Context *context); -void gdm_md5_transform (uint32 buf[4], uint32 const in[16]); +void gdm_md5_init(struct GdmMD5Context *context); +void gdm_md5_update(struct GdmMD5Context *context, + unsigned char const *buf, unsigned len); +void gdm_md5_final(unsigned char digest[16], + struct GdmMD5Context *context); +void gdm_md5_transform(uint32 buf[4], uint32 const in[16]); /* * This is needed to make RSAREF happy on some MS-DOS compilers. */ /* typedef struct gdm_md5_Context gdm_md5__CTX; */ -#endif /* !GdmMD5_H */ +#endif /* !GdmMD5_H */ @@ -36,19 +36,19 @@ #define MAX_ERROR_SIZE 128 -enum __M_ERRORS { M_NOERROR, M_NOMEM, M_BADMEM, M_BADDATA, M_BADWHENCE, M_LASTERR }; +enum __M_ERRORS { M_NOERROR, M_NOMEM, M_BADMEM, M_BADDATA, M_BADWHENCE, + M_LASTERR }; -const char *__m_error_desc[M_LASTERR] = -{ - "no error", "not enough memory", "bad memory structure specified", - "bad data block specified", "bad whence indicator specified" +const char *__m_error_desc[M_LASTERR] = { + "no error", "not enough memory", "bad memory structure specified", + "bad data block specified", "bad whence indicator specified" }; int __m_errno; char __m_error_str[MAX_ERROR_SIZE]; /* internal use only */ -int __m_blkadd(MEM *m); +int __m_blkadd(MEM * m); /* @@ -56,36 +56,34 @@ int __m_blkadd(MEM *m); * * opens a mem-structure */ -MEM* mopen() +MEM *mopen() { - MEM *mp = (MEM*)my_malloc(sizeof(MEM)); - - if (!mp) - { - __m_errno = M_NOMEM; - return NULL; - } - - memset(mp, 0, sizeof(*mp)); - - mp->firstblk = (memblock_t*)my_malloc(sizeof(memblock_t)); - if (!mp->firstblk) - { - __m_errno = M_NOMEM; - my_free(mp); - return NULL; - } - - mp->firstblk->nextblk = NULL; - mp->firstblk->prevblk = NULL; - - mp->lastblk = mp->firstblk; - mp->currblk = mp->firstblk; - - mp->nblocks = 1; - - __m_errno = M_NOERROR; - return mp; + MEM *mp = (MEM *) my_malloc(sizeof(MEM)); + + if (!mp) { + __m_errno = M_NOMEM; + return NULL; + } + + memset(mp, 0, sizeof(*mp)); + + mp->firstblk = (memblock_t *) my_malloc(sizeof(memblock_t)); + if (!mp->firstblk) { + __m_errno = M_NOMEM; + my_free(mp); + return NULL; + } + + mp->firstblk->nextblk = NULL; + mp->firstblk->prevblk = NULL; + + mp->lastblk = mp->firstblk; + mp->currblk = mp->firstblk; + + mp->nblocks = 1; + + __m_errno = M_NOERROR; + return mp; } @@ -95,103 +93,95 @@ MEM* mopen() * closes a mem structure * */ -void mclose(MEM **m) +void mclose(MEM ** m) { - memblock_t *tmp,*next; + memblock_t *tmp, *next; - __m_errno = M_NOERROR; + __m_errno = M_NOERROR; - if (!m || !(*m)) - return; + if (!m || !(*m)) + return; - tmp = (*m)->firstblk; - while (tmp) - { - next = tmp->nextblk; /* save address */ - my_free(tmp); - tmp = next; - } + tmp = (*m)->firstblk; + while (tmp) { + next = tmp->nextblk; /* save address */ + my_free(tmp); + tmp = next; + } - my_free(*m); - *m = NULL; + my_free(*m); + *m = NULL; - return; + return; } - + /* * mwrite() * * writes size bytes of data to the memory associated with m */ -int mwrite(const void *data, int size, MEM *m) +int mwrite(const void *data, int size, MEM * m) { - long left; - - if (!m) - { - __m_errno = M_BADMEM; - return 0; - } - - if (!data) - { - __m_errno = M_BADDATA; - return 0; - } - - if (size <= 0) - return 0; - - - left = _MEMBLOCK_SIZE - m->mpos; - - if (size <= left) - { - /* entire fit */ - memmove(&m->currblk->data[m->mpos], data, size); - m->mpos += size; - - if (size == left) - { - /* update */ - if (m->currblk == m->lastblk) - { - if (!__m_blkadd(m)) - { - m->mpos--; - m->eom = m->mpos; - return size-1; + long left; + + if (!m) { + __m_errno = M_BADMEM; + return 0; + } + + if (!data) { + __m_errno = M_BADDATA; + return 0; + } + + if (size <= 0) + return 0; + + + left = _MEMBLOCK_SIZE - m->mpos; + + if (size <= left) { + /* entire fit */ + memmove(&m->currblk->data[m->mpos], data, size); + m->mpos += size; + + if (size == left) { + /* update */ + if (m->currblk == m->lastblk) { + if (!__m_blkadd(m)) { + m->mpos--; + m->eom = m->mpos; + return size - 1; + } + } + + m->currblk = m->currblk->nextblk; + m->mpos = 0; } - } - m->currblk = m->currblk->nextblk; - m->mpos = 0; + if (m->currblk == m->lastblk && m->mpos > m->eom) + m->eom = m->mpos; + + return size; } - if (m->currblk == m->lastblk && m->mpos > m->eom) - m->eom = m->mpos; - - return size; - } - - /* copy everything that can be placed */ - memmove(&m->currblk->data[m->mpos], data, left); - m->mpos += left; - - if (m->currblk == m->lastblk) - { - /* need a new block */ - if (!__m_blkadd(m)) - return left; - - m->eom = 0; - } - - m->currblk = m->currblk->nextblk; /* advance current block */ - m->mpos = 0; - - return left + mwrite(&((char*)data)[left], size - left, m); + /* copy everything that can be placed */ + memmove(&m->currblk->data[m->mpos], data, left); + m->mpos += left; + + if (m->currblk == m->lastblk) { + /* need a new block */ + if (!__m_blkadd(m)) + return left; + + m->eom = 0; + } + + m->currblk = m->currblk->nextblk; /* advance current block */ + m->mpos = 0; + + return left + mwrite(&((char *) data)[left], size - left, m); } @@ -202,58 +192,54 @@ int mwrite(const void *data, int size, MEM *m) * * returns the number of bytes actually read */ -int mread(void *data, int size, MEM *m) +int mread(void *data, int size, MEM * m) { - long left; - - if (!m) - { - __m_errno = M_BADMEM; - return 0; - } - - if (!data) - { - __m_errno = M_BADDATA; - return 0; - } - - if (size <= 0) - return 0; - - if (m->lastblk == m->currblk) - left = m->eom - m->mpos; - else - left = _MEMBLOCK_SIZE - m->mpos; - - if (left <= 0) - return 0; - - if (size < left) - { - /* entire fit */ - memmove(data, &m->currblk->data[m->mpos], size); - m->mpos += size; - - return size; - } - - /* copy everything that can be placed */ - memmove(data, &m->currblk->data[m->mpos], left); - m->mpos += left; - - if (m->currblk == m->lastblk) - { - /* no more data */ - return left; - } - - m->currblk = m->currblk->nextblk; /* advance current block */ - m->mpos = 0; - - return left + mread(&((char*)data)[left], size - left, m); + long left; + + if (!m) { + __m_errno = M_BADMEM; + return 0; + } + + if (!data) { + __m_errno = M_BADDATA; + return 0; + } + + if (size <= 0) + return 0; + + if (m->lastblk == m->currblk) + left = m->eom - m->mpos; + else + left = _MEMBLOCK_SIZE - m->mpos; + + if (left <= 0) + return 0; + + if (size < left) { + /* entire fit */ + memmove(data, &m->currblk->data[m->mpos], size); + m->mpos += size; + + return size; + } + + /* copy everything that can be placed */ + memmove(data, &m->currblk->data[m->mpos], left); + m->mpos += left; + + if (m->currblk == m->lastblk) { + /* no more data */ + return left; + } + + m->currblk = m->currblk->nextblk; /* advance current block */ + m->mpos = 0; + + return left + mread(&((char *) data)[left], size - left, m); } - + /* * mseek() @@ -265,95 +251,83 @@ int mread(void *data, int size, MEM *m) * * returns 0 on succes, -1 on error */ -int mseek(MEM *m, long offset, int whence) +int mseek(MEM * m, long offset, int whence) { - long left; - - if (!m) - { - __m_errno = M_BADMEM; - return -1; - } - - switch (whence) - { - case SEEK_SET: - m->currblk = m->firstblk; - m->mpos = 0; - - if (offset <= 0) - return 0; + long left; - return mseek(m, offset, SEEK_CUR); + if (!m) { + __m_errno = M_BADMEM; + return -1; + } - case SEEK_CUR: - if (offset == 0) - return 0; - - if (offset > 0) - { - left = _MEMBLOCK_SIZE - m->mpos; - if (offset >= left) - { - if (m->currblk == m->lastblk) - { - m->mpos = m->eom; - return 0; + switch (whence) { + case SEEK_SET: + m->currblk = m->firstblk; + m->mpos = 0; + + if (offset <= 0) + return 0; + + return mseek(m, offset, SEEK_CUR); + + case SEEK_CUR: + if (offset == 0) + return 0; + + if (offset > 0) { + left = _MEMBLOCK_SIZE - m->mpos; + if (offset >= left) { + if (m->currblk == m->lastblk) { + m->mpos = m->eom; + return 0; + } + + m->currblk = m->currblk->nextblk; + m->mpos = 0; + return mseek(m, offset - left, SEEK_CUR); + } else { + m->mpos += offset; + + if (m->currblk == m->lastblk + && m->mpos > m->eom) + m->mpos = m->eom; + + return 0; + } + } else { + /* offset < 0, walk backwards */ + left = -m->mpos; + + if (offset <= left) { + if (m->currblk == m->firstblk) { + m->mpos = 0; + return 0; + } + + m->currblk = m->currblk->prevblk; + m->mpos = _MEMBLOCK_SIZE; + return mseek(m, offset - left, SEEK_CUR); + } else { + m->mpos += offset; /* remember: offset<0 */ + return 0; + } } - - m->currblk = m->currblk->nextblk; - m->mpos = 0; - return mseek(m, offset - left, SEEK_CUR); - } - else - { - m->mpos += offset; - - if (m->currblk == m->lastblk && m->mpos > m->eom) + + case SEEK_END: + m->currblk = m->lastblk; m->mpos = m->eom; - return 0; - } - } - else - { - /* offset < 0, walk backwards */ - left = - m->mpos; - - if (offset <= left) - { - if (m->currblk == m->firstblk) - { - m->mpos = 0; - return 0; - } - - m->currblk = m->currblk->prevblk; - m->mpos = _MEMBLOCK_SIZE; - return mseek(m, offset - left, SEEK_CUR); - } - else - { - m->mpos += offset; /* remember: offset<0 */ - return 0; - } - } - - case SEEK_END: - m->currblk = m->lastblk; - m->mpos = m->eom; - - if (offset >= 0) - return 0; + if (offset >= 0) + return 0; - return mseek(m, offset, SEEK_CUR); + return mseek(m, offset, SEEK_CUR); - default: - __m_errno = M_BADWHENCE; - return -1; - } + default: + __m_errno = M_BADWHENCE; + return -1; + } - return 0; + return 0; } @@ -362,32 +336,29 @@ int mseek(MEM *m, long offset, int whence) * * gives the current position in bytes (absolute cnt) */ -long mtell(MEM *m) +long mtell(MEM * m) { - memblock_t *tmp; - long pos = 0; - - if (!m) - { - __m_errno = M_BADMEM; - return -1; - } - - tmp = m->firstblk; - while (tmp && tmp != m->currblk) - { - pos += _MEMBLOCK_SIZE; - tmp = tmp->nextblk; - } - - if (!tmp) - { - __m_errno = M_BADMEM; - return -1; - } - - pos += m->mpos; - return pos; + memblock_t *tmp; + long pos = 0; + + if (!m) { + __m_errno = M_BADMEM; + return -1; + } + + tmp = m->firstblk; + while (tmp && tmp != m->currblk) { + pos += _MEMBLOCK_SIZE; + tmp = tmp->nextblk; + } + + if (!tmp) { + __m_errno = M_BADMEM; + return -1; + } + + pos += m->mpos; + return pos; } @@ -396,10 +367,10 @@ long mtell(MEM *m) * * equivalent to mseek(m, 0, SEEK_SET) */ -void mrewind(MEM *m) +void mrewind(MEM * m) { - mseek(m, 0, SEEK_SET); - __m_errno = M_NOERROR; + mseek(m, 0, SEEK_SET); + __m_errno = M_NOERROR; } @@ -408,15 +379,14 @@ void mrewind(MEM *m) * * returns a ptr to a string describing the status of the last operation */ -char* merror() +char *merror() { - if (__m_errno >= 0 && __m_errno < M_LASTERR) - { - strncpy(__m_error_str, __m_error_desc[__m_errno], MAX_ERROR_SIZE); - return __m_error_str; - } - else - return NULL; + if (__m_errno >= 0 && __m_errno < M_LASTERR) { + strncpy(__m_error_str, __m_error_desc[__m_errno], + MAX_ERROR_SIZE); + return __m_error_str; + } else + return NULL; } @@ -425,33 +395,32 @@ char* merror() * * restores a memory block to the state just after it was created with mopen() */ -void mreset(MEM *m) +void mreset(MEM * m) { - memblock_t *tmp,*next; - - __m_errno = M_NOERROR; - - if (!m) - return; - - tmp = m->firstblk; - if (tmp) - tmp = tmp->nextblk; - - while (tmp) - { - next = tmp->nextblk; /* save address */ - my_free(tmp); - tmp = next; - m->nblocks--; - } - - m->firstblk->nextblk = NULL; - m->mpos = 0; - m->eom = 0; - - m->currblk = m->firstblk; - m->lastblk = m->firstblk; + memblock_t *tmp, *next; + + __m_errno = M_NOERROR; + + if (!m) + return; + + tmp = m->firstblk; + if (tmp) + tmp = tmp->nextblk; + + while (tmp) { + next = tmp->nextblk; /* save address */ + my_free(tmp); + tmp = next; + m->nblocks--; + } + + m->firstblk->nextblk = NULL; + m->mpos = 0; + m->eom = 0; + + m->currblk = m->firstblk; + m->lastblk = m->firstblk; } @@ -460,28 +429,26 @@ void mreset(MEM *m) * adds a block to m * returns 0 on failure, 1 on succes */ -int __m_blkadd(MEM *m) +int __m_blkadd(MEM * m) { - memblock_t *newblk; - - if (!m) - { - __m_errno = M_BADMEM; - return 0; - } - - newblk = (memblock_t*)my_malloc(sizeof(memblock_t)); - if (!newblk) - { - __m_errno = M_NOMEM; - return 0; - } - - newblk->prevblk = m->lastblk; - newblk->nextblk = NULL; - - m->nblocks++; - m->lastblk->nextblk = newblk; - m->lastblk = newblk; - return 1; + memblock_t *newblk; + + if (!m) { + __m_errno = M_BADMEM; + return 0; + } + + newblk = (memblock_t *) my_malloc(sizeof(memblock_t)); + if (!newblk) { + __m_errno = M_NOMEM; + return 0; + } + + newblk->prevblk = m->lastblk; + newblk->nextblk = NULL; + + m->nblocks++; + m->lastblk->nextblk = newblk; + m->lastblk = newblk; + return 1; } @@ -34,34 +34,32 @@ #define _MEMBLOCK_SIZE (512ul*1024ul) -struct memblock -{ - char data[_MEMBLOCK_SIZE]; - struct memblock *nextblk,*prevblk; +struct memblock { + char data[_MEMBLOCK_SIZE]; + struct memblock *nextblk, *prevblk; }; typedef struct memblock memblock_t; -struct MEM_TYPE -{ - int nblocks; - long mpos,eom; /* eom = end-of-mem; these positions are relative to - * currblk (mpos) and lastblk (eom) - */ +struct MEM_TYPE { + int nblocks; + long mpos, eom; /* eom = end-of-mem; these positions are relative to + * currblk (mpos) and lastblk (eom) + */ - memblock_t *firstblk,*currblk,*lastblk; + memblock_t *firstblk, *currblk, *lastblk; }; - + typedef struct MEM_TYPE MEM; -MEM* mopen(void); -void mclose(MEM **m); -int mwrite(const void *data, int size, MEM *m); -int mread(void *data, int size, MEM *m); -int mseek(MEM *m, long offset, int whence); -long mtell(MEM *m); -void mrewind(MEM *m); -void mreset(MEM *m); -char* merror(void); +MEM *mopen(void); +void mclose(MEM ** m); +int mwrite(const void *data, int size, MEM * m); +int mread(void *data, int size, MEM * m); +int mseek(MEM * m, long offset, int whence); +long mtell(MEM * m); +void mrewind(MEM * m); +void mreset(MEM * m); +char *merror(void); #endif @@ -31,19 +31,21 @@ #define MEM_BLOCK 1024 -struct mime_record -{ +struct mime_record { /* if these are to be changed to ptrs, the following has to be updated: mime.c (duh) db_parse_as_text a cleanup for all the memory allocated */ - char field[MIME_FIELD_MAX]; - char value[MIME_VALUE_MAX]; + char field[MIME_FIELD_MAX]; + char value[MIME_VALUE_MAX]; }; -void mime_findfield(const char *fname, struct list *mimelist, struct mime_record **mr); -int mail_adr_list(char *scan_for_field, struct list *targetlist, struct list *mimelist); -int mime_readheader(char *blkdata, u64_t *blkidx, struct list *mimelist, u64_t *headersize); +void mime_findfield(const char *fname, struct list *mimelist, + struct mime_record **mr); +int mail_adr_list(char *scan_for_field, struct list *targetlist, + struct list *mimelist); +int mime_readheader(char *blkdata, u64_t * blkidx, struct list *mimelist, + u64_t * headersize); #endif @@ -37,85 +37,87 @@ #include "misc.h" -int drop_privileges (char *newuser, char *newgroup) +int drop_privileges(char *newuser, char *newgroup) { - /* will drop running program's priviledges to newuser and newgroup */ - struct passwd *pwd; - struct group *grp; - - grp = getgrnam(newgroup); - - if (grp == NULL) { - trace (TRACE_ERROR,"%s,%s: could not find group %s\n", - __FILE__, __FUNCTION__, newgroup); - return -1; - } - - pwd = getpwnam(newuser); - if (pwd == NULL) { - trace (TRACE_ERROR,"%s,%s: could not find user %s\n", - __FILE__, __FUNCTION__, newuser); - return -1; - } - - if (setgid (grp->gr_gid) !=0) { - trace (TRACE_ERROR,"%s,%s: could not set gid to %s\n", - __FILE__, __FUNCTION__, newgroup); - return -1; - } - - if (setuid (pwd->pw_uid) != 0) { - trace (TRACE_ERROR,"%s,%s: could not set uid to %s\n", - __FILE__, __FUNCTION__, newuser); - return -1; - } - return 0; + /* will drop running program's priviledges to newuser and newgroup */ + struct passwd *pwd; + struct group *grp; + + grp = getgrnam(newgroup); + + if (grp == NULL) { + trace(TRACE_ERROR, "%s,%s: could not find group %s\n", + __FILE__, __FUNCTION__, newgroup); + return -1; + } + + pwd = getpwnam(newuser); + if (pwd == NULL) { + trace(TRACE_ERROR, "%s,%s: could not find user %s\n", + __FILE__, __FUNCTION__, newuser); + return -1; + } + + if (setgid(grp->gr_gid) != 0) { + trace(TRACE_ERROR, "%s,%s: could not set gid to %s\n", + __FILE__, __FUNCTION__, newgroup); + return -1; + } + + if (setuid(pwd->pw_uid) != 0) { + trace(TRACE_ERROR, "%s,%s: could not set uid to %s\n", + __FILE__, __FUNCTION__, newuser); + return -1; + } + return 0; } char *itoa(int i) { - char *s=(char *) malloc(42); /* Enough for a 128 bit integer */ - if (s) sprintf(s,"%d",i); - return s; + char *s = (char *) malloc(42); /* Enough for a 128 bit integer */ + if (s) + sprintf(s, "%d", i); + return s; } void create_unique_id(char *target, u64_t message_idnr) { - char *a_message_idnr, *a_rand; - char *md5_str; - - a_message_idnr = itoa(message_idnr); - a_rand = itoa(rand()); - - if (message_idnr != 0) - snprintf(target, UID_SIZE, "%s:%s", - a_message_idnr, a_rand); - else - snprintf(target, UID_SIZE, "%s", a_rand); - md5_str = makemd5(target); - snprintf(target, UID_SIZE, "%s", md5_str); - trace(TRACE_DEBUG,"%s,%s: created: %s", __FILE__, __FUNCTION__, target); - my_free(md5_str); - my_free(a_message_idnr); - my_free(a_rand); + char *a_message_idnr, *a_rand; + char *md5_str; + + a_message_idnr = itoa(message_idnr); + a_rand = itoa(rand()); + + if (message_idnr != 0) + snprintf(target, UID_SIZE, "%s:%s", + a_message_idnr, a_rand); + else + snprintf(target, UID_SIZE, "%s", a_rand); + md5_str = makemd5(target); + snprintf(target, UID_SIZE, "%s", md5_str); + trace(TRACE_DEBUG, "%s,%s: created: %s", __FILE__, __FUNCTION__, + target); + my_free(md5_str); + my_free(a_message_idnr); + my_free(a_rand); } -void create_current_timestring(timestring_t *timestring) +void create_current_timestring(timestring_t * timestring) { time_t td; struct tm tm; - + if (time(&td) == -1) trace(TRACE_FATAL, "%s,%s: error getting time from OS", __FILE__, __FUNCTION__); - tm = *localtime(&td); /* get components */ - strftime((char*)timestring, sizeof(timestring_t), + tm = *localtime(&td); /* get components */ + strftime((char *) timestring, sizeof(timestring_t), "%Y-%m-%d %H:%M:%S", &tm); } -char *mailbox_add_namespace(const char *mailbox_name, u64_t owner_idnr, - u64_t user_idnr) +char *mailbox_add_namespace(const char *mailbox_name, u64_t owner_idnr, + u64_t user_idnr) { char *fq_name; char *owner_name; @@ -126,42 +128,45 @@ char *mailbox_add_namespace(const char *mailbox_name, u64_t owner_idnr, "NULL.", __FILE__, __FUNCTION__); return NULL; } - + if (user_idnr == owner_idnr) { /* mailbox owned by current user */ return strdup(mailbox_name); } else { owner_name = auth_get_userid(owner_idnr); if (owner_name == NULL) { - trace(TRACE_ERROR, "%s,%s: error owner_name is NULL", - __FILE__, __FUNCTION__); + trace(TRACE_ERROR, + "%s,%s: error owner_name is NULL", __FILE__, + __FUNCTION__); return NULL; } trace(TRACE_ERROR, "%s,%s: owner name = %s", __FILE__, __FUNCTION__, owner_name); if (strcmp(owner_name, PUBLIC_FOLDER_USER) == 0) { fq_name_len = strlen(NAMESPACE_PUBLIC) + - strlen(MAILBOX_SEPERATOR) + - strlen(mailbox_name) + 1; - if (!(fq_name = my_malloc(fq_name_len * + strlen(MAILBOX_SEPERATOR) + + strlen(mailbox_name) + 1; + if (!(fq_name = my_malloc(fq_name_len * sizeof(char)))) { - trace(TRACE_ERROR, "%s,%s: not enough memory", - __FILE__, __FUNCTION__); + trace(TRACE_ERROR, + "%s,%s: not enough memory", __FILE__, + __FUNCTION__); return NULL; } snprintf(fq_name, fq_name_len, "%s%s%s", - NAMESPACE_PUBLIC, MAILBOX_SEPERATOR, + NAMESPACE_PUBLIC, MAILBOX_SEPERATOR, mailbox_name); } else { fq_name_len = strlen(NAMESPACE_USER) + - strlen(MAILBOX_SEPERATOR) + - strlen(owner_name) + - strlen(MAILBOX_SEPERATOR) + - strlen(mailbox_name) + 1; + strlen(MAILBOX_SEPERATOR) + + strlen(owner_name) + + strlen(MAILBOX_SEPERATOR) + + strlen(mailbox_name) + 1; if (!(fq_name = my_malloc(fq_name_len * sizeof(char)))) { - trace(TRACE_ERROR, "%s,%s: not enough memory", - __FILE__, __FUNCTION__); + trace(TRACE_ERROR, + "%s,%s: not enough memory", __FILE__, + __FUNCTION__); return NULL; } snprintf(fq_name, fq_name_len, "%s%s%s%s%s", @@ -186,24 +191,27 @@ const char *mailbox_remove_namespace(const char *fq_name) if (strcmp(fq_name, NAMESPACE_USER) == 0) { temp = strstr(fq_name, MAILBOX_SEPERATOR); if (temp == NULL || strlen(temp) <= 1) { - trace(TRACE_ERROR, "%s,%s wronly constructed mailbox " - "name", __FILE__, __FUNCTION__); + trace(TRACE_ERROR, + "%s,%s wronly constructed mailbox " "name", + __FILE__, __FUNCTION__); return NULL; } temp = strstr(&temp[1], MAILBOX_SEPERATOR); if (temp == NULL || strlen(temp) <= 1) { - trace(TRACE_ERROR, "%s,%s wronly constructed mailbox " - "name", __FILE__, __FUNCTION__); + trace(TRACE_ERROR, + "%s,%s wronly constructed mailbox " "name", + __FILE__, __FUNCTION__); return NULL; } return &temp[1]; } if (strcmp(fq_name, NAMESPACE_PUBLIC) == 0) { temp = strstr(fq_name, MAILBOX_SEPERATOR); - + if (temp == NULL || strlen(temp) <= 1) { - trace(TRACE_ERROR, "%s,%s wronly constructed mailbox " - "name", __FILE__, __FUNCTION__); + trace(TRACE_ERROR, + "%s,%s wronly constructed mailbox " "name", + __FILE__, __FUNCTION__); return NULL; } return &temp[1]; @@ -223,186 +231,188 @@ const char *mailbox_remove_namespace(const char *fq_name) #define BAD -1 static const char base64val[] = { - BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, - BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, - BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,BAD,BAD, BAD,BAD,BAD,BAD, - BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,BAD, BAD,BAD,BAD,BAD, - BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,BAD, BAD,BAD,BAD,BAD + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BAD, BAD, BAD, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, + BAD, BAD, BAD, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 62, BAD, + BAD, BAD, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, BAD, BAD, BAD, BAD, BAD, + BAD, + BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, BAD, BAD, BAD, BAD, + BAD, + BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, BAD, BAD, BAD, BAD, BAD }; #define DECODE64(c) (isascii(c) ? base64val[c] : BAD) /* Base64 to raw bytes in quasi-big-endian order */ /* Returns 0 on success, -1 on failure */ -int base64_decode_internal(const char *in, size_t inlen, size_t maxlen, char *out, size_t *outlen) +int base64_decode_internal(const char *in, size_t inlen, size_t maxlen, + char *out, size_t * outlen) { - size_t pos = 0; - size_t len = 0; - register unsigned char digit1, digit2, digit3, digit4; - - /* Don't even bother if the string is too short */ - if (inlen < 4) - return -1; - - do - { - digit1 = in[0]; - if (DECODE64(digit1) == BAD) - return -1; - digit2 = in[1]; - if (DECODE64(digit2) == BAD) - return -1; - digit3 = in[2]; - if (digit3 != '=' && DECODE64(digit3) == BAD) - return -1; - digit4 = in[3]; - if (digit4 != '=' && DECODE64(digit4) == BAD) - return -1; - in += 4; - pos += 4; - ++len; - if (maxlen && len > maxlen) - return -1; - *out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4); - if (digit3 != '=') - { - ++len; - if (maxlen && len > maxlen) - return -1; - *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2); - if (digit4 != '=') - { - ++len; - if (maxlen && len > maxlen) - return -1; - *out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4); - } - } - } while ( pos < inlen && digit4 != '='); - - *out = '\0'; - - *outlen = len; - return 0; + size_t pos = 0; + size_t len = 0; + register unsigned char digit1, digit2, digit3, digit4; + + /* Don't even bother if the string is too short */ + if (inlen < 4) + return -1; + + do { + digit1 = in[0]; + if (DECODE64(digit1) == BAD) + return -1; + digit2 = in[1]; + if (DECODE64(digit2) == BAD) + return -1; + digit3 = in[2]; + if (digit3 != '=' && DECODE64(digit3) == BAD) + return -1; + digit4 = in[3]; + if (digit4 != '=' && DECODE64(digit4) == BAD) + return -1; + in += 4; + pos += 4; + ++len; + if (maxlen && len > maxlen) + return -1; + *out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4); + if (digit3 != '=') { + ++len; + if (maxlen && len > maxlen) + return -1; + *out++ = + ((DECODE64(digit2) << 4) & 0xf0) | + (DECODE64(digit3) >> 2); + if (digit4 != '=') { + ++len; + if (maxlen && len > maxlen) + return -1; + *out++ = + ((DECODE64(digit3) << 6) & 0xc0) | + DECODE64(digit4); + } + } + } while (pos < inlen && digit4 != '='); + + *out = '\0'; + + *outlen = len; + return 0; } /* A frontend to the base64_decode_internal() that deals with embedded strings */ char **base64_decode(char *str, size_t len) { - size_t i, j, n, maxlen; - size_t numstrings = 0; - char *str_decoded = NULL; - size_t len_decoded = 0; - char **ret = NULL; - - /* Base64 encoding required about 40% more space. - * So we'll allocate 50% more space. */ - maxlen = 3 * len / 2; - str_decoded = (char *)malloc(sizeof(char) * maxlen); - if (str_decoded == NULL) - return NULL; - - if (0 != base64_decode_internal(str, len, maxlen, str_decoded, &len_decoded)) - return NULL; - if (str_decoded == NULL) - return NULL; - - /* Count up the number of embedded strings... */ - for (i = 0; i <= len_decoded; i++) - { - if (str_decoded[i] == '\0') - { - numstrings++; - } - } - - /* Allocate an array of arrays large enough - * for the strings and a terminating NULL */ - ret = (char **)malloc(sizeof(char *) * (numstrings + 1)); - if (ret == NULL) - return NULL; - - /* If there are more strings, copy those, too */ - for (i = j = n = 0; i <= len_decoded; i++) - { - if (str_decoded[i] == '\0') - { - ret[n] = strdup(str_decoded + j); - j = i + 1; - n++; - } - } - - /* Put that final NULL on the end of the array */ - ret[n] = NULL; - - my_free(str_decoded); - - return ret; + size_t i, j, n, maxlen; + size_t numstrings = 0; + char *str_decoded = NULL; + size_t len_decoded = 0; + char **ret = NULL; + + /* Base64 encoding required about 40% more space. + * So we'll allocate 50% more space. */ + maxlen = 3 * len / 2; + str_decoded = (char *) malloc(sizeof(char) * maxlen); + if (str_decoded == NULL) + return NULL; + + if (0 != + base64_decode_internal(str, len, maxlen, str_decoded, + &len_decoded)) + return NULL; + if (str_decoded == NULL) + return NULL; + + /* Count up the number of embedded strings... */ + for (i = 0; i <= len_decoded; i++) { + if (str_decoded[i] == '\0') { + numstrings++; + } + } + + /* Allocate an array of arrays large enough + * for the strings and a terminating NULL */ + ret = (char **) malloc(sizeof(char *) * (numstrings + 1)); + if (ret == NULL) + return NULL; + + /* If there are more strings, copy those, too */ + for (i = j = n = 0; i <= len_decoded; i++) { + if (str_decoded[i] == '\0') { + ret[n] = strdup(str_decoded + j); + j = i + 1; + n++; + } + } + + /* Put that final NULL on the end of the array */ + ret[n] = NULL; + + my_free(str_decoded); + + return ret; } void base64_free(char **ret) { - size_t i; + size_t i; - if (ret == NULL) - return; + if (ret == NULL) + return; - for (i = 0; ret[i] != NULL; i++) - { - my_free(ret[i]); - } + for (i = 0; ret[i] != NULL; i++) { + my_free(ret[i]); + } - my_free(ret); + my_free(ret); } /* Return 0 is all's well. Returns something else if not... */ -int read_from_stream(FILE *instream, char **m_buf, size_t maxlen) +int read_from_stream(FILE * instream, char **m_buf, size_t maxlen) { - size_t f_len = 0; - size_t f_pos = 0; - char *tmp_buf = NULL; - char *f_buf = NULL; - - /* Give up on a zero length request */ - if (maxlen < 1) - { - *m_buf = NULL; - return 0; - } - - tmp_buf = malloc(sizeof(char) * (f_len+=512)); - if (tmp_buf != NULL) - f_buf = tmp_buf; - else - return -2; - - /* Shouldn't this also check for ferror() or feof() ?? */ - while (f_pos < maxlen) - { - if (f_pos + 1 >= f_len) - { - /* Per suggestion of my CS instructor, double the - * buffer every time it is too small. This yields - * a logarithmic number of reallocations. */ - tmp_buf = realloc(f_buf, sizeof(char) * (f_len*=2)); - if (tmp_buf != NULL) - f_buf = tmp_buf; - else - return -2; - } - f_buf[f_pos] = fgetc(instream); - f_pos++; - } - - if (f_pos) - f_buf[f_pos] = '\0'; - - *m_buf = f_buf; - - return 0; + size_t f_len = 0; + size_t f_pos = 0; + char *tmp_buf = NULL; + char *f_buf = NULL; + + /* Give up on a zero length request */ + if (maxlen < 1) { + *m_buf = NULL; + return 0; + } + + tmp_buf = malloc(sizeof(char) * (f_len += 512)); + if (tmp_buf != NULL) + f_buf = tmp_buf; + else + return -2; + + /* Shouldn't this also check for ferror() or feof() ?? */ + while (f_pos < maxlen) { + if (f_pos + 1 >= f_len) { + /* Per suggestion of my CS instructor, double the + * buffer every time it is too small. This yields + * a logarithmic number of reallocations. */ + tmp_buf = + realloc(f_buf, sizeof(char) * (f_len *= 2)); + if (tmp_buf != NULL) + f_buf = tmp_buf; + else + return -2; + } + f_buf[f_pos] = fgetc(instream); + f_pos++; + } + + if (f_pos) + f_buf[f_pos] = '\0'; + + *m_buf = f_buf; + + return 0; } /* Finds what lurks between two bounding symbols. @@ -415,53 +425,54 @@ int read_from_stream(FILE *instream, char **m_buf, size_t maxlen) * * The caller is responsible for free()ing *retchar. * */ -int find_bounded(char *value, char left, char right, char **retchar, size_t *retsize, size_t *retlast) +int find_bounded(char *value, char left, char right, char **retchar, + size_t * retsize, size_t * retlast) { - char *tmpleft; - char *tmpright; - size_t tmplen; - - tmpleft = value; - tmpright = value + strlen(value); - - while (tmpleft[0] != left && tmpleft < tmpright) - tmpleft++; - while (tmpright[0] != right && tmpright > tmpleft) - tmpright--; - - if (tmpleft[0] != left || tmpright[0] != right) - { - trace(TRACE_INFO, "%s, %s: Found nothing between '%c' and '%c'", - __FILE__, __FUNCTION__, left, right); - *retchar = NULL; - *retsize = 0; - *retlast = 0; - return -1; - } - else - { - /* Step left up to skip the actual left thinger */ - if (tmpright != tmpleft) - tmpleft++; - - tmplen = tmpright - tmpleft; - *retchar = my_malloc(sizeof(char) * (tmplen + 1)); - if (*retchar == NULL) - { - *retchar = NULL; - *retsize = 0; - *retlast = 0; - trace(TRACE_INFO, "%s, %s: Found [%s] of length [%zd] between '%c' and '%c' so next skip [%zd]", - __FILE__, __FUNCTION__, *retchar, *retsize, left, right, *retlast); - return -2; - } - strncpy(*retchar, tmpleft, tmplen); - (*retchar)[tmplen] = '\0'; - *retsize = tmplen; - *retlast = tmpright - value; - trace(TRACE_INFO, "%s, %s: Found [%s] of length [%zd] between '%c' and '%c' so next skip [%zd]", - __FILE__, __FUNCTION__, *retchar, *retsize, left, right, *retlast); - return 0; - } + char *tmpleft; + char *tmpright; + size_t tmplen; + + tmpleft = value; + tmpright = value + strlen(value); + + while (tmpleft[0] != left && tmpleft < tmpright) + tmpleft++; + while (tmpright[0] != right && tmpright > tmpleft) + tmpright--; + + if (tmpleft[0] != left || tmpright[0] != right) { + trace(TRACE_INFO, + "%s, %s: Found nothing between '%c' and '%c'", + __FILE__, __FUNCTION__, left, right); + *retchar = NULL; + *retsize = 0; + *retlast = 0; + return -1; + } else { + /* Step left up to skip the actual left thinger */ + if (tmpright != tmpleft) + tmpleft++; + + tmplen = tmpright - tmpleft; + *retchar = my_malloc(sizeof(char) * (tmplen + 1)); + if (*retchar == NULL) { + *retchar = NULL; + *retsize = 0; + *retlast = 0; + trace(TRACE_INFO, + "%s, %s: Found [%s] of length [%zd] between '%c' and '%c' so next skip [%zd]", + __FILE__, __FUNCTION__, *retchar, *retsize, + left, right, *retlast); + return -2; + } + strncpy(*retchar, tmpleft, tmplen); + (*retchar)[tmplen] = '\0'; + *retsize = tmplen; + *retlast = tmpright - value; + trace(TRACE_INFO, + "%s, %s: Found [%s] of length [%zd] between '%c' and '%c' so next skip [%zd]", + __FILE__, __FUNCTION__, *retchar, *retsize, left, + right, *retlast); + return 0; + } } - @@ -44,7 +44,7 @@ - -1 on error - 0 on success */ -int drop_privileges (char *newuser, char *newgroup); +int drop_privileges(char *newuser, char *newgroup); /** * \brief convert integer to string (length 42, long enough for @@ -52,7 +52,7 @@ int drop_privileges (char *newuser, char *newgroup); * \param i the integer * \return string */ -char * itoa (int i); +char *itoa(int i); /** * \brief create a unique id for a message (used for pop, stored per message) @@ -65,7 +65,7 @@ void create_unique_id(char *target, u64_t message_idnr); * \brief create a timestring with the current time. * \param timestring an allocated timestring object. */ -void create_current_timestring(timestring_t *timestring); +void create_current_timestring(timestring_t * timestring); /** * \brief decorate a mailbox name with a namespace if needed @@ -91,8 +91,10 @@ const char *mailbox_remove_namespace(const char *fq_name); char **base64_decode(char *str, size_t len); void base64_free(char **ret); -int read_from_stream(FILE *instream, char **m_buf, size_t maxlen); -int find_bounded(char *value, char left, char right, char **retchar, size_t *retsize, size_t *retlast); -int base64_grow_ret(char ***inchar, size_t **inint, size_t newcount, size_t newchar); +int read_from_stream(FILE * instream, char **m_buf, size_t maxlen); +int find_bounded(char *value, char left, char right, char **retchar, + size_t * retsize, size_t * retlast); +int base64_grow_ret(char ***inchar, size_t ** inint, size_t newcount, + size_t newchar); #endif diff --git a/mysql/dbmysql.c b/mysql/dbmysql.c index 21876fdc..1d0e85ac 100644 --- a/mysql/dbmysql.c +++ b/mysql/dbmysql.c @@ -47,7 +47,7 @@ static MYSQL conn; /**< MySQL database connection */ static MYSQL_RES *res = NULL; /**< MySQL result set */ static MYSQL_RES *msgbuf_res = NULL; /**< MySQL result set for msgbuf */ static MYSQL_RES *auth_res = NULL; /**< MySQL result set for authentication */ -static MYSQL_RES *stored_res = NULL; /**< MySQL result set backup */ +static MYSQL_RES *stored_res = NULL; /**< MySQL result set backup */ static unsigned last_row_nr = -1; /**< number of last row that was used */ static MYSQL_ROW last_row; /**< last result set */ @@ -65,12 +65,12 @@ db_param_t _db_params; */ static int db_check_connection(void); -int db_connect() -{ +int db_connect() +{ char *sock = NULL; - /* connect */ + /* connect */ mysql_init(&conn); - + /* auto re-connect */ conn.reconnect = 1; @@ -88,27 +88,26 @@ int db_connect() "will be attempted using the default socket.", __FILE__, __FUNCTION__); sock = NULL; - } else + } else sock = _db_params.sock; } - - - if (mysql_real_connect (&conn, _db_params.host, _db_params.user, - _db_params.pass, _db_params.db, - _db_params.port, sock, - 0) == NULL) { - trace(TRACE_ERROR,"%s,%s: mysql_real_connect failed: %s", - __FILE__, __FUNCTION__, mysql_error(&conn)); - return -1; - } -#ifdef mysql_errno - if (mysql_errno(&conn)) { - trace(TRACE_ERROR,"%s,%s: mysql_real_connect failed: %s", - __FILE__, __FUNCTION__, mysql_error(&conn)); - return -1; - } -#endif - return 0; + + + if (mysql_real_connect(&conn, _db_params.host, _db_params.user, + _db_params.pass, _db_params.db, + _db_params.port, sock, 0) == NULL) { + trace(TRACE_ERROR, "%s,%s: mysql_real_connect failed: %s", + __FILE__, __FUNCTION__, mysql_error(&conn)); + return -1; + } +#ifdef mysql_errno + if (mysql_errno(&conn)) { + trace(TRACE_ERROR, "%s,%s: mysql_real_connect failed: %s", + __FILE__, __FUNCTION__, mysql_error(&conn)); + return -1; + } +#endif + return 0; } unsigned db_num_rows() @@ -118,7 +117,7 @@ unsigned db_num_rows() * should return 0 */ if (!res) return 0; - + return mysql_num_rows(res); } @@ -144,38 +143,38 @@ char *db_get_result(unsigned row, unsigned field) if (!res) { trace(TRACE_WARNING, "%s,%s: result set is null\n", - __FILE__, __FUNCTION__); - return NULL; - } - - if ((row >= db_num_rows()) || - (field >= db_num_fields())) { - trace(TRACE_WARNING, "%s, %s: " - "row = %u, field = %u, bigger than size of result set", __FILE__, __FUNCTION__,row, field); - return NULL; - } + __FILE__, __FUNCTION__); + return NULL; + } + + if ((row >= db_num_rows()) || (field >= db_num_fields())) { + trace(TRACE_WARNING, "%s, %s: " + "row = %u, field = %u, bigger than size of result set", + __FILE__, __FUNCTION__, row, field); + return NULL; + } /* get the right row */ - if(last_row_nr == row) { - } else if((last_row_nr + 1) == row) { + if (last_row_nr == row) { + } else if ((last_row_nr + 1) == row) { last_row = mysql_fetch_row(res); } else { - mysql_data_seek(res, row); + mysql_data_seek(res, row); last_row = mysql_fetch_row(res); } - result = last_row[field]; - if (result == NULL) + result = last_row[field]; + if (result == NULL) trace(TRACE_WARNING, "%s,%s: result is null\n", __FILE__, __FUNCTION__); last_row_nr = row; - return result; -} + return result; +} int db_disconnect() -{ - db_free_result(); - mysql_close(&conn); - return 0; -} +{ + db_free_result(); + mysql_close(&conn); + return 0; +} int db_check_connection() { @@ -191,66 +190,69 @@ int db_check_connection() return 0; } -u64_t db_insert_result(const char *sequence_identifier UNUSED) -{ - u64_t insert_result; - insert_result = mysql_insert_id(&conn); - return insert_result; -} +u64_t db_insert_result(const char *sequence_identifier UNUSED) +{ + u64_t insert_result; + insert_result = mysql_insert_id(&conn); + return insert_result; +} -int db_query(const char *the_query) -{ +int db_query(const char *the_query) +{ unsigned int querysize = 0; last_row_nr = -1; if (db_check_connection() < 0) { trace(TRACE_ERROR, "%s,%s: no database connection", - __FILE__, __FUNCTION__); + __FILE__, __FUNCTION__); + return -1; + } + if (the_query != NULL) { + querysize = strlen(the_query); + if (querysize > 0) { + trace(TRACE_DEBUG, "%s,%s: " + "executing query [%s]", + __FILE__, __FUNCTION__, the_query); + if (mysql_real_query(&conn, + the_query, querysize) < 0) { + trace(TRACE_ERROR, "%s,%s: " + "query [%s] failed", + __FILE__, __FUNCTION__, the_query); + trace(TRACE_ERROR, "%s,%s: " + "mysql_real_query failed: %s", + __FILE__, __FUNCTION__, + mysql_error(&conn)); + return -1; + } + } else { + trace(TRACE_ERROR, "%s,%s: " + "querysize is wrong: [%d]", __FILE__, + __FUNCTION__, querysize); + return -1; + } + } else { + trace(TRACE_ERROR, "%s,%s: " + "query buffer is NULL, this is not supposed to happen\n", + __FILE__, __FUNCTION__); return -1; } - if (the_query != NULL) { - querysize = strlen(the_query); - if (querysize > 0) { - trace(TRACE_DEBUG, "%s,%s: " - "executing query [%s]", - __FILE__, __FUNCTION__, the_query); - if (mysql_real_query(&conn, - the_query, querysize) < 0) { - trace(TRACE_ERROR, "%s,%s: " - "query [%s] failed", - __FILE__, __FUNCTION__, the_query); - trace(TRACE_ERROR, "%s,%s: " - "mysql_real_query failed: %s", - __FILE__, __FUNCTION__, mysql_error(&conn)); - return -1; - } - } else { - trace(TRACE_ERROR, "%s,%s: " - "querysize is wrong: [%d]", __FILE__, __FUNCTION__,querysize); - return -1; - } - } else { - trace (TRACE_ERROR,"%s,%s: " - "query buffer is NULL, this is not supposed to happen\n", - __FILE__, __FUNCTION__); - return -1; - } /* mysql_store_result is only needed if a SELECT or an OPTIMIZE is done */ if (strncasecmp(the_query, "SELECT", 6) == 0 || - strncasecmp(the_query, "OPTIMIZE", 8) == 0) { - res = mysql_store_result(&conn); - if (res == NULL) { - trace(TRACE_ERROR, "%s,%s: could not store query result", - __FILE__, __FUNCTION__); - return -1; - } - } - return 0; + strncasecmp(the_query, "OPTIMIZE", 8) == 0) { + res = mysql_store_result(&conn); + if (res == NULL) { + trace(TRACE_ERROR, + "%s,%s: could not store query result", + __FILE__, __FUNCTION__); + return -1; + } + } + return 0; } -unsigned long db_escape_string(char *to, - const char *from, unsigned long length) +unsigned long db_escape_string(char *to, + const char *from, unsigned long length) { return mysql_real_escape_string(&conn, to, from, length); } @@ -262,11 +264,13 @@ int db_do_cleanup(const char **tables, int num) int result = 0; for (i = 0; i < num; i++) { - snprintf(query, DEF_QUERYSIZE, "OPTIMIZE TABLE %s", tables[i]); + snprintf(query, DEF_QUERYSIZE, "OPTIMIZE TABLE %s", + tables[i]); if (db_query(query) == -1) { - trace(TRACE_ERROR, "%s,%s: error optimizing table [%s]", - __FILE__, __FUNCTION__, tables[i]); + trace(TRACE_ERROR, + "%s,%s: error optimizing table [%s]", + __FILE__, __FUNCTION__, tables[i]); result = -1; } db_free_result(); @@ -280,19 +284,19 @@ u64_t db_get_length(unsigned row, unsigned field) if (!res) { trace(TRACE_WARNING, "%s,%s: result set is null\n", __FILE__, __FUNCTION__); - return -1; - } - - if ((row >= db_num_rows()) || - (field >= db_num_fields())) { - trace(TRACE_ERROR, "%s, %s: " - "row = %u, field = %u, bigger than size of result set", __FILE__, __FUNCTION__,row, field); - return -1; - } + return -1; + } + + if ((row >= db_num_rows()) || (field >= db_num_fields())) { + trace(TRACE_ERROR, "%s, %s: " + "row = %u, field = %u, bigger than size of result set", + __FILE__, __FUNCTION__, row, field); + return -1; + } /* get the right row */ if (last_row_nr == row) { // Don't do anything, we're already there - } else if(last_row_nr + 1 == row) { + } else if (last_row_nr + 1 == row) { // Get the next row last_row = mysql_fetch_row(res); } else { @@ -305,7 +309,7 @@ u64_t db_get_length(unsigned row, unsigned field) u64_t db_get_affected_rows() { - return (u64_t) mysql_affected_rows(&conn); + return (u64_t) mysql_affected_rows(&conn); } void db_use_msgbuf_result() @@ -332,13 +336,12 @@ void db_store_auth_result() res = stored_res; } -void* db_get_result_set() +void *db_get_result_set() { - return (void*) res; + return (void *) res; } void db_set_result_set(void *the_result_set) { - res = (MYSQL_RES*) the_result_set; + res = (MYSQL_RES *) the_result_set; } - diff --git a/pgsql/dbpgsql.c b/pgsql/dbpgsql.c index 5e776f7f..192cc1f9 100644 --- a/pgsql/dbpgsql.c +++ b/pgsql/dbpgsql.c @@ -28,7 +28,7 @@ #endif #include "db.h" -#include "libpq-fe.h" /* PostgreSQL header */ +#include "libpq-fe.h" /* PostgreSQL header */ #include "dbmail.h" #include "dbmailtypes.h" @@ -60,287 +60,292 @@ static int db_check_connection(void); int db_connect() { - char connectionstring[255]; - - /* use the standard port for postgresql if none is given. This looks a bit - dirty.. can't we get this info from somewhere else? */ - if (_db_params.port != 0) - snprintf (connectionstring, 255, - "host='%s' user='%s' password='%s' dbname='%s' " - "port='%u'", - _db_params.host, _db_params.user, _db_params.pass, - _db_params.db, _db_params.port); - else - snprintf (connectionstring, 255, - "host='%s' user='%s' password='%s' dbname='%s' ", - _db_params.host, _db_params.user, _db_params.pass, - _db_params.db); - - conn = PQconnectdb(connectionstring); - - if (PQstatus(conn) == CONNECTION_BAD) { - trace(TRACE_ERROR, - "%si,%s: PQconnectdb failed: %s", - __FILE__, __FUNCTION__, - PQerrorMessage(conn)); - return -1; - } - - return 0; + char connectionstring[255]; + + /* use the standard port for postgresql if none is given. This looks a bit + dirty.. can't we get this info from somewhere else? */ + if (_db_params.port != 0) + snprintf(connectionstring, 255, + "host='%s' user='%s' password='%s' dbname='%s' " + "port='%u'", + _db_params.host, _db_params.user, _db_params.pass, + _db_params.db, _db_params.port); + else + snprintf(connectionstring, 255, + "host='%s' user='%s' password='%s' dbname='%s' ", + _db_params.host, _db_params.user, _db_params.pass, + _db_params.db); + + conn = PQconnectdb(connectionstring); + + if (PQstatus(conn) == CONNECTION_BAD) { + trace(TRACE_ERROR, + "%si,%s: PQconnectdb failed: %s", + __FILE__, __FUNCTION__, PQerrorMessage(conn)); + return -1; + } + + return 0; } int db_disconnect() { - db_free_result(); - PQfinish(conn); - conn = NULL; + db_free_result(); + PQfinish(conn); + conn = NULL; - return 0; + return 0; } int db_check_connection() { - /* if there is no connection, try making one */ - if (!conn) { - trace(TRACE_DEBUG, "%s,%s: no database connection, trying " - "to establish one", __FILE__, __FUNCTION__); - if (db_connect() < 0) { - trace(TRACE_ERROR, "%s,%s: unable to connect to database", - __FILE__, __FUNCTION__); - return -1; - } - return 0; - } - - /* check status of current connection */ - if (PQstatus(conn) != CONNECTION_OK) { - trace(TRACE_DEBUG, "%s,%s: connection lost, trying to reset", - __FILE__, __FUNCTION__); - PQreset(conn); - - if (PQstatus(conn) != CONNECTION_OK) { - trace(TRACE_ERROR, "%s,%s: Connection failed: [%s]", - __FILE__, __FUNCTION__, PQerrorMessage(conn)); - trace(TRACE_ERROR, "%s,%s: Could not establish dbase " - "connection", __FILE__, __FUNCTION__); - conn = NULL; - return -1; - } - } - return 0; + /* if there is no connection, try making one */ + if (!conn) { + trace(TRACE_DEBUG, "%s,%s: no database connection, trying " + "to establish one", __FILE__, __FUNCTION__); + if (db_connect() < 0) { + trace(TRACE_ERROR, + "%s,%s: unable to connect to database", + __FILE__, __FUNCTION__); + return -1; + } + return 0; + } + + /* check status of current connection */ + if (PQstatus(conn) != CONNECTION_OK) { + trace(TRACE_DEBUG, + "%s,%s: connection lost, trying to reset", __FILE__, + __FUNCTION__); + PQreset(conn); + + if (PQstatus(conn) != CONNECTION_OK) { + trace(TRACE_ERROR, + "%s,%s: Connection failed: [%s]", __FILE__, + __FUNCTION__, PQerrorMessage(conn)); + trace(TRACE_ERROR, + "%s,%s: Could not establish dbase " + "connection", __FILE__, __FUNCTION__); + conn = NULL; + return -1; + } + } + return 0; } - + unsigned db_num_rows() { - int num_rows; - if (!res) - return 0; - - num_rows = PQntuples(res); - if (num_rows < 0) - return 0; - else - return (unsigned) num_rows; + int num_rows; + if (!res) + return 0; + + num_rows = PQntuples(res); + if (num_rows < 0) + return 0; + else + return (unsigned) num_rows; } unsigned db_num_fields() { - int num_fields; - - if (!res) - return 0; - num_fields = PQnfields(res); - if (num_fields < 0) - return 0; - else - return (unsigned) num_fields; + int num_fields; + + if (!res) + return 0; + num_fields = PQnfields(res); + if (num_fields < 0) + return 0; + else + return (unsigned) num_fields; } void db_free_result() { - if (res != NULL) - PQclear(res); - res = NULL; + if (res != NULL) + PQclear(res); + res = NULL; } char *db_get_result(unsigned row, unsigned field) { - if (!res) { - trace(TRACE_WARNING, "%s,%s: result set is NULL", - __FILE__, __FUNCTION__); - return NULL; - } - - if ((row >= db_num_rows()) || - (field >= db_num_fields())) { - trace(TRACE_WARNING, "%s,%s: " - "(row = %u,field = %u) bigger then size of result set", - __FILE__, __FUNCTION__, row, field); - return NULL; - } - return PQgetvalue(res, row, field); + if (!res) { + trace(TRACE_WARNING, "%s,%s: result set is NULL", + __FILE__, __FUNCTION__); + return NULL; + } + + if ((row >= db_num_rows()) || (field >= db_num_fields())) { + trace(TRACE_WARNING, "%s,%s: " + "(row = %u,field = %u) bigger then size of result set", + __FILE__, __FUNCTION__, row, field); + return NULL; + } + return PQgetvalue(res, row, field); } u64_t db_insert_result(const char *sequence_identifier) { - char query[DEF_QUERYSIZE]; - u64_t insert_result; - - /* postgres uses the currval call on a sequence to determine - * the result value of an insert query */ - snprintf(query, DEF_QUERYSIZE, - "SELECT currval('%s_seq')", sequence_identifier); - - db_query(query); - if (db_num_rows() == 0) { - db_free_result(); - return 0; - } - insert_result = strtoull(db_get_result(0, 0), NULL, 10); - db_free_result(); - return insert_result; + char query[DEF_QUERYSIZE]; + u64_t insert_result; + + /* postgres uses the currval call on a sequence to determine + * the result value of an insert query */ + snprintf(query, DEF_QUERYSIZE, + "SELECT currval('%s_seq')", sequence_identifier); + + db_query(query); + if (db_num_rows() == 0) { + db_free_result(); + return 0; + } + insert_result = strtoull(db_get_result(0, 0), NULL, 10); + db_free_result(); + return insert_result; } int db_query(const char *the_query) { - int PQresultStatusVar; - char *result_string; - PGresult *temp_res; /**< temp_res is used as a temporary result set. If + int PQresultStatusVar; + char *result_string; + PGresult *temp_res; + /**< temp_res is used as a temporary result set. If the query succeeds, and needs to return a result set (i.e. it is a SELECT query) the global res is set to this temp_res result set */ - if (db_check_connection() < 0) { - trace(TRACE_ERROR, "%s,%s: No database connection", - __FILE__, __FUNCTION__); - return -1; - } - - if (the_query != NULL) { - trace(TRACE_DEBUG, "%s,%s: " - "executing query [%s]", __FILE__, __FUNCTION__, the_query); - temp_res = PQexec (conn, the_query); - if (!temp_res) - return -1; - - PQresultStatusVar = PQresultStatus(temp_res); - - if (PQresultStatusVar != PGRES_COMMAND_OK && - PQresultStatusVar != PGRES_TUPLES_OK) - { - trace(TRACE_ERROR,"%s, %s: " - "Error executing query [%s] : [%s]\n", - __FILE__, __FUNCTION__, - the_query, PQresultErrorMessage(temp_res)); - return -1; - } - - /* get the number of rows affected by the query */ - result_string = PQcmdTuples(temp_res); - if (result_string) - affected_rows = strtoull(result_string, NULL, 10); - else - affected_rows = 0; - - /* only keep the result set if this was a SELECT - * query */ - if (strncasecmp(the_query, "SELECT", 6) != 0) { - if (temp_res != NULL) - PQclear(temp_res); - } - - else { - if (res) - trace(TRACE_WARNING, "%s,%s: previous result set is possibly " - "not freed.", __FILE__, __FUNCTION__); - res = temp_res; - } - } else { - trace (TRACE_ERROR,"%s,%s: " - "query buffer is NULL, this is not supposed to happen\n", - __FILE__,__FUNCTION__); - return -1; - } - return 0; + if (db_check_connection() < 0) { + trace(TRACE_ERROR, "%s,%s: No database connection", + __FILE__, __FUNCTION__); + return -1; + } + + if (the_query != NULL) { + trace(TRACE_DEBUG, "%s,%s: " + "executing query [%s]", __FILE__, __FUNCTION__, + the_query); + temp_res = PQexec(conn, the_query); + if (!temp_res) + return -1; + + PQresultStatusVar = PQresultStatus(temp_res); + + if (PQresultStatusVar != PGRES_COMMAND_OK && + PQresultStatusVar != PGRES_TUPLES_OK) { + trace(TRACE_ERROR, "%s, %s: " + "Error executing query [%s] : [%s]\n", + __FILE__, __FUNCTION__, + the_query, PQresultErrorMessage(temp_res)); + return -1; + } + + /* get the number of rows affected by the query */ + result_string = PQcmdTuples(temp_res); + if (result_string) + affected_rows = strtoull(result_string, NULL, 10); + else + affected_rows = 0; + + /* only keep the result set if this was a SELECT + * query */ + if (strncasecmp(the_query, "SELECT", 6) != 0) { + if (temp_res != NULL) + PQclear(temp_res); + } + + else { + if (res) + trace(TRACE_WARNING, + "%s,%s: previous result set is possibly " + "not freed.", __FILE__, + __FUNCTION__); + res = temp_res; + } + } else { + trace(TRACE_ERROR, "%s,%s: " + "query buffer is NULL, this is not supposed to happen\n", + __FILE__, __FUNCTION__); + return -1; + } + return 0; } unsigned long db_escape_string(char *to, const char *from, unsigned long length) { - return PQescapeString(to, from, length); + return PQescapeString(to, from, length); } int db_do_cleanup(const char **tables, int num_tables) { - int result = 0; - int i; - char query[DEF_QUERYSIZE]; - - for (i = 0; i < num_tables; i++) { - snprintf(query, DEF_QUERYSIZE, "VACUUM %s", tables[i]); - if (db_query(query) == -1) { - trace(TRACE_ERROR, "%s,%s: error vacuuming table [%s]", - __FILE__, __FUNCTION__, tables[i]); - result = -1; - } - } - return result; + int result = 0; + int i; + char query[DEF_QUERYSIZE]; + + for (i = 0; i < num_tables; i++) { + snprintf(query, DEF_QUERYSIZE, "VACUUM %s", tables[i]); + if (db_query(query) == -1) { + trace(TRACE_ERROR, + "%s,%s: error vacuuming table [%s]", + __FILE__, __FUNCTION__, tables[i]); + result = -1; + } + } + return result; } u64_t db_get_length(unsigned row, unsigned field) { - if (!res) { - trace(TRACE_WARNING, "%s,%s: result set is NULL", - __FILE__, __FUNCTION__); - return -1; - } - - if ((row >= db_num_rows()) || - (field >= db_num_fields())) { - trace(TRACE_ERROR, "%s,%s: " - "(row = %u,field = %u) bigger then size of result set", - __FILE__, __FUNCTION__, row, field); - return -1; - } - return PQgetlength(res, row, field); + if (!res) { + trace(TRACE_WARNING, "%s,%s: result set is NULL", + __FILE__, __FUNCTION__); + return -1; + } + + if ((row >= db_num_rows()) || (field >= db_num_fields())) { + trace(TRACE_ERROR, "%s,%s: " + "(row = %u,field = %u) bigger then size of result set", + __FILE__, __FUNCTION__, row, field); + return -1; + } + return PQgetlength(res, row, field); } u64_t db_get_affected_rows() { - return affected_rows; + return affected_rows; } - + void db_use_msgbuf_result() { - stored_res = res; - res = msgbuf_res; + stored_res = res; + res = msgbuf_res; } void db_store_msgbuf_result() { - msgbuf_res = res; - res = stored_res; + msgbuf_res = res; + res = stored_res; } void db_use_auth_result() { - stored_res = res; - res = auth_res; + stored_res = res; + res = auth_res; } void db_store_auth_result() { - auth_res = res; - res = stored_res; + auth_res = res; + res = stored_res; } -void* db_get_result_set() + +void *db_get_result_set() { - return (void*) res; + return (void *) res; } void db_set_result_set(void *the_result_set) { - res = (PGresult*) the_result_set; + res = (PGresult *) the_result_set; } - @@ -68,56 +68,61 @@ extern struct list smtpItems, sysItems; /* * Send an automatic notification using sendmail */ -static int send_notification(const char *to, const char *from, const char *subject) +static int send_notification(const char *to, const char *from, + const char *subject) { - FILE *mailpipe = NULL; - char *sendmail_command = NULL; - field_t sendmail; - int result; + FILE *mailpipe = NULL; + char *sendmail_command = NULL; + field_t sendmail; + int result; - GetConfigValue("SENDMAIL", &smtpItems, sendmail); - if (sendmail[0] == '\0') - trace(TRACE_FATAL, "send_notification(): SENDMAIL not configured (see config file). Stop."); + GetConfigValue("SENDMAIL", &smtpItems, sendmail); + if (sendmail[0] == '\0') + trace(TRACE_FATAL, + "send_notification(): SENDMAIL not configured (see config file). Stop."); - trace(TRACE_DEBUG, "send_notification(): found sendmail command to be [%s]", sendmail); + trace(TRACE_DEBUG, + "send_notification(): found sendmail command to be [%s]", + sendmail); - - sendmail_command = (char *)my_malloc(strlen((char *)(to))+ - strlen(sendmail)+2); /* +2 for extra space and \0 */ - if (!sendmail_command) - { - trace(TRACE_ERROR,"send_notification(): out of memory"); - return -1; - } - trace (TRACE_DEBUG,"send_notification(): allocated memory for" - " external command call"); - sprintf (sendmail_command, "%s %s",sendmail, to); + sendmail_command = (char *) my_malloc(strlen((char *) (to)) + strlen(sendmail) + 2); /* +2 for extra space and \0 */ + if (!sendmail_command) { + trace(TRACE_ERROR, "send_notification(): out of memory"); + return -1; + } + + trace(TRACE_DEBUG, "send_notification(): allocated memory for" + " external command call"); + sprintf(sendmail_command, "%s %s", sendmail, to); - trace (TRACE_INFO,"send_notification(): opening pipe to command " - "%s",sendmail_command); + trace(TRACE_INFO, "send_notification(): opening pipe to command " + "%s", sendmail_command); - if (! (mailpipe = popen(sendmail_command, "w")) ) - { - trace(TRACE_ERROR, "send_notification(): could not open pipe to sendmail using cmd [%s]", sendmail); - return 1; - } + if (!(mailpipe = popen(sendmail_command, "w"))) { + trace(TRACE_ERROR, + "send_notification(): could not open pipe to sendmail using cmd [%s]", + sendmail); + return 1; + } - trace(TRACE_DEBUG, "send_notification(): pipe opened, sending data"); + trace(TRACE_DEBUG, + "send_notification(): pipe opened, sending data"); - fprintf(mailpipe, "To: %s\n", to); - fprintf(mailpipe, "From: %s\n", from); - fprintf(mailpipe, "Subject: %s\n", subject); - fprintf(mailpipe, "\n"); + fprintf(mailpipe, "To: %s\n", to); + fprintf(mailpipe, "From: %s\n", from); + fprintf(mailpipe, "Subject: %s\n", subject); + fprintf(mailpipe, "\n"); - result = pclose(mailpipe); - trace(TRACE_DEBUG, "send_notification(): pipe closed"); + result = pclose(mailpipe); + trace(TRACE_DEBUG, "send_notification(): pipe closed"); - if (result != 0) - trace(TRACE_ERROR,"send_notification(): reply could not be sent: sendmail error"); + if (result != 0) + trace(TRACE_ERROR, + "send_notification(): reply could not be sent: sendmail error"); - return 0; + return 0; } @@ -126,166 +131,175 @@ static int send_notification(const char *to, const char *from, const char *subje */ static int send_reply(struct list *headerfields, const char *body) { - struct element *el; - struct mime_record *record; - char *from = NULL, *to = NULL, *replyto = NULL, *subject = NULL; - FILE *mailpipe = NULL; - char *send_address; - char *escaped_send_address; - char comm[MAX_COMM_SIZE]; /**< command sent to sendmail (needs to escaped) */ - field_t sendmail; - int result; - unsigned int i,j; - - GetConfigValue("SENDMAIL", &smtpItems, sendmail); - if (sendmail[0] == '\0') - trace(TRACE_FATAL, "send_reply(): SENDMAIL not configured (see config file). Stop."); - - trace(TRACE_DEBUG, "send_reply(): found sendmail command to be [%s]", sendmail); - - /* find To: and Reply-To:/From: field */ - el = list_getstart(headerfields); - - while (el) - { - record = (struct mime_record*)el->data; - - if (strcasecmp(record->field, "from") == 0) - { - from = record->value; - trace(TRACE_DEBUG, "send_reply(): found FROM [%s]", from); - } - else if (strcasecmp(record->field, "reply-to") == 0) - { - replyto = record->value; - trace(TRACE_DEBUG, "send_reply(): found REPLY-TO [%s]", replyto); - } - else if (strcasecmp(record->field, "subject") == 0) - { - subject = record->value; - trace(TRACE_DEBUG, "send_reply(): found SUBJECT [%s]", subject); - } - else if (strcasecmp(record->field, "deliver-to") == 0) - { - to = record->value; - trace(TRACE_DEBUG, "send_reply(): found TO [%s]", to); - } - - el = el->nextnode; - } - - if (!from && !replyto) - { - trace(TRACE_ERROR, "send_reply(): no address to send to"); - return 0; - } - - - trace(TRACE_DEBUG, "send_reply(): header fields scanned; opening pipe to sendmail"); - send_address = replyto ? replyto : from; - /* allocate a string twice the size of send_address */ - escaped_send_address = (char*) my_malloc(strlen((send_address) + 1) - * 2 * sizeof(char)); - i = 0; - j = 0; - /* get all characters from send_address, and escape every ' */ - while (i < (strlen(send_address) + 1)) { - if (send_address[i] == '\'') - escaped_send_address[j++] = '\\'; - escaped_send_address[j++] = send_address[i++]; - } - snprintf(comm, MAX_COMM_SIZE, "%s '%s'", sendmail, escaped_send_address); - - if (! (mailpipe = popen(comm, "w")) ) - { - trace(TRACE_ERROR, "send_reply(): could not open pipe to sendmail using cmd [%s]", comm); - return 1; - } - - trace(TRACE_DEBUG, "send_reply(): sending data"); - - fprintf(mailpipe, "To: %s\n", replyto ? replyto : from); - fprintf(mailpipe, "From: %s\n", to ? to : "(unknown)"); - fprintf(mailpipe, "Subject: AW: %s\n", subject ? subject : "<no subject>"); - fprintf(mailpipe, "\n"); - fprintf(mailpipe, "%s\n", body ? body : "--"); - - result = pclose(mailpipe); - trace(TRACE_DEBUG, "send_reply(): pipe closed"); - if (result != 0) - trace(TRACE_ERROR,"send_reply(): reply could not be sent: sendmail error"); - - return 0; + struct element *el; + struct mime_record *record; + char *from = NULL, *to = NULL, *replyto = NULL, *subject = NULL; + FILE *mailpipe = NULL; + char *send_address; + char *escaped_send_address; + char comm[MAX_COMM_SIZE]; + /**< command sent to sendmail (needs to escaped) */ + field_t sendmail; + int result; + unsigned int i, j; + + GetConfigValue("SENDMAIL", &smtpItems, sendmail); + if (sendmail[0] == '\0') + trace(TRACE_FATAL, + "send_reply(): SENDMAIL not configured (see config file). Stop."); + + trace(TRACE_DEBUG, + "send_reply(): found sendmail command to be [%s]", sendmail); + + /* find To: and Reply-To:/From: field */ + el = list_getstart(headerfields); + + while (el) { + record = (struct mime_record *) el->data; + + if (strcasecmp(record->field, "from") == 0) { + from = record->value; + trace(TRACE_DEBUG, "send_reply(): found FROM [%s]", + from); + } else if (strcasecmp(record->field, "reply-to") == 0) { + replyto = record->value; + trace(TRACE_DEBUG, + "send_reply(): found REPLY-TO [%s]", + replyto); + } else if (strcasecmp(record->field, "subject") == 0) { + subject = record->value; + trace(TRACE_DEBUG, + "send_reply(): found SUBJECT [%s]", subject); + } else if (strcasecmp(record->field, "deliver-to") == 0) { + to = record->value; + trace(TRACE_DEBUG, "send_reply(): found TO [%s]", + to); + } + + el = el->nextnode; + } + + if (!from && !replyto) { + trace(TRACE_ERROR, "send_reply(): no address to send to"); + return 0; + } + + + trace(TRACE_DEBUG, + "send_reply(): header fields scanned; opening pipe to sendmail"); + send_address = replyto ? replyto : from; + /* allocate a string twice the size of send_address */ + escaped_send_address = + (char *) my_malloc(strlen((send_address) + 1) + * 2 * sizeof(char)); + i = 0; + j = 0; + /* get all characters from send_address, and escape every ' */ + while (i < (strlen(send_address) + 1)) { + if (send_address[i] == '\'') + escaped_send_address[j++] = '\\'; + escaped_send_address[j++] = send_address[i++]; + } + snprintf(comm, MAX_COMM_SIZE, "%s '%s'", sendmail, + escaped_send_address); + + if (!(mailpipe = popen(comm, "w"))) { + trace(TRACE_ERROR, + "send_reply(): could not open pipe to sendmail using cmd [%s]", + comm); + return 1; + } + + trace(TRACE_DEBUG, "send_reply(): sending data"); + + fprintf(mailpipe, "To: %s\n", replyto ? replyto : from); + fprintf(mailpipe, "From: %s\n", to ? to : "(unknown)"); + fprintf(mailpipe, "Subject: AW: %s\n", + subject ? subject : "<no subject>"); + fprintf(mailpipe, "\n"); + fprintf(mailpipe, "%s\n", body ? body : "--"); + + result = pclose(mailpipe); + trace(TRACE_DEBUG, "send_reply(): pipe closed"); + if (result != 0) + trace(TRACE_ERROR, + "send_reply(): reply could not be sent: sendmail error"); + + return 0; } /* Yeah, RAN. That's Reply And Notify ;-) */ static int execute_auto_ran(u64_t useridnr, struct list *headerfields) { - field_t val; - int do_auto_notify = 0, do_auto_reply = 0; - char *reply_body = NULL; - char *notify_address = NULL; - - /* message has been succesfully inserted, perform auto-notification & auto-reply */ - GetConfigValue("AUTO_NOTIFY", &smtpItems, val); - if (strcasecmp(val, "yes") == 0) - do_auto_notify = 1; - - GetConfigValue("AUTO_REPLY", &smtpItems, val); - if (strcasecmp(val, "yes") == 0) - do_auto_reply = 1; - - if (do_auto_notify) - { - trace(TRACE_DEBUG, "execute_auto_ran(): starting auto-notification procedure"); - - if (db_get_notify_address(useridnr, ¬ify_address) != 0) - trace(TRACE_ERROR, "execute_auto_ran(): error fetching notification address"); - else - { - if (notify_address == NULL) - trace(TRACE_DEBUG, "execute_auto_ran(): no notification address specified, skipping"); - else - { - trace(TRACE_DEBUG, "execute_auto_ran(): sending notifcation to [%s]", notify_address); - send_notification(notify_address, AUTO_NOTIFY_SENDER, AUTO_NOTIFY_SUBJECT); - my_free(notify_address); - } - } - } - - if (do_auto_reply) - { - trace(TRACE_DEBUG, "execute_auto_ran(): starting auto-reply procedure"); - - if (db_get_reply_body(useridnr, &reply_body) != 0) - trace(TRACE_ERROR, "execute_auto_ran(): error fetching reply body"); - else - { - if (reply_body == NULL || reply_body[0] == '\0') - trace(TRACE_DEBUG, "execute_auto_ran(): no reply body specified, skipping"); - else - { - send_reply(headerfields, reply_body); - my_free(reply_body); - } - } - } - - return 0; + field_t val; + int do_auto_notify = 0, do_auto_reply = 0; + char *reply_body = NULL; + char *notify_address = NULL; + + /* message has been succesfully inserted, perform auto-notification & auto-reply */ + GetConfigValue("AUTO_NOTIFY", &smtpItems, val); + if (strcasecmp(val, "yes") == 0) + do_auto_notify = 1; + + GetConfigValue("AUTO_REPLY", &smtpItems, val); + if (strcasecmp(val, "yes") == 0) + do_auto_reply = 1; + + if (do_auto_notify) { + trace(TRACE_DEBUG, + "execute_auto_ran(): starting auto-notification procedure"); + + if (db_get_notify_address(useridnr, ¬ify_address) != 0) + trace(TRACE_ERROR, + "execute_auto_ran(): error fetching notification address"); + else { + if (notify_address == NULL) + trace(TRACE_DEBUG, + "execute_auto_ran(): no notification address specified, skipping"); + else { + trace(TRACE_DEBUG, + "execute_auto_ran(): sending notifcation to [%s]", + notify_address); + send_notification(notify_address, + AUTO_NOTIFY_SENDER, + AUTO_NOTIFY_SUBJECT); + my_free(notify_address); + } + } + } + + if (do_auto_reply) { + trace(TRACE_DEBUG, + "execute_auto_ran(): starting auto-reply procedure"); + + if (db_get_reply_body(useridnr, &reply_body) != 0) + trace(TRACE_ERROR, + "execute_auto_ran(): error fetching reply body"); + else { + if (reply_body == NULL || reply_body[0] == '\0') + trace(TRACE_DEBUG, + "execute_auto_ran(): no reply body specified, skipping"); + else { + send_reply(headerfields, reply_body); + my_free(reply_body); + } + } + } + + return 0; } /* read from instream, but simply discard all input! */ -void discard_client_input(FILE *instream) +void discard_client_input(FILE * instream) { char *tmpline; - memtst ((tmpline= (char *)my_malloc(MAX_LINE_SIZE+1))==NULL); - while(!feof(instream)) { + memtst((tmpline = (char *) my_malloc(MAX_LINE_SIZE + 1)) == NULL); + while (!feof(instream)) { fgets(tmpline, MAX_LINE_SIZE, instream); - + if (!tmpline) break; @@ -305,164 +319,168 @@ void discard_client_input(FILE *instream) * * returns a message id number, or -1 on error. * */ -static int store_message_temp(FILE *instream, - char *header, u64_t headersize, u64_t headerrfcsize, - u64_t *msgsize, u64_t *rfcsize, u64_t *temp_message_idnr) +static int store_message_temp(FILE * instream, + char *header, u64_t headersize, + u64_t headerrfcsize, u64_t * msgsize, + u64_t * rfcsize, u64_t * temp_message_idnr) { - int myeof=0; - u64_t msgidnr=0; - size_t i=0, usedmem=0, linemem=0; - u64_t totalmem = 0, rfclines=0; - char *strblock=NULL, *tmpline=NULL; - char unique_id[UID_SIZE]; - u64_t messageblk_idnr; - u64_t user_idnr; - int result; - - result = auth_user_exists(DBMAIL_DELIVERY_USERNAME, &user_idnr); - if (result < 0) { - trace(TRACE_ERROR, "%s,%s: unable to find user_idnr for user " - "[%s]\n", __FILE__, __FUNCTION__, DBMAIL_DELIVERY_USERNAME); - return -1; - } - if (result == 0) { - trace(TRACE_ERROR, "%s,%s: unable to find user_idnr for user " - "[%s]. Make sure this system user is in the database!\n", - __FILE__, __FUNCTION__, DBMAIL_DELIVERY_USERNAME); - return -1; - } - - create_unique_id(unique_id, user_idnr); - - /* create a message record */ - switch (db_insert_message(user_idnr, DBMAIL_TEMPMBOX, - CREATE_IF_MBOX_NOT_FOUND, unique_id, &msgidnr)) - { - case -1: - trace(TRACE_ERROR, "store_message_temp(): returned -1, aborting"); - return -1; - } - - switch (db_insert_message_block(header, headersize, msgidnr, &messageblk_idnr)) - { - case -1: - trace(TRACE_ERROR, "store_message_temp(): error inserting msgblock [header]"); - return -1; - } - - trace(TRACE_DEBUG, "store_message_temp(): allocating [%ld] bytes of memory for readblock", - READ_BLOCK_SIZE); - - memtst ((strblock = (char *)my_malloc(READ_BLOCK_SIZE+1))==NULL); - memset((void*) strblock, '\0', READ_BLOCK_SIZE+1); - memtst ((tmpline= (char *)my_malloc(MAX_LINE_SIZE+1))==NULL); - memset((void*) tmpline, '\0', MAX_LINE_SIZE+1); - - while ((!feof(instream) && (!myeof)) || (linemem != 0)) - { - /* Copy the line that didn't fit before */ - if (linemem > 0) - { - strncpy(strblock, tmpline, linemem); - usedmem += linemem; - - /* Resetting strlen for tmpline */ - tmpline[0] = '\0'; - linemem = 0; - } - - /* We want to fill up each block if possible, - * unless of course we're at the end of the file */ - while (!feof(instream) && (usedmem +linemem < READ_BLOCK_SIZE)) - { - fgets(tmpline, MAX_LINE_SIZE, instream); - linemem = strlen(tmpline); - /* The RFC size assumes all lines end in \r\n, - * so if we have a newline (\n) but don't have - * a carriage return (\r), count it in rfcsize. */ - if (linemem > 0 && tmpline[linemem-1] == '\n') - if (linemem == 1 || (linemem > 1 && tmpline[linemem-2] != '\r')) - rfclines++; - - if (ferror(instream)) - { - trace(TRACE_ERROR,"store_message_temp(): error on instream: [%s]", strerror(errno)); - /* FIXME: Umm, don't we need to free a few things?! */ - return -1; - } - - /* This should be the one and only valid - * end to a message over SMTP/LMTP... - * FIXME: If there's a compatibility problem, it's probably here! */ - if (strcmp(tmpline, ".\r\n") == 0) - { - /* This is the end of the message! */ - myeof = 1; - linemem = 0; - break; - } - else - { - /* See if the line fits into this block */ - if (usedmem + linemem < READ_BLOCK_SIZE) - { - strncpy(strblock+usedmem, tmpline, linemem); - usedmem += linemem; - - /* Resetting strlen for tmpline */ - tmpline[0] = '\0'; - linemem = 0; - } - /* Don't need an else, see above this while loop for more */ - } - } - - /* replace all errorneous '\0' by ' ' (space) */ - for (i = 0; i < usedmem; i++) - { - if (strblock[i] == '\0') - { - strblock[i] = ' '; - } - } - - /* fread won't do this for us! */ - strblock[usedmem] = '\0'; - - if (usedmem > 0) /* usedmem is 0 with an EOF */ - { - totalmem += usedmem; - - switch (db_insert_message_block(strblock, usedmem, msgidnr, &messageblk_idnr)) - { - case -1: - trace(TRACE_STOP, "store_message_temp(): error inserting msgblock"); - return -1; - } - } - - /* resetting strlen for strblock */ - strblock[0] = '\0'; - usedmem = 0; - } - - trace(TRACE_DEBUG, "store_message_temp(): end of instream"); - - my_free (tmpline); - trace(TRACE_DEBUG, "store_message_temp(): tmpline freed"); - - my_free (strblock); - trace(TRACE_DEBUG, "store_message_temp(): strblock freed"); - - db_update_message(msgidnr, unique_id, (totalmem+headersize), - (totalmem+rfclines+headerrfcsize)); - - /* Pass the message id out to the caller. */ - *temp_message_idnr = msgidnr; - *rfcsize = totalmem + rfclines + headerrfcsize; - *msgsize = totalmem + headersize; - - return 0; + int myeof = 0; + u64_t msgidnr = 0; + size_t i = 0, usedmem = 0, linemem = 0; + u64_t totalmem = 0, rfclines = 0; + char *strblock = NULL, *tmpline = NULL; + char unique_id[UID_SIZE]; + u64_t messageblk_idnr; + u64_t user_idnr; + int result; + + result = auth_user_exists(DBMAIL_DELIVERY_USERNAME, &user_idnr); + if (result < 0) { + trace(TRACE_ERROR, + "%s,%s: unable to find user_idnr for user " "[%s]\n", + __FILE__, __FUNCTION__, DBMAIL_DELIVERY_USERNAME); + return -1; + } + if (result == 0) { + trace(TRACE_ERROR, + "%s,%s: unable to find user_idnr for user " + "[%s]. Make sure this system user is in the database!\n", + __FILE__, __FUNCTION__, DBMAIL_DELIVERY_USERNAME); + return -1; + } + + create_unique_id(unique_id, user_idnr); + + /* create a message record */ + switch (db_insert_message(user_idnr, DBMAIL_TEMPMBOX, + CREATE_IF_MBOX_NOT_FOUND, unique_id, + &msgidnr)) { + case -1: + trace(TRACE_ERROR, + "store_message_temp(): returned -1, aborting"); + return -1; + } + + switch (db_insert_message_block + (header, headersize, msgidnr, &messageblk_idnr)) { + case -1: + trace(TRACE_ERROR, + "store_message_temp(): error inserting msgblock [header]"); + return -1; + } + + trace(TRACE_DEBUG, + "store_message_temp(): allocating [%ld] bytes of memory for readblock", + READ_BLOCK_SIZE); + + memtst((strblock = + (char *) my_malloc(READ_BLOCK_SIZE + 1)) == NULL); + memset((void *) strblock, '\0', READ_BLOCK_SIZE + 1); + memtst((tmpline = (char *) my_malloc(MAX_LINE_SIZE + 1)) == NULL); + memset((void *) tmpline, '\0', MAX_LINE_SIZE + 1); + + while ((!feof(instream) && (!myeof)) || (linemem != 0)) { + /* Copy the line that didn't fit before */ + if (linemem > 0) { + strncpy(strblock, tmpline, linemem); + usedmem += linemem; + + /* Resetting strlen for tmpline */ + tmpline[0] = '\0'; + linemem = 0; + } + + /* We want to fill up each block if possible, + * unless of course we're at the end of the file */ + while (!feof(instream) + && (usedmem + linemem < READ_BLOCK_SIZE)) { + fgets(tmpline, MAX_LINE_SIZE, instream); + linemem = strlen(tmpline); + /* The RFC size assumes all lines end in \r\n, + * so if we have a newline (\n) but don't have + * a carriage return (\r), count it in rfcsize. */ + if (linemem > 0 && tmpline[linemem - 1] == '\n') + if (linemem == 1 + || (linemem > 1 + && tmpline[linemem - 2] != '\r')) + rfclines++; + + if (ferror(instream)) { + trace(TRACE_ERROR, + "store_message_temp(): error on instream: [%s]", + strerror(errno)); + /* FIXME: Umm, don't we need to free a few things?! */ + return -1; + } + + /* This should be the one and only valid + * end to a message over SMTP/LMTP... + * FIXME: If there's a compatibility problem, it's probably here! */ + if (strcmp(tmpline, ".\r\n") == 0) { + /* This is the end of the message! */ + myeof = 1; + linemem = 0; + break; + } else { + /* See if the line fits into this block */ + if (usedmem + linemem < READ_BLOCK_SIZE) { + strncpy(strblock + usedmem, + tmpline, linemem); + usedmem += linemem; + + /* Resetting strlen for tmpline */ + tmpline[0] = '\0'; + linemem = 0; + } + /* Don't need an else, see above this while loop for more */ + } + } + + /* replace all errorneous '\0' by ' ' (space) */ + for (i = 0; i < usedmem; i++) { + if (strblock[i] == '\0') { + strblock[i] = ' '; + } + } + + /* fread won't do this for us! */ + strblock[usedmem] = '\0'; + + if (usedmem > 0) { /* usedmem is 0 with an EOF */ + totalmem += usedmem; + + switch (db_insert_message_block + (strblock, usedmem, msgidnr, + &messageblk_idnr)) { + case -1: + trace(TRACE_STOP, + "store_message_temp(): error inserting msgblock"); + return -1; + } + } + + /* resetting strlen for strblock */ + strblock[0] = '\0'; + usedmem = 0; + } + + trace(TRACE_DEBUG, "store_message_temp(): end of instream"); + + my_free(tmpline); + trace(TRACE_DEBUG, "store_message_temp(): tmpline freed"); + + my_free(strblock); + trace(TRACE_DEBUG, "store_message_temp(): strblock freed"); + + db_update_message(msgidnr, unique_id, (totalmem + headersize), + (totalmem + rfclines + headerrfcsize)); + + /* Pass the message id out to the caller. */ + *temp_message_idnr = msgidnr; + *rfcsize = totalmem + rfclines + headerrfcsize; + *msgsize = totalmem + headersize; + + return 0; } /* Here's the real *meat* of this source file! @@ -498,117 +516,129 @@ static int store_message_temp(FILE *instream, * - 0 on success * - -1 on full failure */ -int insert_messages(FILE *instream, char *header, u64_t headersize, u64_t headerrfcsize, - struct list *headerfields, struct list *dsnusers, struct list *returnpath) +int insert_messages(FILE * instream, char *header, u64_t headersize, + u64_t headerrfcsize, struct list *headerfields, + struct list *dsnusers, struct list *returnpath) { - struct element *element, *ret_path; - u64_t msgsize, rfcsize, tmpmsgidnr; - - /* Read in the rest of the stream and store it into a temporary message */ - switch (store_message_temp(instream, header, headersize, headerrfcsize, - &msgsize, &rfcsize, &tmpmsgidnr)) - { - case -1: - /* Major trouble. Bail out immediately. */ - trace(TRACE_ERROR, "%s, %s: failed to store temporary message.", - __FILE__, __FUNCTION__ ); - return -1; - default: - trace(TRACE_DEBUG, "%s, %s: temporary msgidnr is [%llu]", - __FILE__, __FUNCTION__, tmpmsgidnr ); - break; - } - - /* Loop through the users list. */ - for (element = list_getstart(dsnusers); element != NULL; element = element->nextnode) - { - struct element *userid_elem; - int has_2 = 0, has_4 = 0, has_5 = 0; - deliver_to_user_t *delivery = (deliver_to_user_t *)element->data; - - /* Each user may have a list of user_idnr's for local delivery. */ - for (userid_elem = list_getstart(delivery->userids); - userid_elem != NULL; userid_elem = userid_elem->nextnode) - { - u64_t useridnr = *(u64_t *)userid_elem->data; - trace(TRACE_DEBUG, "%s, %s: calling sort_and_deliver for useridnr [%llu]", - __FILE__, __FUNCTION__, useridnr); - - switch (sort_and_deliver(tmpmsgidnr, - header, headersize, msgsize, rfcsize, - useridnr, delivery->mailbox)) - { - case DSN_CLASS_OK: - /* Indicate success. */ - trace(TRACE_DEBUG, "%s, %s: successful sort_and_deliver for useridnr [%llu]", - __FILE__, __FUNCTION__, useridnr); - has_2 = 1; - break; - case DSN_CLASS_FAIL: - /* Indicate permanent failure. */ - trace(TRACE_ERROR, "%s, %s: permanent failure sort_and_deliver for useridnr [%llu]", - __FILE__, __FUNCTION__, useridnr); - has_5 = 1; - break; - case DSN_CLASS_TEMP: - case -1: - default: - /* Assume a temporary failure */ - trace(TRACE_ERROR, "%s, %s: temporary failure sort_and_deliver for useridnr [%llu]", - __FILE__, __FUNCTION__, useridnr); - has_4 = 1; - break; - } - - /* Automatic reply and notification */ - execute_auto_ran(useridnr, headerfields); - } /* from: the useridnr for loop */ - - switch (dsnuser_worstcase_int(has_2, has_4, has_5)) - { - case DSN_CLASS_OK: - delivery->dsn.class = DSN_CLASS_OK; /* Success. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 5; /* Valid. */ - break; - case DSN_CLASS_TEMP: - delivery->dsn.class = DSN_CLASS_TEMP; /* Temporary transient failure. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 5; /* Valid. */ - break; - case DSN_CLASS_FAIL: - delivery->dsn.class = DSN_CLASS_FAIL; /* Permanent failure. */ - delivery->dsn.subject = 1; /* Address related. */ - delivery->dsn.detail = 1; /* Does not exist. */ - break; - } - - trace(TRACE_DEBUG,"insert_messages(): we need to deliver [%ld] " - "messages to external addresses", list_totalnodes(delivery->forwards)); - - /* Each user may also have a list of external forwarding addresses. */ - if (list_totalnodes(delivery->forwards) > 0) - { - - trace(TRACE_DEBUG, "insert_messages(): delivering to external addresses"); - - /* Only the last step of the returnpath is used. */ - ret_path = list_getstart(returnpath); - - /* Forward using the temporary stored message. */ - forward(tmpmsgidnr, delivery->forwards, (ret_path ? ret_path->data : "DBMAIL-MAILER"), header, headersize); - } - - } /* from: the delivery for loop */ - - /* Always delete the temporary message, even if the delivery failed. - * It is the MTA's job to requeue or bounce the message, - * and our job to keep a tidy database ;-) */ - db_delete_message(tmpmsgidnr); - trace(TRACE_DEBUG, "insert_messages(): temporary message deleted from database"); - - trace(TRACE_DEBUG, "insert_messages(): End of function"); - - return 0; -} + struct element *element, *ret_path; + u64_t msgsize, rfcsize, tmpmsgidnr; + + /* Read in the rest of the stream and store it into a temporary message */ + switch (store_message_temp + (instream, header, headersize, headerrfcsize, &msgsize, + &rfcsize, &tmpmsgidnr)) { + case -1: + /* Major trouble. Bail out immediately. */ + trace(TRACE_ERROR, + "%s, %s: failed to store temporary message.", + __FILE__, __FUNCTION__); + return -1; + default: + trace(TRACE_DEBUG, "%s, %s: temporary msgidnr is [%llu]", + __FILE__, __FUNCTION__, tmpmsgidnr); + break; + } + /* Loop through the users list. */ + for (element = list_getstart(dsnusers); element != NULL; + element = element->nextnode) { + struct element *userid_elem; + int has_2 = 0, has_4 = 0, has_5 = 0; + deliver_to_user_t *delivery = + (deliver_to_user_t *) element->data; + + /* Each user may have a list of user_idnr's for local delivery. */ + for (userid_elem = list_getstart(delivery->userids); + userid_elem != NULL; + userid_elem = userid_elem->nextnode) { + u64_t useridnr = *(u64_t *) userid_elem->data; + trace(TRACE_DEBUG, + "%s, %s: calling sort_and_deliver for useridnr [%llu]", + __FILE__, __FUNCTION__, useridnr); + + switch (sort_and_deliver(tmpmsgidnr, + header, headersize, + msgsize, rfcsize, + useridnr, + delivery->mailbox)) { + case DSN_CLASS_OK: + /* Indicate success. */ + trace(TRACE_DEBUG, + "%s, %s: successful sort_and_deliver for useridnr [%llu]", + __FILE__, __FUNCTION__, useridnr); + has_2 = 1; + break; + case DSN_CLASS_FAIL: + /* Indicate permanent failure. */ + trace(TRACE_ERROR, + "%s, %s: permanent failure sort_and_deliver for useridnr [%llu]", + __FILE__, __FUNCTION__, useridnr); + has_5 = 1; + break; + case DSN_CLASS_TEMP: + case -1: + default: + /* Assume a temporary failure */ + trace(TRACE_ERROR, + "%s, %s: temporary failure sort_and_deliver for useridnr [%llu]", + __FILE__, __FUNCTION__, useridnr); + has_4 = 1; + break; + } + + /* Automatic reply and notification */ + execute_auto_ran(useridnr, headerfields); + } /* from: the useridnr for loop */ + + switch (dsnuser_worstcase_int(has_2, has_4, has_5)) { + case DSN_CLASS_OK: + delivery->dsn.class = DSN_CLASS_OK; /* Success. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 5; /* Valid. */ + break; + case DSN_CLASS_TEMP: + delivery->dsn.class = DSN_CLASS_TEMP; /* Temporary transient failure. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 5; /* Valid. */ + break; + case DSN_CLASS_FAIL: + delivery->dsn.class = DSN_CLASS_FAIL; /* Permanent failure. */ + delivery->dsn.subject = 1; /* Address related. */ + delivery->dsn.detail = 1; /* Does not exist. */ + break; + } + + trace(TRACE_DEBUG, + "insert_messages(): we need to deliver [%ld] " + "messages to external addresses", + list_totalnodes(delivery->forwards)); + + /* Each user may also have a list of external forwarding addresses. */ + if (list_totalnodes(delivery->forwards) > 0) { + + trace(TRACE_DEBUG, + "insert_messages(): delivering to external addresses"); + + /* Only the last step of the returnpath is used. */ + ret_path = list_getstart(returnpath); + + /* Forward using the temporary stored message. */ + forward(tmpmsgidnr, delivery->forwards, + (ret_path ? ret_path-> + data : "DBMAIL-MAILER"), header, + headersize); + } + + } /* from: the delivery for loop */ + + /* Always delete the temporary message, even if the delivery failed. + * It is the MTA's job to requeue or bounce the message, + * and our job to keep a tidy database ;-) */ + db_delete_message(tmpmsgidnr); + trace(TRACE_DEBUG, + "insert_messages(): temporary message deleted from database"); + + trace(TRACE_DEBUG, "insert_messages(): End of function"); + + return 0; +} @@ -45,14 +45,15 @@ * \param headerfields list of header fields * \return 0 */ -int insert_messages(FILE *instream, - char *header, u64_t headersize, u64_t headerrfcsize, - struct list *headerfields, struct list *dsnusers, struct list *returnpath); +int insert_messages(FILE * instream, + char *header, u64_t headersize, u64_t headerrfcsize, + struct list *headerfields, struct list *dsnusers, + struct list *returnpath); /** * \brief discards all input coming from instream * \param instream FILE stream holding input from a client */ -void discard_client_input(FILE *instream); +void discard_client_input(FILE * instream); #endif @@ -55,809 +55,972 @@ extern int pop_before_smtp; -int pop3 (void *stream, char *buffer, char *client_ip, PopSession_t *session); +int pop3(void *stream, char *buffer, char *client_ip, + PopSession_t * session); /* allowed pop3 commands */ -const char *commands [] = -{ - "quit", /**< POP3_QUIT */ - "user", /**< POP3_USER */ - "pass", /**< POP3_PASS */ - "stat", /**< POP3_STAT */ - "list", /**< POP3_LIST */ - "retr", /**< POP3_RETR */ - "dele", /**< POP3_DELE */ - "noop", /**< POP3_NOOP */ - "last", /**< POP3_LAST */ - "rset", /**< POP3_RSET */ - "uidl", /**< POP3_UIDL */ - "apop", /**< POP3_APOP */ - "auth", /**< POP3_AUTH */ - "top", /**< POP3_TOP */ - "capa" /**< POP3_CAPA */ +const char *commands[] = { + "quit", + /**< POP3_QUIT */ + "user", + /**< POP3_USER */ + "pass", + /**< POP3_PASS */ + "stat", + /**< POP3_STAT */ + "list", + /**< POP3_LIST */ + "retr", + /**< POP3_RETR */ + "dele", + /**< POP3_DELE */ + "noop", + /**< POP3_NOOP */ + "last", + /**< POP3_LAST */ + "rset", + /**< POP3_RSET */ + "uidl", + /**< POP3_UIDL */ + "apop", + /**< POP3_APOP */ + "auth", + /**< POP3_AUTH */ + "top", + /**< POP3_TOP */ + "capa" + /**< POP3_CAPA */ }; const char validchars[] = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - "_.!@#$%^&*()-+=~[]{}<>:;\\/ "; + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "_.!@#$%^&*()-+=~[]{}<>:;\\/ "; -int pop3_handle_connection (clientinfo_t *ci) +int pop3_handle_connection(clientinfo_t * ci) { - /* - Handles connection and calls - pop command handler - */ - - int done = 1; /* loop state */ - char *buffer = NULL; /* connection buffer */ - char myhostname[64]; - int cnt; /* counter */ - PopSession_t session; /* current connection session */ - char unique_id[UID_SIZE]; - - /* setting Session variables */ - session.error_count = 0; - session.was_apop = 0; - - session.username = NULL; - session.password = NULL; - - session.apop_stamp = NULL; - - session.SessionResult = 0; - - /* reset counters */ - session.totalsize = 0; - session.virtual_totalsize = 0; - session.totalmessages = 0; - session.virtual_totalmessages = 0; - - /* getting hostname */ - gethostname (myhostname,64); - myhostname[63] = '\0'; /* make sure string is terminated */ - - buffer=(char *)my_malloc(INCOMING_BUFFER_SIZE*sizeof(char)); - - if (!buffer) - { - trace (TRACE_MESSAGE,"pop3_handle_connection(): Could not allocate buffer"); - return 0; - } - - /* create an unique timestamp + processid for APOP authentication */ - session.apop_stamp = (char *)my_malloc(APOP_STAMP_SIZE*sizeof(char)); - if (!session.apop_stamp) - { - trace (TRACE_MESSAGE,"pop3_handle_connection(): Could not allocate buffer for apop"); - return 0; - } - /* create an unique timestamp + processid for APOP authentication */ - create_unique_id(unique_id, 0); - snprintf(session.apop_stamp, APOP_STAMP_SIZE, - "<%s@%s>", unique_id, myhostname); - - if (ci->tx) - { - /* sending greeting */ - fprintf (ci->tx,"+OK DBMAIL pop3 server ready to rock %s\r\n", - session.apop_stamp); - fflush (ci->tx); - } - else - { - trace (TRACE_MESSAGE,"pop3_handle_connection(): TX stream is null!"); - return 0; - } - - /* set authorization state */ - session.state = POP3_AUTHORIZATION_STATE; - - while (done > 0) - { - /* set the timeout counter */ - alarm (ci->timeout); - - /* clear the buffer */ - memset(buffer, 0, INCOMING_BUFFER_SIZE); - - for (cnt=0; cnt < INCOMING_BUFFER_SIZE-1; cnt++) - { - do - { - clearerr(ci->rx); - fread(&buffer[cnt], 1, 1, ci->rx); - - /* leave, an alarm has occured during fread */ - if (!ci->rx) return 0; - - } while (ferror(ci->rx) && errno == EINTR); - - if (buffer[cnt] == '\n' || feof(ci->rx) || ferror(ci->rx)) - { - buffer[cnt+1] = '\0'; - break; - } - } - - if (feof(ci->rx) || ferror(ci->rx)) - done = -1; /* check client eof */ - else - { - alarm (0); /* reset function handle timeout */ - done = pop3(ci->tx, buffer, ci->ip, &session); /* handle pop3 commands */ - } - fflush (ci->tx); - } - - /* we've reached the state */ - session.state = POP3_UPDATE_STATE; - - /* memory cleanup */ - my_free(buffer); - buffer = NULL; - - my_free(session.apop_stamp); - session.apop_stamp = NULL; - - if (session.username != NULL && (session.was_apop || session.password != NULL)) - { - switch (session.SessionResult) - { - case 0: - { - trace (TRACE_MESSAGE, "pop3_handle_connection(): user %s logging out" - " [messages=%llu, octets=%llu]", - session.username, session.virtual_totalmessages, - session.virtual_totalsize); - - /* if everything went well, write down everything and do a cleanup */ - db_update_pop(&session); - break; - } - - case 1: trace (TRACE_ERROR, "pop3_handle_connection(): EOF from client, " - " connection terminated"); break; - - case 2: trace (TRACE_ERROR, "pop3_handle_connection(): alert! possible flood attempt," - " closing connection"); break; - - case 3: trace (TRACE_ERROR, "pop3_handle_connection(): authorization layer failure"); break; - case 4: trace (TRACE_ERROR, "pop3_handle_connection(): storage layer failure"); break; - } - } - else - trace (TRACE_ERROR, "pop3_handle_connection(): error, uncomplete session"); - - if (session.username != NULL) - { - /* username cleanup */ - my_free(session.username); - session.username = NULL; - } - - if (session.password != NULL) - { - /* password cleanup */ - my_free(session.password); - session.password = NULL; - } - - /* reset timers */ - alarm (0); - __debug_dumpallocs(); - - return 0; + /* + Handles connection and calls + pop command handler + */ + + int done = 1; /* loop state */ + char *buffer = NULL; /* connection buffer */ + char myhostname[64]; + int cnt; /* counter */ + PopSession_t session; /* current connection session */ + char unique_id[UID_SIZE]; + + /* setting Session variables */ + session.error_count = 0; + session.was_apop = 0; + + session.username = NULL; + session.password = NULL; + + session.apop_stamp = NULL; + + session.SessionResult = 0; + + /* reset counters */ + session.totalsize = 0; + session.virtual_totalsize = 0; + session.totalmessages = 0; + session.virtual_totalmessages = 0; + + /* getting hostname */ + gethostname(myhostname, 64); + myhostname[63] = '\0'; /* make sure string is terminated */ + + buffer = (char *) my_malloc(INCOMING_BUFFER_SIZE * sizeof(char)); + + if (!buffer) { + trace(TRACE_MESSAGE, + "pop3_handle_connection(): Could not allocate buffer"); + return 0; + } + + /* create an unique timestamp + processid for APOP authentication */ + session.apop_stamp = + (char *) my_malloc(APOP_STAMP_SIZE * sizeof(char)); + if (!session.apop_stamp) { + trace(TRACE_MESSAGE, + "pop3_handle_connection(): Could not allocate buffer for apop"); + return 0; + } + /* create an unique timestamp + processid for APOP authentication */ + create_unique_id(unique_id, 0); + snprintf(session.apop_stamp, APOP_STAMP_SIZE, + "<%s@%s>", unique_id, myhostname); + + if (ci->tx) { + /* sending greeting */ + fprintf(ci->tx, + "+OK DBMAIL pop3 server ready to rock %s\r\n", + session.apop_stamp); + fflush(ci->tx); + } else { + trace(TRACE_MESSAGE, + "pop3_handle_connection(): TX stream is null!"); + return 0; + } + + /* set authorization state */ + session.state = POP3_AUTHORIZATION_STATE; + + while (done > 0) { + /* set the timeout counter */ + alarm(ci->timeout); + + /* clear the buffer */ + memset(buffer, 0, INCOMING_BUFFER_SIZE); + + for (cnt = 0; cnt < INCOMING_BUFFER_SIZE - 1; cnt++) { + do { + clearerr(ci->rx); + fread(&buffer[cnt], 1, 1, ci->rx); + + /* leave, an alarm has occured during fread */ + if (!ci->rx) + return 0; + + } while (ferror(ci->rx) && errno == EINTR); + + if (buffer[cnt] == '\n' || feof(ci->rx) + || ferror(ci->rx)) { + buffer[cnt + 1] = '\0'; + break; + } + } + + if (feof(ci->rx) || ferror(ci->rx)) + done = -1; /* check client eof */ + else { + alarm(0); /* reset function handle timeout */ + done = pop3(ci->tx, buffer, ci->ip, &session); /* handle pop3 commands */ + } + fflush(ci->tx); + } + + /* we've reached the state */ + session.state = POP3_UPDATE_STATE; + + /* memory cleanup */ + my_free(buffer); + buffer = NULL; + + my_free(session.apop_stamp); + session.apop_stamp = NULL; + + if (session.username != NULL + && (session.was_apop || session.password != NULL)) { + switch (session.SessionResult) { + case 0: + { + trace(TRACE_MESSAGE, + "pop3_handle_connection(): user %s logging out" + " [messages=%llu, octets=%llu]", + session.username, + session.virtual_totalmessages, + session.virtual_totalsize); + + /* if everything went well, write down everything and do a cleanup */ + db_update_pop(&session); + break; + } + + case 1: + trace(TRACE_ERROR, + "pop3_handle_connection(): EOF from client, " + " connection terminated"); + break; + + case 2: + trace(TRACE_ERROR, + "pop3_handle_connection(): alert! possible flood attempt," + " closing connection"); + break; + + case 3: + trace(TRACE_ERROR, + "pop3_handle_connection(): authorization layer failure"); + break; + case 4: + trace(TRACE_ERROR, + "pop3_handle_connection(): storage layer failure"); + break; + } + } else + trace(TRACE_ERROR, + "pop3_handle_connection(): error, uncomplete session"); + + if (session.username != NULL) { + /* username cleanup */ + my_free(session.username); + session.username = NULL; + } + + if (session.password != NULL) { + /* password cleanup */ + my_free(session.password); + session.password = NULL; + } + + /* reset timers */ + alarm(0); + __debug_dumpallocs(); + + return 0; } -int pop3_error(PopSession_t *session, void *stream, const char *formatstring, ...) - __attribute__((format(printf, 3, 4))); -int pop3_error(PopSession_t *session, void *stream, const char *formatstring, ...) +int pop3_error(PopSession_t * session, void *stream, + const char *formatstring, ...) + __attribute__ ((format(printf, 3, 4))); +int pop3_error(PopSession_t * session, void *stream, + const char *formatstring, ...) { - va_list argp; - - if (session->error_count>=MAX_ERRORS) - { - trace(TRACE_MESSAGE, "pop3_error(): too many errors (MAX_ERRORS is %d)", MAX_ERRORS); - fprintf((FILE *)stream, "-ERR loser, go play somewhere else\r\n"); - session->SessionResult = 2; /* possible flood */ - return -3; - } - else - { - va_start(argp, formatstring); - vfprintf((FILE *)stream, formatstring, argp); - va_end(argp); - } - - trace(TRACE_DEBUG, "pop3_error(): an invalid command was issued"); - session->error_count++; - return 1; + va_list argp; + + if (session->error_count >= MAX_ERRORS) { + trace(TRACE_MESSAGE, + "pop3_error(): too many errors (MAX_ERRORS is %d)", + MAX_ERRORS); + fprintf((FILE *) stream, + "-ERR loser, go play somewhere else\r\n"); + session->SessionResult = 2; /* possible flood */ + return -3; + } else { + va_start(argp, formatstring); + vfprintf((FILE *) stream, formatstring, argp); + va_end(argp); + } + + trace(TRACE_DEBUG, "pop3_error(): an invalid command was issued"); + session->error_count++; + return 1; } -int pop3 (void *stream, char *buffer, char *client_ip, PopSession_t *session) +int pop3(void *stream, char *buffer, char *client_ip, + PopSession_t * session) { - /* returns a 0 on a quit - * -1 on a failure - * 1 on a success */ - char *command, *value; - Pop3Cmd_t cmdtype; - int found=0; - int indx=0; - u64_t result; - int validate_result; - u64_t top_lines, top_messageid; - struct element *tmpelement; - char *md5_apop_he; - char *searchptr; - u64_t user_idnr; - - /* buffer overflow attempt */ - if (strlen(buffer)>MAX_IN_BUFFER) - { - trace(TRACE_DEBUG, "pop3(): buffer overflow attempt"); - return -3; - } - - /* check for command issued */ - while (strchr(validchars, buffer[indx])) - indx++; - - /* end buffer */ - buffer[indx]='\0'; - - trace(TRACE_DEBUG,"pop3(): incoming buffer: [%s]",buffer); - - command=buffer; - - value=strstr (command," "); /* look for the separator */ - - if (value!=NULL) - { - *value = '\0'; /* set a \0 on the command end */ - value++; /* skip space */ - - if (strlen(value) == 0) - value=NULL; /* no value specified */ - else - { - trace (TRACE_DEBUG,"pop3(): command issued :cmd [%s], value [%s]\n",command, value); - } - } - - /* find command that was issued */ - for (cmdtype = POP3_QUIT; cmdtype <= POP3_CAPA; cmdtype ++) - if (strcasecmp(command, commands[cmdtype]) == 0) { - session->was_apop = 1; - break; - } - - trace (TRACE_DEBUG,"pop3(): command looked up as commandtype %d", cmdtype); - - /* commands that are allowed to have no arguments */ - if ((value==NULL) && (cmdtype!=POP3_QUIT) && (cmdtype!=POP3_LIST) && - (cmdtype!=POP3_STAT) && (cmdtype!=POP3_RSET) && - (cmdtype!=POP3_NOOP) && (cmdtype!=POP3_LAST) && - (cmdtype!=POP3_UIDL) && (cmdtype!=POP3_AUTH) && - (cmdtype!=POP3_CAPA)) - { - return pop3_error(session, stream, "-ERR your command does not compute\r\n"); - } - - switch (cmdtype) - { - case POP3_QUIT : - { - fprintf ((FILE *)stream, "+OK see ya later\r\n"); - return 0; - } - case POP3_USER : - { - if (session->state != POP3_AUTHORIZATION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - if (session->username != NULL) - { - /* reset username */ - my_free(session->username); - session->username = NULL; - } - - if (session->username == NULL) - { - if (strlen(value)>MAX_USERID_SIZE) - return pop3_error(session, stream,"-ERR userid is too long\r\n"); - - /* create memspace for username */ - memtst((session->username = (char *)my_malloc(strlen(value)+1))==NULL); - strncpy (session->username, value, strlen(value)+1); - } - - fprintf ((FILE *)stream, "+OK Password required for %s\r\n", - session->username); - return 1; - } - - case POP3_PASS : - { - if (session->state != POP3_AUTHORIZATION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - if (session->password != NULL) - { - my_free(session->password); - session->password = NULL; - } - - if (session->password == NULL) - { - /* create memspace for password */ - memtst((session->password = (char *)my_malloc(strlen(value)+1))==NULL); - strncpy (session->password, value, strlen(value)+1); - } - - /* check in authorization layer if these credentials are correct */ - validate_result = auth_validate(session->username, - session->password, - &result); - switch (validate_result) { - case -1: - session->SessionResult = 3; return -1; - case 0: - { - trace (TRACE_ERROR,"pop3(): user [%s] tried to " - "login with wrong password", - session->username); - - /* clear username, must be re-entered according to RFC */ - my_free (session->username); - session->username = NULL; - - /* also, if the password is set, clear it */ - if (session->password != NULL) - { - my_free (session->password); - session->password = NULL; - } - return pop3_error (session, stream,"-ERR username/password incorrect\r\n"); - } - default: - { - /* user logged in OK */ - session->state = POP3_TRANSACTION_STATE; - - /* now we're going to build up a session for this user */ - trace(TRACE_DEBUG,"pop3(): validation OK, building a session for user [%s]", - session->username); - - /* if pop_before_smtp is active, log this ip */ - if (pop_before_smtp) - db_log_ip(client_ip); - - result = db_createsession (result, session); - if (result == 1) - { - fprintf ((FILE *)stream, "+OK %s has %llu messages (%llu octets)\r\n", - session->username, session->virtual_totalmessages, - session->virtual_totalsize); - trace(TRACE_MESSAGE, - "pop3(): user %s logged in [messages=%llu, octets=%llu]", - session->username, session->virtual_totalmessages, - session->virtual_totalsize); + /* returns a 0 on a quit + * -1 on a failure + * 1 on a success */ + char *command, *value; + Pop3Cmd_t cmdtype; + int found = 0; + int indx = 0; + u64_t result; + int validate_result; + u64_t top_lines, top_messageid; + struct element *tmpelement; + char *md5_apop_he; + char *searchptr; + u64_t user_idnr; + + /* buffer overflow attempt */ + if (strlen(buffer) > MAX_IN_BUFFER) { + trace(TRACE_DEBUG, "pop3(): buffer overflow attempt"); + return -3; + } + + /* check for command issued */ + while (strchr(validchars, buffer[indx])) + indx++; + + /* end buffer */ + buffer[indx] = '\0'; + + trace(TRACE_DEBUG, "pop3(): incoming buffer: [%s]", buffer); + + command = buffer; + + value = strstr(command, " "); /* look for the separator */ + + if (value != NULL) { + *value = '\0'; /* set a \0 on the command end */ + value++; /* skip space */ + + if (strlen(value) == 0) + value = NULL; /* no value specified */ + else { + trace(TRACE_DEBUG, + "pop3(): command issued :cmd [%s], value [%s]\n", + command, value); + } + } + + /* find command that was issued */ + for (cmdtype = POP3_QUIT; cmdtype <= POP3_CAPA; cmdtype++) + if (strcasecmp(command, commands[cmdtype]) == 0) { + session->was_apop = 1; + break; + } + + trace(TRACE_DEBUG, "pop3(): command looked up as commandtype %d", + cmdtype); + + /* commands that are allowed to have no arguments */ + if ((value == NULL) && (cmdtype != POP3_QUIT) + && (cmdtype != POP3_LIST) && (cmdtype != POP3_STAT) + && (cmdtype != POP3_RSET) && (cmdtype != POP3_NOOP) + && (cmdtype != POP3_LAST) && (cmdtype != POP3_UIDL) + && (cmdtype != POP3_AUTH) && (cmdtype != POP3_CAPA)) { + return pop3_error(session, stream, + "-ERR your command does not compute\r\n"); + } + + switch (cmdtype) { + case POP3_QUIT: + { + fprintf((FILE *) stream, "+OK see ya later\r\n"); + return 0; + } + case POP3_USER: + { + if (session->state != POP3_AUTHORIZATION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + if (session->username != NULL) { + /* reset username */ + my_free(session->username); + session->username = NULL; + } + + if (session->username == NULL) { + if (strlen(value) > MAX_USERID_SIZE) + return pop3_error(session, stream, + "-ERR userid is too long\r\n"); + + /* create memspace for username */ + memtst((session->username = + (char *) my_malloc(strlen(value) + + 1)) == NULL); + strncpy(session->username, value, + strlen(value) + 1); + } + + fprintf((FILE *) stream, + "+OK Password required for %s\r\n", + session->username); + return 1; + } + + case POP3_PASS: + { + if (session->state != POP3_AUTHORIZATION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + if (session->password != NULL) { + my_free(session->password); + session->password = NULL; + } + + if (session->password == NULL) { + /* create memspace for password */ + memtst((session->password = + (char *) my_malloc(strlen(value) + + 1)) == NULL); + strncpy(session->password, value, + strlen(value) + 1); + } + + /* check in authorization layer if these credentials are correct */ + validate_result = auth_validate(session->username, + session->password, + &result); + switch (validate_result) { + case -1: + session->SessionResult = 3; + return -1; + case 0: + { + trace(TRACE_ERROR, + "pop3(): user [%s] tried to " + "login with wrong password", + session->username); + + /* clear username, must be re-entered according to RFC */ + my_free(session->username); + session->username = NULL; + + /* also, if the password is set, clear it */ + if (session->password != NULL) { + my_free(session->password); + session->password = NULL; + } + return pop3_error(session, stream, + "-ERR username/password incorrect\r\n"); + } + default: + { + /* user logged in OK */ + session->state = + POP3_TRANSACTION_STATE; + + /* now we're going to build up a session for this user */ + trace(TRACE_DEBUG, + "pop3(): validation OK, building a session for user [%s]", + session->username); + + /* if pop_before_smtp is active, log this ip */ + if (pop_before_smtp) + db_log_ip(client_ip); + + result = + db_createsession(result, + session); + if (result == 1) { + fprintf((FILE *) stream, + "+OK %s has %llu messages (%llu octets)\r\n", + session->username, + session-> + virtual_totalmessages, + session-> + virtual_totalsize); + trace(TRACE_MESSAGE, + "pop3(): user %s logged in [messages=%llu, octets=%llu]", + session->username, + session-> + virtual_totalmessages, + session-> + virtual_totalsize); #ifdef PROC_TITLES - /* sets the program ARGV's with username */ - set_proc_title("USER %s [%s]", session->username, client_ip); + /* sets the program ARGV's with username */ + set_proc_title + ("USER %s [%s]", + session->username, + client_ip); #endif - } - else - session->SessionResult = 4; /* something went wrong on DB layer */ - return result; - } - } - return 1; - } - - case POP3_LIST : - { - if (session->state != POP3_TRANSACTION_STATE) - return pop3_error(session, stream, "-ERR wrong command mode, sir\r\n"); - - tmpelement = list_getstart (&session->messagelst); - if (value != NULL) - { - /* they're asking for a specific message */ - while (tmpelement != NULL) - { - if (((struct message *)tmpelement->data)->messageid==strtoull(value, NULL, 10) && - ((struct message *)tmpelement->data)->virtual_messagestatus<2) - { - fprintf ((FILE *)stream,"+OK %llu %llu\r\n",((struct message *)tmpelement->data)->messageid, - ((struct message *)tmpelement->data)->msize); - found = 1; - } - tmpelement=tmpelement->nextnode; - } - if (!found) - return pop3_error (session, stream,"-ERR no such message\r\n"); - else - return 1; - } - - /* just drop the list */ - fprintf ((FILE *)stream, "+OK %llu messages (%llu octets)\r\n", - session->virtual_totalmessages, - session->virtual_totalsize); - - if (session->virtual_totalmessages>0) - { - /* traversing list */ - while (tmpelement!=NULL) - { - if (((struct message *)tmpelement->data)->virtual_messagestatus<2) - fprintf ((FILE *)stream,"%llu %llu\r\n",((struct message *)tmpelement->data)->messageid, - ((struct message *)tmpelement->data)->msize); - tmpelement=tmpelement->nextnode; - } - } - fprintf ((FILE *)stream,".\r\n"); - return 1; - } - - case POP3_STAT : - { - if (session->state != POP3_TRANSACTION_STATE) - return pop3_error(session, stream, "-ERR wrong command mode, sir\r\n"); - - fprintf ((FILE *)stream, "+OK %llu %llu\r\n", - session->virtual_totalmessages, - session->virtual_totalsize); - - return 1; - } - - case POP3_RETR : - { - trace(TRACE_DEBUG,"pop3():RETR command, retrieving message"); - - if (session->state != POP3_TRANSACTION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - tmpelement=list_getstart(&(session->messagelst)); - - /* selecting a message */ - trace(TRACE_DEBUG,"pop3(): RETR command, selecting message"); - while (tmpelement!=NULL) - { - if (((struct message *)tmpelement->data)->messageid==strtoull(value, NULL, 10) && - ((struct message *)tmpelement->data)->virtual_messagestatus<2) /* message is not deleted */ - { - ((struct message *)tmpelement->data)->virtual_messagestatus=1; - fprintf ((FILE *)stream,"+OK %llu octets\r\n",((struct message *)tmpelement->data)->msize); - return db_send_message_lines ((void *)stream, ((struct message *)tmpelement->data)->realmessageid,-2, 0); - } - tmpelement = tmpelement->nextnode; - } - return pop3_error (session, stream,"-ERR no such message\r\n"); - } - - case POP3_DELE : - { - if (session->state != POP3_TRANSACTION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - tmpelement=list_getstart(&(session->messagelst)); - - /* selecting a message */ - while (tmpelement!=NULL) - { - if (((struct message *)tmpelement->data)->messageid==strtoull(value, NULL, 10) && - ((struct message *)tmpelement->data)->virtual_messagestatus<2) /* message is not deleted */ - { - ((struct message *)tmpelement->data)->virtual_messagestatus=2; - /* decrease our virtual list fields */ - session->virtual_totalsize-=((struct message *)tmpelement->data)->msize; - session->virtual_totalmessages-=1; - - fprintf((FILE *)stream,"+OK message %llu deleted\r\n", - ((struct message *)tmpelement->data)->messageid); - return 1; - } - tmpelement = tmpelement->nextnode; - } - return pop3_error (session, stream,"-ERR [%s] no such message\r\n",value); - } - - case POP3_RSET : - { - if (session->state != POP3_TRANSACTION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - tmpelement=list_getstart(&(session->messagelst)); - - session->virtual_totalsize = session->totalsize; - session->virtual_totalmessages = session->totalmessages; - - while (tmpelement!=NULL) - { - ((struct message *)tmpelement->data)->virtual_messagestatus=((struct message *)tmpelement->data)->messagestatus; - tmpelement=tmpelement->nextnode; - } - - fprintf ((FILE *)stream, "+OK %llu messages (%llu octets)\r\n", - session->virtual_totalmessages, - session->virtual_totalsize); - - return 1; - } - - case POP3_LAST : - { - if (session->state != POP3_TRANSACTION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - tmpelement = list_getstart(&(session->messagelst)); - - while (tmpelement!=NULL) - { - if (((struct message *)tmpelement->data)->virtual_messagestatus==0) - { - /* we need the last message that has been accessed */ - fprintf ((FILE *)stream, "+OK %llu\r\n",((struct message *)tmpelement->data)->messageid-1); - return 1; - } - tmpelement = tmpelement->nextnode; - } - - /* all old messages */ - fprintf ((FILE *)stream, "+OK %llu\r\n", - session->virtual_totalmessages); - - return 1; - } - - case POP3_NOOP : - { - if (session->state != POP3_TRANSACTION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - fprintf ((FILE *)stream, "+OK\r\n"); - return 1; - } - - case POP3_UIDL : - { - if (session->state != POP3_TRANSACTION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - tmpelement = list_getstart(&(session->messagelst)); - - if (value!=NULL) - { - /* they're asking for a specific message */ - while (tmpelement!=NULL) - { - if (((struct message *)tmpelement->data)->messageid==strtoull(value, NULL, 10)&& - ((struct message *)tmpelement->data)->virtual_messagestatus<2) - { - fprintf ((FILE *)stream,"+OK %llu %s\r\n",((struct message *)tmpelement->data)->messageid, - ((struct message *)tmpelement->data)->uidl); - found = 1; - } - tmpelement = tmpelement->nextnode; - } - if (!found) - return pop3_error (session, stream,"-ERR no such message\r\n"); - else - return 1; - } - - /* just drop the list */ - fprintf ((FILE *)stream, "+OK Some very unique numbers for you\r\n"); - - if (session->virtual_totalmessages > 0) - { - /* traversing list */ - while (tmpelement!=NULL) - { - if (((struct message *)tmpelement->data)->virtual_messagestatus<2) - fprintf ((FILE *)stream,"%llu %s\r\n",((struct message *)tmpelement->data)->messageid, - ((struct message *)tmpelement->data)->uidl); - - tmpelement = tmpelement->nextnode; - } - } - - fprintf ((FILE *)stream,".\r\n"); - - return 1; - } - - case POP3_APOP: - { - if (session->state != POP3_AUTHORIZATION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - /* find out where the md5 hash starts */ - searchptr=strstr(value," "); - - if (searchptr==NULL) - return pop3_error (session, stream,"-ERR your command does not compute\r\n"); - - /* skip the space */ - searchptr = searchptr+1; - - /* value should now be the username */ - value[searchptr-value-1]='\0'; - - if (strlen(searchptr)!=32) - return pop3_error(session, stream,"-ERR the thingy you issued is not a valid md5 hash\r\n"); - - /* create memspace for md5 hash */ - memtst((md5_apop_he=(char *)my_malloc(strlen(searchptr)+1))==NULL); - strncpy (md5_apop_he,searchptr,strlen(searchptr)+1); - - if (strlen(value)>MAX_USERID_SIZE) - return pop3_error(session, stream,"-ERR userid is too long\r\n"); - - /* create memspace for username */ - memtst((session->username = (char *)my_malloc(strlen(value)+1))==NULL); - strncpy (session->username,value,strlen(value)+1); - - /* - * check the encryption used for this user - * note that if the user does not exist it is not noted - * by db_getencryption() - */ - if (auth_user_exists(session->username, &user_idnr) == -1) { - trace(TRACE_ERROR, "%s,%s: error finding if user exists. " - "username = [%s]", __FILE__, __FUNCTION__, - session->username); - return -1; - } - if (strcasecmp(auth_getencryption(user_idnr), "") != 0) - { - /* it should be clear text */ - my_free(md5_apop_he); - my_free(session->username); - session->username = NULL; - md5_apop_he = 0; - return pop3_error(session, stream,"-ERR APOP command is not supported for this user\r\n"); - } - - trace (TRACE_DEBUG,"pop3(): APOP auth, username [%s], md5_hash [%s]", - session->username, - md5_apop_he); - - result = auth_md5_validate (session->username, md5_apop_he, session->apop_stamp); - - my_free(md5_apop_he); - md5_apop_he = 0; - - switch (result) - { - case -1: session->SessionResult = 3; return -1; - case 0: - trace (TRACE_ERROR,"pop3(): user [%s] tried to login with wrong password", - session->username); - - my_free (session->username); - session->username = NULL; - - my_free (session->password); - session->password = NULL; - - return pop3_error(session, stream,"-ERR authentication attempt is invalid\r\n"); - - default: - { - /* user logged in OK */ - session->state = POP3_TRANSACTION_STATE; - - /* user seems to be valid, let's build a session */ - trace(TRACE_DEBUG,"pop3(): validation OK, building a session for user [%s]", - session->username); - - /* if pop_before_smtp is active, log this ip */ - if (pop_before_smtp) - db_log_ip(client_ip); - - result=db_createsession(result, session); - if (result == 1) - { - fprintf((FILE *)stream, "+OK %s has %llu messages (%llu octets)\r\n", - session->username, session->virtual_totalmessages, - session->virtual_totalsize); - - trace(TRACE_MESSAGE,"pop3(): user %s logged in [messages=%llu, octets=%llu]", - session->username, session->virtual_totalmessages, - session->virtual_totalsize); + } else + session->SessionResult = 4; /* something went wrong on DB layer */ + return result; + } + } + return 1; + } + + case POP3_LIST: + { + if (session->state != POP3_TRANSACTION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + tmpelement = list_getstart(&session->messagelst); + if (value != NULL) { + /* they're asking for a specific message */ + while (tmpelement != NULL) { + if (((struct message *) + tmpelement->data)-> + messageid == strtoull(value, + NULL, 10) + && ((struct message *) + tmpelement->data)-> + virtual_messagestatus < 2) { + fprintf((FILE *) stream, + "+OK %llu %llu\r\n", + ((struct message *) + tmpelement-> + data)->messageid, + ((struct message *) + tmpelement-> + data)->msize); + found = 1; + } + tmpelement = tmpelement->nextnode; + } + if (!found) + return pop3_error(session, stream, + "-ERR no such message\r\n"); + else + return 1; + } + + /* just drop the list */ + fprintf((FILE *) stream, + "+OK %llu messages (%llu octets)\r\n", + session->virtual_totalmessages, + session->virtual_totalsize); + + if (session->virtual_totalmessages > 0) { + /* traversing list */ + while (tmpelement != NULL) { + if (((struct message *) + tmpelement->data)-> + virtual_messagestatus < 2) + fprintf((FILE *) stream, + "%llu %llu\r\n", + ((struct message *) + tmpelement-> + data)->messageid, + ((struct message *) + tmpelement-> + data)->msize); + tmpelement = tmpelement->nextnode; + } + } + fprintf((FILE *) stream, ".\r\n"); + return 1; + } + + case POP3_STAT: + { + if (session->state != POP3_TRANSACTION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + fprintf((FILE *) stream, "+OK %llu %llu\r\n", + session->virtual_totalmessages, + session->virtual_totalsize); + + return 1; + } + + case POP3_RETR: + { + trace(TRACE_DEBUG, + "pop3():RETR command, retrieving message"); + + if (session->state != POP3_TRANSACTION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + tmpelement = list_getstart(&(session->messagelst)); + + /* selecting a message */ + trace(TRACE_DEBUG, + "pop3(): RETR command, selecting message"); + while (tmpelement != NULL) { + if (((struct message *) tmpelement->data)->messageid == strtoull(value, NULL, 10) && ((struct message *) tmpelement->data)->virtual_messagestatus < 2) { /* message is not deleted */ + ((struct message *) tmpelement-> + data)->virtual_messagestatus = 1; + fprintf((FILE *) stream, + "+OK %llu octets\r\n", + ((struct message *) + tmpelement->data)->msize); + return + db_send_message_lines((void *) + stream, + ((struct + message + *) + tmpelement-> + data)-> + realmessageid, + -2, 0); + } + tmpelement = tmpelement->nextnode; + } + return pop3_error(session, stream, + "-ERR no such message\r\n"); + } + + case POP3_DELE: + { + if (session->state != POP3_TRANSACTION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + tmpelement = list_getstart(&(session->messagelst)); + + /* selecting a message */ + while (tmpelement != NULL) { + if (((struct message *) tmpelement->data)->messageid == strtoull(value, NULL, 10) && ((struct message *) tmpelement->data)->virtual_messagestatus < 2) { /* message is not deleted */ + ((struct message *) tmpelement-> + data)->virtual_messagestatus = 2; + /* decrease our virtual list fields */ + session->virtual_totalsize -= + ((struct message *) + tmpelement->data)->msize; + session->virtual_totalmessages -= + 1; + + fprintf((FILE *) stream, + "+OK message %llu deleted\r\n", + ((struct message *) + tmpelement->data)-> + messageid); + return 1; + } + tmpelement = tmpelement->nextnode; + } + return pop3_error(session, stream, + "-ERR [%s] no such message\r\n", + value); + } + + case POP3_RSET: + { + if (session->state != POP3_TRANSACTION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + tmpelement = list_getstart(&(session->messagelst)); + + session->virtual_totalsize = session->totalsize; + session->virtual_totalmessages = + session->totalmessages; + + while (tmpelement != NULL) { + ((struct message *) tmpelement->data)-> + virtual_messagestatus = + ((struct message *) tmpelement->data)-> + messagestatus; + tmpelement = tmpelement->nextnode; + } + + fprintf((FILE *) stream, + "+OK %llu messages (%llu octets)\r\n", + session->virtual_totalmessages, + session->virtual_totalsize); + + return 1; + } + + case POP3_LAST: + { + if (session->state != POP3_TRANSACTION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + tmpelement = list_getstart(&(session->messagelst)); + + while (tmpelement != NULL) { + if (((struct message *) tmpelement->data)-> + virtual_messagestatus == 0) { + /* we need the last message that has been accessed */ + fprintf((FILE *) stream, + "+OK %llu\r\n", + ((struct message *) + tmpelement->data)-> + messageid - 1); + return 1; + } + tmpelement = tmpelement->nextnode; + } + + /* all old messages */ + fprintf((FILE *) stream, "+OK %llu\r\n", + session->virtual_totalmessages); + + return 1; + } + + case POP3_NOOP: + { + if (session->state != POP3_TRANSACTION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + fprintf((FILE *) stream, "+OK\r\n"); + return 1; + } + + case POP3_UIDL: + { + if (session->state != POP3_TRANSACTION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + tmpelement = list_getstart(&(session->messagelst)); + + if (value != NULL) { + /* they're asking for a specific message */ + while (tmpelement != NULL) { + if (((struct message *) + tmpelement->data)-> + messageid == strtoull(value, + NULL, 10) + && ((struct message *) + tmpelement->data)-> + virtual_messagestatus < 2) { + fprintf((FILE *) stream, + "+OK %llu %s\r\n", + ((struct message *) + tmpelement-> + data)->messageid, + ((struct message *) + tmpelement-> + data)->uidl); + found = 1; + } + tmpelement = tmpelement->nextnode; + } + if (!found) + return pop3_error(session, stream, + "-ERR no such message\r\n"); + else + return 1; + } + + /* just drop the list */ + fprintf((FILE *) stream, + "+OK Some very unique numbers for you\r\n"); + + if (session->virtual_totalmessages > 0) { + /* traversing list */ + while (tmpelement != NULL) { + if (((struct message *) + tmpelement->data)-> + virtual_messagestatus < 2) + fprintf((FILE *) stream, + "%llu %s\r\n", + ((struct message *) + tmpelement-> + data)->messageid, + ((struct message *) + tmpelement-> + data)->uidl); + + tmpelement = tmpelement->nextnode; + } + } + + fprintf((FILE *) stream, ".\r\n"); + + return 1; + } + + case POP3_APOP: + { + if (session->state != POP3_AUTHORIZATION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + /* find out where the md5 hash starts */ + searchptr = strstr(value, " "); + + if (searchptr == NULL) + return pop3_error(session, stream, + "-ERR your command does not compute\r\n"); + + /* skip the space */ + searchptr = searchptr + 1; + + /* value should now be the username */ + value[searchptr - value - 1] = '\0'; + + if (strlen(searchptr) != 32) + return pop3_error(session, stream, + "-ERR the thingy you issued is not a valid md5 hash\r\n"); + + /* create memspace for md5 hash */ + memtst((md5_apop_he = + (char *) my_malloc(strlen(searchptr) + + 1)) == NULL); + strncpy(md5_apop_he, searchptr, + strlen(searchptr) + 1); + + if (strlen(value) > MAX_USERID_SIZE) + return pop3_error(session, stream, + "-ERR userid is too long\r\n"); + + /* create memspace for username */ + memtst((session->username = + (char *) my_malloc(strlen(value) + 1)) == + NULL); + strncpy(session->username, value, + strlen(value) + 1); + + /* + * check the encryption used for this user + * note that if the user does not exist it is not noted + * by db_getencryption() + */ + if (auth_user_exists(session->username, &user_idnr) + == -1) { + trace(TRACE_ERROR, + "%s,%s: error finding if user exists. " + "username = [%s]", __FILE__, + __FUNCTION__, session->username); + return -1; + } + if (strcasecmp(auth_getencryption(user_idnr), "") + != 0) { + /* it should be clear text */ + my_free(md5_apop_he); + my_free(session->username); + session->username = NULL; + md5_apop_he = 0; + return pop3_error(session, stream, + "-ERR APOP command is not supported for this user\r\n"); + } + + trace(TRACE_DEBUG, + "pop3(): APOP auth, username [%s], md5_hash [%s]", + session->username, md5_apop_he); + + result = + auth_md5_validate(session->username, + md5_apop_he, + session->apop_stamp); + + my_free(md5_apop_he); + md5_apop_he = 0; + + switch (result) { + case -1: + session->SessionResult = 3; + return -1; + case 0: + trace(TRACE_ERROR, + "pop3(): user [%s] tried to login with wrong password", + session->username); + + my_free(session->username); + session->username = NULL; + + my_free(session->password); + session->password = NULL; + + return pop3_error(session, stream, + "-ERR authentication attempt is invalid\r\n"); + + default: + { + /* user logged in OK */ + session->state = + POP3_TRANSACTION_STATE; + + /* user seems to be valid, let's build a session */ + trace(TRACE_DEBUG, + "pop3(): validation OK, building a session for user [%s]", + session->username); + + /* if pop_before_smtp is active, log this ip */ + if (pop_before_smtp) + db_log_ip(client_ip); + + result = + db_createsession(result, + session); + if (result == 1) { + fprintf((FILE *) stream, + "+OK %s has %llu messages (%llu octets)\r\n", + session->username, + session-> + virtual_totalmessages, + session-> + virtual_totalsize); + + trace(TRACE_MESSAGE, + "pop3(): user %s logged in [messages=%llu, octets=%llu]", + session->username, + session-> + virtual_totalmessages, + session-> + virtual_totalsize); #ifdef PROC_TITLES - set_proc_title("USER %s [%s]", session->username, client_ip); + set_proc_title + ("USER %s [%s]", + session->username, + client_ip); #endif - } - else - session->SessionResult = 4; /* storage layer error */ - - return result; - } - } - return 1; - } - - case POP3_AUTH: - { - if (session->state != POP3_AUTHORIZATION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - fprintf ((FILE *)stream, "+OK List of supported mechanisms\r\n.\r\n"); - return 1; - } - - case POP3_TOP: - { - if (session->state != POP3_TRANSACTION_STATE) - return pop3_error(session, stream,"-ERR wrong command mode, sir\r\n"); - - /* find out how many lines they want */ - searchptr = strstr(value," "); - - /* insufficient parameters */ - if (searchptr == NULL) - return pop3_error (session, stream,"-ERR your command does not compute\r\n"); - - /* skip the space */ - searchptr = searchptr + 1; - - /* value should now be the the message that needs to be retrieved */ - value[searchptr-value-1] = '\0'; - - /* check if searchptr or value are negative. If so return an - error. This is done by only letting the strings contain - digits (0-9) */ - if (strspn(searchptr, "0123456789") != strlen(searchptr)) - return pop3_error(session, stream, "-ERR wrong parameter\r\n"); - if (strspn(value, "0123456789") != strlen(value)) - return pop3_error(session, stream, "-ERR wrong parameter\r\n"); - - top_lines = strtoull(searchptr, NULL, 10); - top_messageid = strtoull(value, NULL, 10); - if (top_messageid < 1) - return pop3_error(session, stream,"-ERR wrong parameter\r\n"); - - trace(TRACE_DEBUG,"pop3():TOP command (partially) retrieving message"); - - tmpelement=list_getstart(&(session->messagelst)); - - /* selecting a message */ - trace(TRACE_DEBUG,"pop3(): TOP command, selecting message"); - - while (tmpelement != NULL) - { - if (((struct message *)tmpelement->data)->messageid==top_messageid && - ((struct message *)tmpelement->data)->virtual_messagestatus<2) /* message is not deleted */ - { - fprintf ((FILE *)stream,"+OK %llu lines of message %llu\r\n",top_lines, top_messageid); - return db_send_message_lines (stream, ((struct message *)tmpelement->data)->realmessageid, top_lines, 0); - } - tmpelement = tmpelement->nextnode; - } - return pop3_error (session, stream,"-ERR no such message\r\n"); - - return 1; - } - case POP3_CAPA: - { - fprintf((FILE *)stream, - "+OK, Capability list follows\r\n" - "TOP\r\nUSER\r\nUIDL\r\n.\r\n"); - return 1; - } - - default : - { - return pop3_error(session, stream,"-ERR command not understood, sir\r\n"); - } - } - return 1; + } else + session->SessionResult = 4; /* storage layer error */ + + return result; + } + } + return 1; + } + + case POP3_AUTH: + { + if (session->state != POP3_AUTHORIZATION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + fprintf((FILE *) stream, + "+OK List of supported mechanisms\r\n.\r\n"); + return 1; + } + + case POP3_TOP: + { + if (session->state != POP3_TRANSACTION_STATE) + return pop3_error(session, stream, + "-ERR wrong command mode, sir\r\n"); + + /* find out how many lines they want */ + searchptr = strstr(value, " "); + + /* insufficient parameters */ + if (searchptr == NULL) + return pop3_error(session, stream, + "-ERR your command does not compute\r\n"); + + /* skip the space */ + searchptr = searchptr + 1; + + /* value should now be the the message that needs to be retrieved */ + value[searchptr - value - 1] = '\0'; + + /* check if searchptr or value are negative. If so return an + error. This is done by only letting the strings contain + digits (0-9) */ + if (strspn(searchptr, "0123456789") != + strlen(searchptr)) + return pop3_error(session, stream, + "-ERR wrong parameter\r\n"); + if (strspn(value, "0123456789") != strlen(value)) + return pop3_error(session, stream, + "-ERR wrong parameter\r\n"); + + top_lines = strtoull(searchptr, NULL, 10); + top_messageid = strtoull(value, NULL, 10); + if (top_messageid < 1) + return pop3_error(session, stream, + "-ERR wrong parameter\r\n"); + + trace(TRACE_DEBUG, + "pop3():TOP command (partially) retrieving message"); + + tmpelement = list_getstart(&(session->messagelst)); + + /* selecting a message */ + trace(TRACE_DEBUG, + "pop3(): TOP command, selecting message"); + + while (tmpelement != NULL) { + if (((struct message *) tmpelement->data)->messageid == top_messageid && ((struct message *) tmpelement->data)->virtual_messagestatus < 2) { /* message is not deleted */ + fprintf((FILE *) stream, + "+OK %llu lines of message %llu\r\n", + top_lines, top_messageid); + return + db_send_message_lines(stream, + ((struct + message + *) + tmpelement-> + data)-> + realmessageid, + top_lines, + 0); + } + tmpelement = tmpelement->nextnode; + } + return pop3_error(session, stream, + "-ERR no such message\r\n"); + + return 1; + } + case POP3_CAPA: + { + fprintf((FILE *) stream, + "+OK, Capability list follows\r\n" + "TOP\r\nUSER\r\nUIDL\r\n.\r\n"); + return 1; + } + + default: + { + return pop3_error(session, stream, + "-ERR command not understood, sir\r\n"); + } + } + return 1; } @@ -54,7 +54,7 @@ /* processes */ #define MAXCHILDREN 5 -#define DEFAULT_CHILDREN 5 +#define DEFAULT_CHILDREN 5 #define POP3_DEF_MAXCONNECT 1500 /* connection */ @@ -62,21 +62,21 @@ /** * all POP3 commands */ typedef enum { - POP3_QUIT, - POP3_USER, - POP3_PASS, - POP3_STAT, - POP3_LIST, - POP3_RETR, - POP3_DELE, - POP3_NOOP, - POP3_LAST, - POP3_RSET, - POP3_UIDL, - POP3_APOP, - POP3_AUTH, - POP3_TOP, - POP3_CAPA, + POP3_QUIT, + POP3_USER, + POP3_PASS, + POP3_STAT, + POP3_LIST, + POP3_RETR, + POP3_DELE, + POP3_NOOP, + POP3_LAST, + POP3_RSET, + POP3_UIDL, + POP3_APOP, + POP3_AUTH, + POP3_TOP, + POP3_CAPA, } Pop3Cmd_t; /** @@ -90,7 +90,8 @@ typedef enum { * 0 on QUIT (client command) * 1 on success */ -int pop3 (void *stream, char *buffer, char *client_ip, PopSession_t *session); +int pop3(void *stream, char *buffer, char *client_ip, + PopSession_t * session); /** * \brief handles connection and calls pop command handler @@ -98,6 +99,6 @@ int pop3 (void *stream, char *buffer, char *client_ip, PopSession_t *session); * function * \return 0 */ -int pop3_handle_connection (clientinfo_t *ci); +int pop3_handle_connection(clientinfo_t * ci); #endif @@ -37,7 +37,7 @@ #include <signal.h> #include <unistd.h> #include <errno.h> -#include <unistd.h> /* for getopt() */ +#include <unistd.h> /* for getopt() */ #include "imap4.h" #include "server.h" #include "debug.h" @@ -60,10 +60,10 @@ char *configFile = DEFAULT_CONFIG_FILE; /* set up database login data */ extern db_param_t _db_params; -static void SetConfigItems(serverConfig_t *config, struct list *items); +static void SetConfigItems(serverConfig_t * config, struct list *items); static void Daemonize(void); static int SetMainSigHandler(void); -static void MainSigHandler(int sig, siginfo_t *info, void *data); +static void MainSigHandler(int sig, siginfo_t * info, void *data); int pop_before_smtp = 0; int mainRestart = 0; @@ -76,268 +76,298 @@ char *timeout_setting; #ifdef PROC_TITLES int main(int argc, char *argv[], char **envp) #else - int main(int argc, char *argv[]) +int main(int argc, char *argv[]) #endif { - serverConfig_t config; - struct list popItems, sysItems; - int result, status; - pid_t pid; - int opt; - - openlog(PNAME, LOG_PID, LOG_MAIL); - - /* get command-line options */ - opterr = 0; /* suppress error message from getopt() */ - while ((opt = getopt(argc, argv, "vhf:")) != -1) { - switch (opt) { - case 'v': - printf ("\n*** DBMAIL: dbmail-pop3d version " - "$Revision$ %s\n\n",COPYRIGHT); - return 0; - case 'h': - printf ("\ndbmail-pop3d: DBMAIL pop3 daemon\n"); - printf ("Usage: dbmail-pop3d (-v|-h|[-f config_filename])\n"); - return 0; - case 'f': - if (optarg && strlen(optarg) > 0) - configFile = optarg; - else { - fprintf(stderr,"dbmail-pop3d: -f requires a filename " - "argument\n\n"); - return 1; - } - break; - - default: - break; - } - } - - SetMainSigHandler(); - Daemonize(); - result = 0; - - do - { - mainStop = 0; - mainRestart = 0; - - trace(TRACE_DEBUG, "main(): reading config"); -#ifdef PROC_TITLES - init_set_proc_title(argc, argv, envp, PNAME); - set_proc_title("%s", "Idle"); -#endif - - ReadConfig("POP", configFile, &popItems); - ReadConfig("DBMAIL", configFile, &sysItems); - SetConfigItems(&config, &popItems); - SetTraceLevel(&popItems); - GetDBParams(&_db_params, &sysItems); - - config.ClientHandler = pop3_handle_connection; - config.timeoutMsg = POP_TIMEOUT_MSG; - - CreateSocket(&config); - trace(TRACE_DEBUG, "main(): socket created, starting server"); - - switch ( (pid = fork()) ) - { - case -1: - close(config.listenSocket); - trace(TRACE_FATAL, "main(): fork failed [%s]", strerror(errno)); - - case 0: - /* child process */ - drop_privileges(config.serverUser, config.serverGroup); - result = StartServer(&config); - - trace(TRACE_INFO, "main(): server done, exit."); - exit(result); - - default: - /* parent process, wait for child to exit */ - while (waitpid(pid, &status, WNOHANG|WUNTRACED) == 0) - { - if (mainStop) - kill(pid, SIGTERM); - - if (mainRestart) - kill(pid, SIGHUP); - - sleep(2); - } - - if (WIFEXITED(status)) - { - /* child process terminated neatly */ - result = WEXITSTATUS(status); - trace(TRACE_DEBUG, "main(): server has exited, exit status [%d]", result); - } - else - { - /* child stopped or signaled, don't like */ - /* make sure it is dead */ - trace(TRACE_DEBUG, "main(): server has not exited normally. Killing.."); - - kill(pid, SIGKILL); - result = 0; - } + serverConfig_t config; + struct list popItems, sysItems; + int result, status; + pid_t pid; + int opt; + + openlog(PNAME, LOG_PID, LOG_MAIL); + + /* get command-line options */ + opterr = 0; /* suppress error message from getopt() */ + while ((opt = getopt(argc, argv, "vhf:")) != -1) { + switch (opt) { + case 'v': + printf("\n*** DBMAIL: dbmail-pop3d version " + "$Revision$ %s\n\n", COPYRIGHT); + return 0; + case 'h': + printf("\ndbmail-pop3d: DBMAIL pop3 daemon\n"); + printf + ("Usage: dbmail-pop3d (-v|-h|[-f config_filename])\n"); + return 0; + case 'f': + if (optarg && strlen(optarg) > 0) + configFile = optarg; + else { + fprintf(stderr, + "dbmail-pop3d: -f requires a filename " + "argument\n\n"); + return 1; + } + break; + + default: + break; + } } - list_freelist(&popItems.start); - list_freelist(&sysItems.start); - close(config.listenSocket); + SetMainSigHandler(); + Daemonize(); + result = 0; - } while (result == 1 && !mainStop) ; /* 1 means reread-config and restart */ + do { + mainStop = 0; + mainRestart = 0; + + trace(TRACE_DEBUG, "main(): reading config"); +#ifdef PROC_TITLES + init_set_proc_title(argc, argv, envp, PNAME); + set_proc_title("%s", "Idle"); +#endif - trace(TRACE_INFO, "main(): exit"); - return 0; + ReadConfig("POP", configFile, &popItems); + ReadConfig("DBMAIL", configFile, &sysItems); + SetConfigItems(&config, &popItems); + SetTraceLevel(&popItems); + GetDBParams(&_db_params, &sysItems); + + config.ClientHandler = pop3_handle_connection; + config.timeoutMsg = POP_TIMEOUT_MSG; + + CreateSocket(&config); + trace(TRACE_DEBUG, + "main(): socket created, starting server"); + + switch ((pid = fork())) { + case -1: + close(config.listenSocket); + trace(TRACE_FATAL, "main(): fork failed [%s]", + strerror(errno)); + + case 0: + /* child process */ + drop_privileges(config.serverUser, + config.serverGroup); + result = StartServer(&config); + + trace(TRACE_INFO, "main(): server done, exit."); + exit(result); + + default: + /* parent process, wait for child to exit */ + while (waitpid(pid, &status, WNOHANG | WUNTRACED) + == 0) { + if (mainStop) + kill(pid, SIGTERM); + + if (mainRestart) + kill(pid, SIGHUP); + + sleep(2); + } + + if (WIFEXITED(status)) { + /* child process terminated neatly */ + result = WEXITSTATUS(status); + trace(TRACE_DEBUG, + "main(): server has exited, exit status [%d]", + result); + } else { + /* child stopped or signaled, don't like */ + /* make sure it is dead */ + trace(TRACE_DEBUG, + "main(): server has not exited normally. Killing.."); + + kill(pid, SIGKILL); + result = 0; + } + } + + list_freelist(&popItems.start); + list_freelist(&sysItems.start); + close(config.listenSocket); + + } while (result == 1 && !mainStop); /* 1 means reread-config and restart */ + + trace(TRACE_INFO, "main(): exit"); + return 0; } -void MainSigHandler(int sig, siginfo_t *info UNUSED, void *data UNUSED) +void MainSigHandler(int sig, siginfo_t * info UNUSED, void *data UNUSED) { - trace(TRACE_DEBUG, "MainSigHandler(): got signal [%d]", sig); + trace(TRACE_DEBUG, "MainSigHandler(): got signal [%d]", sig); - if (sig == SIGHUP) - mainRestart = 1; - else - mainStop = 1; + if (sig == SIGHUP) + mainRestart = 1; + else + mainStop = 1; } void Daemonize() { - if (fork()) - exit(0); - setsid(); + if (fork()) + exit(0); + setsid(); - if (fork()) - exit(0); + if (fork()) + exit(0); } int SetMainSigHandler() { - struct sigaction act; + struct sigaction act; - /* init & install signal handlers */ - memset(&act, 0, sizeof(act)); + /* init & install signal handlers */ + memset(&act, 0, sizeof(act)); - act.sa_sigaction = MainSigHandler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; + act.sa_sigaction = MainSigHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; - sigaction(SIGINT, &act, 0); - sigaction(SIGQUIT, &act, 0); - sigaction(SIGTERM, &act, 0); - sigaction(SIGHUP, &act, 0); + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); + sigaction(SIGTERM, &act, 0); + sigaction(SIGHUP, &act, 0); - return 0; + return 0; } -void SetConfigItems(serverConfig_t *config, struct list *items) +void SetConfigItems(serverConfig_t * config, struct list *items) { - field_t val; + field_t val; - /* read items: NCHILDREN */ - GetConfigValue("NCHILDREN", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for NCHILDREN in config file"); + /* read items: NCHILDREN */ + GetConfigValue("NCHILDREN", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for NCHILDREN in config file"); - if ( (config->nChildren = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for NCHILDREN is invalid: [%d]", config->nChildren); + if ((config->nChildren = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for NCHILDREN is invalid: [%d]", + config->nChildren); - trace(TRACE_DEBUG, "SetConfigItems(): server will create [%d] children", config->nChildren); + trace(TRACE_DEBUG, + "SetConfigItems(): server will create [%d] children", + config->nChildren); - /* read items: MAXCONNECTS */ - GetConfigValue("MAXCONNECTS", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for MAXCONNECTS in config file"); + /* read items: MAXCONNECTS */ + GetConfigValue("MAXCONNECTS", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for MAXCONNECTS in config file"); - if ( (config->childMaxConnect = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", config->childMaxConnect); + if ((config->childMaxConnect = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", + config->childMaxConnect); - trace(TRACE_DEBUG, "SetConfigItems(): children will make max. [%d] connections", config->childMaxConnect); + trace(TRACE_DEBUG, + "SetConfigItems(): children will make max. [%d] connections", + config->childMaxConnect); - /* read items: TIMEOUT */ - GetConfigValue("TIMEOUT", items, val); - if (strlen(val) == 0) - { - trace(TRACE_DEBUG, "SetConfigItems(): no value for TIMEOUT in config file"); - config->timeout = 0; - } - else if ( (config->timeout = atoi(val)) <= 30) - trace(TRACE_FATAL, "SetConfigItems(): value for TIMEOUT is invalid: [%d]", config->timeout); + /* read items: TIMEOUT */ + GetConfigValue("TIMEOUT", items, val); + if (strlen(val) == 0) { + trace(TRACE_DEBUG, + "SetConfigItems(): no value for TIMEOUT in config file"); + config->timeout = 0; + } else if ((config->timeout = atoi(val)) <= 30) + trace(TRACE_FATAL, + "SetConfigItems(): value for TIMEOUT is invalid: [%d]", + config->timeout); - trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", config->timeout); + trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", + config->timeout); - /* read items: PORT */ - GetConfigValue("PORT", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for PORT in config file"); + /* read items: PORT */ + GetConfigValue("PORT", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for PORT in config file"); - if ( (config->port = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for PORT is invalid: [%d]", config->port); + if ((config->port = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for PORT is invalid: [%d]", + config->port); - trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", config->port); + trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", + config->port); - /* read items: BINDIP */ - GetConfigValue("BINDIP", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for BINDIP in config file"); + /* read items: BINDIP */ + GetConfigValue("BINDIP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for BINDIP in config file"); - strncpy(config->ip, val, IPLEN); - config->ip[IPLEN-1] = '\0'; + strncpy(config->ip, val, IPLEN); + config->ip[IPLEN - 1] = '\0'; - trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", config->ip); + trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", + config->ip); - /* read items: RESOLVE_IP */ - GetConfigValue("RESOLVE_IP", items, val); - if (strlen(val) == 0) - trace(TRACE_DEBUG, "SetConfigItems(): no value for RESOLVE_IP in config file"); + /* read items: RESOLVE_IP */ + GetConfigValue("RESOLVE_IP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, + "SetConfigItems(): no value for RESOLVE_IP in config file"); - config->resolveIP = (strcasecmp(val, "yes") == 0); + config->resolveIP = (strcasecmp(val, "yes") == 0); - trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", config->resolveIP ? "" : "not "); + trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", + config->resolveIP ? "" : "not "); - /* read items: IMAP-BEFORE-SMTP */ - GetConfigValue("POP_BEFORE_SMTP", items, val); - if (strlen(val) == 0) - trace(TRACE_DEBUG, "SetConfigItems(): no value for POP_BEFORE_SMTP in config file"); + /* read items: IMAP-BEFORE-SMTP */ + GetConfigValue("POP_BEFORE_SMTP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, + "SetConfigItems(): no value for POP_BEFORE_SMTP in config file"); - pop_before_smtp = (strcasecmp(val, "yes") == 0); + pop_before_smtp = (strcasecmp(val, "yes") == 0); - trace(TRACE_DEBUG, "SetConfigItems(): %s POP-before-SMTP", - pop_before_smtp ? "Enabling" : "Disabling"); + trace(TRACE_DEBUG, "SetConfigItems(): %s POP-before-SMTP", + pop_before_smtp ? "Enabling" : "Disabling"); - /* read items: EFFECTIVE-USER */ - GetConfigValue("EFFECTIVE_USER", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_USER in config file"); + /* read items: EFFECTIVE-USER */ + GetConfigValue("EFFECTIVE_USER", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for EFFECTIVE_USER in config file"); - strncpy(config->serverUser, val, FIELDSIZE); - config->serverUser[FIELDSIZE-1] = '\0'; + strncpy(config->serverUser, val, FIELDSIZE); + config->serverUser[FIELDSIZE - 1] = '\0'; - trace(TRACE_DEBUG, "SetConfigItems(): effective user shall be [%s]", config->serverUser); + trace(TRACE_DEBUG, + "SetConfigItems(): effective user shall be [%s]", + config->serverUser); - /* read items: EFFECTIVE-GROUP */ - GetConfigValue("EFFECTIVE_GROUP", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_GROUP in config file"); + /* read items: EFFECTIVE-GROUP */ + GetConfigValue("EFFECTIVE_GROUP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for EFFECTIVE_GROUP in config file"); - strncpy(config->serverGroup, val, FIELDSIZE); - config->serverGroup[FIELDSIZE-1] = '\0'; + strncpy(config->serverGroup, val, FIELDSIZE); + config->serverGroup[FIELDSIZE - 1] = '\0'; - trace(TRACE_DEBUG, "SetConfigItems(): effective group shall be [%s]", config->serverGroup); + trace(TRACE_DEBUG, + "SetConfigItems(): effective group shall be [%s]", + config->serverGroup); } diff --git a/proctitleutils.c b/proctitleutils.c index 07621c46..8110ce9b 100644 --- a/proctitleutils.c +++ b/proctitleutils.c @@ -29,68 +29,68 @@ #include "proctitleutils.h" /* Globals */ -static char **Argv = ((void *)0); -static char *LastArgv = ((void *)0); +static char **Argv = ((void *) 0); +static char *LastArgv = ((void *) 0); static int start = 0; -void init_set_proc_title(int argc, char *argv[], char *envp[], const char *name) +void init_set_proc_title(int argc, char *argv[], char *envp[], + const char *name) { - int i, envpsize; - extern char **environ; - char **p; - char *ptr; - - for(i = envpsize = 0; envp[i] != NULL; i++) - envpsize += strlen(envp[i]) + 1; - - if((p = (char **) malloc((i + 1) * sizeof(char *))) != NULL ) { - environ = p; - - for(i = 0; envp[i] != NULL; i++) { - if((environ[i] = malloc(strlen(envp[i]) + 1)) != NULL) - strcpy(environ[i], envp[i]); - } - - environ[i] = NULL; - } - - Argv = argv; - - for(i = 0; envp[i] != NULL; i++) { - if((LastArgv + 1) == envp[i]) // Not sure if this conditional is needed - LastArgv = envp[i] + strlen(envp[i]); - } - - // Clear the title (from the start of argv to the start of envp) - // All command line arguments should have been taken care of by now... - for(ptr=Argv[0]; ptr<envp[0]; ptr++) - *ptr='\0'; - - set_proc_title("%s : ", name); - start=strlen(name)+3; + int i, envpsize; + extern char **environ; + char **p; + char *ptr; + + for (i = envpsize = 0; envp[i] != NULL; i++) + envpsize += strlen(envp[i]) + 1; + + if ((p = (char **) malloc((i + 1) * sizeof(char *))) != NULL) { + environ = p; + + for (i = 0; envp[i] != NULL; i++) { + if ((environ[i] = + malloc(strlen(envp[i]) + 1)) != NULL) + strcpy(environ[i], envp[i]); + } + + environ[i] = NULL; + } + + Argv = argv; + + for (i = 0; envp[i] != NULL; i++) { + if ((LastArgv + 1) == envp[i]) // Not sure if this conditional is needed + LastArgv = envp[i] + strlen(envp[i]); + } + + // Clear the title (from the start of argv to the start of envp) + // All command line arguments should have been taken care of by now... + for (ptr = Argv[0]; ptr < envp[0]; ptr++) + *ptr = '\0'; + + set_proc_title("%s : ", name); + start = strlen(name) + 3; } -void set_proc_title(char *fmt,...) +void set_proc_title(char *fmt, ...) { - va_list msg; - static char statbuf[8192]; - char *p = Argv[0]; - int maxlen = (LastArgv - Argv[0]) - 2; + va_list msg; + static char statbuf[8192]; + char *p = Argv[0]; + int maxlen = (LastArgv - Argv[0]) - 2; - // Clear old Argv[0] - for(p+=start;*p; p++) - *p='\0'; - - va_start(msg,fmt); + // Clear old Argv[0] + for (p += start; *p; p++) + *p = '\0'; - memset(statbuf, 0, sizeof(statbuf)); - vsnprintf(statbuf, sizeof(statbuf), fmt, msg); + va_start(msg, fmt); - va_end(msg); + memset(statbuf, 0, sizeof(statbuf)); + vsnprintf(statbuf, sizeof(statbuf), fmt, msg); - snprintf(Argv[0]+start, maxlen, "%s", statbuf); - - Argv[1] = ((void *)0) ; -} + va_end(msg); + snprintf(Argv[0] + start, maxlen, "%s", statbuf); + Argv[1] = ((void *) 0); +} diff --git a/proctitleutils.h b/proctitleutils.h index 7430c126..07a6aa19 100644 --- a/proctitleutils.h +++ b/proctitleutils.h @@ -32,7 +32,8 @@ #include "config.h" #endif -void set_proc_title(char *fmt,...); -void init_set_proc_title(int argc, char *argv[], char *envp[], const char *name); +void set_proc_title(char *fmt, ...); +void init_set_proc_title(int argc, char *argv[], char *envp[], + const char *name); #endif @@ -30,16 +30,19 @@ /* Allocate a quota structure for `n_resources' resources. * Returns NULL on failure. */ -quota_t *quota_alloc(int n_resources) { - quota_t *quota; +quota_t *quota_alloc(int n_resources) +{ + quota_t *quota; - quota = malloc(sizeof(quota_t) + n_resources * sizeof(resource_limit_t)); - if (quota != NULL) { - quota->root = NULL; - quota->n_resources = n_resources; - } + quota = + malloc(sizeof(quota_t) + + n_resources * sizeof(resource_limit_t)); + if (quota != NULL) { + quota->root = NULL; + quota->n_resources = n_resources; + } - return quota; + return quota; } /* Set a resource limit in a quota structure. @@ -49,13 +52,14 @@ quota_t *quota_alloc(int n_resources) { * usage: the current usage of the resource. * limit: the usage limit for the resource. */ -void quota_set_resource_limit(quota_t *quota, int resource_idx, +void quota_set_resource_limit(quota_t * quota, int resource_idx, resource_type_t type, - u64_t usage, u64_t limit) { - resource_limit_t * rl = &(quota->resource[resource_idx]); - rl->type = type; - rl->usage = usage; - rl->limit = limit; + u64_t usage, u64_t limit) +{ + resource_limit_t *rl = &(quota->resource[resource_idx]); + rl->type = type; + rl->usage = usage; + rl->limit = limit; } /* Set the name of the quota root. @@ -63,16 +67,18 @@ void quota_set_resource_limit(quota_t *quota, int resource_idx, * quota: the quota object to modify. * root: the (new) name of the quota root. */ -int quota_set_root(quota_t *quota, char *root) { - free(quota->root); - quota->root = strdup(root); - return (quota->root == NULL); +int quota_set_root(quota_t * quota, char *root) +{ + free(quota->root); + quota->root = strdup(root); + return (quota->root == NULL); } /* Free a quota structure. */ -void quota_free(quota_t *quota) { - free(quota->root); - free(quota); +void quota_free(quota_t * quota) +{ + free(quota->root); + free(quota); } @@ -86,15 +92,16 @@ void quota_free(quota_t *quota) { * errormsg: will point to an error message if NULL is returned. */ char *quota_get_quotaroot(u64_t useridnr, const char *mailbox, - char **errormsg) { - u64_t mailbox_idnr; - - if (db_findmailbox(mailbox, useridnr, &mailbox_idnr) <= 0) { - *errormsg = "mailbox not found"; - return NULL; - } - - return ""; + char **errormsg) +{ + u64_t mailbox_idnr; + + if (db_findmailbox(mailbox, useridnr, &mailbox_idnr) <= 0) { + *errormsg = "mailbox not found"; + return NULL; + } + + return ""; } /* Get the quota for a given quota root. @@ -106,48 +113,53 @@ char *quota_get_quotaroot(u64_t useridnr, const char *mailbox, * quotaroot: the quotaroot. * errormsg: will point to an error message if NULL is returned. */ -quota_t *quota_get_quota(u64_t useridnr, char *quotaroot, char **errormsg) { - quota_t *quota; - u64_t maxmail_size, usage; - - /* Currently, there's only the quota root "". */ - if (strcmp(quotaroot, "") != 0) { - trace(TRACE_ERROR, "quota_get_quota(): unknown quota root \"%s\"\n", - quotaroot); - *errormsg = "unknown quota root"; - return NULL; - } - - if (auth_getmaxmailsize(useridnr, &maxmail_size) == -1) { - trace(TRACE_ERROR, "quota_get_quota(): auth_getmaxmailsize() failed\n"); - *errormsg = "invalid user"; - return NULL; - } - - if (db_get_quotum_used(useridnr, &usage) == -1) { - trace(TRACE_ERROR, - "quota_get_quota(): db_get_quotum_used() failed\n"); - *errormsg = "internal error"; - return NULL; - } - - /* We support exactly one resource: RT_STORAGE */ - quota = quota_alloc(1); - if (quota == NULL) { - trace(TRACE_ERROR, "quota_get_quota(): out of memory\n"); - *errormsg = "out of memory"; - return NULL; - } - - /* Set quota root */ - if (quota_set_root(quota, quotaroot)) { - trace(TRACE_ERROR, "quota_get_quota(): quota_set_root() failed\n"); - *errormsg = "out of memory"; - return NULL; - } - - /* Set usage and limit for RT_STORAGE */ - quota_set_resource_limit(quota, 0, RT_STORAGE, usage, maxmail_size); - - return quota; +quota_t *quota_get_quota(u64_t useridnr, char *quotaroot, char **errormsg) +{ + quota_t *quota; + u64_t maxmail_size, usage; + + /* Currently, there's only the quota root "". */ + if (strcmp(quotaroot, "") != 0) { + trace(TRACE_ERROR, + "quota_get_quota(): unknown quota root \"%s\"\n", + quotaroot); + *errormsg = "unknown quota root"; + return NULL; + } + + if (auth_getmaxmailsize(useridnr, &maxmail_size) == -1) { + trace(TRACE_ERROR, + "quota_get_quota(): auth_getmaxmailsize() failed\n"); + *errormsg = "invalid user"; + return NULL; + } + + if (db_get_quotum_used(useridnr, &usage) == -1) { + trace(TRACE_ERROR, + "quota_get_quota(): db_get_quotum_used() failed\n"); + *errormsg = "internal error"; + return NULL; + } + + /* We support exactly one resource: RT_STORAGE */ + quota = quota_alloc(1); + if (quota == NULL) { + trace(TRACE_ERROR, "quota_get_quota(): out of memory\n"); + *errormsg = "out of memory"; + return NULL; + } + + /* Set quota root */ + if (quota_set_root(quota, quotaroot)) { + trace(TRACE_ERROR, + "quota_get_quota(): quota_set_root() failed\n"); + *errormsg = "out of memory"; + return NULL; + } + + /* Set usage and limit for RT_STORAGE */ + quota_set_resource_limit(quota, 0, RT_STORAGE, usage, + maxmail_size); + + return quota; } @@ -31,7 +31,7 @@ * RT_STORAGE: "STORAGE" */ typedef enum { - RT_STORAGE + RT_STORAGE } resource_type_t; /* A resource limit. @@ -40,9 +40,9 @@ typedef enum { * limit: the maximum allowed usage of the resource */ typedef struct { - resource_type_t type; - u64_t usage; - u64_t limit; + resource_type_t type; + u64_t usage; + u64_t limit; } resource_limit_t; /* A quota root and its resource limits. @@ -52,19 +52,19 @@ typedef struct { * describing a resource limit */ typedef struct { - char *root; - int n_resources; - resource_limit_t resource[0]; + char *root; + int n_resources; + resource_limit_t resource[0]; } quota_t; /* Functions for manipulating quota_t objects */ quota_t *quota_alloc(int n_resources); -void quota_free(quota_t *quota); -void quota_set_resource_limit(quota_t *quota, int resource_idx, +void quota_free(quota_t * quota); +void quota_set_resource_limit(quota_t * quota, int resource_idx, resource_type_t type, u64_t usage, u64_t limit); -int quota_set_root(quota_t *quota, char *root); +int quota_set_root(quota_t * quota, char *root); /* Functions for querying quota and quota root */ char *quota_get_quotaroot(u64_t useridnr, const char *mailbox, @@ -41,60 +41,58 @@ /* * frees all the memory associated with a msg */ -void db_free_msg(mime_message_t *msg) +void db_free_msg(mime_message_t * msg) { - struct element *tmp; + struct element *tmp; - if (!msg) - return; + if (!msg) + return; - /* free the children msg's */ - tmp = list_getstart(&msg->children); + /* free the children msg's */ + tmp = list_getstart(&msg->children); - while (tmp) - { - db_free_msg((mime_message_t*)tmp->data); - tmp = tmp->nextnode; - } + while (tmp) { + db_free_msg((mime_message_t *) tmp->data); + tmp = tmp->nextnode; + } + + tmp = list_getstart(&msg->children); + list_freelist(&tmp); - tmp = list_getstart(&msg->children); - list_freelist(&tmp); - - tmp = list_getstart(&msg->mimeheader); - list_freelist(&tmp); + tmp = list_getstart(&msg->mimeheader); + list_freelist(&tmp); - tmp = list_getstart(&msg->rfcheader); - list_freelist(&tmp); + tmp = list_getstart(&msg->rfcheader); + list_freelist(&tmp); - memset(msg, 0, sizeof(*msg)); + memset(msg, 0, sizeof(*msg)); } - + /* * reverses the children lists of a msg */ -void db_reverse_msg(mime_message_t *msg) +void db_reverse_msg(mime_message_t * msg) { - struct element *tmp; + struct element *tmp; - if (!msg) - return; + if (!msg) + return; - /* reverse the children msg's */ - tmp = list_getstart(&msg->children); + /* reverse the children msg's */ + tmp = list_getstart(&msg->children); - while (tmp) - { - db_reverse_msg((mime_message_t*)tmp->data); - tmp = tmp->nextnode; - } + while (tmp) { + db_reverse_msg((mime_message_t *) tmp->data); + tmp = tmp->nextnode; + } - /* reverse this list */ - msg->children.start = dbmail_list_reverse(msg->children.start); + /* reverse this list */ + msg->children.start = dbmail_list_reverse(msg->children.start); - /* reverse header items */ - msg->mimeheader.start = dbmail_list_reverse(msg->mimeheader.start); - msg->rfcheader.start = dbmail_list_reverse(msg->rfcheader.start); + /* reverse header items */ + msg->mimeheader.start = dbmail_list_reverse(msg->mimeheader.start); + msg->rfcheader.start = dbmail_list_reverse(msg->rfcheader.start); } /* @@ -116,94 +114,98 @@ void db_reverse_msg(mime_message_t *msg) * -1 parse error but msg is retrieved as plaintext * 0 success */ -int db_fetch_headers(u64_t msguid, mime_message_t *msg) +int db_fetch_headers(u64_t msguid, mime_message_t * msg) { - int result,level=0,maxlevel=-1; + int result, level = 0, maxlevel = -1; - if (db_init_msgfetch(msguid) != 1) - { - trace(TRACE_ERROR,"db_fetch_headers(): could not init msgfetch\n"); - return -2; - } + if (db_init_msgfetch(msguid) != 1) { + trace(TRACE_ERROR, + "db_fetch_headers(): could not init msgfetch\n"); + return -2; + } - result = db_start_msg(msg, NULL, &level, maxlevel); /* fetch message */ - if (result < 0) - { - trace(TRACE_INFO, "db_fetch_headers(): error fetching message, ID: %llu\n",msguid); - trace(TRACE_INFO, "db_fetch_headers(): got error at level %d\n",level); + result = db_start_msg(msg, NULL, &level, maxlevel); /* fetch message */ + if (result < 0) { + trace(TRACE_INFO, + "db_fetch_headers(): error fetching message, ID: %llu\n", + msguid); + trace(TRACE_INFO, + "db_fetch_headers(): got error at level %d\n", + level); - db_close_msgfetch(); - db_free_msg(msg); + db_close_msgfetch(); + db_free_msg(msg); - if (result < -1) - return result; /* memory/dbase error */ + if (result < -1) + return result; /* memory/dbase error */ - /* - * so an error occurred parsing the message. - * try to lower the maxlevel of recursion - */ + /* + * so an error occurred parsing the message. + * try to lower the maxlevel of recursion + */ - for (maxlevel = level-1; maxlevel >= 0; maxlevel--) - { - trace(TRACE_DEBUG, "db_fetch_headers(): trying to fetch at maxlevel %d...\n",maxlevel); + for (maxlevel = level - 1; maxlevel >= 0; maxlevel--) { + trace(TRACE_DEBUG, + "db_fetch_headers(): trying to fetch at maxlevel %d...\n", + maxlevel); - if (db_init_msgfetch(msguid) != 1) - { - trace(TRACE_ERROR,"db_fetch_headers(): could not init msgfetch\n"); - return -2; - } + if (db_init_msgfetch(msguid) != 1) { + trace(TRACE_ERROR, + "db_fetch_headers(): could not init msgfetch\n"); + return -2; + } - level = 0; - result = db_start_msg(msg, NULL, &level, maxlevel); + level = 0; + result = db_start_msg(msg, NULL, &level, maxlevel); - db_close_msgfetch(); + db_close_msgfetch(); - if (result != -1) - break; + if (result != -1) + break; - db_free_msg(msg); - } + db_free_msg(msg); + } - if (result < -1) - { - db_free_msg(msg); - return result; - } + if (result < -1) { + db_free_msg(msg); + return result; + } - if (result >= 0) - { - trace(TRACE_WARNING,"db_fetch_headers(): succesfully recovered erroneous message %llu\n", - msguid); - db_reverse_msg(msg); - return 0; - } + if (result >= 0) { + trace(TRACE_WARNING, + "db_fetch_headers(): succesfully recovered erroneous message %llu\n", + msguid); + db_reverse_msg(msg); + return 0; + } - /* ok still problems... try to make a message */ - if (db_init_msgfetch(msguid) != 1) - { - trace(TRACE_ERROR,"db_fetch_headers(): could not init msgfetch\n"); - return -2; - } + /* ok still problems... try to make a message */ + if (db_init_msgfetch(msguid) != 1) { + trace(TRACE_ERROR, + "db_fetch_headers(): could not init msgfetch\n"); + return -2; + } - result = db_parse_as_text(msg); - if (result < 0) - { - /* probably some serious dbase error */ - trace(TRACE_ERROR,"db_fetch_headers(): could not recover message as plain text\n"); - db_free_msg(msg); - return result; + result = db_parse_as_text(msg); + if (result < 0) { + /* probably some serious dbase error */ + trace(TRACE_ERROR, + "db_fetch_headers(): could not recover message as plain text\n"); + db_free_msg(msg); + return result; + } + + trace(TRACE_WARNING, + "db_fetch_headers(): message recovered as plain text\n"); + db_close_msgfetch(); + return -1; } - trace(TRACE_WARNING, "db_fetch_headers(): message recovered as plain text\n"); - db_close_msgfetch(); - return -1; - } - - db_reverse_msg(msg); + db_reverse_msg(msg); - db_close_msgfetch(); - return 0; + db_close_msgfetch(); + return 0; } @@ -219,223 +221,244 @@ int db_fetch_headers(u64_t msguid, mime_message_t *msg) * * returns the number of lines parsed or -1 on parse error, -2 on dbase error, -3 on memory error */ -int db_start_msg(mime_message_t *msg, char *stopbound, int *level, int maxlevel) +int db_start_msg(mime_message_t * msg, char *stopbound, int *level, + int maxlevel) { - int len,sblen,result,totallines=0,nlines,hdrlines; - struct mime_record *mr; - char *newbound,*bptr; - int continue_recursion = (maxlevel==0 && *level == 0) ? 0 : 1; - - trace(TRACE_DEBUG,"db_start_msg(): starting, stopbound: '%s'\n",stopbound ? stopbound : "<null>"); - - list_init(&msg->children); - msg->message_has_errors = (!continue_recursion); - - - /* read header */ - if (db_update_msgbuf(MSGBUF_FORCE_UPDATE) == -1) - return -2; - - if ((hdrlines = mime_readheader(&msgbuf_buf[msgbuf_idx], &msgbuf_idx, - &msg->rfcheader, &msg->rfcheadersize)) < 0) - return hdrlines; /* error reading header */ - - db_give_msgpos(&msg->bodystart); - msg->rfcheaderlines = hdrlines; + int len, sblen, result, totallines = 0, nlines, hdrlines; + struct mime_record *mr; + char *newbound, *bptr; + int continue_recursion = (maxlevel == 0 && *level == 0) ? 0 : 1; - mime_findfield("content-type", &msg->rfcheader, &mr); - if (continue_recursion && - mr && strncasecmp(mr->value,"multipart", strlen("multipart")) == 0) - { - trace(TRACE_DEBUG,"db_start_msg(): found multipart msg\n"); + trace(TRACE_DEBUG, "db_start_msg(): starting, stopbound: '%s'\n", + stopbound ? stopbound : "<null>"); - /* multipart msg, find new boundary */ - for (bptr = mr->value; *bptr; bptr++) - if (strncasecmp(bptr, "boundary=", sizeof("boundary=")-1) == 0) - break; + list_init(&msg->children); + msg->message_has_errors = (!continue_recursion); - if (!bptr) - { - trace(TRACE_WARNING, "db_start_msg(): could not find a new msg-boundary\n"); - return -1; /* no new boundary ??? */ - } - - bptr += sizeof("boundary=")-1; - if (*bptr == '\"') - { - bptr++; - newbound = bptr; - while (*newbound && *newbound != '\"') newbound++; - } - else - { - newbound = bptr; - while (*newbound && !isspace(*newbound) && *newbound!=';') newbound++; - } - - len = newbound - bptr; - if (!(newbound = (char*)my_malloc(len+1))) - { - trace(TRACE_ERROR, "db_start_msg(): out of memory\n"); - return -3; - } - - strncpy(newbound, bptr, len); - newbound[len] = '\0'; - - trace(TRACE_DEBUG,"db_start_msg(): found new boundary: [%s], msgbuf_idx %llu\n",newbound,msgbuf_idx); - - /* advance to first boundary */ - if (db_update_msgbuf(MSGBUF_FORCE_UPDATE) == -1) - { - trace(TRACE_ERROR, "db_startmsg(): error updating msgbuf\n"); - my_free(newbound); - return -2; - } - - while (msgbuf_buf[msgbuf_idx]) - { - if (strncmp(&msgbuf_buf[msgbuf_idx], newbound, strlen(newbound)) == 0) - break; - if (msgbuf_buf[msgbuf_idx] == '\n') - totallines++; + /* read header */ + if (db_update_msgbuf(MSGBUF_FORCE_UPDATE) == -1) + return -2; - msgbuf_idx++; - } + if ((hdrlines = + mime_readheader(&msgbuf_buf[msgbuf_idx], &msgbuf_idx, + &msg->rfcheader, &msg->rfcheadersize)) < 0) + return hdrlines; /* error reading header */ + + db_give_msgpos(&msg->bodystart); + msg->rfcheaderlines = hdrlines; + + mime_findfield("content-type", &msg->rfcheader, &mr); + if (continue_recursion && + mr + && strncasecmp(mr->value, "multipart", + strlen("multipart")) == 0) { + trace(TRACE_DEBUG, + "db_start_msg(): found multipart msg\n"); + + /* multipart msg, find new boundary */ + for (bptr = mr->value; *bptr; bptr++) + if (strncasecmp + (bptr, "boundary=", + sizeof("boundary=") - 1) == 0) + break; + + if (!bptr) { + trace(TRACE_WARNING, + "db_start_msg(): could not find a new msg-boundary\n"); + return -1; /* no new boundary ??? */ + } - if (!msgbuf_buf[msgbuf_idx]) - { - trace(TRACE_WARNING, "db_start_msg(): unexpected end-of-data\n"); - my_free(newbound); - return -1; - } + bptr += sizeof("boundary=") - 1; + if (*bptr == '\"') { + bptr++; + newbound = bptr; + while (*newbound && *newbound != '\"') + newbound++; + } else { + newbound = bptr; + while (*newbound && !isspace(*newbound) + && *newbound != ';') + newbound++; + } - msgbuf_idx += strlen(newbound); /* skip the boundary */ - msgbuf_idx++; /* skip \n */ - totallines++; /* and count it */ - - /* find MIME-parts */ - (*level)++; - if ((nlines = db_add_mime_children(&msg->children, newbound, level, maxlevel)) < 0) - { - trace(TRACE_WARNING, "db_start_msg(): error adding MIME-children\n"); - my_free(newbound); - return nlines; - } - (*level)--; - totallines += nlines; - - /* skip stopbound if present */ - if (stopbound) - { - sblen = strlen(stopbound); - msgbuf_idx += (2+sblen); /* double hyphen preceeds */ - } + len = newbound - bptr; + if (!(newbound = (char *) my_malloc(len + 1))) { + trace(TRACE_ERROR, + "db_start_msg(): out of memory\n"); + return -3; + } - my_free(newbound); - newbound = NULL; + strncpy(newbound, bptr, len); + newbound[len] = '\0'; - if (msgbuf_idx > 0) - { - /* walk back because bodyend is inclusive */ - msgbuf_idx--; - db_give_msgpos(&msg->bodyend); - msgbuf_idx++; - } - else - db_give_msgpos(&msg->bodyend); /* this case should never happen... */ + trace(TRACE_DEBUG, + "db_start_msg(): found new boundary: [%s], msgbuf_idx %llu\n", + newbound, msgbuf_idx); + /* advance to first boundary */ + if (db_update_msgbuf(MSGBUF_FORCE_UPDATE) == -1) { + trace(TRACE_ERROR, + "db_startmsg(): error updating msgbuf\n"); + my_free(newbound); + return -2; + } - msg->bodysize = db_give_range_size(&msg->bodystart, &msg->bodyend); - msg->bodylines = totallines; + while (msgbuf_buf[msgbuf_idx]) { + if (strncmp + (&msgbuf_buf[msgbuf_idx], newbound, + strlen(newbound)) == 0) + break; - return totallines+hdrlines; /* done */ - } - else - { - /* single part msg, read untill stopbound OR end of buffer */ - trace(TRACE_DEBUG,"db_start_msg(): found singlepart msg\n"); + if (msgbuf_buf[msgbuf_idx] == '\n') + totallines++; - if (stopbound) - { - sblen = strlen(stopbound); + msgbuf_idx++; + } - while (msgbuf_buf[msgbuf_idx]) - { - if (db_update_msgbuf(sblen+3) == -1) - return -2; + if (!msgbuf_buf[msgbuf_idx]) { + trace(TRACE_WARNING, + "db_start_msg(): unexpected end-of-data\n"); + my_free(newbound); + return -1; + } - if (msgbuf_buf[msgbuf_idx] == '\n') - msg->bodylines++; - - if (msgbuf_buf[msgbuf_idx+1] == '-' && msgbuf_buf[msgbuf_idx+2] == '-' && - strncmp(&msgbuf_buf[msgbuf_idx+3], stopbound, sblen) == 0) - { - db_give_msgpos(&msg->bodyend); - msg->bodysize = db_give_range_size(&msg->bodystart, &msg->bodyend); - - msgbuf_idx++; /* msgbuf_buf[msgbuf_idx] == '-' now */ - - /* advance to after stopbound */ - msgbuf_idx += sblen+2; /* (add 2 cause double hyphen preceeds) */ - while (isspace(msgbuf_buf[msgbuf_idx])) - { - if (msgbuf_buf[msgbuf_idx] == '\n') totallines++; - msgbuf_idx++; - } - - trace(TRACE_DEBUG,"db_start_msg(): stopbound reached\n"); - return (totallines+msg->bodylines+hdrlines); + msgbuf_idx += strlen(newbound); /* skip the boundary */ + msgbuf_idx++; /* skip \n */ + totallines++; /* and count it */ + + /* find MIME-parts */ + (*level)++; + if ((nlines = + db_add_mime_children(&msg->children, newbound, level, + maxlevel)) < 0) { + trace(TRACE_WARNING, + "db_start_msg(): error adding MIME-children\n"); + my_free(newbound); + return nlines; } + (*level)--; + totallines += nlines; - msgbuf_idx++; - } + /* skip stopbound if present */ + if (stopbound) { + sblen = strlen(stopbound); + msgbuf_idx += (2 + sblen); /* double hyphen preceeds */ + } - /* end of buffer reached, invalid message encountered: there should be a stopbound! */ - /* but lets pretend there's nothing wrong... */ - db_give_msgpos(&msg->bodyend); - msg->bodysize = db_give_range_size(&msg->bodystart, &msg->bodyend); - totallines += msg->bodylines; - - trace(TRACE_WARNING, "db_start_msg(): no stopbound where expected...\n"); + my_free(newbound); + newbound = NULL; + + if (msgbuf_idx > 0) { + /* walk back because bodyend is inclusive */ + msgbuf_idx--; + db_give_msgpos(&msg->bodyend); + msgbuf_idx++; + } else + db_give_msgpos(&msg->bodyend); /* this case should never happen... */ + + + msg->bodysize = + db_give_range_size(&msg->bodystart, &msg->bodyend); + msg->bodylines = totallines; + + return totallines + hdrlines; /* done */ + } else { + /* single part msg, read untill stopbound OR end of buffer */ + trace(TRACE_DEBUG, + "db_start_msg(): found singlepart msg\n"); + + if (stopbound) { + sblen = strlen(stopbound); + + while (msgbuf_buf[msgbuf_idx]) { + if (db_update_msgbuf(sblen + 3) == -1) + return -2; + + if (msgbuf_buf[msgbuf_idx] == '\n') + msg->bodylines++; + + if (msgbuf_buf[msgbuf_idx + 1] == '-' + && msgbuf_buf[msgbuf_idx + 2] == '-' + && strncmp(&msgbuf_buf[msgbuf_idx + 3], + stopbound, sblen) == 0) { + db_give_msgpos(&msg->bodyend); + msg->bodysize = + db_give_range_size(&msg-> + bodystart, + &msg-> + bodyend); + + msgbuf_idx++; /* msgbuf_buf[msgbuf_idx] == '-' now */ + + /* advance to after stopbound */ + msgbuf_idx += sblen + 2; /* (add 2 cause double hyphen preceeds) */ + while (isspace + (msgbuf_buf[msgbuf_idx])) { + if (msgbuf_buf[msgbuf_idx] + == '\n') + totallines++; + msgbuf_idx++; + } + + trace(TRACE_DEBUG, + "db_start_msg(): stopbound reached\n"); + return (totallines + + msg->bodylines + hdrlines); + } + + msgbuf_idx++; + } + + /* end of buffer reached, invalid message encountered: there should be a stopbound! */ + /* but lets pretend there's nothing wrong... */ + db_give_msgpos(&msg->bodyend); + msg->bodysize = + db_give_range_size(&msg->bodystart, + &msg->bodyend); + totallines += msg->bodylines; + + trace(TRACE_WARNING, + "db_start_msg(): no stopbound where expected...\n"); /* return -1; */ - } - else - { - /* walk on till end of buffer */ - result = 1; - while (1) - { - for ( ; msgbuf_idx < msgbuf_buflen-1 && msgbuf_buf[msgbuf_idx]; msgbuf_idx++) - if (msgbuf_buf[msgbuf_idx] == '\n') - msg->bodylines++; - - if (result == 0) - { - /* end of msg reached, one char left in msgbuf */ - if (msgbuf_buf[msgbuf_idx] == '\n') - msg->bodylines++; - - break; + } else { + /* walk on till end of buffer */ + result = 1; + while (1) { + for (; + msgbuf_idx < msgbuf_buflen - 1 + && msgbuf_buf[msgbuf_idx]; + msgbuf_idx++) + if (msgbuf_buf[msgbuf_idx] == '\n') + msg->bodylines++; + + if (result == 0) { + /* end of msg reached, one char left in msgbuf */ + if (msgbuf_buf[msgbuf_idx] == '\n') + msg->bodylines++; + + break; + } + + result = + db_update_msgbuf(MSGBUF_FORCE_UPDATE); + if (result == -1) + return -2; + } + + db_give_msgpos(&msg->bodyend); + msg->bodysize = + db_give_range_size(&msg->bodystart, + &msg->bodyend); + totallines += msg->bodylines; } - - result = db_update_msgbuf(MSGBUF_FORCE_UPDATE); - if (result == -1) - return -2; - } - - db_give_msgpos(&msg->bodyend); - msg->bodysize = db_give_range_size(&msg->bodystart, &msg->bodyend); - totallines += msg->bodylines; } - } - trace(TRACE_DEBUG,"db_start_msg(): exit\n"); + trace(TRACE_DEBUG, "db_start_msg(): exit\n"); - return totallines; + return totallines; } @@ -444,246 +467,266 @@ int db_start_msg(mime_message_t *msg, char *stopbound, int *level, int maxlevel) * assume to enter just after a splitbound * returns -1 on parse error, -2 on dbase error, -3 on memory error */ -int db_add_mime_children(struct list *brothers, char *splitbound, int *level, int maxlevel) +int db_add_mime_children(struct list *brothers, char *splitbound, + int *level, int maxlevel) { - mime_message_t part; - struct mime_record *mr; - int sblen,nlines,totallines = 0,len; - u64_t dummy; - char *bptr,*newbound; - int continue_recursion = (maxlevel < 0 || *level < maxlevel) ? 1 : 0; - - trace(TRACE_DEBUG,"db_add_mime_children(): starting, splitbound: '%s'\n",splitbound); - sblen = strlen(splitbound); - - do - { - db_update_msgbuf(MSGBUF_FORCE_UPDATE); - memset(&part, 0, sizeof(part)); - part.message_has_errors = (!continue_recursion); - - /* should have a MIME header right here */ - if ((nlines = mime_readheader(&msgbuf_buf[msgbuf_idx], &msgbuf_idx, &part.mimeheader, &dummy)) < 0) - { - trace(TRACE_WARNING,"db_add_mime_children(): error reading MIME-header\n"); - db_free_msg(&part); - return nlines; /* error reading header */ - } - totallines += nlines; - - mime_findfield("content-type", &part.mimeheader, &mr); - - if (continue_recursion && - mr && strncasecmp(mr->value, "message/rfc822", strlen("message/rfc822")) == 0) - { - trace(TRACE_DEBUG,"db_add_mime_children(): found an RFC822 message\n"); - - /* a message will follow */ - if ((nlines = db_start_msg(&part, splitbound, level, maxlevel)) < 0) - { - trace(TRACE_WARNING,"db_add_mime_children(): error retrieving message\n"); - db_free_msg(&part); - return nlines; - } - trace(TRACE_DEBUG,"db_add_mime_children(): got %d newlines from start_msg()\n",nlines); - totallines += nlines; - part.mimerfclines = nlines; - } - else if (continue_recursion && - mr && strncasecmp(mr->value, "multipart", strlen("multipart")) == 0) - { - trace(TRACE_DEBUG,"db_add_mime_children(): found a MIME multipart sub message\n"); - - /* multipart msg, find new boundary */ - for (bptr = mr->value; *bptr; bptr++) - if (strncasecmp(bptr, "boundary=", sizeof("boundary=")-1) == 0) - break; - - if (!bptr) - { - trace(TRACE_WARNING, "db_add_mime_children(): could not find a new msg-boundary\n"); - db_free_msg(&part); - return -1; /* no new boundary ??? */ - } - - bptr += sizeof("boundary=")-1; - if (*bptr == '\"') - { - bptr++; - newbound = bptr; - while (*newbound && *newbound != '\"') newbound++; - } - else - { - newbound = bptr; - while (*newbound && !isspace(*newbound) && *newbound!=';') newbound++; - } - - len = newbound - bptr; - if (!(newbound = (char*)my_malloc(len+1))) - { - trace(TRACE_ERROR, "db_add_mime_children(): out of memory\n"); - db_free_msg(&part); - return -3; - } - - strncpy(newbound, bptr, len); - newbound[len] = '\0'; - - trace(TRACE_DEBUG,"db_add_mime_children(): found new boundary: [%s], msgbuf_idx %llu\n", - newbound,msgbuf_idx); - - - /* advance to first boundary */ - if (db_update_msgbuf(MSGBUF_FORCE_UPDATE) == -1) - { - trace(TRACE_ERROR, "db_add_mime_children(): error updating msgbuf\n"); - db_free_msg(&part); - my_free(newbound); - return -2; - } - - while (msgbuf_buf[msgbuf_idx]) - { - if (strncmp(&msgbuf_buf[msgbuf_idx], newbound, strlen(newbound)) == 0) - break; - - if (msgbuf_buf[msgbuf_idx] == '\n') - { - totallines++; - part.bodylines++; + mime_message_t part; + struct mime_record *mr; + int sblen, nlines, totallines = 0, len; + u64_t dummy; + char *bptr, *newbound; + int continue_recursion = (maxlevel < 0 + || *level < maxlevel) ? 1 : 0; + + trace(TRACE_DEBUG, + "db_add_mime_children(): starting, splitbound: '%s'\n", + splitbound); + sblen = strlen(splitbound); + + do { + db_update_msgbuf(MSGBUF_FORCE_UPDATE); + memset(&part, 0, sizeof(part)); + part.message_has_errors = (!continue_recursion); + + /* should have a MIME header right here */ + if ((nlines = + mime_readheader(&msgbuf_buf[msgbuf_idx], &msgbuf_idx, + &part.mimeheader, &dummy)) < 0) { + trace(TRACE_WARNING, + "db_add_mime_children(): error reading MIME-header\n"); + db_free_msg(&part); + return nlines; /* error reading header */ } - - msgbuf_idx++; - } - - if (!msgbuf_buf[msgbuf_idx]) - { - trace(TRACE_WARNING, "db_add_mime_children(): unexpected end-of-data\n"); - my_free(newbound); - db_free_msg(&part); - return -1; - } - - msgbuf_idx += strlen(newbound); /* skip the boundary */ - msgbuf_idx++; /* skip \n */ - totallines++; /* and count it */ - part.bodylines++; - db_give_msgpos(&part.bodystart); /* remember position */ - - (*level)++; - if ((nlines = db_add_mime_children(&part.children, newbound, level, maxlevel)) < 0) - { - trace(TRACE_WARNING, "db_add_mime_children(): error adding mime children\n"); - my_free(newbound); - db_free_msg(&part); - return nlines; - } - (*level)--; - - my_free(newbound); - newbound = NULL; - msgbuf_idx += sblen+2; /* skip splitbound */ - - if (msgbuf_idx > 0) - { - /* walk back because bodyend is inclusive */ - msgbuf_idx--; - db_give_msgpos(&part.bodyend); - msgbuf_idx++; - } - else - db_give_msgpos(&part.bodyend); /* this case should never happen... */ - - - part.bodysize = db_give_range_size(&part.bodystart, &part.bodyend); - part.bodylines += nlines; - totallines += nlines; - } - else - { - trace(TRACE_DEBUG,"db_add_mime_children(): expecting body data...\n"); - - /* just body data follows, advance to splitbound */ - db_give_msgpos(&part.bodystart); - - while (msgbuf_buf[msgbuf_idx]) - { - if (db_update_msgbuf(sblen+3) == -1) - { - db_free_msg(&part); - return -2; + totallines += nlines; + + mime_findfield("content-type", &part.mimeheader, &mr); + + if (continue_recursion && + mr + && strncasecmp(mr->value, "message/rfc822", + strlen("message/rfc822")) == 0) { + trace(TRACE_DEBUG, + "db_add_mime_children(): found an RFC822 message\n"); + + /* a message will follow */ + if ((nlines = + db_start_msg(&part, splitbound, level, + maxlevel)) < 0) { + trace(TRACE_WARNING, + "db_add_mime_children(): error retrieving message\n"); + db_free_msg(&part); + return nlines; + } + trace(TRACE_DEBUG, + "db_add_mime_children(): got %d newlines from start_msg()\n", + nlines); + totallines += nlines; + part.mimerfclines = nlines; + } else if (continue_recursion && + mr + && strncasecmp(mr->value, "multipart", + strlen("multipart")) == 0) { + trace(TRACE_DEBUG, + "db_add_mime_children(): found a MIME multipart sub message\n"); + + /* multipart msg, find new boundary */ + for (bptr = mr->value; *bptr; bptr++) + if (strncasecmp + (bptr, "boundary=", + sizeof("boundary=") - 1) == 0) + break; + + if (!bptr) { + trace(TRACE_WARNING, + "db_add_mime_children(): could not find a new msg-boundary\n"); + db_free_msg(&part); + return -1; /* no new boundary ??? */ + } + + bptr += sizeof("boundary=") - 1; + if (*bptr == '\"') { + bptr++; + newbound = bptr; + while (*newbound && *newbound != '\"') + newbound++; + } else { + newbound = bptr; + while (*newbound && !isspace(*newbound) + && *newbound != ';') + newbound++; + } + + len = newbound - bptr; + if (!(newbound = (char *) my_malloc(len + 1))) { + trace(TRACE_ERROR, + "db_add_mime_children(): out of memory\n"); + db_free_msg(&part); + return -3; + } + + strncpy(newbound, bptr, len); + newbound[len] = '\0'; + + trace(TRACE_DEBUG, + "db_add_mime_children(): found new boundary: [%s], msgbuf_idx %llu\n", + newbound, msgbuf_idx); + + + /* advance to first boundary */ + if (db_update_msgbuf(MSGBUF_FORCE_UPDATE) == -1) { + trace(TRACE_ERROR, + "db_add_mime_children(): error updating msgbuf\n"); + db_free_msg(&part); + my_free(newbound); + return -2; + } + + while (msgbuf_buf[msgbuf_idx]) { + if (strncmp + (&msgbuf_buf[msgbuf_idx], newbound, + strlen(newbound)) == 0) + break; + + if (msgbuf_buf[msgbuf_idx] == '\n') { + totallines++; + part.bodylines++; + } + + msgbuf_idx++; + } + + if (!msgbuf_buf[msgbuf_idx]) { + trace(TRACE_WARNING, + "db_add_mime_children(): unexpected end-of-data\n"); + my_free(newbound); + db_free_msg(&part); + return -1; + } + + msgbuf_idx += strlen(newbound); /* skip the boundary */ + msgbuf_idx++; /* skip \n */ + totallines++; /* and count it */ + part.bodylines++; + db_give_msgpos(&part.bodystart); /* remember position */ + + (*level)++; + if ((nlines = + db_add_mime_children(&part.children, newbound, + level, maxlevel)) < 0) { + trace(TRACE_WARNING, + "db_add_mime_children(): error adding mime children\n"); + my_free(newbound); + db_free_msg(&part); + return nlines; + } + (*level)--; + + my_free(newbound); + newbound = NULL; + msgbuf_idx += sblen + 2; /* skip splitbound */ + + if (msgbuf_idx > 0) { + /* walk back because bodyend is inclusive */ + msgbuf_idx--; + db_give_msgpos(&part.bodyend); + msgbuf_idx++; + } else + db_give_msgpos(&part.bodyend); /* this case should never happen... */ + + + part.bodysize = + db_give_range_size(&part.bodystart, + &part.bodyend); + part.bodylines += nlines; + totallines += nlines; + } else { + trace(TRACE_DEBUG, + "db_add_mime_children(): expecting body data...\n"); + + /* just body data follows, advance to splitbound */ + db_give_msgpos(&part.bodystart); + + while (msgbuf_buf[msgbuf_idx]) { + if (db_update_msgbuf(sblen + 3) == -1) { + db_free_msg(&part); + return -2; + } + + if (msgbuf_buf[msgbuf_idx] == '\n') + part.bodylines++; + + if (msgbuf_buf[msgbuf_idx + 1] == '-' + && msgbuf_buf[msgbuf_idx + 2] == '-' + && strncmp(&msgbuf_buf[msgbuf_idx + 3], + splitbound, sblen) == 0) + break; + + msgbuf_idx++; + } + + /* at this point msgbuf_buf[msgbuf_idx] is either + * 0 (end of data) -- invalid message! + * or the character right before '--<splitbound>' + */ + + totallines += part.bodylines; + + if (!msgbuf_buf[msgbuf_idx]) { + trace(TRACE_WARNING, + "db_add_mime_children(): unexpected end of data\n"); + db_free_msg(&part); + return -1; /* ?? splitbound should follow */ + } + + db_give_msgpos(&part.bodyend); + part.bodysize = + db_give_range_size(&part.bodystart, + &part.bodyend); + + msgbuf_idx++; /* msgbuf_buf[msgbuf_idx] == '-' after this statement */ + + msgbuf_idx += sblen + 2; /* skip the boundary & double hypen */ } - if (msgbuf_buf[msgbuf_idx] == '\n') - part.bodylines++; - - if (msgbuf_buf[msgbuf_idx+1] == '-' && msgbuf_buf[msgbuf_idx+2] == '-' && - strncmp(&msgbuf_buf[msgbuf_idx+3], splitbound, sblen) == 0) - break; - - msgbuf_idx++; - } - - /* at this point msgbuf_buf[msgbuf_idx] is either - * 0 (end of data) -- invalid message! - * or the character right before '--<splitbound>' - */ - - totallines += part.bodylines; - - if (!msgbuf_buf[msgbuf_idx]) - { - trace(TRACE_WARNING,"db_add_mime_children(): unexpected end of data\n"); - db_free_msg(&part); - return -1; /* ?? splitbound should follow */ - } - - db_give_msgpos(&part.bodyend); - part.bodysize = db_give_range_size(&part.bodystart, &part.bodyend); - - msgbuf_idx++; /* msgbuf_buf[msgbuf_idx] == '-' after this statement */ - - msgbuf_idx += sblen+2; /* skip the boundary & double hypen */ - } - - /* add this part to brother list */ - if (list_nodeadd(brothers, &part, sizeof(part)) == NULL) - { - trace(TRACE_WARNING,"db_add_mime_children(): could not add node\n"); - db_free_msg(&part); - return -3; - } - - /* if double hyphen ('--') follows we're done */ - if (msgbuf_buf[msgbuf_idx] == '-' && msgbuf_buf[msgbuf_idx+1] == '-') - { - trace(TRACE_DEBUG,"db_add_mime_children(): found end after boundary [%s],\n",splitbound); - trace(TRACE_DEBUG," followed by [%.*s],\n", - 48,&msgbuf_buf[msgbuf_idx]); - - msgbuf_idx += 2; /* skip hyphens */ - - /* probably some newlines will follow (not specified but often there) */ - while (msgbuf_buf[msgbuf_idx] == '\n') - { - totallines++; - msgbuf_idx++; - } + /* add this part to brother list */ + if (list_nodeadd(brothers, &part, sizeof(part)) == NULL) { + trace(TRACE_WARNING, + "db_add_mime_children(): could not add node\n"); + db_free_msg(&part); + return -3; + } - return totallines; - } + /* if double hyphen ('--') follows we're done */ + if (msgbuf_buf[msgbuf_idx] == '-' + && msgbuf_buf[msgbuf_idx + 1] == '-') { + trace(TRACE_DEBUG, + "db_add_mime_children(): found end after boundary [%s],\n", + splitbound); + trace(TRACE_DEBUG, + " followed by [%.*s],\n", + 48, &msgbuf_buf[msgbuf_idx]); + + msgbuf_idx += 2; /* skip hyphens */ + + /* probably some newlines will follow (not specified but often there) */ + while (msgbuf_buf[msgbuf_idx] == '\n') { + totallines++; + msgbuf_idx++; + } + + return totallines; + } - if (msgbuf_buf[msgbuf_idx] == '\n') - { - totallines++; - msgbuf_idx++; /* skip the newline itself */ + if (msgbuf_buf[msgbuf_idx] == '\n') { + totallines++; + msgbuf_idx++; /* skip the newline itself */ + } } - } - while (msgbuf_buf[msgbuf_idx]) ; + while (msgbuf_buf[msgbuf_idx]); - trace(TRACE_WARNING,"db_add_mime_children(): sudden end of message\n"); - return totallines; + trace(TRACE_WARNING, + "db_add_mime_children(): sudden end of message\n"); + return totallines; /* trace(TRACE_ERROR,"db_add_mime_children(): invalid message (no ending boundary found)\n"); return -1; @@ -700,60 +743,61 @@ int db_add_mime_children(struct list *brothers, char *splitbound, int *level, in * * returns -1 on dbase failure, -2 on memory error */ -int db_parse_as_text(mime_message_t *msg) +int db_parse_as_text(mime_message_t * msg) { - int result; - struct mime_record mr; - struct element *el = NULL; - - memset(msg, 0, sizeof(*msg)); - - strcpy(mr.field, "subject"); - strcpy(mr.value, "dbmail IMAP server info: this message could not be parsed"); - el = list_nodeadd(&msg->rfcheader, &mr, sizeof(mr)); - if (!el) - return -3; - - strcpy(mr.field, "from"); - strcpy(mr.value, "imapserver@dbmail.org"); - el = list_nodeadd(&msg->rfcheader, &mr, sizeof(mr)); - if (!el) - return -3; - - msg->rfcheadersize = strlen("subject: dbmail IMAP server info: this message could not be parsed\r\n") - + strlen("from: imapserver@dbmail.org\r\n"); - msg->rfcheaderlines = 4; - - db_give_msgpos(&msg->bodystart); - - /* walk on till end of buffer */ - result = 1; - while (1) - { - for ( ; msgbuf_idx < msgbuf_buflen - 1; msgbuf_idx++) - if (msgbuf_buf[msgbuf_idx] == '\n') - msg->bodylines++; - - if (result == 0) - { - /* end of msg reached, one char left in msgbuf_buf */ - if (msgbuf_buf[msgbuf_idx] == '\n') - msg->bodylines++; - - break; - } + int result; + struct mime_record mr; + struct element *el = NULL; + + memset(msg, 0, sizeof(*msg)); + + strcpy(mr.field, "subject"); + strcpy(mr.value, + "dbmail IMAP server info: this message could not be parsed"); + el = list_nodeadd(&msg->rfcheader, &mr, sizeof(mr)); + if (!el) + return -3; + + strcpy(mr.field, "from"); + strcpy(mr.value, "imapserver@dbmail.org"); + el = list_nodeadd(&msg->rfcheader, &mr, sizeof(mr)); + if (!el) + return -3; + + msg->rfcheadersize = + strlen + ("subject: dbmail IMAP server info: this message could not be parsed\r\n") + + strlen("from: imapserver@dbmail.org\r\n"); + msg->rfcheaderlines = 4; + + db_give_msgpos(&msg->bodystart); + + /* walk on till end of buffer */ + result = 1; + while (1) { + for (; msgbuf_idx < msgbuf_buflen - 1; msgbuf_idx++) + if (msgbuf_buf[msgbuf_idx] == '\n') + msg->bodylines++; + + if (result == 0) { + /* end of msg reached, one char left in msgbuf_buf */ + if (msgbuf_buf[msgbuf_idx] == '\n') + msg->bodylines++; + + break; + } - result = db_update_msgbuf(MSGBUF_FORCE_UPDATE); - if (result == -1) - return -2; - } + result = db_update_msgbuf(MSGBUF_FORCE_UPDATE); + if (result == -1) + return -2; + } - db_give_msgpos(&msg->bodyend); - msg->bodysize = db_give_range_size(&msg->bodystart, &msg->bodyend); + db_give_msgpos(&msg->bodyend); + msg->bodysize = db_give_range_size(&msg->bodystart, &msg->bodyend); - return 0; + return 0; } - + /* * db_msgdump() @@ -761,85 +805,82 @@ int db_parse_as_text(mime_message_t *msg) * dumps a message to stderr * returns the size (in bytes) that the message occupies in memory */ -int db_msgdump(mime_message_t *msg, u64_t msguid, int level) +int db_msgdump(mime_message_t * msg, u64_t msguid, int level) { - struct element *curr; - struct mime_record *mr; - char *spaces; - int size = sizeof(mime_message_t); - - if (level < 0) - return 0; - - if (!msg) - { - trace(TRACE_DEBUG,"db_msgdump: got null\n"); - return 0; - } - - spaces = (char*)my_malloc(3*level + 1); - if (!spaces) - return 0; - - memset(spaces, ' ', 3*level); - spaces[3*level] = 0; - - - trace(TRACE_DEBUG,"%sMIME-header: \n",spaces); - curr = list_getstart(&msg->mimeheader); - if (!curr) - trace(TRACE_DEBUG,"%s%snull\n",spaces,spaces); - else - { - while (curr) - { - mr = (struct mime_record *)curr->data; - trace(TRACE_DEBUG,"%s%s[%s] : [%s]\n",spaces,spaces,mr->field, mr->value); - curr = curr->nextnode; - size += sizeof(struct mime_record); + struct element *curr; + struct mime_record *mr; + char *spaces; + int size = sizeof(mime_message_t); + + if (level < 0) + return 0; + + if (!msg) { + trace(TRACE_DEBUG, "db_msgdump: got null\n"); + return 0; + } + + spaces = (char *) my_malloc(3 * level + 1); + if (!spaces) + return 0; + + memset(spaces, ' ', 3 * level); + spaces[3 * level] = 0; + + + trace(TRACE_DEBUG, "%sMIME-header: \n", spaces); + curr = list_getstart(&msg->mimeheader); + if (!curr) + trace(TRACE_DEBUG, "%s%snull\n", spaces, spaces); + else { + while (curr) { + mr = (struct mime_record *) curr->data; + trace(TRACE_DEBUG, "%s%s[%s] : [%s]\n", spaces, + spaces, mr->field, mr->value); + curr = curr->nextnode; + size += sizeof(struct mime_record); + } } - } - trace(TRACE_DEBUG,"%s*** MIME-header end\n",spaces); - - trace(TRACE_DEBUG,"%sRFC822-header: \n",spaces); - curr = list_getstart(&msg->rfcheader); - if (!curr) - trace(TRACE_DEBUG,"%s%snull\n",spaces,spaces); - else - { - while (curr) - { - mr = (struct mime_record *)curr->data; - trace(TRACE_DEBUG,"%s%s[%s] : [%s]\n",spaces,spaces,mr->field, mr->value); - curr = curr->nextnode; - size += sizeof(struct mime_record); + trace(TRACE_DEBUG, "%s*** MIME-header end\n", spaces); + + trace(TRACE_DEBUG, "%sRFC822-header: \n", spaces); + curr = list_getstart(&msg->rfcheader); + if (!curr) + trace(TRACE_DEBUG, "%s%snull\n", spaces, spaces); + else { + while (curr) { + mr = (struct mime_record *) curr->data; + trace(TRACE_DEBUG, "%s%s[%s] : [%s]\n", spaces, + spaces, mr->field, mr->value); + curr = curr->nextnode; + size += sizeof(struct mime_record); + } } - } - trace(TRACE_DEBUG,"%s*** RFC822-header end\n",spaces); + trace(TRACE_DEBUG, "%s*** RFC822-header end\n", spaces); + + trace(TRACE_DEBUG, "%s*** Body range:\n", spaces); + trace(TRACE_DEBUG, + "%s%s(%llu, %llu) - (%llu, %llu), size: %llu, newlines: %llu\n", + spaces, spaces, msg->bodystart.block, msg->bodystart.pos, + msg->bodyend.block, msg->bodyend.pos, msg->bodysize, + msg->bodylines); - trace(TRACE_DEBUG,"%s*** Body range:\n",spaces); - trace(TRACE_DEBUG,"%s%s(%llu, %llu) - (%llu, %llu), size: %llu, newlines: %llu\n", - spaces,spaces, - msg->bodystart.block, msg->bodystart.pos, - msg->bodyend.block, msg->bodyend.pos, - msg->bodysize, msg->bodylines); - /* trace(TRACE_DEBUG,"body: \n"); db_dump_range(msg->bodystart, msg->bodyend, msguid); trace(TRACE_DEBUG,"*** body end\n"); */ - trace(TRACE_DEBUG,"%sChildren of this msg:\n",spaces); - - curr = list_getstart(&msg->children); - while (curr) - { - size += db_msgdump((mime_message_t*)curr->data,msguid,level+1); - curr = curr->nextnode; - } - trace(TRACE_DEBUG,"%s*** child list end\n",spaces); - - my_free(spaces); - return size; -} + trace(TRACE_DEBUG, "%sChildren of this msg:\n", spaces); + + curr = list_getstart(&msg->children); + while (curr) { + size += + db_msgdump((mime_message_t *) curr->data, msguid, + level + 1); + curr = curr->nextnode; + } + trace(TRACE_DEBUG, "%s*** child list end\n", spaces); + my_free(spaces); + return size; +} @@ -32,13 +32,15 @@ #include "dbmailtypes.h" -void db_free_msg(mime_message_t *msg); -void db_reverse_msg(mime_message_t *msg); - -int db_fetch_headers(u64_t msguid, mime_message_t *msg); -int db_add_mime_children(struct list *brothers, char *splitbound, int *level, int maxlevel); -int db_start_msg(mime_message_t *msg, char *stopbound, int *level, int maxlevel); -int db_parse_as_text(mime_message_t *msg); -int db_msgdump(mime_message_t *msg, u64_t msguid, int level); +void db_free_msg(mime_message_t * msg); +void db_reverse_msg(mime_message_t * msg); + +int db_fetch_headers(u64_t msguid, mime_message_t * msg); +int db_add_mime_children(struct list *brothers, char *splitbound, + int *level, int maxlevel); +int db_start_msg(mime_message_t * msg, char *stopbound, int *level, + int maxlevel); +int db_parse_as_text(mime_message_t * msg); +int db_msgdump(mime_message_t * msg, u64_t msguid, int level); #endif @@ -53,246 +53,253 @@ int Restart = 0; pid_t ParentPID = 0; /* some extra prototypes (defintions are below) */ -static void ParentSigHandler(int sig, siginfo_t *info, void *data); +static void ParentSigHandler(int sig, siginfo_t * info, void *data); static int SetParentSigHandler(void); int SetParentSigHandler() { - struct sigaction act; - - /* init & install signal handlers */ - memset(&act, 0, sizeof(act)); - - act.sa_sigaction = ParentSigHandler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - - sigaction(SIGCHLD, &act, 0); - sigaction(SIGINT, &act, 0); - sigaction(SIGQUIT, &act, 0); - sigaction(SIGILL, &act, 0); - sigaction(SIGBUS, &act, 0); - sigaction(SIGFPE, &act, 0); - sigaction(SIGSEGV, &act, 0); - sigaction(SIGTERM, &act, 0); - sigaction(SIGALRM, &act, 0); - sigaction(SIGHUP, &act, 0); - - return 0; + struct sigaction act; + + /* init & install signal handlers */ + memset(&act, 0, sizeof(act)); + + act.sa_sigaction = ParentSigHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + + sigaction(SIGCHLD, &act, 0); + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); + sigaction(SIGILL, &act, 0); + sigaction(SIGBUS, &act, 0); + sigaction(SIGFPE, &act, 0); + sigaction(SIGSEGV, &act, 0); + sigaction(SIGTERM, &act, 0); + sigaction(SIGALRM, &act, 0); + sigaction(SIGHUP, &act, 0); + + return 0; } -int StartServer(serverConfig_t *conf) +int StartServer(serverConfig_t * conf) { - int i,stillSomeAlive,cnt; - pid_t *pid = (pid_t*)malloc(sizeof(pid_t) * conf->nChildren); - ChildInfo_t childinfo; + int i, stillSomeAlive, cnt; + pid_t *pid = (pid_t *) malloc(sizeof(pid_t) * conf->nChildren); + ChildInfo_t childinfo; - if (!pid) - trace(TRACE_FATAL, "StartServer(): no memory for PID list. Fatal."); + if (!pid) + trace(TRACE_FATAL, + "StartServer(): no memory for PID list. Fatal."); - if (!conf) - trace(TRACE_FATAL, "StartServer(): NULL configuration"); + if (!conf) + trace(TRACE_FATAL, "StartServer(): NULL configuration"); - trace(TRACE_DEBUG, "StartServer(): init"); + trace(TRACE_DEBUG, "StartServer(): init"); - ParentPID = getpid(); - Restart = 0; - GeneralStopRequested = 0; - SetParentSigHandler(); + ParentPID = getpid(); + Restart = 0; + GeneralStopRequested = 0; + SetParentSigHandler(); // AllocSharedMemory(); // AttachSharedMemory(); - trace(TRACE_DEBUG, "StartServer(): init ok. Creating children.."); + trace(TRACE_DEBUG, "StartServer(): init ok. Creating children.."); - childinfo.maxConnect = conf->childMaxConnect; - childinfo.listenSocket = conf->listenSocket; - childinfo.timeout = conf->timeout; - childinfo.ClientHandler = conf->ClientHandler; - childinfo.timeoutMsg = conf->timeoutMsg; - childinfo.resolveIP = conf->resolveIP; + childinfo.maxConnect = conf->childMaxConnect; + childinfo.listenSocket = conf->listenSocket; + childinfo.timeout = conf->timeout; + childinfo.ClientHandler = conf->ClientHandler; + childinfo.timeoutMsg = conf->timeoutMsg; + childinfo.resolveIP = conf->resolveIP; - for (i=0; i<conf->nChildren; i++) - { - if ( (pid[i] = CreateChild(&childinfo)) == -1) - { - trace(TRACE_ERROR, "StartServer(): could not create child"); - trace(TRACE_ERROR, "StartServer(): killing children"); - - while (--i >= 0) - kill(pid[i], SIGKILL); + for (i = 0; i < conf->nChildren; i++) { + if ((pid[i] = CreateChild(&childinfo)) == -1) { + trace(TRACE_ERROR, + "StartServer(): could not create child"); + trace(TRACE_ERROR, + "StartServer(): killing children"); - trace(TRACE_FATAL, "StartServer(): could not create children. Fatal."); - } - } - - trace(TRACE_DEBUG, "StartServer(): children created, starting main service loop"); - - while (!GeneralStopRequested) - { - for (i=0; i<conf->nChildren; i++) - { - if (waitpid(pid[i], NULL, WNOHANG|WUNTRACED) == pid[i]) - { - trace(TRACE_DEBUG, "StartServer(): child [%u] has exited", (unsigned)pid[i]); - trace(TRACE_DEBUG, "StartServer(): creating new child"); - pid[i] = CreateChild(&childinfo); - } + while (--i >= 0) + kill(pid[i], SIGKILL); + + trace(TRACE_FATAL, + "StartServer(): could not create children. Fatal."); + } } - sleep(1); - } - - trace(TRACE_INFO, "StartServer(): General stop requested. Killing children.. "); - - stillSomeAlive = 1; - cnt = 0; - while (stillSomeAlive && cnt < 10) - { - stillSomeAlive = 0; - cnt++; - - for (i=0; i<conf->nChildren; i++) - { - if (pid[i] == 0) - continue; - - if (CheckChildAlive(pid[i])) - { - trace(TRACE_DEBUG, "StartServer(): child [%d] is still alive, sending SIGTERM", pid[i]); - kill(pid[i], SIGTERM); - usleep(1000); - } - else - trace(TRACE_DEBUG, "StartServer(): child [%d] is dead, zombie not yet cleaned", pid[i]); - - - if (waitpid(pid[i], NULL, WNOHANG|WUNTRACED) == pid[i]) - { - trace(TRACE_DEBUG, "StartServer(): child [%d] has exited, zombie cleaned up", pid[i]); - pid[i] = 0; - } - else - { - stillSomeAlive = 1; - trace(TRACE_DEBUG, "StartServer(): child [%d] hasn't provided exit status yet", pid[i]); - } + trace(TRACE_DEBUG, + "StartServer(): children created, starting main service loop"); + + while (!GeneralStopRequested) { + for (i = 0; i < conf->nChildren; i++) { + if (waitpid(pid[i], NULL, WNOHANG | WUNTRACED) == + pid[i]) { + trace(TRACE_DEBUG, + "StartServer(): child [%u] has exited", + (unsigned) pid[i]); + trace(TRACE_DEBUG, + "StartServer(): creating new child"); + pid[i] = CreateChild(&childinfo); + } + } + + sleep(1); } - - if (stillSomeAlive) - usleep(500); - } - - if (stillSomeAlive) - { - trace(TRACE_INFO, "StartServer(): not all children terminated at SIGTERM, killing hard now"); - - for (i=0; i<conf->nChildren; i++) - { - if (pid[i] != 0) - kill(pid[i], SIGKILL);; + + trace(TRACE_INFO, + "StartServer(): General stop requested. Killing children.. "); + + stillSomeAlive = 1; + cnt = 0; + while (stillSomeAlive && cnt < 10) { + stillSomeAlive = 0; + cnt++; + + for (i = 0; i < conf->nChildren; i++) { + if (pid[i] == 0) + continue; + + if (CheckChildAlive(pid[i])) { + trace(TRACE_DEBUG, + "StartServer(): child [%d] is still alive, sending SIGTERM", + pid[i]); + kill(pid[i], SIGTERM); + usleep(1000); + } else + trace(TRACE_DEBUG, + "StartServer(): child [%d] is dead, zombie not yet cleaned", + pid[i]); + + + if (waitpid(pid[i], NULL, WNOHANG | WUNTRACED) == + pid[i]) { + trace(TRACE_DEBUG, + "StartServer(): child [%d] has exited, zombie cleaned up", + pid[i]); + pid[i] = 0; + } else { + stillSomeAlive = 1; + trace(TRACE_DEBUG, + "StartServer(): child [%d] hasn't provided exit status yet", + pid[i]); + } + } + + if (stillSomeAlive) + usleep(500); } - } + if (stillSomeAlive) { + trace(TRACE_INFO, + "StartServer(): not all children terminated at SIGTERM, killing hard now"); + + for (i = 0; i < conf->nChildren; i++) { + if (pid[i] != 0) + kill(pid[i], SIGKILL);; + } + } // DeleteSharedMemory(); - free(pid); - return Restart; + free(pid); + return Restart; } - -void ParentSigHandler(int sig, siginfo_t *info, void *data) -{ - if (ParentPID != getpid()) - { - trace(TRACE_INFO, "ParentSigHandler(): i'm no longer father"); - ChildSigHandler(sig, info, data); /* this call is for a child but it's handler is not yet installed */ - } +void ParentSigHandler(int sig, siginfo_t * info, void *data) +{ + if (ParentPID != getpid()) { + trace(TRACE_INFO, + "ParentSigHandler(): i'm no longer father"); + ChildSigHandler(sig, info, data); /* this call is for a child but it's handler is not yet installed */ + } #ifdef _USE_STR_SIGNAL - trace(TRACE_INFO, "ParentSigHandler(): got signal [%s]", strsignal(sig)); + trace(TRACE_INFO, "ParentSigHandler(): got signal [%s]", + strsignal(sig)); #else - trace(TRACE_INFO, "ParentSigHandler(): got signal [%d]", sig); + trace(TRACE_INFO, "ParentSigHandler(): got signal [%d]", sig); #endif - switch (sig) - { - case SIGCHLD: - break; /* ignore, wait for child in main loop */ + switch (sig) { + case SIGCHLD: + break; /* ignore, wait for child in main loop */ - case SIGHUP: - trace(TRACE_DEBUG, "ParentSigHandler(): SIGHUP, setting Restart"); - Restart = 1; + case SIGHUP: + trace(TRACE_DEBUG, + "ParentSigHandler(): SIGHUP, setting Restart"); + Restart = 1; - default: - GeneralStopRequested = 1; - } + default: + GeneralStopRequested = 1; + } } -int CreateSocket(serverConfig_t *conf) +int CreateSocket(serverConfig_t * conf) { - int sock, r, len; - struct sockaddr_in saServer; - int so_reuseaddress = 1; /**< reuseaddr to 1, so address will be reused */ - - /* make a tcp/ip socket */ - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock == -1) - trace(TRACE_FATAL, "CreateSocket(): socket creation failed [%s]", strerror(errno)); - - trace(TRACE_DEBUG, "CreateSocket(): socket created"); - - /* make an (socket)address */ - memset(&saServer, 0, sizeof(saServer)); - - saServer.sin_family = AF_INET; - saServer.sin_port = htons(conf->port); - - if (conf->ip[0] == '*') - saServer.sin_addr.s_addr = htonl(INADDR_ANY); - else - { - r = inet_aton(conf->ip, &saServer.sin_addr); - if (!r) - { - close(sock); - trace(TRACE_FATAL, "CreateSocket(): invalid IP [%s]", conf->ip); + int sock, r, len; + struct sockaddr_in saServer; + int so_reuseaddress = 1; + /**< reuseaddr to 1, so address will be reused */ + + /* make a tcp/ip socket */ + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock == -1) + trace(TRACE_FATAL, + "CreateSocket(): socket creation failed [%s]", + strerror(errno)); + + trace(TRACE_DEBUG, "CreateSocket(): socket created"); + + /* make an (socket)address */ + memset(&saServer, 0, sizeof(saServer)); + + saServer.sin_family = AF_INET; + saServer.sin_port = htons(conf->port); + + if (conf->ip[0] == '*') + saServer.sin_addr.s_addr = htonl(INADDR_ANY); + else { + r = inet_aton(conf->ip, &saServer.sin_addr); + if (!r) { + close(sock); + trace(TRACE_FATAL, + "CreateSocket(): invalid IP [%s]", conf->ip); + } } - } - trace(TRACE_DEBUG, "CreateSocket(): socket IP requested [%s] OK", conf->ip); + trace(TRACE_DEBUG, "CreateSocket(): socket IP requested [%s] OK", + conf->ip); - /* set socket option: reuse address */ - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddress, sizeof(so_reuseaddress)); + /* set socket option: reuse address */ + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddress, + sizeof(so_reuseaddress)); - /* bind the address */ - len = sizeof(saServer); - r = bind(sock, (struct sockaddr*)&saServer, len); + /* bind the address */ + len = sizeof(saServer); + r = bind(sock, (struct sockaddr *) &saServer, len); - if (r == -1) - { - close(sock); - trace(TRACE_FATAL, "CreateSocket(): could not bind address to socket"); - } - - trace(TRACE_DEBUG, "CreateSocket(): IP bound to socket"); + if (r == -1) { + close(sock); + trace(TRACE_FATAL, + "CreateSocket(): could not bind address to socket"); + } - r = listen(sock, BACKLOG); - if (r == -1) - { - close(sock); - trace(TRACE_FATAL, "CreateSocket(): error making socket listen [%s]", strerror(errno)); - } - - trace(TRACE_INFO, "CreateSocket(): socket creation complete"); - conf->listenSocket = sock; + trace(TRACE_DEBUG, "CreateSocket(): IP bound to socket"); - return 0; -} - + r = listen(sock, BACKLOG); + if (r == -1) { + close(sock); + trace(TRACE_FATAL, + "CreateSocket(): error making socket listen [%s]", + strerror(errno)); + } + trace(TRACE_INFO, "CreateSocket(): socket creation complete"); + conf->listenSocket = sock; + return 0; +} @@ -37,26 +37,20 @@ #include "dbmail.h" #include "clientinfo.h" -typedef struct -{ - int listenSocket; - int nChildren; - int childMaxConnect; - int timeout; - char ip[IPLEN]; - int port; - int resolveIP; - char *timeoutMsg; - field_t serverUser, serverGroup; - int (*ClientHandler)(clientinfo_t *); +typedef struct { + int listenSocket; + int nChildren; + int childMaxConnect; + int timeout; + char ip[IPLEN]; + int port; + int resolveIP; + char *timeoutMsg; + field_t serverUser, serverGroup; + int (*ClientHandler) (clientinfo_t *); } serverConfig_t; -int CreateSocket(serverConfig_t *conf); -int StartServer(serverConfig_t *conf); +int CreateSocket(serverConfig_t * conf); +int StartServer(serverConfig_t * conf); #endif - - - - - diff --git a/serverchild.c b/serverchild.c index a988ef9c..cc634041 100644 --- a/serverchild.c +++ b/serverchild.c @@ -56,128 +56,129 @@ int ChildStopRequested = 0; int connected = 0; clientinfo_t client; -int PerformChildTask(ChildInfo_t *info); +int PerformChildTask(ChildInfo_t * info); -void ChildSigHandler(int sig, siginfo_t *info UNUSED, void *data UNUSED) +void ChildSigHandler(int sig, siginfo_t * info UNUSED, void *data UNUSED) { - static int triedDisconnect = 0; + static int triedDisconnect = 0; #ifdef _USE_STR_SIGNAL - trace(TRACE_ERROR, "ChildSighandler(): got signal [%s]", strsignal(sig)); + trace(TRACE_ERROR, "ChildSighandler(): got signal [%s]", + strsignal(sig)); #else - trace(TRACE_ERROR, "ChildSighandler(): got signal [%d]", sig); + trace(TRACE_ERROR, "ChildSighandler(): got signal [%d]", sig); #endif - /* perform reinit at SIGHUP otherwise exit */ - switch (sig) - { - case SIGALRM: - trace(TRACE_DEBUG, "ChildSighandler(): timeout received"); - - if (client.tx) - { - trace(TRACE_DEBUG, "ChildSighandler(): write stream open, closing"); - fprintf(client.tx, "%s", client.timeoutMsg); - fflush(client.tx); - fclose(client.tx); /* closes clientSocket as well */ - client.tx = NULL; + /* perform reinit at SIGHUP otherwise exit */ + switch (sig) { + case SIGALRM: + trace(TRACE_DEBUG, "ChildSighandler(): timeout received"); + + if (client.tx) { + trace(TRACE_DEBUG, + "ChildSighandler(): write stream open, closing"); + fprintf(client.tx, "%s", client.timeoutMsg); + fflush(client.tx); + fclose(client.tx); /* closes clientSocket as well */ + client.tx = NULL; + } + + if (client.rx) { + trace(TRACE_DEBUG, + "ChildSighandler(): read stream open, closing"); + shutdown(fileno(client.rx), SHUT_RDWR); + fclose(client.rx); + client.rx = NULL; + } + + break; + + case SIGHUP: + case SIGTERM: + case SIGQUIT: + case SIGSTOP: + if (ChildStopRequested) { + trace(TRACE_DEBUG, + "ChildSighandler(): already caught a stop request. Closing right now"); + + /* already caught this signal, exit the hard way now */ + if (client.tx) { + trace(TRACE_DEBUG, + "ChildSighandler(): write stream still open, closing"); + fflush(client.tx); + fclose(client.tx); /* closes clientSocket as well */ + client.tx = NULL; + } + + if (client.rx) { + trace(TRACE_DEBUG, + "ChildSighandler(): read stream still open, closing"); + shutdown(fileno(client.rx), SHUT_RDWR); + fclose(client.rx); + client.rx = NULL; + } + + if (connected) { + trace(TRACE_DEBUG, + "ChildSighandler(): database connection still open, closing"); + db_disconnect(); + auth_disconnect(); + connected = 0; + } + + trace(TRACE_DEBUG, "ChildSighandler(): exit"); + exit(1); + } + trace(TRACE_DEBUG, + "ChildSighandler(): setting stop request"); + ChildStopRequested = 1; + break; + + default: + /* bad shtuff, exit */ + trace(TRACE_DEBUG, + "ChildSighandler(): cannot ignore this. Terminating"); + + /* + * For some reason i have not yet determined the process starts eating up + * all CPU time when trying to disconnect. + * For now: just bail out :-) + */ + _exit(1); + + if (!triedDisconnect) { + triedDisconnect = 1; + + if (client.tx) { + trace(TRACE_DEBUG, + "ChildSighandler(): write stream still open, closing"); + fflush(client.tx); + fclose(client.tx); /* closes clientSocket as well */ + client.tx = NULL; + } + + if (client.rx) { + trace(TRACE_DEBUG, + "ChildSighandler(): read stream still open, closing"); + shutdown(fileno(client.rx), SHUT_RDWR); + fclose(client.rx); + client.rx = NULL; + } + + if (connected) { + trace(TRACE_DEBUG, + "ChildSighandler(): database connection still open, closing"); + db_disconnect(); + auth_disconnect(); + } + + connected = 0; + } + + trace(TRACE_DEBUG, "ChildSighandler(): exit"); + exit(1); } - - if (client.rx) - { - trace(TRACE_DEBUG, "ChildSighandler(): read stream open, closing"); - shutdown(fileno(client.rx), SHUT_RDWR); - fclose(client.rx); - client.rx = NULL; - } - - break; - - case SIGHUP: - case SIGTERM: - case SIGQUIT: - case SIGSTOP: - if (ChildStopRequested) - { - trace(TRACE_DEBUG, "ChildSighandler(): already caught a stop request. Closing right now"); - - /* already caught this signal, exit the hard way now */ - if (client.tx) - { - trace(TRACE_DEBUG, "ChildSighandler(): write stream still open, closing"); - fflush(client.tx); - fclose(client.tx); /* closes clientSocket as well */ - client.tx = NULL; - } - - if (client.rx) - { - trace(TRACE_DEBUG, "ChildSighandler(): read stream still open, closing"); - shutdown(fileno(client.rx), SHUT_RDWR); - fclose(client.rx); - client.rx = NULL; - } - - if (connected) - { - trace(TRACE_DEBUG, "ChildSighandler(): database connection still open, closing"); - db_disconnect(); - auth_disconnect(); - connected = 0; - } - - trace(TRACE_DEBUG, "ChildSighandler(): exit"); - exit(1); - } - trace(TRACE_DEBUG, "ChildSighandler(): setting stop request"); - ChildStopRequested = 1; - break; - - default: - /* bad shtuff, exit */ - trace(TRACE_DEBUG, "ChildSighandler(): cannot ignore this. Terminating"); - - /* - * For some reason i have not yet determined the process starts eating up - * all CPU time when trying to disconnect. - * For now: just bail out :-) - */ - _exit(1); - - if (!triedDisconnect) - { - triedDisconnect = 1; - - if (client.tx) - { - trace(TRACE_DEBUG, "ChildSighandler(): write stream still open, closing"); - fflush(client.tx); - fclose(client.tx); /* closes clientSocket as well */ - client.tx = NULL; - } - - if (client.rx) - { - trace(TRACE_DEBUG, "ChildSighandler(): read stream still open, closing"); - shutdown(fileno(client.rx), SHUT_RDWR); - fclose(client.rx); - client.rx = NULL; - } - - if (connected) - { - trace(TRACE_DEBUG, "ChildSighandler(): database connection still open, closing"); - db_disconnect(); - auth_disconnect(); - } - - connected = 0; - } - - trace(TRACE_DEBUG, "ChildSighandler(): exit"); - exit(1); - } } @@ -189,27 +190,27 @@ void ChildSigHandler(int sig, siginfo_t *info UNUSED, void *data UNUSED) */ int SetChildSigHandler() { - struct sigaction act; - - /* init & install signal handlers */ - memset(&act, 0, sizeof(act)); - - act.sa_sigaction = ChildSigHandler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - - sigaction(SIGINT, &act, 0); - sigaction(SIGQUIT, &act, 0); - sigaction(SIGILL, &act, 0); - sigaction(SIGBUS, &act, 0); - sigaction(SIGPIPE, &act, 0); - sigaction(SIGFPE, &act, 0); - sigaction(SIGSEGV, &act, 0); - sigaction(SIGTERM, &act, 0); - sigaction(SIGHUP, &act, 0); - sigaction(SIGALRM, &act, 0); - - return 0; + struct sigaction act; + + /* init & install signal handlers */ + memset(&act, 0, sizeof(act)); + + act.sa_sigaction = ChildSigHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); + sigaction(SIGILL, &act, 0); + sigaction(SIGBUS, &act, 0); + sigaction(SIGPIPE, &act, 0); + sigaction(SIGFPE, &act, 0); + sigaction(SIGSEGV, &act, 0); + sigaction(SIGTERM, &act, 0); + sigaction(SIGHUP, &act, 0); + sigaction(SIGALRM, &act, 0); + + return 0; } @@ -218,21 +219,22 @@ int SetChildSigHandler() * * creates a new child, returning only to the parent process */ -pid_t CreateChild(ChildInfo_t *info) +pid_t CreateChild(ChildInfo_t * info) { - pid_t pid = fork(); - - if (pid != 0) - return pid; + pid_t pid = fork(); - ChildStopRequested = 0; - SetChildSigHandler(); - trace(TRACE_INFO, "CreateChild(): signal handler placed, going to perform task now"); + if (pid != 0) + return pid; - PerformChildTask(info); + ChildStopRequested = 0; + SetChildSigHandler(); + trace(TRACE_INFO, + "CreateChild(): signal handler placed, going to perform task now"); - usleep(10000); - exit(0); + PerformChildTask(info); + + usleep(10000); + exit(0); } @@ -242,138 +244,144 @@ pid_t CreateChild(ChildInfo_t *info) */ int CheckChildAlive(pid_t pid) { - return (kill(pid, 0) == -1) ? 0 : 1; + return (kill(pid, 0) == -1) ? 0 : 1; } -int PerformChildTask(ChildInfo_t *info) +int PerformChildTask(ChildInfo_t * info) { - int i,len,clientSocket; - struct sockaddr_in saClient; - struct hostent *clientHost; - - if (!info) - { - trace(TRACE_ERROR, "PerformChildTask(): NULL info supplied"); - return -1; - } - - if (db_connect() != 0) - { - trace(TRACE_ERROR, "PerformChildTask(): could not connect to database"); - return -1; - } - - if (auth_connect() != 0) - { - trace(TRACE_ERROR, "PerformChildTask(): could not connect to authentication"); - return -1; - } - - srand((int) ((int) time(NULL) + (int) getpid()) ); - connected = 1; - - for (i=0; i<info->maxConnect && !ChildStopRequested; i++) - { - trace(TRACE_INFO, "PerformChildTask(): waiting for connection"); - - /* wait for connect */ - len = sizeof(saClient); - clientSocket = accept(info->listenSocket, (struct sockaddr*)&saClient, &len); - - if (clientSocket == -1) - { - i--; /* don't count this as a connect */ - trace(TRACE_INFO, "PerformChildTask(): accept failed"); - continue; /* accept failed, refuse connection & continue */ + int i, len, clientSocket; + struct sockaddr_in saClient; + struct hostent *clientHost; + + if (!info) { + trace(TRACE_ERROR, + "PerformChildTask(): NULL info supplied"); + return -1; } - memset(&client, 0, sizeof(client)); /* zero-init */ - - client.timeoutMsg = info->timeoutMsg; - client.timeout = info->timeout; - strncpy(client.ip, inet_ntoa(saClient.sin_addr), IPNUM_LEN); - client.clientname[0] = '\0'; - - if (info->resolveIP) - { - clientHost = gethostbyaddr((char *)&saClient.sin_addr, - sizeof(saClient.sin_addr), - saClient.sin_family); - - if (clientHost && clientHost->h_name) - strncpy(client.clientname, clientHost->h_name, FIELDSIZE); - - trace (TRACE_MESSAGE,"PerformChildTask(): incoming connection from [%s (%s)]", - client.ip, client.clientname[0] ? client.clientname : "Lookup failed"); - } - else - { - trace (TRACE_MESSAGE,"PerformChildTask(): incoming connection from [%s]", - client.ip); + if (db_connect() != 0) { + trace(TRACE_ERROR, + "PerformChildTask(): could not connect to database"); + return -1; } - /* make streams */ - if (! (client.rx = fdopen(dup(clientSocket), "r")) ) - { - /* read-FILE opening failure */ - trace(TRACE_ERROR, "PerformChildTask(): error opening read file stream"); - close(clientSocket); - continue; - } - - if (! (client.tx = fdopen(clientSocket, "w")) ) - { - /* write-FILE opening failure */ - trace(TRACE_ERROR, "PerformChildTask(): error opening write file stream"); - fclose(client.rx); - close(clientSocket); - memset(&client, 0, sizeof(client)); - continue; + if (auth_connect() != 0) { + trace(TRACE_ERROR, + "PerformChildTask(): could not connect to authentication"); + return -1; } - - setlinebuf(client.tx); - setlinebuf(client.rx); - - trace(TRACE_DEBUG, "PerformChildTask(): client info init complete, calling client handler"); - - /* streams are ready, perform handling */ - info->ClientHandler(&client); + + srand((int) ((int) time(NULL) + (int) getpid())); + connected = 1; + + for (i = 0; i < info->maxConnect && !ChildStopRequested; i++) { + trace(TRACE_INFO, + "PerformChildTask(): waiting for connection"); + + /* wait for connect */ + len = sizeof(saClient); + clientSocket = + accept(info->listenSocket, + (struct sockaddr *) &saClient, &len); + + if (clientSocket == -1) { + i--; /* don't count this as a connect */ + trace(TRACE_INFO, + "PerformChildTask(): accept failed"); + continue; /* accept failed, refuse connection & continue */ + } + + memset(&client, 0, sizeof(client)); /* zero-init */ + + client.timeoutMsg = info->timeoutMsg; + client.timeout = info->timeout; + strncpy(client.ip, inet_ntoa(saClient.sin_addr), + IPNUM_LEN); + client.clientname[0] = '\0'; + + if (info->resolveIP) { + clientHost = + gethostbyaddr((char *) &saClient.sin_addr, + sizeof(saClient.sin_addr), + saClient.sin_family); + + if (clientHost && clientHost->h_name) + strncpy(client.clientname, + clientHost->h_name, FIELDSIZE); + + trace(TRACE_MESSAGE, + "PerformChildTask(): incoming connection from [%s (%s)]", + client.ip, + client.clientname[0] ? client. + clientname : "Lookup failed"); + } else { + trace(TRACE_MESSAGE, + "PerformChildTask(): incoming connection from [%s]", + client.ip); + } + + /* make streams */ + if (!(client.rx = fdopen(dup(clientSocket), "r"))) { + /* read-FILE opening failure */ + trace(TRACE_ERROR, + "PerformChildTask(): error opening read file stream"); + close(clientSocket); + continue; + } + + if (!(client.tx = fdopen(clientSocket, "w"))) { + /* write-FILE opening failure */ + trace(TRACE_ERROR, + "PerformChildTask(): error opening write file stream"); + fclose(client.rx); + close(clientSocket); + memset(&client, 0, sizeof(client)); + continue; + } + + setlinebuf(client.tx); + setlinebuf(client.rx); + + trace(TRACE_DEBUG, + "PerformChildTask(): client info init complete, calling client handler"); + + /* streams are ready, perform handling */ + info->ClientHandler(&client); #ifdef PROC_TITLES - set_proc_title("%s", "Idle"); + set_proc_title("%s", "Idle"); #endif - trace(TRACE_DEBUG, "PerformChildTask(): client handling complete, closing streams"); + trace(TRACE_DEBUG, + "PerformChildTask(): client handling complete, closing streams"); - if (client.tx) - { - fflush(client.tx); - fclose(client.tx); /* closes clientSocket as well */ - client.tx = NULL; - } + if (client.tx) { + fflush(client.tx); + fclose(client.tx); /* closes clientSocket as well */ + client.tx = NULL; + } + + if (client.rx) { + shutdown(fileno(client.rx), SHUT_RDWR); + fclose(client.rx); + client.rx = NULL; + } - if (client.rx) - { - shutdown(fileno(client.rx), SHUT_RDWR); - fclose(client.rx); - client.rx = NULL; + trace(TRACE_INFO, "PerformChildTask(): connection closed"); } - - trace(TRACE_INFO, "PerformChildTask(): connection closed"); - } - - db_disconnect(); - auth_disconnect(); - connected = 0; /* FIXME a signal between this line and the previous one - * would screw things up. Would like to have all this in - * db_disconnect() making 'connected' obsolete - */ - - if (!ChildStopRequested) - trace(TRACE_ERROR, "PerformChildTask(): maximum number of connections reached, stopping now"); - else - trace(TRACE_ERROR, "PerformChildTask(): stop requested"); - - return 0; -} + db_disconnect(); + auth_disconnect(); + connected = 0; /* FIXME a signal between this line and the previous one + * would screw things up. Would like to have all this in + * db_disconnect() making 'connected' obsolete + */ + + if (!ChildStopRequested) + trace(TRACE_ERROR, + "PerformChildTask(): maximum number of connections reached, stopping now"); + else + trace(TRACE_ERROR, "PerformChildTask(): stop requested"); + + return 0; +} diff --git a/serverchild.h b/serverchild.h index 4fe7188d..4dd25751 100644 --- a/serverchild.h +++ b/serverchild.h @@ -35,20 +35,19 @@ #include <signal.h> #include "clientinfo.h" -typedef struct -{ - int maxConnect; - int listenSocket; - int resolveIP; - int timeout; - char *timeoutMsg; - int (*ClientHandler)(clientinfo_t *); +typedef struct { + int maxConnect; + int listenSocket; + int resolveIP; + int timeout; + char *timeoutMsg; + int (*ClientHandler) (clientinfo_t *); } ChildInfo_t; -void ChildSigHandler(int sig, siginfo_t *info, void *data); +void ChildSigHandler(int sig, siginfo_t * info, void *data); int CheckChildAlive(pid_t pid); int SetChildSigHandler(void); -pid_t CreateChild(ChildInfo_t *info); +pid_t CreateChild(ChildInfo_t * info); #endif @@ -14,80 +14,75 @@ #define LINE_BUFFER_SIZE 516 -int main (int argc, char *argv[]) +int main(int argc, char *argv[]) { - FILE *configfile; - char *readbuf, *field, *val,*fname; - int i; - - readbuf = (char *)malloc(LINE_BUFFER_SIZE); - - printf("*** dbmail-config ***\n\n"); - if (argc<2) - { - printf("No configuration file specified, using %s\n",DEFAULT_CONFIG_FILE); - fname = DEFAULT_CONFIG_FILE; - } - else - { - fname = argv[1]; - } + FILE *configfile; + char *readbuf, *field, *val, *fname; + int i; - if (db_connect() != 0) - { - printf ("Could not connect to database.\n"); - return -1; - } - - if (auth_connect() != 0) - { - printf ("Could not connect to authentication.\n"); - return -1; - } - - printf("reading configuration for %s...\n", fname); - configfile = fopen(fname,"r"); /* open the configuration file */ - if (configfile == NULL) /* error test */ - { - fprintf (stderr,"Error: can not open input file %s\n",fname); - return 8; - } - - i = 0; - - /* clear existing configuration */ - db_clear_config(); + readbuf = (char *) malloc(LINE_BUFFER_SIZE); - while (!feof(configfile)) - { - fgets (readbuf, LINE_BUFFER_SIZE,configfile); - if (readbuf != NULL) - { - i++; - readbuf[strlen(readbuf)-1]='\0'; - if ((readbuf[0] != '#') && (strlen(readbuf)>3)) /* ignore comments */ - { - val = strchr(readbuf, '='); - field = readbuf; - if (!val) - { - fprintf (stderr,"Configread error in line: %d\n",i); - } - else - { - *val='\0'; - val++; - if (db_insert_config_item (field, val) != 0) - fprintf (stderr,"error in line:%d, could not insert item\n",i); - else - printf ("%s is now set to %s\n",field,val); - } - } + printf("*** dbmail-config ***\n\n"); + if (argc < 2) { + printf("No configuration file specified, using %s\n", + DEFAULT_CONFIG_FILE); + fname = DEFAULT_CONFIG_FILE; + } else { + fname = argv[1]; } - else - fprintf (stderr,"end of buffer\n"); - - } - return 0; -} + if (db_connect() != 0) { + printf("Could not connect to database.\n"); + return -1; + } + + if (auth_connect() != 0) { + printf("Could not connect to authentication.\n"); + return -1; + } + + printf("reading configuration for %s...\n", fname); + configfile = fopen(fname, "r"); /* open the configuration file */ + if (configfile == NULL) { /* error test */ + fprintf(stderr, "Error: can not open input file %s\n", + fname); + return 8; + } + + i = 0; + + /* clear existing configuration */ + db_clear_config(); + + while (!feof(configfile)) { + fgets(readbuf, LINE_BUFFER_SIZE, configfile); + if (readbuf != NULL) { + i++; + readbuf[strlen(readbuf) - 1] = '\0'; + if ((readbuf[0] != '#') && (strlen(readbuf) > 3)) { /* ignore comments */ + val = strchr(readbuf, '='); + field = readbuf; + if (!val) { + fprintf(stderr, + "Configread error in line: %d\n", + i); + } else { + *val = '\0'; + val++; + if (db_insert_config_item + (field, val) != 0) + fprintf(stderr, + "error in line:%d, could not insert item\n", + i); + else + printf + ("%s is now set to %s\n", + field, val); + } + } + } else + fprintf(stderr, "end of buffer\n"); + + } + return 0; +} @@ -51,321 +51,311 @@ extern db_param_t _db_params; int main(int argc, char *argv[]) { - struct list sysItems; - int res = 0, opt = 0, act = 0; - u64_t user_idnr = 0; - char *user_name = NULL; - char *name = NULL; - FILE *source = NULL; - extern char *optarg; - - openlog(PNAME, LOG_PID, LOG_MAIL); - - setvbuf(stdout, 0, _IONBF, 0); - - ReadConfig("DBMAIL", configFile, &sysItems); - SetTraceLevel(&sysItems); - GetDBParams(&_db_params, &sysItems); - - configure_debug(TRACE_ERROR, 1, 0); - - while (opt != -1 && act != 'h') - { - opt = getopt(argc, argv, "a:d:i:r:u:l"); - - switch (opt) - { - case -1: - /* Break right away if this is the end of the args */ - break; - case 'a': - case 'd': - case 'i': - case 'r': - if (act != 0) - act = 'h'; - else - act = opt; - name = optarg; - source = stdin; // FIXME to take files as input, too - break; - case 'u': - user_name = strdup(optarg); - break; - case 'l': - if (act != 0) - act = 'h'; - else - act = opt; - break; - default: - act = 'h'; - break; - } - } - - if (act != 'h' && act != 0) - { - printf ("*** dbmail-sievecmd ***\n"); - - /* Open database connection */ - printf ("Opening connection to database...\n"); - if (db_connect() != 0) - { - printf ("Failed. Could not connect to database (check log)\n"); - return -1; - } - - /* Open authentication connection */ - printf ("Opening connection to authentication...\n"); - if (auth_connect() != 0) - { - printf ("Failed. Could not connect to authentication (check log)\n"); - return -1; - } - - printf ("Ok. Connected!\n"); - - /* Retrieve the user ID number */ - switch(auth_user_exists(user_name, &user_idnr)) - { - case 0: - printf( "User [%s] does not exist!\n", user_name); - break; - case -1: - printf( "Error retrieving User ID Number\n" ); - res = -1; - goto mainend; - } - } - - switch (act) - { - case 'a': - res = do_activate(user_idnr, name); - break; - case 'd': - res = do_deactivate(user_idnr, name); - break; - case 'i': - res = do_insert(user_idnr, name, source); - break; - case 'r': - res = do_remove(user_idnr, name); - break; - case 'l': - res = do_list(user_idnr); - break; - case 'h': - default: - res = do_showhelp(); - break; - } - - mainend: - free(user_name); - db_disconnect(); - auth_disconnect(); - return res; + struct list sysItems; + int res = 0, opt = 0, act = 0; + u64_t user_idnr = 0; + char *user_name = NULL; + char *name = NULL; + FILE *source = NULL; + extern char *optarg; + + openlog(PNAME, LOG_PID, LOG_MAIL); + + setvbuf(stdout, 0, _IONBF, 0); + + ReadConfig("DBMAIL", configFile, &sysItems); + SetTraceLevel(&sysItems); + GetDBParams(&_db_params, &sysItems); + + configure_debug(TRACE_ERROR, 1, 0); + + while (opt != -1 && act != 'h') { + opt = getopt(argc, argv, "a:d:i:r:u:l"); + + switch (opt) { + case -1: + /* Break right away if this is the end of the args */ + break; + case 'a': + case 'd': + case 'i': + case 'r': + if (act != 0) + act = 'h'; + else + act = opt; + name = optarg; + source = stdin; // FIXME to take files as input, too + break; + case 'u': + user_name = strdup(optarg); + break; + case 'l': + if (act != 0) + act = 'h'; + else + act = opt; + break; + default: + act = 'h'; + break; + } + } + + if (act != 'h' && act != 0) { + printf("*** dbmail-sievecmd ***\n"); + + /* Open database connection */ + printf("Opening connection to database...\n"); + if (db_connect() != 0) { + printf + ("Failed. Could not connect to database (check log)\n"); + return -1; + } + + /* Open authentication connection */ + printf("Opening connection to authentication...\n"); + if (auth_connect() != 0) { + printf + ("Failed. Could not connect to authentication (check log)\n"); + return -1; + } + + printf("Ok. Connected!\n"); + + /* Retrieve the user ID number */ + switch (auth_user_exists(user_name, &user_idnr)) { + case 0: + printf("User [%s] does not exist!\n", user_name); + break; + case -1: + printf("Error retrieving User ID Number\n"); + res = -1; + goto mainend; + } + } + + switch (act) { + case 'a': + res = do_activate(user_idnr, name); + break; + case 'd': + res = do_deactivate(user_idnr, name); + break; + case 'i': + res = do_insert(user_idnr, name, source); + break; + case 'r': + res = do_remove(user_idnr, name); + break; + case 'l': + res = do_list(user_idnr); + break; + case 'h': + default: + res = do_showhelp(); + break; + } + + mainend: + free(user_name); + db_disconnect(); + auth_disconnect(); + return res; } int do_activate(u64_t user_idnr, char *name) { - int res = 0; - - res = db_activate_sievescript(user_idnr, name); - if (res == -3) - { - printf( "Script [%s] does not exist.\n", name ); - return -1; - } - else if (res != 0) - { - printf( "Error activating script [%s].\n" - "It is possible that no script is currently active!\n", name ); - return -1; - } - printf( "Script [%s] is now active. All others are inactive.\n", name ); - - return 0; + int res = 0; + + res = db_activate_sievescript(user_idnr, name); + if (res == -3) { + printf("Script [%s] does not exist.\n", name); + return -1; + } else if (res != 0) { + printf("Error activating script [%s].\n" + "It is possible that no script is currently active!\n", + name); + return -1; + } + printf("Script [%s] is now active. All others are inactive.\n", + name); + + return 0; } int do_deactivate(u64_t user_idnr, char *name) { - int res = 0; - - res = db_deactivate_sievescript(user_idnr, name); - if (res == -3) - { - printf( "Script [%s] does not exist.\n", name ); - return -1; - } - else if (res != 0) - { - printf( "Error deactivating script [%s].\n", name ); - return -1; - } - printf( "Script [%s] is now deactivated. No scripts are currently active.\n", name ); - - return 0; + int res = 0; + + res = db_deactivate_sievescript(user_idnr, name); + if (res == -3) { + printf("Script [%s] does not exist.\n", name); + return -1; + } else if (res != 0) { + printf("Error deactivating script [%s].\n", name); + return -1; + } + printf + ("Script [%s] is now deactivated. No scripts are currently active.\n", + name); + + return 0; } -int do_insert(u64_t user_idnr, char *name, FILE *source) +int do_insert(u64_t user_idnr, char *name, FILE * source) { - int res = 0; - char *buf = NULL; - char *errmsg = NULL; - - /* Read the file into a char array */ - res = read_script_file(source, &buf); - if (res != 0) - { - printf( "Error reading in your script!\n" ); - return -1; - } - - /* Check if the script is valid */ - res = my_sieve_script_validate(buf, &errmsg); - if (res != 0) - { - printf( "Script has errors: [%s].\n", name, errmsg ); - return -1; - } - - /* Make the DB call to store the script */ - res = db_add_sievescript(user_idnr, name, buf); - if (res == -3) - { - printf( "Script [%s] already exists.\n", name ); - return -1; - } - else if (res != 0) - { - printf( "Error inserting script [%s] into the database!\n", name ); - return -1; - } - - printf( "Script [%s] successfully inserted and marked inactive!\n", name ); - return 0; + int res = 0; + char *buf = NULL; + char *errmsg = NULL; + + /* Read the file into a char array */ + res = read_script_file(source, &buf); + if (res != 0) { + printf("Error reading in your script!\n"); + return -1; + } + + /* Check if the script is valid */ + res = my_sieve_script_validate(buf, &errmsg); + if (res != 0) { + printf("Script has errors: [%s].\n", name, errmsg); + return -1; + } + + /* Make the DB call to store the script */ + res = db_add_sievescript(user_idnr, name, buf); + if (res == -3) { + printf("Script [%s] already exists.\n", name); + return -1; + } else if (res != 0) { + printf("Error inserting script [%s] into the database!\n", + name); + return -1; + } + + printf("Script [%s] successfully inserted and marked inactive!\n", + name); + return 0; } int do_remove(u64_t user_idnr, char *name) { - int res; - - res = db_delete_sievescript(user_idnr, name); - if (res == -3) - { - printf( "Script [%s] does not exist.\n", name ); - return -1; - } - else if (res != 0) - { - printf( "Error deleting script [%s].\n", name ); - return -1; - } - - printf( "Script [%s] deleted.\n", name ); - - return 0; + int res; + + res = db_delete_sievescript(user_idnr, name); + if (res == -3) { + printf("Script [%s] does not exist.\n", name); + return -1; + } else if (res != 0) { + printf("Error deleting script [%s].\n", name); + return -1; + } + + printf("Script [%s] deleted.\n", name); + + return 0; } int do_list(u64_t user_idnr) { - struct list scriptlist; - struct element *tmp; - - if(db_get_sievescript_listall(user_idnr, &scriptlist) < 0) - { - printf("Error retrieving Sieve script list.\n"); - return -1; - } - - if (list_totalnodes(&scriptlist) > 0) - printf( "Found %ld scripts:\n", list_totalnodes(&scriptlist) ); - else - printf( "No scripts found!\n" ); - - tmp = list_getstart(&scriptlist); - while (tmp) - { - struct ssinfo *info = (struct ssinfo *)tmp->data; - if(info->active == 1) - printf(" + "); - else - printf(" - "); - printf("%s\n", info->name); - tmp = tmp->nextnode; - } - - if (scriptlist.start) - list_freelist(&scriptlist.start); - - return 0; + struct list scriptlist; + struct element *tmp; + + if (db_get_sievescript_listall(user_idnr, &scriptlist) < 0) { + printf("Error retrieving Sieve script list.\n"); + return -1; + } + + if (list_totalnodes(&scriptlist) > 0) + printf("Found %ld scripts:\n", + list_totalnodes(&scriptlist)); + else + printf("No scripts found!\n"); + + tmp = list_getstart(&scriptlist); + while (tmp) { + struct ssinfo *info = (struct ssinfo *) tmp->data; + if (info->active == 1) + printf(" + "); + else + printf(" - "); + printf("%s\n", info->name); + tmp = tmp->nextnode; + } + + if (scriptlist.start) + list_freelist(&scriptlist.start); + + return 0; } int do_showhelp() { - printf ("*** dbmail-sievecmd ***\n"); - - printf("Use this program to manage your users' Sieve scripts.\n"); - printf("See the man page for more info. Summary:\n\n"); - printf(" -u username Username of script user \n"); - printf(" -l List scripts belonging to user \n"); - printf(" -a scriptname Activate the named script \n"); - printf(" (only one script can be active; \n" - " deactivates any others) \n"); - printf(" -d scriptname Deactivate the named script \n"); - printf(" (no scripts will be active after this) \n"); - printf(" -i scriptname file Insert the named script from file \n"); - printf(" (a single dash, -, indicates input \n" - " from STDIN) \n"); - printf(" -r scriptname Remove the named script \n"); - printf(" (if script was active, no script is \n" - " active after deletion) \n"); - - return 0; + printf("*** dbmail-sievecmd ***\n"); + + printf("Use this program to manage your users' Sieve scripts.\n"); + printf("See the man page for more info. Summary:\n\n"); + printf(" -u username Username of script user \n"); + printf + (" -l List scripts belonging to user \n"); + printf(" -a scriptname Activate the named script \n"); + printf + (" (only one script can be active; \n" + " deactivates any others) \n"); + printf + (" -d scriptname Deactivate the named script \n"); + printf + (" (no scripts will be active after this) \n"); + printf + (" -i scriptname file Insert the named script from file \n"); + printf + (" (a single dash, -, indicates input \n" + " from STDIN) \n"); + printf(" -r scriptname Remove the named script \n"); + printf + (" (if script was active, no script is \n" + " active after deletion) \n"); + + return 0; } -int read_script_file(FILE *f, char **m_buf) +int read_script_file(FILE * f, char **m_buf) { - size_t f_len=0; - size_t f_pos=0; - char *tmp_buf = NULL; - char *f_buf = NULL; - - if (!f) - { - printf( "Received NULL as script input\n" ); - return -1; - } - - while(!feof(f)) - { - if( f_pos + 1 >= f_len ) - { - tmp_buf = realloc(f_buf, sizeof(char) * (f_len+=200)); - if( tmp_buf != NULL ) - f_buf = tmp_buf; - else - return -2; - } - f_buf[f_pos] = fgetc(f); - f_pos++; - } - - if(f_pos) - f_buf[f_pos] = '\0'; - - /* Since f_buf is either NULL or valid, we're golden */ - *m_buf = f_buf; - return 0; + size_t f_len = 0; + size_t f_pos = 0; + char *tmp_buf = NULL; + char *f_buf = NULL; + + if (!f) { + printf("Received NULL as script input\n"); + return -1; + } + + while (!feof(f)) { + if (f_pos + 1 >= f_len) { + tmp_buf = + realloc(f_buf, sizeof(char) * (f_len += 200)); + if (tmp_buf != NULL) + f_buf = tmp_buf; + else + return -2; + } + f_buf[f_pos] = fgetc(f); + f_pos++; + } + + if (f_pos) + f_buf[f_pos] = '\0'; + + /* Since f_buf is either NULL or valid, we're golden */ + *m_buf = f_buf; + return 0; } - @@ -33,7 +33,6 @@ int do_list(u64_t user_idnr); int do_activate(u64_t user_idnr, char *name); int do_deactivate(u64_t user_idnr, char *name); int do_remove(u64_t user_idnr, char *name); -int do_insert(u64_t user_idnr, char *name, FILE *source); - -int read_script_file(FILE *f, char **m_buf); +int do_insert(u64_t user_idnr, char *name, FILE * source); +int read_script_file(FILE * f, char **m_buf); diff --git a/smtp-convert.c b/smtp-convert.c index a098c34e..585b5a26 100644 --- a/smtp-convert.c +++ b/smtp-convert.c @@ -48,229 +48,220 @@ char blk[READ_BLOCK_SIZE + MAX_LINESIZE + 1]; /* syslog */ #define PNAME "dbmail/uni-one-convertor" -char *getusername (char *path); -int traverse (char *path); +char *getusername(char *path); +int traverse(char *path); int process_mboxfile(char *file, u64_t userid); -int main (int argc, char* argv[]) +int main(int argc, char *argv[]) { - time_t start; - time_t stop; - int result; - - if (argc < 2) - { - printf ("Error, traverse need a directory as argument\n"); - return -1; - } - - openlog(PNAME, LOG_PID, LOG_MAIL); /* open connection to syslog */ - configure_debug(TRACE_ERROR, 1, 0); - - /* open database connection */ - if (db_connect() != 0) - { - printf("Error opening database connection\n"); - return -1; - } - - /* open authentication connection */ - if (auth_connect() != 0) - { - printf("Error opening authentication connection\n"); - return -1; - } - - srand((int) ((int) time(NULL) + (int) getpid()) ); - - time (&start); /* mark the starting time */ - result = traverse (argv[1]); - time (&stop); /* mark the ending time */ - - printf ("Conversion started @ %s", ctime(&start)); - printf ("Conversion finished @ %s", ctime(&stop)); - - return result; + time_t start; + time_t stop; + int result; + + if (argc < 2) { + printf("Error, traverse need a directory as argument\n"); + return -1; + } + + openlog(PNAME, LOG_PID, LOG_MAIL); /* open connection to syslog */ + configure_debug(TRACE_ERROR, 1, 0); + + /* open database connection */ + if (db_connect() != 0) { + printf("Error opening database connection\n"); + return -1; + } + + /* open authentication connection */ + if (auth_connect() != 0) { + printf("Error opening authentication connection\n"); + return -1; + } + + srand((int) ((int) time(NULL) + (int) getpid())); + + time(&start); /* mark the starting time */ + result = traverse(argv[1]); + time(&stop); /* mark the ending time */ + + printf("Conversion started @ %s", ctime(&start)); + printf("Conversion finished @ %s", ctime(&stop)); + + return result; } -char *getusername (char *path) +char *getusername(char *path) { - int i; - char *tmp; - - i = strlen (path); - tmp = path+i; - - while ( (tmp!=path) && (*tmp!='/')) - tmp--; - - return tmp+1; + int i; + char *tmp; + + i = strlen(path); + tmp = path + i; + + while ((tmp != path) && (*tmp != '/')) + tmp--; + + return tmp + 1; } -int traverse (char *path) +int traverse(char *path) { - char newpath [1024]; - char *username; - struct dirent **namelist; - int n; - u64_t userid; - - n = scandir (path, &namelist, 0, alphasort); - - if (n < 0) - { - printf ("file %s\n",path); - username = getusername(path); - printf ("username %s\n", username); - - printf("creating user..."); - userid = auth_adduser(username, "default", "", "0", "10M"); - if (userid != -1 && userid != 0) - { - printf("Ok id [%llu]\n", userid); - printf("converting mailbox..."); - fflush(stdout); - n = process_mboxfile(path, userid); - if (n != 0) - printf("Warning: error converting mailbox\n"); - else - printf ("done :)\n"); - } - else - { - printf("user already exists. Skipping\n"); + char newpath[1024]; + char *username; + struct dirent **namelist; + int n; + u64_t userid; + + n = scandir(path, &namelist, 0, alphasort); + + if (n < 0) { + printf("file %s\n", path); + username = getusername(path); + printf("username %s\n", username); + + printf("creating user..."); + userid = auth_adduser(username, "default", "", "0", "10M"); + if (userid != -1 && userid != 0) { + printf("Ok id [%llu]\n", userid); + printf("converting mailbox..."); + fflush(stdout); + n = process_mboxfile(path, userid); + if (n != 0) + printf + ("Warning: error converting mailbox\n"); + else + printf("done :)\n"); + } else { + printf("user already exists. Skipping\n"); + } + + } else { + while (n--) { + if ((strcmp(namelist[n]->d_name, "..") != 0) && + (strcmp(namelist[n]->d_name, ".") != 0)) { + sprintf(newpath, "%s/%s", path, + namelist[n]->d_name); + traverse(newpath); + } + free(namelist[n]); + } + free(namelist); } - - } - else - { - while (n--) - { - if ((strcmp(namelist[n]->d_name,"..")!=0) && - (strcmp(namelist[n]->d_name,".")!=0)) - { - sprintf (newpath,"%s/%s",path, namelist[n]->d_name); - traverse (newpath); - } - free (namelist[n]); - } - free(namelist); - } - return 0; + return 0; } int process_mboxfile(char *file, u64_t userid) { - regex_t preg; - int result; - FILE *infile; - int in_msg, header_passed; - char newunique[UID_SIZE]; - unsigned cnt,len,newlines; - u64_t msgid=0, size; - char saved; - - if ((result = regcomp(&preg, mbox_delimiter_pattern, REG_NOSUB)) != 0) - { - trace(TRACE_ERROR,"Regex compilation failed."); - return -1; - } - - if ( (infile = fopen(file, "r")) == 0) - { - - trace(TRACE_ERROR,"Could not open file [%s]", infile); - return -1; - } - - in_msg = 0; - cnt = 0; - size = 0; - newlines = 0; - - while (!feof(infile) && !ferror(infile)) - { - if (fgets(&blk[cnt], MAX_LINESIZE, infile) == 0) - break; - - /* check if this is an mbox delimiter */ - if (regexec(&preg, &blk[cnt], 0, NULL, 0) == 0) - { - if (!in_msg) - in_msg = 1; /* ok start of a new msg */ - else - { - /* update & end message */ - db_insert_message_block(blk, cnt, msgid); - - create_unique_id(newunique, msgid); - db_update_message(msgid, newunique, size+cnt, size+cnt+newlines); - trace(TRACE_ERROR, "message [%llu] inserted, [%u] bytes", msgid, size+cnt); - } - - /* start new message */ - msgid = db_insert_message(userid, 0, ERROR_IF_MBOX_NOT_FOUND, 0); - header_passed = 0; - cnt = 0; - size = 0; - newlines = 0; + regex_t preg; + int result; + FILE *infile; + int in_msg, header_passed; + char newunique[UID_SIZE]; + unsigned cnt, len, newlines; + u64_t msgid = 0, size; + char saved; + + if ((result = + regcomp(&preg, mbox_delimiter_pattern, REG_NOSUB)) != 0) { + trace(TRACE_ERROR, "Regex compilation failed."); + return -1; } - else - { - newlines++; - if (header_passed == 0) - { - /* we're still reading the header */ - len = strlen(&blk[cnt]); - if (strcmp(&blk[cnt], "\n") == 0) - { - db_insert_message_block(blk, cnt+len, msgid); - header_passed = 1; - size += (cnt+len); - cnt = 0; - } - else - cnt += len; - } - else - { - /* this is body data */ - len = strlen(&blk[cnt]); - cnt += len; - - if (cnt >= READ_BLOCK_SIZE) - { - /* write block */ - saved = blk[READ_BLOCK_SIZE]; - - blk[READ_BLOCK_SIZE] = '\0'; - db_insert_message_block(blk, READ_BLOCK_SIZE, msgid); - blk[READ_BLOCK_SIZE] = saved; - - memmove(blk, &blk[READ_BLOCK_SIZE], cnt - (READ_BLOCK_SIZE)); - size += READ_BLOCK_SIZE; - cnt -= READ_BLOCK_SIZE; + + if ((infile = fopen(file, "r")) == 0) { + + trace(TRACE_ERROR, "Could not open file [%s]", infile); + return -1; + } + + in_msg = 0; + cnt = 0; + size = 0; + newlines = 0; + + while (!feof(infile) && !ferror(infile)) { + if (fgets(&blk[cnt], MAX_LINESIZE, infile) == 0) + break; + + /* check if this is an mbox delimiter */ + if (regexec(&preg, &blk[cnt], 0, NULL, 0) == 0) { + if (!in_msg) + in_msg = 1; /* ok start of a new msg */ + else { + /* update & end message */ + db_insert_message_block(blk, cnt, msgid); + + create_unique_id(newunique, msgid); + db_update_message(msgid, newunique, + size + cnt, + size + cnt + newlines); + trace(TRACE_ERROR, + "message [%llu] inserted, [%u] bytes", + msgid, size + cnt); + } + + /* start new message */ + msgid = + db_insert_message(userid, 0, + ERROR_IF_MBOX_NOT_FOUND, 0); + header_passed = 0; + cnt = 0; + size = 0; + newlines = 0; + } else { + newlines++; + if (header_passed == 0) { + /* we're still reading the header */ + len = strlen(&blk[cnt]); + if (strcmp(&blk[cnt], "\n") == 0) { + db_insert_message_block(blk, + cnt + len, + msgid); + header_passed = 1; + size += (cnt + len); + cnt = 0; + } else + cnt += len; + } else { + /* this is body data */ + len = strlen(&blk[cnt]); + cnt += len; + + if (cnt >= READ_BLOCK_SIZE) { + /* write block */ + saved = blk[READ_BLOCK_SIZE]; + + blk[READ_BLOCK_SIZE] = '\0'; + db_insert_message_block(blk, + READ_BLOCK_SIZE, + msgid); + blk[READ_BLOCK_SIZE] = saved; + + memmove(blk, &blk[READ_BLOCK_SIZE], + cnt - (READ_BLOCK_SIZE)); + size += READ_BLOCK_SIZE; + cnt -= READ_BLOCK_SIZE; + } + } } - } } - } - /* update & end message */ - if (msgid > 0) - { - db_insert_message_block(blk, cnt, msgid); + /* update & end message */ + if (msgid > 0) { + db_insert_message_block(blk, cnt, msgid); - create_unique_id(newunique, msgid); - db_update_message(msgid, newunique, size+cnt, size+cnt+newlines); - trace(TRACE_ERROR, "message [%llu] inserted, [%u] bytes", msgid, size+cnt); - } + create_unique_id(newunique, msgid); + db_update_message(msgid, newunique, size + cnt, + size + cnt + newlines); + trace(TRACE_ERROR, "message [%llu] inserted, [%u] bytes", + msgid, size + cnt); + } - fclose(infile); - return 0; + fclose(infile); + return 0; } @@ -24,14 +24,14 @@ #define SA_SIEVE 6 typedef struct sort_action { - int method; - char *destination; - char *message; + int method; + char *destination; + char *message; } sort_action_t; dsn_class_t sort_and_deliver(u64_t msgidnr, - const char *header, u64_t headersize, - u64_t msgsize, u64_t rfcsize, - u64_t useridnr, const char *mailbox); + const char *header, u64_t headersize, + u64_t msgsize, u64_t rfcsize, + u64_t useridnr, const char *mailbox); -#endif /* #ifndef _SORTING_H */ +#endif /* #ifndef _SORTING_H */ diff --git a/sort/sort.c b/sort/sort.c index 2ab0eea7..00acf28e 100644 --- a/sort/sort.c +++ b/sort/sort.c @@ -46,285 +46,333 @@ extern struct list smtpItems, sysItems; * Then do it! * */ dsn_class_t sort_and_deliver(u64_t msgidnr, - const char *header, u64_t headersize, - u64_t totalmsgsize, u64_t totalrfcsize, - u64_t useridnr, const char *mailbox) + const char *header, u64_t headersize, + u64_t totalmsgsize, u64_t totalrfcsize, + u64_t useridnr, const char *mailbox) { - field_t val; - int do_regex = 0, do_sieve = 0; - struct list actions; - struct element *tmp; - int actiontaken = 0, ret = 0; - u64_t mboxidnr, newmsgidnr; - char unique_id[UID_SIZE]; - char *bounce_id = NULL; - char *inbox = "INBOX"; + field_t val; + int do_regex = 0, do_sieve = 0; + struct list actions; + struct element *tmp; + int actiontaken = 0, ret = 0; + u64_t mboxidnr, newmsgidnr; + char unique_id[UID_SIZE]; + char *bounce_id = NULL; + char *inbox = "INBOX"; - GetConfigValue("SQLREGEX", &smtpItems, val); - if (strcasecmp(val, "yes") == 0) - do_regex = 1; + GetConfigValue("SQLREGEX", &smtpItems, val); + if (strcasecmp(val, "yes") == 0) + do_regex = 1; - GetConfigValue("LIBSIEVE", &smtpItems, val); - if (strcasecmp(val, "yes") == 0) - do_sieve = 1; + GetConfigValue("LIBSIEVE", &smtpItems, val); + if (strcasecmp(val, "yes") == 0) + do_sieve = 1; - list_init(&actions); + list_init(&actions); - if (do_regex) - { - /* Call out to Jonas' regex sorting function! - * */ - // ret = db_regexsort(useridnr, header, actions); - trace(TRACE_ERROR, "%s, %s: Regex sort is enabled in dbmail.conf, but has not been compiled", __FILE__, __FUNCTION__); - } + if (do_regex) { + /* Call out to Jonas' regex sorting function! + * */ + // ret = db_regexsort(useridnr, header, actions); + trace(TRACE_ERROR, + "%s, %s: Regex sort is enabled in dbmail.conf, but has not been compiled", + __FILE__, __FUNCTION__); + } - if (do_sieve) - { - /* Don't code the Sieve guts right here, - * call out to a function that encapsulates it! - * */ + if (do_sieve) { + /* Don't code the Sieve guts right here, + * call out to a function that encapsulates it! + * */ #ifdef SIEVE - ret = sortsieve_msgsort(useridnr, header, headersize, totalmsgsize, &actions); + ret = + sortsieve_msgsort(useridnr, header, headersize, + totalmsgsize, &actions); #else - /* Give the postmaster a clue as to why Sieve isn't working... */ - trace(TRACE_ERROR, "%s, %s: Sieve enabled in dbmail.conf, but Sieve support has not been compiled", __FILE__, __FUNCTION__); -#endif /* SIEVE */ - } + /* Give the postmaster a clue as to why Sieve isn't working... */ + trace(TRACE_ERROR, + "%s, %s: Sieve enabled in dbmail.conf, but Sieve support has not been compiled", + __FILE__, __FUNCTION__); +#endif /* SIEVE */ + } - if (mailbox == NULL) - mailbox = inbox; + if (mailbox == NULL) + mailbox = inbox; - /* actions is a list of things to do with this message - * each data pointer in the actions list references - * a structure like this: - * - * typedef sort_action { - * int method, - * char *destination, - * char *message - * } sort_action_t; - * - * Where message is some descriptive text, used - * primarily for rejection noticed, and where - * destination is either a mailbox name or a - * forwarding address, and method is one of these: - * - * SA_KEEP, - * SA_DISCARD, - * SA_REDIRECT, - * SA_REJECT, - * SA_FILEINTO - * (see RFC 3028 [SIEVE] for details) - * - * SA_SIEVE: - * In addition, this implementation allows for - * the internel Regex matching to call a Sieve - * script into action. In this case, the method - * is SA_SIEVE and the destination is the script's name. - * Note that Sieve must be enabled in the configuration - * file or else an error will be generated. - * - * In the absence of any valid actions (ie. actions - * is an empty list, or all attempts at performing the - * actions fail...) an implicit SA_KEEP is performed, - * using INBOX as the destination (hardcoded). - * */ + /* actions is a list of things to do with this message + * each data pointer in the actions list references + * a structure like this: + * + * typedef sort_action { + * int method, + * char *destination, + * char *message + * } sort_action_t; + * + * Where message is some descriptive text, used + * primarily for rejection noticed, and where + * destination is either a mailbox name or a + * forwarding address, and method is one of these: + * + * SA_KEEP, + * SA_DISCARD, + * SA_REDIRECT, + * SA_REJECT, + * SA_FILEINTO + * (see RFC 3028 [SIEVE] for details) + * + * SA_SIEVE: + * In addition, this implementation allows for + * the internel Regex matching to call a Sieve + * script into action. In this case, the method + * is SA_SIEVE and the destination is the script's name. + * Note that Sieve must be enabled in the configuration + * file or else an error will be generated. + * + * In the absence of any valid actions (ie. actions + * is an empty list, or all attempts at performing the + * actions fail...) an implicit SA_KEEP is performed, + * using INBOX as the destination (hardcoded). + * */ - if (list_totalnodes(&actions) > 0) - { - tmp = list_getstart(&actions); - while (tmp != NULL) - { - /* Try not to think about the structures too hard ;-) */ - switch ( (int)((sort_action_t *)tmp->data)->method ) - { - case SA_SIEVE: - { - /* Run the script specified by destination and - * add the resulting list onto the *end* of the - * actions list. Note that this is a deep hack... - * */ - if ((char *)((sort_action_t *)tmp->data)->destination != NULL) - { - struct list localtmplist; - struct element *localtmpelem; + if (list_totalnodes(&actions) > 0) { + tmp = list_getstart(&actions); + while (tmp != NULL) { + /* Try not to think about the structures too hard ;-) */ + switch ((int) ((sort_action_t *) tmp->data)-> + method) { + case SA_SIEVE: + { + /* Run the script specified by destination and + * add the resulting list onto the *end* of the + * actions list. Note that this is a deep hack... + * */ + if ((char *) ((sort_action_t *) + tmp->data)-> + destination != NULL) { + struct list localtmplist; + struct element + *localtmpelem; // if (sortsieve_msgsort(useridnr, header, headersize, (char *)((sort_action_t *)tmp->data)->destination, localtmplist)) - { - /* FIXME: This can all be replaced with some - * function called list_append(), if written! */ - /* Fast forward to the end of the actions list */ - localtmpelem = list_getstart(&actions); - while (localtmpelem != NULL) - { - localtmpelem = localtmpelem->nextnode; - } - /* And tack on the start of the Sieve list */ - localtmpelem->nextnode = list_getstart(&localtmplist); - /* Remeber to increment the node count, too */ - actions.total_nodes += list_totalnodes(&localtmplist); - } - } - break; - } - case SA_FILEINTO: - { - char *fileinto_mailbox = (char *)((sort_action_t *)tmp->data)->destination; + { + /* FIXME: This can all be replaced with some + * function called list_append(), if written! */ + /* Fast forward to the end of the actions list */ + localtmpelem = + list_getstart + (&actions); + while (localtmpelem + != NULL) { + localtmpelem + = + localtmpelem-> + nextnode; + } + /* And tack on the start of the Sieve list */ + localtmpelem-> + nextnode = + list_getstart + (&localtmplist); + /* Remeber to increment the node count, too */ + actions. + total_nodes += + list_totalnodes + (&localtmplist); + } + } + break; + } + case SA_FILEINTO: + { + char *fileinto_mailbox = + (char *) ((sort_action_t *) + tmp->data)-> + destination; - /* If the action doesn't come with a mailbox, use the default. */ + /* If the action doesn't come with a mailbox, use the default. */ - if (fileinto_mailbox == NULL) - { - /* Cast the const away because fileinto_mailbox may need to be freed. */ - fileinto_mailbox = (char *)mailbox; - trace(TRACE_MESSAGE, "sort_and_deliver(): mailbox not specified, using [%s]", - fileinto_mailbox); - } + if (fileinto_mailbox == NULL) { + /* Cast the const away because fileinto_mailbox may need to be freed. */ + fileinto_mailbox = + (char *) mailbox; + trace(TRACE_MESSAGE, + "sort_and_deliver(): mailbox not specified, using [%s]", + fileinto_mailbox); + } - /* Did we fail to create the mailbox? */ - if (db_find_create_mailbox(fileinto_mailbox, useridnr, &mboxidnr) != 0) - { - /* FIXME: Serious failure situation! This needs to be - * passed up the chain to notify the user, sender, etc. - * Perhaps we should *force* the implicit-keep to occur, - * or give another try at using INBOX. */ - trace(TRACE_ERROR, "sort_and_deliver(): mailbox [%s] not found nor created, message may not have been delivered", - fileinto_mailbox); - } - else - { - switch(db_copymsg(msgidnr, mboxidnr, useridnr, &newmsgidnr)) - { - case -2: - /* Couldn't deliver because the quota has been reached */ - bounce_id = auth_get_userid(useridnr); - bounce(header, bounce_id, BOUNCE_STORAGE_LIMIT_REACHED); - my_free (bounce_id); - break; - case -1: - /* Couldn't deliver because something something went wrong */ - trace(TRACE_ERROR, "sort_and_deliver(): error copying message to user [%llu]", useridnr); - /* Don't worry about error conditions. - * It's annoying if the message isn't delivered, - * but as long as *something* happens it's OK. - * Otherwise, actiontaken will be 0 and another - * delivery attempt will be made before passing - * up the error at the end of the function. - * */ - break; - default: - trace(TRACE_MESSAGE, "sort_and_deliver(): message id=%llu, size=%llu is inserted", - newmsgidnr, totalmsgsize); - - /* Create a unique ID for this message; - * Each message for each user must have a unique ID! - * */ - create_unique_id(unique_id, newmsgidnr); - db_message_set_unique_id(newmsgidnr, unique_id); - - actiontaken = 1; - break; - } - } + /* Did we fail to create the mailbox? */ + if (db_find_create_mailbox + (fileinto_mailbox, useridnr, + &mboxidnr) != 0) { + /* FIXME: Serious failure situation! This needs to be + * passed up the chain to notify the user, sender, etc. + * Perhaps we should *force* the implicit-keep to occur, + * or give another try at using INBOX. */ + trace(TRACE_ERROR, + "sort_and_deliver(): mailbox [%s] not found nor created, message may not have been delivered", + fileinto_mailbox); + } else { + switch (db_copymsg + (msgidnr, mboxidnr, + useridnr, + &newmsgidnr)) { + case -2: + /* Couldn't deliver because the quota has been reached */ + bounce_id = + auth_get_userid + (useridnr); + bounce(header, + bounce_id, + BOUNCE_STORAGE_LIMIT_REACHED); + my_free(bounce_id); + break; + case -1: + /* Couldn't deliver because something something went wrong */ + trace(TRACE_ERROR, + "sort_and_deliver(): error copying message to user [%llu]", + useridnr); + /* Don't worry about error conditions. + * It's annoying if the message isn't delivered, + * but as long as *something* happens it's OK. + * Otherwise, actiontaken will be 0 and another + * delivery attempt will be made before passing + * up the error at the end of the function. + * */ + break; + default: + trace + (TRACE_MESSAGE, + "sort_and_deliver(): message id=%llu, size=%llu is inserted", + newmsgidnr, + totalmsgsize); - /* If these are not same pointers, then we need to free. */ - if (fileinto_mailbox != mailbox) - my_free(fileinto_mailbox); + /* Create a unique ID for this message; + * Each message for each user must have a unique ID! + * */ + create_unique_id + (unique_id, + newmsgidnr); + db_message_set_unique_id + (newmsgidnr, + unique_id); - break; - } - case SA_DISCARD: - { - /* Basically do nothing! */ - actiontaken = 1; - break; - } - case SA_REJECT: - { - // FIXME: I'm happy with this code, but it's not quite right... - // Plus we want to specify a message to go along with it! - bounce_id = auth_get_userid(useridnr); - bounce(header, bounce_id, BOUNCE_NO_SUCH_USER); + actiontaken = 1; + break; + } + } - my_free(bounce_id); - actiontaken = 1; - break; - } - case SA_REDIRECT: - { - char *forward_id; - struct list targets; + /* If these are not same pointers, then we need to free. */ + if (fileinto_mailbox != mailbox) + my_free(fileinto_mailbox); - list_init(&targets); - list_nodeadd(&targets, (char *)((sort_action_t *)tmp->data)->destination, strlen((char *)((sort_action_t *)tmp->data)->destination)+1); - my_free((char *)((sort_action_t *)tmp->data)->destination); + break; + } + case SA_DISCARD: + { + /* Basically do nothing! */ + actiontaken = 1; + break; + } + case SA_REJECT: + { + // FIXME: I'm happy with this code, but it's not quite right... + // Plus we want to specify a message to go along with it! + bounce_id = + auth_get_userid(useridnr); + bounce(header, bounce_id, + BOUNCE_NO_SUCH_USER); - /* Put the destination into the targets list */ - /* The From header will contain... */ - forward_id = auth_get_userid(useridnr); - forward(msgidnr, &targets, forward_id, header, headersize); + my_free(bounce_id); + actiontaken = 1; + break; + } + case SA_REDIRECT: + { + char *forward_id; + struct list targets; - list_freelist(&targets.start); - my_free (forward_id); - actiontaken = 1; - break; - } - /* - case SA_KEEP: - default: - { - // Don't worry! This is handled by implicit keep :-) - break; - } - */ - } /* case */ - tmp = tmp->nextnode; - } /* while */ - list_freelist(&actions.start); - } /* if */ - else - { - /* Might as well be explicit about this... */ - actiontaken = 0; - } + list_init(&targets); + list_nodeadd(&targets, + (char + *) ((sort_action_t *) + tmp->data)-> + destination, + strlen((char + *) ((sort_action_t *) tmp->data)->destination) + 1); + my_free((char *) ((sort_action_t *) + tmp->data)-> + destination); - /* This is that implicit keep I mentioned earlier... - * If possible, put the message in the specified - * mailbox, otherwise use INBOX. */ - if (actiontaken == 0) - { - /* Did we fail to create the mailbox? */ - if (db_find_create_mailbox(mailbox, useridnr, &mboxidnr) != 0) - { - /* Serious failure situation! */ - trace(TRACE_ERROR, "sort_and_deliver(): INBOX not found"); - } - else - { - switch(db_copymsg(msgidnr, mboxidnr, useridnr, &newmsgidnr)) - { - case -2: - /* Couldn't deliver because the quotum is exceeded. */ - trace(TRACE_DEBUG, "%s, %s: error copying message to user [%llu], maxmail exceeded", - __FILE__, __FUNCTION__, useridnr); - break; - case -1: - /* Couldn't deliver because something something went wrong. */ - trace(TRACE_ERROR, "%s, %s: error copying message to user [%llu]", - __FILE__, __FUNCTION__, useridnr); - break; - default: - trace(TRACE_MESSAGE,"%s, %s: message id=%llu, size=%llu is inserted", - __FILE__, __FUNCTION__, newmsgidnr, totalmsgsize); - actiontaken = 1; - break; - } - } - } + /* Put the destination into the targets list */ + /* The From header will contain... */ + forward_id = + auth_get_userid(useridnr); + forward(msgidnr, &targets, + forward_id, header, + headersize); - if (actiontaken) - return DSN_CLASS_OK; - return DSN_CLASS_TEMP; -} + list_freelist(&targets.start); + my_free(forward_id); + actiontaken = 1; + break; + } + /* + case SA_KEEP: + default: + { + // Don't worry! This is handled by implicit keep :-) + break; + } + */ + } /* case */ + tmp = tmp->nextnode; + } /* while */ + list_freelist(&actions.start); + } /* if */ + else { + /* Might as well be explicit about this... */ + actiontaken = 0; + } + + /* This is that implicit keep I mentioned earlier... + * If possible, put the message in the specified + * mailbox, otherwise use INBOX. */ + if (actiontaken == 0) { + /* Did we fail to create the mailbox? */ + if (db_find_create_mailbox(mailbox, useridnr, &mboxidnr) != + 0) { + /* Serious failure situation! */ + trace(TRACE_ERROR, + "sort_and_deliver(): INBOX not found"); + } else { + switch (db_copymsg + (msgidnr, mboxidnr, useridnr, + &newmsgidnr)) { + case -2: + /* Couldn't deliver because the quotum is exceeded. */ + trace(TRACE_DEBUG, + "%s, %s: error copying message to user [%llu], maxmail exceeded", + __FILE__, __FUNCTION__, useridnr); + break; + case -1: + /* Couldn't deliver because something something went wrong. */ + trace(TRACE_ERROR, + "%s, %s: error copying message to user [%llu]", + __FILE__, __FUNCTION__, useridnr); + break; + default: + trace(TRACE_MESSAGE, + "%s, %s: message id=%llu, size=%llu is inserted", + __FILE__, __FUNCTION__, newmsgidnr, + totalmsgsize); + actiontaken = 1; + break; + } + } + } + if (actiontaken) + return DSN_CLASS_OK; + return DSN_CLASS_TEMP; +} diff --git a/sort/sortsieve.c b/sort/sortsieve.c index aa2fe424..a5cc9ab2 100644 --- a/sort/sortsieve.c +++ b/sort/sortsieve.c @@ -51,272 +51,285 @@ extern struct list smtpItems, sysItems; * such as dbmail-lmtpd, the daemon should * finish storing the message and restart. * */ -int sortsieve_msgsort(u64_t useridnr, char *header, u64_t headersize, u64_t messagesize, struct list *actions) +int sortsieve_msgsort(u64_t useridnr, char *header, u64_t headersize, + u64_t messagesize, struct list *actions) { - sieve2_message_t *m; - sieve2_support_t *p; - sieve2_script_t *s; - sieve2_action_t *a; - sieve2_loader_t scriptloader, msgloader; - char *scriptname = NULL, *script = NULL, *freestr = NULL; - int res = 0, ret = 0; - - /* Pass the address of the char *script, and it will come - * back magically allocated. Don't forget to free it later! */ - res = db_get_sievescript_active(useridnr, &scriptname); - if( res < 0 ) { - printf("db_get_sievescript_active() returns %d\n", res); - ret = -1; - goto no_free; - } - - printf( "Looking up script [%s]\n", scriptname ); - res = db_get_sievescript_byname(useridnr, scriptname, &script); - if( res < 0 ) { - printf("db_get_sievescript_byname() returns %d\n", res); - ret = -1; - goto char_scriptname_free; - } - - res = sieve2_action_alloc(&a); - if (res != SIEVE2_OK) { - printf("sieve2_action_alloc() returns %d\n", res); - ret = -1; - goto char_script_free; - } - - res = sieve2_support_alloc(&p); - if (res != SIEVE2_OK) { - printf("sieve2_support_alloc() returns %d\n", res); - ret = -1; - goto action_free; - } - - res = sieve2_support_register(p, SIEVE2_ACTION_FILEINTO); - res = sieve2_support_register(p, SIEVE2_ACTION_REDIRECT); - res = sieve2_support_register(p, SIEVE2_ACTION_REJECT); + sieve2_message_t *m; + sieve2_support_t *p; + sieve2_script_t *s; + sieve2_action_t *a; + sieve2_loader_t scriptloader, msgloader; + char *scriptname = NULL, *script = NULL, *freestr = NULL; + int res = 0, ret = 0; + + /* Pass the address of the char *script, and it will come + * back magically allocated. Don't forget to free it later! */ + res = db_get_sievescript_active(useridnr, &scriptname); + if (res < 0) { + printf("db_get_sievescript_active() returns %d\n", res); + ret = -1; + goto no_free; + } + + printf("Looking up script [%s]\n", scriptname); + res = db_get_sievescript_byname(useridnr, scriptname, &script); + if (res < 0) { + printf("db_get_sievescript_byname() returns %d\n", res); + ret = -1; + goto char_scriptname_free; + } + + res = sieve2_action_alloc(&a); + if (res != SIEVE2_OK) { + printf("sieve2_action_alloc() returns %d\n", res); + ret = -1; + goto char_script_free; + } + + res = sieve2_support_alloc(&p); + if (res != SIEVE2_OK) { + printf("sieve2_support_alloc() returns %d\n", res); + ret = -1; + goto action_free; + } + + res = sieve2_support_register(p, SIEVE2_ACTION_FILEINTO); + res = sieve2_support_register(p, SIEVE2_ACTION_REDIRECT); + res = sieve2_support_register(p, SIEVE2_ACTION_REJECT); // res = sieve2_support_register(p, SIEVE2_ACTION_NOTIFY); - res = sieve2_script_alloc(&s); - if (res != SIEVE2_OK) { - printf("sieve2_script_alloc() returns %d\n", res); - ret = -1; - goto support_free; - } - - res = sieve2_support_bind(p, s); - if (res != SIEVE2_OK) { - printf("sieve2_support_bind() returns %d\n", res); - ret = -1; - goto script_free; - } - - res = sieve2_script_parse(s, script); - if (res != SIEVE2_OK) { - printf("sieve2_script_parse() returns %d: %s\n", res, sieve2_errstr(res, &freestr)); - my_free(freestr); - ret = -1; - goto script_free; - } - - res = sieve2_message_alloc(&m); - if (res != SIEVE2_OK) { - printf("sieve2_message_alloc() returns %d\n", res); - ret = -1; - goto script_free; - } - - res = sieve2_message_register(m, &messagesize, SIEVE2_MESSAGE_SIZE); - if (res != SIEVE2_OK) { - printf("sieve2_message_register() returns %d\n", res); - ret = -1; - goto message_free; - } - res = sieve2_message_register(m, header, SIEVE2_MESSAGE_HEADER); - if (res != SIEVE2_OK) { - printf("sieve2_message_register() returns %d\n", res); - ret = -1; - goto message_free; - } - - res = sieve2_script_exec(s, m, a); - if (res != SIEVE2_OK) { - printf("sieve2_execute_script() returns %d\n", res); - ret = -1; - goto message_free; - } - - res = sortsieve_unroll_action(a, actions); - if (res != SIEVE2_OK && res != SIEVE2_DONE ) { - printf("unroll_action() returns %d\n", res); - ret = -1; - goto action_free; - } - -message_free: - res = sieve2_message_free(m); - if (res != SIEVE2_OK) { - printf("sieve2_message_free() returns %d\n", res); - ret = 1; - } - -script_free: - res = sieve2_script_free(s); - if (res != SIEVE2_OK) { - printf("sieve2_script_free() returns %d\n", res); - ret = 1; - } - -support_free: - res = sieve2_support_free(p); - if (res != SIEVE2_OK) { - printf("sieve2_support_free() returns %d\n", res); - ret = 1; - } - -action_free: - res = sieve2_action_free(a); - if (res != SIEVE2_OK) { - printf("sieve2_action_free() returns %d\n", res); - ret = 1; - } - - /* Good thing we're not forgetting ;-) */ -char_script_free: - if (script != NULL) - my_free(script); -char_scriptname_free: - if (scriptname != NULL) - my_free(scriptname); - -no_free: - return ret; + res = sieve2_script_alloc(&s); + if (res != SIEVE2_OK) { + printf("sieve2_script_alloc() returns %d\n", res); + ret = -1; + goto support_free; + } + + res = sieve2_support_bind(p, s); + if (res != SIEVE2_OK) { + printf("sieve2_support_bind() returns %d\n", res); + ret = -1; + goto script_free; + } + + res = sieve2_script_parse(s, script); + if (res != SIEVE2_OK) { + printf("sieve2_script_parse() returns %d: %s\n", res, + sieve2_errstr(res, &freestr)); + my_free(freestr); + ret = -1; + goto script_free; + } + + res = sieve2_message_alloc(&m); + if (res != SIEVE2_OK) { + printf("sieve2_message_alloc() returns %d\n", res); + ret = -1; + goto script_free; + } + + res = + sieve2_message_register(m, &messagesize, SIEVE2_MESSAGE_SIZE); + if (res != SIEVE2_OK) { + printf("sieve2_message_register() returns %d\n", res); + ret = -1; + goto message_free; + } + res = sieve2_message_register(m, header, SIEVE2_MESSAGE_HEADER); + if (res != SIEVE2_OK) { + printf("sieve2_message_register() returns %d\n", res); + ret = -1; + goto message_free; + } + + res = sieve2_script_exec(s, m, a); + if (res != SIEVE2_OK) { + printf("sieve2_execute_script() returns %d\n", res); + ret = -1; + goto message_free; + } + + res = sortsieve_unroll_action(a, actions); + if (res != SIEVE2_OK && res != SIEVE2_DONE) { + printf("unroll_action() returns %d\n", res); + ret = -1; + goto action_free; + } + + message_free: + res = sieve2_message_free(m); + if (res != SIEVE2_OK) { + printf("sieve2_message_free() returns %d\n", res); + ret = 1; + } + + script_free: + res = sieve2_script_free(s); + if (res != SIEVE2_OK) { + printf("sieve2_script_free() returns %d\n", res); + ret = 1; + } + + support_free: + res = sieve2_support_free(p); + if (res != SIEVE2_OK) { + printf("sieve2_support_free() returns %d\n", res); + ret = 1; + } + + action_free: + res = sieve2_action_free(a); + if (res != SIEVE2_OK) { + printf("sieve2_action_free() returns %d\n", res); + ret = 1; + } + + /* Good thing we're not forgetting ;-) */ + char_script_free: + if (script != NULL) + my_free(script); + char_scriptname_free: + if (scriptname != NULL) + my_free(scriptname); + + no_free: + return ret; } -int sortsieve_unroll_action(sieve2_action_t *a, struct list *actions) +int sortsieve_unroll_action(sieve2_action_t * a, struct list *actions) { - int res = SIEVE2_OK; - int code; - void *action_context; - - /* Working variables to set up - * the struct then nodeadd it */ - sort_action_t *tmpsa = NULL; - char *tmpdest = NULL; - char *tmpmsg = NULL; - int tmpmeth = 0; - - while(res == SIEVE2_OK) - { - if((tmpsa = malloc(sizeof(sort_action_t))) == NULL) - break; - res = sieve2_action_next(&a, &code, &action_context); - if(res == SIEVE2_DONE) - { - printf("We've reached the end.\n"); - break; - } - else if (res != SIEVE2_OK) - { - printf("Error in action list.\n"); - break; - } - printf("Action code is: %d\n", code); - - switch (code) - { - case SIEVE2_ACTION_REDIRECT: - { - sieve2_redirect_context_t *context = (sieve2_redirect_context_t *)action_context; - printf( "Action is REDIRECT: " ); - printf( "Destination is %s\n", context->addr); - tmpmeth = SA_REDIRECT; - tmpdest = strdup(context->addr); - break; - } - case SIEVE2_ACTION_REJECT: - { - sieve2_reject_context_t *context = (sieve2_reject_context_t *)action_context; - printf( "Action is REJECT: " ); - printf( "Message is %s\n", context->msg); - tmpmeth = SA_REJECT; - tmpmsg = strdup(context->msg); - break; - } - case SIEVE2_ACTION_DISCARD: - printf( "Action is DISCARD\n" ); - tmpmeth = SA_DISCARD; - break; - case SIEVE2_ACTION_FILEINTO: - { - sieve2_fileinto_context_t *context = (sieve2_fileinto_context_t *)action_context; - printf( "Action is FILEINTO: " ); - printf( "Destination is %s\n", context->mailbox); - tmpmeth = SA_FILEINTO; - tmpdest = strdup(context->mailbox); - break; - } - case SIEVE2_ACTION_NOTIFY: - { - sieve2_notify_context_t *context = (sieve2_notify_context_t *)action_context; - printf( "Action is NOTIFY: \n" ); - // FIXME: Prefer to have a function for this? - while(context != NULL) - { - printf( " ID \"%s\" is %s\n", context->id, ( context->isactive ? "ACTIVE" : "INACTIVE" ) ); - printf( " Method is %s\n", context->method ); - printf( " Priority is %s\n", context->priority ); - printf( " Message is %s\n", context->message ); - if(context->options != NULL) - { - size_t opt = 0; - while(context->options[opt] != NULL) - { - printf( " Options are %s\n", context->options[opt] ); - opt++; - } - } - context = context->next; - } - break; - } - case SIEVE2_ACTION_KEEP: - printf( "Action is KEEP\n" ); - break; - default: - printf( "Unrecognized action code: %d\n", code ); - break; - } /* case */ - - tmpsa->method = tmpmeth; - tmpsa->destination = tmpdest; - tmpsa->message = tmpmsg; - - list_nodeadd(actions, tmpsa, sizeof(sort_action_t)); - - my_free(tmpsa); - tmpsa = NULL; - - } /* while */ - - if (tmpsa != NULL) - my_free(tmpsa); - - return res; + int res = SIEVE2_OK; + int code; + void *action_context; + + /* Working variables to set up + * the struct then nodeadd it */ + sort_action_t *tmpsa = NULL; + char *tmpdest = NULL; + char *tmpmsg = NULL; + int tmpmeth = 0; + + while (res == SIEVE2_OK) { + if ((tmpsa = malloc(sizeof(sort_action_t))) == NULL) + break; + res = sieve2_action_next(&a, &code, &action_context); + if (res == SIEVE2_DONE) { + printf("We've reached the end.\n"); + break; + } else if (res != SIEVE2_OK) { + printf("Error in action list.\n"); + break; + } + printf("Action code is: %d\n", code); + + switch (code) { + case SIEVE2_ACTION_REDIRECT: + { + sieve2_redirect_context_t *context = + (sieve2_redirect_context_t *) + action_context; + printf("Action is REDIRECT: "); + printf("Destination is %s\n", + context->addr); + tmpmeth = SA_REDIRECT; + tmpdest = strdup(context->addr); + break; + } + case SIEVE2_ACTION_REJECT: + { + sieve2_reject_context_t *context = + (sieve2_reject_context_t *) + action_context; + printf("Action is REJECT: "); + printf("Message is %s\n", context->msg); + tmpmeth = SA_REJECT; + tmpmsg = strdup(context->msg); + break; + } + case SIEVE2_ACTION_DISCARD: + printf("Action is DISCARD\n"); + tmpmeth = SA_DISCARD; + break; + case SIEVE2_ACTION_FILEINTO: + { + sieve2_fileinto_context_t *context = + (sieve2_fileinto_context_t *) + action_context; + printf("Action is FILEINTO: "); + printf("Destination is %s\n", + context->mailbox); + tmpmeth = SA_FILEINTO; + tmpdest = strdup(context->mailbox); + break; + } + case SIEVE2_ACTION_NOTIFY: + { + sieve2_notify_context_t *context = + (sieve2_notify_context_t *) + action_context; + printf("Action is NOTIFY: \n"); + // FIXME: Prefer to have a function for this? + while (context != NULL) { + printf(" ID \"%s\" is %s\n", + context->id, + (context-> + isactive ? "ACTIVE" : + "INACTIVE")); + printf(" Method is %s\n", + context->method); + printf(" Priority is %s\n", + context->priority); + printf(" Message is %s\n", + context->message); + if (context->options != NULL) { + size_t opt = 0; + while (context-> + options[opt] != + NULL) { + printf + (" Options are %s\n", + context-> + options[opt]); + opt++; + } + } + context = context->next; + } + break; + } + case SIEVE2_ACTION_KEEP: + printf("Action is KEEP\n"); + break; + default: + printf("Unrecognized action code: %d\n", code); + break; + } /* case */ + + tmpsa->method = tmpmeth; + tmpsa->destination = tmpdest; + tmpsa->message = tmpmsg; + + list_nodeadd(actions, tmpsa, sizeof(sort_action_t)); + + my_free(tmpsa); + tmpsa = NULL; + + } /* while */ + + if (tmpsa != NULL) + my_free(tmpsa); + + return res; } /* Return 0 on script OK, 1 on script error. */ int sortsieve_script_validate(char *script, char **errmsg) { - if(sieve2_validate(t, s, p, e) == SIEVE2_OK) - { - *errmsg = NULL; - return 0; - } - else - { - *errmsg = "Script error..."; - return 1; - } + if (sieve2_validate(t, s, p, e) == SIEVE2_OK) { + *errmsg = NULL; + return 0; + } else { + *errmsg = "Script error..."; + return 1; + } } - diff --git a/sort/sortsieve.h b/sort/sortsieve.h index 9fb4048e..c1cf3bbe 100644 --- a/sort/sortsieve.h +++ b/sort/sortsieve.h @@ -16,8 +16,9 @@ #define MAX_SIEVE_SCRIPTNAME 100 -int sortsieve_msgsort(u64_t useridnr, char *header, u64_t headersize, u64_t messagesize, struct list *actions); -int sortsieve_unroll_action(sieve2_action_t *a, struct list *actions); +int sortsieve_msgsort(u64_t useridnr, char *header, u64_t headersize, + u64_t messagesize, struct list *actions); +int sortsieve_unroll_action(sieve2_action_t * a, struct list *actions); int sortsieve_script_validate(char *script, char **errmsg); #endif @@ -44,8 +44,7 @@ * and so that part of the Implementation line is absolutely required. */ /* allowed timsieve commands */ -const char *commands [] = -{ +const char *commands[] = { "LOGOUT", "STARTTLS", "CAPABILITY", "LISTSCRIPTS", "AUTHENTICATE", "DELETESCRIPT", "GETSCRIPT", "SETACTIVE", "HAVESPACE", "PUTSCRIPT" @@ -53,684 +52,789 @@ const char *commands [] = /* \" is added to the standard set of stuff... */ const char validchars[] = -"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -"_.!@#$%^&*()-+=~[]{}<>:;\\\"/ "; + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "_.!@#$%^&*()-+=~[]{}<>:;\\\"/ "; char myhostname[64]; -int tims_handle_connection(clientinfo_t *ci) +int tims_handle_connection(clientinfo_t * ci) { - /* - Handles connection and calls - tims command handler - */ - - int done = 1; /* loop state */ - char *buffer = NULL; /* connection buffer */ - int cnt; /* counter */ - time_t timestamp; - - PopSession_t session; /* current connection session */ - - /* setting Session variables */ - session.error_count = 0; - - session.username = NULL; - session.password = NULL; - - session.SessionResult = 0; - - /* reset counters */ - session.totalsize = 0; - session.virtual_totalsize = 0; - session.totalmessages = 0; - session.virtual_totalmessages = 0; - - - /* getting hostname */ - gethostname(myhostname, 64); - myhostname[63] = 0; /* make sure string is terminated */ - - buffer = (char *)my_malloc(INCOMING_BUFFER_SIZE * sizeof(char)); - - if (!buffer) - { - trace(TRACE_MESSAGE, "tims_handle_connection(): Could not allocate buffer"); - return 0; - } - - if (ci->tx) - { - /* This is a macro shared with TIMS_CAPA, per the draft RFC. */ - GREETING(ci->tx); - fflush(ci->tx); - } - else - { - trace(TRACE_MESSAGE, "tims_handle_connection(): TX stream is null!"); - return 0; - } - - while (done > 0) - { - /* set the timeout counter */ - alarm(ci->timeout); - - /* clear the buffer */ - memset(buffer, 0, INCOMING_BUFFER_SIZE); - - for (cnt = 0; cnt < INCOMING_BUFFER_SIZE - 1; cnt++) - { - do - { - clearerr(ci->rx); - fread(&buffer[cnt], 1, 1, ci->rx); - - /* leave, an alarm has occured during fread */ - if (!ci->rx) return 0; - } - while (ferror(ci->rx) && errno == EINTR); - - if (buffer[cnt] == '\n' || feof(ci->rx) || ferror(ci->rx)) - { - if (cnt > 0) - { - /* Ignore single newlines and \r\n pairs */ - if (cnt != 1 || buffer[cnt-1] != '\r') - { - buffer[cnt+1] = '\0'; - break; - } - /* Overwrite those silly extra \r\n's */ - else - { - /* Incremented to 0 at top of loop */ - cnt = -1; - } - } - } - } - - if (feof(ci->rx) || ferror(ci->rx)) - { - /* check client eof */ - done = -1; - } - else - { - /* reset function handle timeout */ - alarm(0); - /* handle tims commands */ - done = tims(ci->tx, ci->rx, buffer, ci->ip, &session); - } - fflush(ci->tx); - } - - /* memory cleanup */ - my_free(buffer); - buffer = NULL; - - /* reset timers */ - alarm (0); - __debug_dumpallocs(); - - return 0; + /* + Handles connection and calls + tims command handler + */ + + int done = 1; /* loop state */ + char *buffer = NULL; /* connection buffer */ + int cnt; /* counter */ + time_t timestamp; + + PopSession_t session; /* current connection session */ + + /* setting Session variables */ + session.error_count = 0; + + session.username = NULL; + session.password = NULL; + + session.SessionResult = 0; + + /* reset counters */ + session.totalsize = 0; + session.virtual_totalsize = 0; + session.totalmessages = 0; + session.virtual_totalmessages = 0; + + + /* getting hostname */ + gethostname(myhostname, 64); + myhostname[63] = 0; /* make sure string is terminated */ + + buffer = (char *) my_malloc(INCOMING_BUFFER_SIZE * sizeof(char)); + + if (!buffer) { + trace(TRACE_MESSAGE, + "tims_handle_connection(): Could not allocate buffer"); + return 0; + } + + if (ci->tx) { + /* This is a macro shared with TIMS_CAPA, per the draft RFC. */ + GREETING(ci->tx); + fflush(ci->tx); + } else { + trace(TRACE_MESSAGE, + "tims_handle_connection(): TX stream is null!"); + return 0; + } + + while (done > 0) { + /* set the timeout counter */ + alarm(ci->timeout); + + /* clear the buffer */ + memset(buffer, 0, INCOMING_BUFFER_SIZE); + + for (cnt = 0; cnt < INCOMING_BUFFER_SIZE - 1; cnt++) { + do { + clearerr(ci->rx); + fread(&buffer[cnt], 1, 1, ci->rx); + + /* leave, an alarm has occured during fread */ + if (!ci->rx) + return 0; + } + while (ferror(ci->rx) && errno == EINTR); + + if (buffer[cnt] == '\n' || feof(ci->rx) + || ferror(ci->rx)) { + if (cnt > 0) { + /* Ignore single newlines and \r\n pairs */ + if (cnt != 1 + || buffer[cnt - 1] != '\r') { + buffer[cnt + 1] = '\0'; + break; + } + /* Overwrite those silly extra \r\n's */ + else { + /* Incremented to 0 at top of loop */ + cnt = -1; + } + } + } + } + + if (feof(ci->rx) || ferror(ci->rx)) { + /* check client eof */ + done = -1; + } else { + /* reset function handle timeout */ + alarm(0); + /* handle tims commands */ + done = + tims(ci->tx, ci->rx, buffer, ci->ip, &session); + } + fflush(ci->tx); + } + + /* memory cleanup */ + my_free(buffer); + buffer = NULL; + + /* reset timers */ + alarm(0); + __debug_dumpallocs(); + + return 0; } -int tims_reset(PopSession_t *session) - { - session->state = STRT; +int tims_reset(PopSession_t * session) +{ + session->state = STRT; - return 1; - } + return 1; +} -int tims_error(PopSession_t *session, void *stream, const char *formatstring, ...) +int tims_error(PopSession_t * session, void *stream, + const char *formatstring, ...) { - va_list argp; - - if (session->error_count >= MAX_ERRORS) - { - trace(TRACE_MESSAGE, "tims_error(): too many errors (MAX_ERRORS is %d)", MAX_ERRORS); - fprintf((FILE *)stream, "BYE \"Too many errors, closing connection.\"\r\n"); - session->SessionResult = 2; /* possible flood */ - tims_reset(session); - return -3; - } - else - { - va_start(argp, formatstring); - vfprintf((FILE *)stream, formatstring, argp); - va_end(argp); - } - - trace(TRACE_DEBUG, "tims_error(): an invalid command was issued"); - session->error_count++; - return 1; + va_list argp; + + if (session->error_count >= MAX_ERRORS) { + trace(TRACE_MESSAGE, + "tims_error(): too many errors (MAX_ERRORS is %d)", + MAX_ERRORS); + fprintf((FILE *) stream, + "BYE \"Too many errors, closing connection.\"\r\n"); + session->SessionResult = 2; /* possible flood */ + tims_reset(session); + return -3; + } else { + va_start(argp, formatstring); + vfprintf((FILE *) stream, formatstring, argp); + va_end(argp); + } + + trace(TRACE_DEBUG, "tims_error(): an invalid command was issued"); + session->error_count++; + return 1; } -int tims(void *stream, void *instream, char *buffer, char *client_ip, PopSession_t *session) +int tims(void *stream, void *instream, char *buffer, char *client_ip, + PopSession_t * session) { - /* returns values: - * 0 to quit - * -1 on failure - * 1 on success */ - char *command, *value; - int cmdtype; - int indx=0; - - /* buffer overflow attempt */ - if (strlen(buffer) > MAX_IN_BUFFER) - { - trace(TRACE_DEBUG, "tims(): buffer overflow attempt"); - return -3; - } - - /* check for command issued */ - while (strchr(validchars, buffer[indx])) - indx++; - - /* end buffer */ - buffer[indx] = '\0'; - - trace(TRACE_DEBUG, "tims(): incoming buffer: [%s]", buffer); - - command = buffer; - - value = strstr(command, " "); /* look for the separator */ - - if (value != NULL) - { - *value = '\0'; /* set a \0 on the command end */ - value++; /* skip space */ - - if (strlen(value) == 0) - { - value = NULL; /* no value specified */ - } - else - { - trace(TRACE_DEBUG, "tims(): command issued: cmd [%s], val [%s]", command, value); - } - } - - for (cmdtype = TIMS_STRT; cmdtype < TIMS_END; cmdtype ++) - if (strcasecmp(command, commands[cmdtype]) == 0) break; - - trace(TRACE_DEBUG, "tims(): command looked up as commandtype %d", cmdtype); - - /* commands that are allowed to have no arguments */ - if ((value == NULL) && !(cmdtype < TIMS_NOARGS) && (cmdtype < TIMS_END)) - { - return tims_error(session, stream, "NO \"This command requires an argument.\"\r\n"); - } - - switch (cmdtype) - { - case TIMS_LOUT : - { - fprintf((FILE *)stream, "OK\r\n"); - tims_reset(session); - return 0; /* return 0 to cause the connection to close */ - } - case TIMS_STLS : - { - /* We don't support TLS, sorry! */ - fprintf((FILE *)stream, "NO\r\n"); - return 1; - } - case TIMS_CAPA : - { - /* This is macro-ized because it is also used in the greeting. */ - GREETING((FILE *)stream); - return 1; - } - case TIMS_AUTH : - { - /* We currently only support plain authentication, - * which means that the command we accept will look - * like this: Authenticate "PLAIN" "base64-password" - * */ - if (strlen(value) > strlen("\"PLAIN\"")) - { - /* Only compare the first part of value */ - if (strncasecmp(value, "\"PLAIN\"", strlen("\"PLAIN\"")) == 0) - { - size_t tmplen=0; - size_t tmppos=0; - char *tmpleft=NULL, **tmp64=NULL; - - /* First see if the base64 SASL is simply quoted */ - if (0 != find_bounded(value+strlen("\"PLAIN\""), '"', '"', &tmpleft, &tmplen, &tmppos)) - { - u64_t authlen; /* Actually, script length must be 32-bit unsigned int. */ - char tmpcharlen[11]; /* A 32-bit unsigned int is ten decimal digits in length. */ - - /* Second, failing that, see if it's an {n+} literal */ - find_bounded(value+strlen("\"PLAIN\""), '{', '+', &tmpleft, &tmplen, &tmppos); - - strncpy(tmpcharlen, tmpleft, (10 < tmplen ? 10 : tmplen)); - tmpcharlen[(10 < tmplen ? 10 : tmplen)] = '\0'; - my_free(tmpleft); - - authlen = strtoull(tmpcharlen, NULL, 10); - if (authlen >= UINT_MAX) - { - fprintf((FILE *)stream, "NO \"Invalid SASL length.\"\r\n"); - tmplen = 0; /* HACK: This prevents the next block from running. */ - } - else - { - if (0 != read_from_stream((FILE *)instream, &tmpleft, authlen)) - { - fprintf((FILE *)stream, "NO \"Error reading SASL.\"\r\n"); - } - else - { - tmplen = authlen; /* HACK: This allows the next block to run. */ - } - } - } - - if (tmplen < 1) - { - /* Definitely an empty password string */ - fprintf((FILE *)stream, "NO \"Password required.\"\r\n"); - } - else - { - size_t i; - u64_t useridnr; - - tmp64 = base64_decode(tmpleft, tmplen); - if (tmp64 == NULL) - { - fprintf((FILE *)stream, "NO \"SASL decode error.\"\r\n"); - } - else - { - for (i = 0; tmp64[i] != NULL; i++) { /* Just count 'em up */ } - if (i < 3) - { - fprintf((FILE *)stream, "NO \"Too few encoded SASL arguments.\"\r\n"); - } - /* The protocol specifies that the base64 encoding - * be made up of three parts: proxy, username, password - * Between them are NULLs, which are conveniently encoded - * by the base64 process... */ - if (auth_validate(tmp64[1], tmp64[2], &useridnr) == 1) - { - fprintf((FILE *)stream, "OK\r\n"); - session->state = AUTH; - session->useridnr = useridnr; - session->username = strdup(tmp64[1]); - session->password = strdup(tmp64[2]); - } - else - { - fprintf((FILE *)stream, "NO \"Username or password incorrect.\"\r\n"); - } - for (i = 0; tmp64[i] != NULL; i++) - { - my_free(tmp64[i]); - } - my_free(tmp64); - } - } /* if... tmplen < 1 */ - } /* if... strncasecmp() == "PLAIN" */ - else - { - trace(TRACE_INFO, "tims(): Input simply was not PLAIN auth"); - fprintf((FILE *)stream, "NO \"Authentication scheme not supported.\"\r\n"); - } - } /* if... strlen() < "PLAIN" */ - else - { - trace(TRACE_INFO, "tims(): Input too short to possibly be PLAIN auth"); - fprintf((FILE *)stream, "NO \"Authentication scheme not supported.\"\r\n"); - } - - return 1; - } - case TIMS_PUTS : - { - if (session->state != AUTH) - { - fprintf((FILE *)stream, "NO \"Please authenticate first.\"\r\n"); - } - else - { - size_t tmplen=0; - size_t tmppos=0; - char *tmpleft=NULL; - - find_bounded(value, '"', '"', &tmpleft, &tmplen, &tmppos); - - if (tmplen < 1) - { - /* Possibly an empty password... */ - fprintf((FILE *)stream, "NO \"Script name required.\"\r\n"); - } - else - { - char scriptname[MAX_SIEVE_SCRIPTNAME+1]; - - strncpy(scriptname, tmpleft, - (MAX_SIEVE_SCRIPTNAME < tmplen ? MAX_SIEVE_SCRIPTNAME : tmplen)); - /* Of course, be sure to NULL terminate, because strncpy() likely won't */ - scriptname[(MAX_SIEVE_SCRIPTNAME < tmplen ? MAX_SIEVE_SCRIPTNAME : tmplen)] = '\0'; - my_free(tmpleft); - - /* Offset from the previous match to make sure not to pull - * the "length" from a script with a malicious name */ - find_bounded(value+tmppos, '{', '+', &tmpleft, &tmplen, &tmppos); - - if (tmplen < 1) - { - /* Possibly an empty password... */ - fprintf((FILE *)stream, "NO \"Length required.\"\r\n"); - } - else - { - u64_t scriptlen; /* Actually, script length must be 32-bit unsigned int. */ - char tmpcharlen[11]; /* A 32-bit unsigned int is ten decimal digits in length. */ - - strncpy(tmpcharlen, tmpleft, (10 < tmplen ? 10 : tmplen)); - tmpcharlen[(10 < tmplen ? 10 : tmplen)] = '\0'; - my_free(tmpleft); - - scriptlen = strtoull(tmpcharlen, NULL, 10); - trace(TRACE_INFO, "%s, %s: Client sending script of length [%llu]", - __FILE__, __FUNCTION__, scriptlen); - if (scriptlen >= UINT_MAX) - { - trace(TRACE_INFO, "%s, %s: Length [%llu] is larger than UINT_MAX [%u]", - __FILE__, __FUNCTION__, scriptlen, UINT_MAX); - fprintf((FILE *)stream, "NO \"Invalid script length.\"\r\n"); - } - else - { - char *f_buf = NULL; - - if (0 != read_from_stream((FILE *)instream, &f_buf, scriptlen)) - { - trace(TRACE_INFO, "%s, %s: Error reading script with read_from_stream()", - __FILE__, __FUNCTION__); - fprintf((FILE *)stream, "NO \"Error reading script.\"\r\n"); - } - else - { - if (0 != db_check_sievescript_quota(session->useridnr, scriptlen)) - { - trace(TRACE_INFO, "%s, %s: Script exceeds user's quota, dumping it", - __FILE__, __FUNCTION__); - fprintf((FILE *)stream, "NO \"Script exceeds available space.\"\r\n"); - } - else - { - char *errmsg = NULL; - - if (0 != sortsieve_script_validate(f_buf, &errmsg)) - { - trace(TRACE_INFO, "%s, %s: Script has syntax errrors: [%s]", - __FILE__, __FUNCTION__, errmsg); - fprintf((FILE *)stream, "NO \"Script error: %s.\"\r\n", errmsg); - } - else - { - /* According to the draft RFC, a script with the same - * name as an existing script should [atomically] replace it. */ - if (0 != db_replace_sievescript(session->useridnr, scriptname, f_buf)) - { - trace(TRACE_INFO, "%s, %s: Error inserting script", - __FILE__, __FUNCTION__); - fprintf((FILE *)stream, "NO \"Error inserting script.\"\r\n"); - } - else - { - trace(TRACE_INFO, "%s, %s: Script successfully received", - __FILE__, __FUNCTION__); - fprintf((FILE *)stream, "OK \"Script successfully received.\"\r\n"); - } - } - my_free(f_buf); - } - } - } - } - } - } - return 1; - } - case TIMS_SETS: - { - if (session->state != AUTH) - { - fprintf((FILE *)stream, "NO \"Please authenticate first.\"\r\n"); - } - else - { - int ret; - size_t tmplen=0; - size_t tmppos=0; - char *tmpleft=NULL; - - find_bounded(value, '"', '"', &tmpleft, &tmplen, &tmppos); - - /* Only activate a new script if one was specified */ - if (tmplen > 0) - { - char scriptname[MAX_SIEVE_SCRIPTNAME+1]; - - strncpy(scriptname, tmpleft, - (MAX_SIEVE_SCRIPTNAME < tmplen ? MAX_SIEVE_SCRIPTNAME : tmplen)); - /* Of course, be sure to NULL terminate, because strncpy() likely won't */ - scriptname[(MAX_SIEVE_SCRIPTNAME < tmplen ? MAX_SIEVE_SCRIPTNAME : tmplen)] = '\0'; - my_free(tmpleft); - - ret = db_activate_sievescript(session->useridnr, scriptname); - if (ret == -3) - { - fprintf((FILE *)stream, "NO \"Script does not exist.\"\r\n"); - return -1; - } - else if (ret != 0) - { - fprintf((FILE *)stream, "NO \"Internal error.\"\r\n"); - return -1; - } - else - { - fprintf((FILE *)stream, "OK \"Script activated.\"\r\n"); - } - } - else - { - char *scriptname=NULL; - ret = db_get_sievescript_active(session->useridnr, &scriptname); - if (scriptname == NULL) - { - fprintf((FILE *)stream, "OK \"No scripts are active at this time.\"\r\n"); - } - else - { - ret = db_deactivate_sievescript(session->useridnr, scriptname); - my_free(scriptname); - if (ret == -3) - { - fprintf((FILE *)stream, "NO \"Active script does not exist.\"\r\n"); - return -1; - } - else if (ret != 0) - { - fprintf((FILE *)stream, "NO \"Internal error.\"\r\n"); - return -1; - } - else - { - fprintf((FILE *)stream, "OK \"All scripts deactivated.\"\r\n"); - } - } - } - } - return 1; - } - case TIMS_GETS: - { - if (session->state != AUTH) - { - fprintf((FILE *)stream, "NO \"Please authenticate first.\"\r\n"); - } - else - { - size_t tmplen=0; - size_t tmppos=0; - char *tmpleft=NULL; - - find_bounded(value, '"', '"', &tmpleft, &tmplen, &tmppos); - - if (tmplen < 1) - { - /* Possibly an empty password... */ - fprintf((FILE *)stream, "NO \"Script name required.\"\r\n"); - } - else - { - int ret = 0; - char *script = NULL; - char scriptname[MAX_SIEVE_SCRIPTNAME+1]; - - strncpy(scriptname, tmpleft, - (MAX_SIEVE_SCRIPTNAME < tmplen ? MAX_SIEVE_SCRIPTNAME : tmplen)); - /* Of course, be sure to NULL terminate, because strncpy() likely won't */ - scriptname[(MAX_SIEVE_SCRIPTNAME < tmplen ? MAX_SIEVE_SCRIPTNAME : tmplen)] = '\0'; - my_free(tmpleft); - - ret = db_get_sievescript_byname(session->useridnr, scriptname, &script); - if (ret == -3) - { - fprintf((FILE *)stream, "NO \"Script not found.\"\r\n"); - } - else if (ret != 0 || script == NULL) - { - fprintf((FILE *)stream, "NO \"Internal error.\"\r\n"); - } - else - { - fprintf((FILE *)stream, "{%u+}\r\n", strlen(script)); - fprintf((FILE *)stream, "%s\r\n", script); - fprintf((FILE *)stream, "OK\r\n"); - } + /* returns values: + * 0 to quit + * -1 on failure + * 1 on success */ + char *command, *value; + int cmdtype; + int indx = 0; + + /* buffer overflow attempt */ + if (strlen(buffer) > MAX_IN_BUFFER) { + trace(TRACE_DEBUG, "tims(): buffer overflow attempt"); + return -3; + } + + /* check for command issued */ + while (strchr(validchars, buffer[indx])) + indx++; + + /* end buffer */ + buffer[indx] = '\0'; + + trace(TRACE_DEBUG, "tims(): incoming buffer: [%s]", buffer); + + command = buffer; + + value = strstr(command, " "); /* look for the separator */ + + if (value != NULL) { + *value = '\0'; /* set a \0 on the command end */ + value++; /* skip space */ + + if (strlen(value) == 0) { + value = NULL; /* no value specified */ + } else { + trace(TRACE_DEBUG, + "tims(): command issued: cmd [%s], val [%s]", + command, value); + } + } + + for (cmdtype = TIMS_STRT; cmdtype < TIMS_END; cmdtype++) + if (strcasecmp(command, commands[cmdtype]) == 0) + break; + + trace(TRACE_DEBUG, "tims(): command looked up as commandtype %d", + cmdtype); + + /* commands that are allowed to have no arguments */ + if ((value == NULL) && !(cmdtype < TIMS_NOARGS) + && (cmdtype < TIMS_END)) { + return tims_error(session, stream, + "NO \"This command requires an argument.\"\r\n"); + } + + switch (cmdtype) { + case TIMS_LOUT: + { + fprintf((FILE *) stream, "OK\r\n"); + tims_reset(session); + return 0; /* return 0 to cause the connection to close */ } - } - return 1; - } - case TIMS_DELS: - { - if (session->state != AUTH) - { - fprintf((FILE *)stream, "NO \"Please authenticate first.\"\r\n"); - } - else - { - size_t tmplen=0; - size_t tmppos=0; - char *tmpleft=NULL; - - find_bounded(value, '"', '"', &tmpleft, &tmplen, &tmppos); - - if (tmplen < 1) - { - /* Possibly an empty password... */ - fprintf((FILE *)stream, "NO \"Script name required.\"\r\n"); - } - else - { - int ret = 0; - char scriptname[MAX_SIEVE_SCRIPTNAME+1]; - - strncpy(scriptname, tmpleft, - (MAX_SIEVE_SCRIPTNAME < tmplen ? MAX_SIEVE_SCRIPTNAME : tmplen)); - /* Of course, be sure to NULL terminate, because strncpy() likely won't */ - scriptname[(MAX_SIEVE_SCRIPTNAME < tmplen ? MAX_SIEVE_SCRIPTNAME : tmplen)] = '\0'; - my_free(tmpleft); - - ret = db_delete_sievescript(session->useridnr, scriptname); - if (ret == -3) - { - fprintf((FILE *)stream, "NO \"Script not found.\"\r\n"); - } - else if (ret != 0) - { - fprintf((FILE *)stream, "NO \"Internal error.\"\r\n"); - } - else - { - fprintf((FILE *)stream, "OK\r\n"); - } + case TIMS_STLS: + { + /* We don't support TLS, sorry! */ + fprintf((FILE *) stream, "NO\r\n"); + return 1; } - } - return 1; - } - case TIMS_SPAC: - { - if (session->state != AUTH) - { - fprintf((FILE *)stream, "NO \"Please authenticate first.\"\r\n"); - } - else - { - fprintf((FILE *)stream, "NO \"Command not implemented.\"\r\n"); - } - return 1; - } - case TIMS_LIST: - { - if (session->state != AUTH) - { - fprintf((FILE *)stream, "NO \"Please authenticate first.\"\r\n"); - } - else - { - struct list scriptlist; - struct element *tmp; - - if(db_get_sievescript_listall(session->useridnr, &scriptlist) < 0) - { - fprintf((FILE *)stream, "NO \"Internal error.\"\r\n"); - } - else - { - if (list_totalnodes(&scriptlist) == 0) - { - /* The command hasn't failed, but there aren't any scripts */ - fprintf((FILE *)stream, "OK \"No scripts found.\"\r\n"); - } - else - { - tmp = list_getstart(&scriptlist); - while (tmp != NULL) - { - struct ssinfo *info = (struct ssinfo *)tmp->data; - fprintf((FILE *)stream, "\"%s\"%s\r\n", - info->name, (info->active == 1 ? " ACTIVE" : "")); - tmp = tmp->nextnode; - } - fprintf((FILE *)stream, "OK\r\n"); - } - if (scriptlist.start) - list_freelist(&scriptlist.start); - } - } - return 1; - } - default : - { - return tims_error(session, stream,"NO \"What are you trying to say here?\"\r\n"); - } - } - return 1; + case TIMS_CAPA: + { + /* This is macro-ized because it is also used in the greeting. */ + GREETING((FILE *) stream); + return 1; + } + case TIMS_AUTH: + { + /* We currently only support plain authentication, + * which means that the command we accept will look + * like this: Authenticate "PLAIN" "base64-password" + * */ + if (strlen(value) > strlen("\"PLAIN\"")) { + /* Only compare the first part of value */ + if (strncasecmp + (value, "\"PLAIN\"", + strlen("\"PLAIN\"")) == 0) { + size_t tmplen = 0; + size_t tmppos = 0; + char *tmpleft = NULL, **tmp64 = + NULL; + + /* First see if the base64 SASL is simply quoted */ + if (0 != + find_bounded(value + + strlen + ("\"PLAIN\""), + '"', '"', + &tmpleft, &tmplen, + &tmppos)) { + u64_t authlen; /* Actually, script length must be 32-bit unsigned int. */ + char tmpcharlen[11]; /* A 32-bit unsigned int is ten decimal digits in length. */ + + /* Second, failing that, see if it's an {n+} literal */ + find_bounded(value + + strlen + ("\"PLAIN\""), + '{', '+', + &tmpleft, + &tmplen, + &tmppos); + + strncpy(tmpcharlen, + tmpleft, + (10 < + tmplen ? 10 : + tmplen)); + tmpcharlen[(10 < + tmplen ? 10 : + tmplen)] = + '\0'; + my_free(tmpleft); + + authlen = + strtoull(tmpcharlen, + NULL, 10); + if (authlen >= UINT_MAX) { + fprintf((FILE *) + stream, + "NO \"Invalid SASL length.\"\r\n"); + tmplen = 0; /* HACK: This prevents the next block from running. */ + } else { + if (0 != + read_from_stream + ((FILE *) + instream, + &tmpleft, + authlen)) { + fprintf((FILE *) stream, "NO \"Error reading SASL.\"\r\n"); + } else { + tmplen = authlen; /* HACK: This allows the next block to run. */ + } + } + } + + if (tmplen < 1) { + /* Definitely an empty password string */ + fprintf((FILE *) stream, + "NO \"Password required.\"\r\n"); + } else { + size_t i; + u64_t useridnr; + + tmp64 = + base64_decode(tmpleft, + tmplen); + if (tmp64 == NULL) { + fprintf((FILE *) + stream, + "NO \"SASL decode error.\"\r\n"); + } else { + for (i = 0; tmp64[i] != NULL; i++) { /* Just count 'em up */ + } + if (i < 3) { + fprintf((FILE *) stream, "NO \"Too few encoded SASL arguments.\"\r\n"); + } + /* The protocol specifies that the base64 encoding + * be made up of three parts: proxy, username, password + * Between them are NULLs, which are conveniently encoded + * by the base64 process... */ + if (auth_validate + (tmp64[1], + tmp64[2], + &useridnr) == + 1) { + fprintf((FILE *) stream, "OK\r\n"); + session-> + state = + AUTH; + session-> + useridnr + = + useridnr; + session-> + username + = + strdup + (tmp64 + [1]); + session-> + password + = + strdup + (tmp64 + [2]); + } else { + fprintf((FILE *) stream, "NO \"Username or password incorrect.\"\r\n"); + } + for (i = 0; + tmp64[i] != + NULL; i++) { + my_free + (tmp64 + [i]); + } + my_free(tmp64); + } + } /* if... tmplen < 1 */ + } /* if... strncasecmp() == "PLAIN" */ + else { + trace(TRACE_INFO, + "tims(): Input simply was not PLAIN auth"); + fprintf((FILE *) stream, + "NO \"Authentication scheme not supported.\"\r\n"); + } + } /* if... strlen() < "PLAIN" */ + else { + trace(TRACE_INFO, + "tims(): Input too short to possibly be PLAIN auth"); + fprintf((FILE *) stream, + "NO \"Authentication scheme not supported.\"\r\n"); + } + + return 1; + } + case TIMS_PUTS: + { + if (session->state != AUTH) { + fprintf((FILE *) stream, + "NO \"Please authenticate first.\"\r\n"); + } else { + size_t tmplen = 0; + size_t tmppos = 0; + char *tmpleft = NULL; + + find_bounded(value, '"', '"', &tmpleft, + &tmplen, &tmppos); + + if (tmplen < 1) { + /* Possibly an empty password... */ + fprintf((FILE *) stream, + "NO \"Script name required.\"\r\n"); + } else { + char scriptname + [MAX_SIEVE_SCRIPTNAME + 1]; + + strncpy(scriptname, tmpleft, + (MAX_SIEVE_SCRIPTNAME < + tmplen ? + MAX_SIEVE_SCRIPTNAME : + tmplen)); + /* Of course, be sure to NULL terminate, because strncpy() likely won't */ + scriptname[(MAX_SIEVE_SCRIPTNAME < + tmplen ? + MAX_SIEVE_SCRIPTNAME : + tmplen)] = '\0'; + my_free(tmpleft); + + /* Offset from the previous match to make sure not to pull + * the "length" from a script with a malicious name */ + find_bounded(value + tmppos, '{', + '+', &tmpleft, + &tmplen, &tmppos); + + if (tmplen < 1) { + /* Possibly an empty password... */ + fprintf((FILE *) stream, + "NO \"Length required.\"\r\n"); + } else { + u64_t scriptlen; /* Actually, script length must be 32-bit unsigned int. */ + char tmpcharlen[11]; /* A 32-bit unsigned int is ten decimal digits in length. */ + + strncpy(tmpcharlen, + tmpleft, + (10 < + tmplen ? 10 : + tmplen)); + tmpcharlen[(10 < + tmplen ? 10 : + tmplen)] = + '\0'; + my_free(tmpleft); + + scriptlen = + strtoull(tmpcharlen, + NULL, 10); + trace(TRACE_INFO, + "%s, %s: Client sending script of length [%llu]", + __FILE__, + __FUNCTION__, + scriptlen); + if (scriptlen >= UINT_MAX) { + trace(TRACE_INFO, + "%s, %s: Length [%llu] is larger than UINT_MAX [%u]", + __FILE__, + __FUNCTION__, + scriptlen, + UINT_MAX); + fprintf((FILE *) + stream, + "NO \"Invalid script length.\"\r\n"); + } else { + char *f_buf = NULL; + + if (0 != + read_from_stream + ((FILE *) + instream, + &f_buf, + scriptlen)) { + trace + (TRACE_INFO, + "%s, %s: Error reading script with read_from_stream()", + __FILE__, + __FUNCTION__); + fprintf((FILE *) stream, "NO \"Error reading script.\"\r\n"); + } else { + if (0 != + db_check_sievescript_quota + (session-> + useridnr, + scriptlen)) + { + trace + (TRACE_INFO, + "%s, %s: Script exceeds user's quota, dumping it", + __FILE__, + __FUNCTION__); + fprintf + ((FILE *) stream, "NO \"Script exceeds available space.\"\r\n"); + } else { + char *errmsg = NULL; + + if (0 != sortsieve_script_validate(f_buf, &errmsg)) { + trace + (TRACE_INFO, + "%s, %s: Script has syntax errrors: [%s]", + __FILE__, + __FUNCTION__, + errmsg); + fprintf + ((FILE *) stream, "NO \"Script error: %s.\"\r\n", errmsg); + } else { + /* According to the draft RFC, a script with the same + * name as an existing script should [atomically] replace it. */ + if (0 != db_replace_sievescript(session->useridnr, scriptname, f_buf)) { + trace + (TRACE_INFO, + "%s, %s: Error inserting script", + __FILE__, + __FUNCTION__); + fprintf + ((FILE *) stream, "NO \"Error inserting script.\"\r\n"); + } else { + trace + (TRACE_INFO, + "%s, %s: Script successfully received", + __FILE__, + __FUNCTION__); + fprintf + ((FILE *) stream, "OK \"Script successfully received.\"\r\n"); + } + } + my_free + (f_buf); + } + } + } + } + } + } + return 1; + } + case TIMS_SETS: + { + if (session->state != AUTH) { + fprintf((FILE *) stream, + "NO \"Please authenticate first.\"\r\n"); + } else { + int ret; + size_t tmplen = 0; + size_t tmppos = 0; + char *tmpleft = NULL; + + find_bounded(value, '"', '"', &tmpleft, + &tmplen, &tmppos); + + /* Only activate a new script if one was specified */ + if (tmplen > 0) { + char scriptname + [MAX_SIEVE_SCRIPTNAME + 1]; + + strncpy(scriptname, tmpleft, + (MAX_SIEVE_SCRIPTNAME < + tmplen ? + MAX_SIEVE_SCRIPTNAME : + tmplen)); + /* Of course, be sure to NULL terminate, because strncpy() likely won't */ + scriptname[(MAX_SIEVE_SCRIPTNAME < + tmplen ? + MAX_SIEVE_SCRIPTNAME : + tmplen)] = '\0'; + my_free(tmpleft); + + ret = + db_activate_sievescript + (session->useridnr, + scriptname); + if (ret == -3) { + fprintf((FILE *) stream, + "NO \"Script does not exist.\"\r\n"); + return -1; + } else if (ret != 0) { + fprintf((FILE *) stream, + "NO \"Internal error.\"\r\n"); + return -1; + } else { + fprintf((FILE *) stream, + "OK \"Script activated.\"\r\n"); + } + } else { + char *scriptname = NULL; + ret = + db_get_sievescript_active + (session->useridnr, + &scriptname); + if (scriptname == NULL) { + fprintf((FILE *) stream, + "OK \"No scripts are active at this time.\"\r\n"); + } else { + ret = + db_deactivate_sievescript + (session->useridnr, + scriptname); + my_free(scriptname); + if (ret == -3) { + fprintf((FILE *) + stream, + "NO \"Active script does not exist.\"\r\n"); + return -1; + } else if (ret != 0) { + fprintf((FILE *) + stream, + "NO \"Internal error.\"\r\n"); + return -1; + } else { + fprintf((FILE *) + stream, + "OK \"All scripts deactivated.\"\r\n"); + } + } + } + } + return 1; + } + case TIMS_GETS: + { + if (session->state != AUTH) { + fprintf((FILE *) stream, + "NO \"Please authenticate first.\"\r\n"); + } else { + size_t tmplen = 0; + size_t tmppos = 0; + char *tmpleft = NULL; + + find_bounded(value, '"', '"', &tmpleft, + &tmplen, &tmppos); + + if (tmplen < 1) { + /* Possibly an empty password... */ + fprintf((FILE *) stream, + "NO \"Script name required.\"\r\n"); + } else { + int ret = 0; + char *script = NULL; + char scriptname + [MAX_SIEVE_SCRIPTNAME + 1]; + + strncpy(scriptname, tmpleft, + (MAX_SIEVE_SCRIPTNAME < + tmplen ? + MAX_SIEVE_SCRIPTNAME : + tmplen)); + /* Of course, be sure to NULL terminate, because strncpy() likely won't */ + scriptname[(MAX_SIEVE_SCRIPTNAME < + tmplen ? + MAX_SIEVE_SCRIPTNAME : + tmplen)] = '\0'; + my_free(tmpleft); + + ret = + db_get_sievescript_byname + (session->useridnr, scriptname, + &script); + if (ret == -3) { + fprintf((FILE *) stream, + "NO \"Script not found.\"\r\n"); + } else if (ret != 0 + || script == NULL) { + fprintf((FILE *) stream, + "NO \"Internal error.\"\r\n"); + } else { + fprintf((FILE *) stream, + "{%u+}\r\n", + strlen(script)); + fprintf((FILE *) stream, + "%s\r\n", script); + fprintf((FILE *) stream, + "OK\r\n"); + } + } + } + return 1; + } + case TIMS_DELS: + { + if (session->state != AUTH) { + fprintf((FILE *) stream, + "NO \"Please authenticate first.\"\r\n"); + } else { + size_t tmplen = 0; + size_t tmppos = 0; + char *tmpleft = NULL; + + find_bounded(value, '"', '"', &tmpleft, + &tmplen, &tmppos); + + if (tmplen < 1) { + /* Possibly an empty password... */ + fprintf((FILE *) stream, + "NO \"Script name required.\"\r\n"); + } else { + int ret = 0; + char scriptname + [MAX_SIEVE_SCRIPTNAME + 1]; + + strncpy(scriptname, tmpleft, + (MAX_SIEVE_SCRIPTNAME < + tmplen ? + MAX_SIEVE_SCRIPTNAME : + tmplen)); + /* Of course, be sure to NULL terminate, because strncpy() likely won't */ + scriptname[(MAX_SIEVE_SCRIPTNAME < + tmplen ? + MAX_SIEVE_SCRIPTNAME : + tmplen)] = '\0'; + my_free(tmpleft); + + ret = + db_delete_sievescript(session-> + useridnr, + scriptname); + if (ret == -3) { + fprintf((FILE *) stream, + "NO \"Script not found.\"\r\n"); + } else if (ret != 0) { + fprintf((FILE *) stream, + "NO \"Internal error.\"\r\n"); + } else { + fprintf((FILE *) stream, + "OK\r\n"); + } + } + } + return 1; + } + case TIMS_SPAC: + { + if (session->state != AUTH) { + fprintf((FILE *) stream, + "NO \"Please authenticate first.\"\r\n"); + } else { + fprintf((FILE *) stream, + "NO \"Command not implemented.\"\r\n"); + } + return 1; + } + case TIMS_LIST: + { + if (session->state != AUTH) { + fprintf((FILE *) stream, + "NO \"Please authenticate first.\"\r\n"); + } else { + struct list scriptlist; + struct element *tmp; + + if (db_get_sievescript_listall + (session->useridnr, &scriptlist) < 0) { + fprintf((FILE *) stream, + "NO \"Internal error.\"\r\n"); + } else { + if (list_totalnodes(&scriptlist) == + 0) { + /* The command hasn't failed, but there aren't any scripts */ + fprintf((FILE *) stream, + "OK \"No scripts found.\"\r\n"); + } else { + tmp = + list_getstart + (&scriptlist); + while (tmp != NULL) { + struct ssinfo *info + = + (struct ssinfo + *) tmp->data; + fprintf((FILE *) + stream, + "\"%s\"%s\r\n", + info->name, + (info-> + active == + 1 ? + " ACTIVE" + : "")); + tmp = + tmp->nextnode; + } + fprintf((FILE *) stream, + "OK\r\n"); + } + if (scriptlist.start) + list_freelist(&scriptlist. + start); + } + } + return 1; + } + default: + { + return tims_error(session, stream, + "NO \"What are you trying to say here?\"\r\n"); + } + } + return 1; } - @@ -38,7 +38,7 @@ /* processes */ #define MAXCHILDREN 5 -#define DEFAULT_CHILDREN 5 +#define DEFAULT_CHILDREN 5 #define TIMS_DEF_MAXCONNECT 1500 @@ -58,22 +58,23 @@ const char *commands [] = "HAVESPACE", "PUTSCRIPT" }; */ -#define TIMS_STRT 0 /* lower bound of array - 0 */ +#define TIMS_STRT 0 /* lower bound of array - 0 */ #define TIMS_LOUT 0 #define TIMS_STLS 1 #define TIMS_CAPA 2 -#define TIMS_LIST 3 -#define TIMS_NOARGS 4 /* use with if( cmd < TIMS_NOARGS )... */ +#define TIMS_LIST 3 +#define TIMS_NOARGS 4 /* use with if( cmd < TIMS_NOARGS )... */ #define TIMS_AUTH 4 #define TIMS_DELS 5 #define TIMS_GETS 6 #define TIMS_SETS 7 -#define TIMS_ONEARG 8 /* use with if( cmd < TIMS_ONEARG )... */ +#define TIMS_ONEARG 8 /* use with if( cmd < TIMS_ONEARG )... */ #define TIMS_SPAC 8 #define TIMS_PUTS 9 -#define TIMS_END 10 /* upper bound of array + 1 */ +#define TIMS_END 10 /* upper bound of array + 1 */ -int tims (void *stream, void *instream, char *buffer, char *client_ip, PopSession_t *session); -int tims_handle_connection (clientinfo_t *ci); +int tims(void *stream, void *instream, char *buffer, char *client_ip, + PopSession_t * session); +int tims_handle_connection(clientinfo_t * ci); #endif diff --git a/timsieved.c b/timsieved.c index 48313439..a6a6422b 100644 --- a/timsieved.c +++ b/timsieved.c @@ -43,10 +43,10 @@ char *configFile = DEFAULT_CONFIG_FILE; /* set up database login data */ extern db_param_t _db_params; -void SetConfigItems(serverConfig_t *config, struct list *items); +void SetConfigItems(serverConfig_t * config, struct list *items); static int SetMainSigHandler(void); static void Daemonize(void); -void MainSigHandler(int sig, siginfo_t *info, void *data); +void MainSigHandler(int sig, siginfo_t * info, void *data); int tims_before_smtp = 0; int mainRestart = 0; @@ -59,256 +59,282 @@ char *timeout_setting; #ifdef PROC_TITLES int main(int argc, char *argv[], char **envp) #else - int main(int argc, char *argv[]) +int main(int argc, char *argv[]) #endif { - serverConfig_t config; - int result, status; - pid_t pid; - - openlog(PNAME, LOG_PID, LOG_MAIL); - - if (argc >= 2 && (argv[1])) - { - if (strcmp (argv[1],"-v") == 0) - { - printf ("\n*** DBMAIL: dbmail-timsieved version $Revision$ %s\n\n",COPYRIGHT); - return 0; - } - else - if (strcmp(argv[1],"-f")==0 && (argv[2])) - configFile = argv[2]; - } - - SetMainSigHandler(); - Daemonize(); - result = 0; - - do - { - mainStop = 0; - mainRestart = 0; - - trace(TRACE_DEBUG, "main(): reading config"); -#ifdef PROC_TITLES - init_set_proc_title(argc, argv, envp, PNAME); - set_proc_title("%s", "Idle"); -#endif - - /* We need smtp config for bounce.c and forward.c */ - ReadConfig("SMTP", configFile, &smtpItems); - ReadConfig("TIMSIEVED", configFile, &timsItems); - ReadConfig("DBMAIL", configFile, &sysItems); - SetConfigItems(&config, &timsItems); - SetTraceLevel(&timsItems); - GetDBParams(&_db_params, &sysItems); - - config.ClientHandler = tims_handle_connection; - config.timeoutMsg = TIMS_TIMEOUT_MSG; - - CreateSocket(&config); - trace(TRACE_DEBUG, "main(): socket created, starting server"); - - switch ( (pid = fork()) ) - { - case -1: - close(config.listenSocket); - trace(TRACE_FATAL, "main(): fork failed [%s]", strerror(errno)); - - case 0: - /* child process */ - drop_privileges(config.serverUser, config.serverGroup); - result = StartServer(&config); - - trace(TRACE_INFO, "main(): server done, exit."); - exit(result); - - default: - /* parent process, wait for child to exit */ - while (waitpid(pid, &status, WNOHANG|WUNTRACED) == 0) - { - if (mainStop) - kill(pid, SIGTERM); - - if (mainRestart) - kill(pid, SIGHUP); - - sleep(2); - } - - if (WIFEXITED(status)) - { - /* child process terminated neatly */ - result = WEXITSTATUS(status); - trace(TRACE_DEBUG, "main(): server has exited, exit status [%d]", result); - } - else - { - /* child stopped or signaled, don't like */ - /* make sure it is dead */ - trace(TRACE_DEBUG, "main(): server has not exited normally. Killing.."); - - kill(pid, SIGKILL); - result = 0; - } + serverConfig_t config; + int result, status; + pid_t pid; + + openlog(PNAME, LOG_PID, LOG_MAIL); + + if (argc >= 2 && (argv[1])) { + if (strcmp(argv[1], "-v") == 0) { + printf + ("\n*** DBMAIL: dbmail-timsieved version $Revision$ %s\n\n", + COPYRIGHT); + return 0; + } else if (strcmp(argv[1], "-f") == 0 && (argv[2])) + configFile = argv[2]; } - list_freelist(&smtpItems.start); - list_freelist(&timsItems.start); - list_freelist(&sysItems.start); - close(config.listenSocket); + SetMainSigHandler(); + Daemonize(); + result = 0; - } while (result == 1 && !mainStop) ; /* 1 means reread-config and restart */ + do { + mainStop = 0; + mainRestart = 0; + + trace(TRACE_DEBUG, "main(): reading config"); +#ifdef PROC_TITLES + init_set_proc_title(argc, argv, envp, PNAME); + set_proc_title("%s", "Idle"); +#endif - trace(TRACE_INFO, "main(): exit"); - return 0; + /* We need smtp config for bounce.c and forward.c */ + ReadConfig("SMTP", configFile, &smtpItems); + ReadConfig("TIMSIEVED", configFile, &timsItems); + ReadConfig("DBMAIL", configFile, &sysItems); + SetConfigItems(&config, &timsItems); + SetTraceLevel(&timsItems); + GetDBParams(&_db_params, &sysItems); + + config.ClientHandler = tims_handle_connection; + config.timeoutMsg = TIMS_TIMEOUT_MSG; + + CreateSocket(&config); + trace(TRACE_DEBUG, + "main(): socket created, starting server"); + + switch ((pid = fork())) { + case -1: + close(config.listenSocket); + trace(TRACE_FATAL, "main(): fork failed [%s]", + strerror(errno)); + + case 0: + /* child process */ + drop_privileges(config.serverUser, + config.serverGroup); + result = StartServer(&config); + + trace(TRACE_INFO, "main(): server done, exit."); + exit(result); + + default: + /* parent process, wait for child to exit */ + while (waitpid(pid, &status, WNOHANG | WUNTRACED) + == 0) { + if (mainStop) + kill(pid, SIGTERM); + + if (mainRestart) + kill(pid, SIGHUP); + + sleep(2); + } + + if (WIFEXITED(status)) { + /* child process terminated neatly */ + result = WEXITSTATUS(status); + trace(TRACE_DEBUG, + "main(): server has exited, exit status [%d]", + result); + } else { + /* child stopped or signaled, don't like */ + /* make sure it is dead */ + trace(TRACE_DEBUG, + "main(): server has not exited normally. Killing.."); + + kill(pid, SIGKILL); + result = 0; + } + } + + list_freelist(&smtpItems.start); + list_freelist(&timsItems.start); + list_freelist(&sysItems.start); + close(config.listenSocket); + + } while (result == 1 && !mainStop); /* 1 means reread-config and restart */ + + trace(TRACE_INFO, "main(): exit"); + return 0; } -void MainSigHandler(int sig, siginfo_t *info, void *data) +void MainSigHandler(int sig, siginfo_t * info, void *data) { - trace(TRACE_DEBUG, "MainSigHandler(): got signal [%d]", sig); + trace(TRACE_DEBUG, "MainSigHandler(): got signal [%d]", sig); - if (sig == SIGHUP) - mainRestart = 1; - else - mainStop = 1; + if (sig == SIGHUP) + mainRestart = 1; + else + mainStop = 1; } void Daemonize() { - if (fork()) - exit(0); - setsid(); + if (fork()) + exit(0); + setsid(); - if (fork()) - exit(0); + if (fork()) + exit(0); } int SetMainSigHandler() { - struct sigaction act; + struct sigaction act; - /* init & install signal handlers */ - memset(&act, 0, sizeof(act)); + /* init & install signal handlers */ + memset(&act, 0, sizeof(act)); - act.sa_sigaction = MainSigHandler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; + act.sa_sigaction = MainSigHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; - sigaction(SIGINT, &act, 0); - sigaction(SIGQUIT, &act, 0); - sigaction(SIGTERM, &act, 0); - sigaction(SIGHUP, &act, 0); + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); + sigaction(SIGTERM, &act, 0); + sigaction(SIGHUP, &act, 0); - return 0; + return 0; } -void SetConfigItems(serverConfig_t *config, struct list *items) +void SetConfigItems(serverConfig_t * config, struct list *items) { - field_t val; + field_t val; - /* read items: NCHILDREN */ - GetConfigValue("NCHILDREN", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for NCHILDREN in config file"); + /* read items: NCHILDREN */ + GetConfigValue("NCHILDREN", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for NCHILDREN in config file"); - if ( (config->nChildren = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for NCHILDREN is invalid: [%d]", config->nChildren); + if ((config->nChildren = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for NCHILDREN is invalid: [%d]", + config->nChildren); - trace(TRACE_DEBUG, "SetConfigItems(): server will create [%d] children", config->nChildren); + trace(TRACE_DEBUG, + "SetConfigItems(): server will create [%d] children", + config->nChildren); - /* read items: MAXCONNECTS */ - GetConfigValue("MAXCONNECTS", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for MAXCONNECTS in config file"); + /* read items: MAXCONNECTS */ + GetConfigValue("MAXCONNECTS", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for MAXCONNECTS in config file"); - if ( (config->childMaxConnect = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", config->childMaxConnect); + if ((config->childMaxConnect = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", + config->childMaxConnect); - trace(TRACE_DEBUG, "SetConfigItems(): children will make max. [%d] connections", config->childMaxConnect); + trace(TRACE_DEBUG, + "SetConfigItems(): children will make max. [%d] connections", + config->childMaxConnect); - /* read items: TIMEOUT */ - GetConfigValue("TIMEOUT", items, val); - if (strlen(val) == 0) - { - trace(TRACE_DEBUG, "SetConfigItems(): no value for TIMEOUT in config file"); - config->timeout = 0; - } - else if ( (config->timeout = atoi(val)) <= 30) - trace(TRACE_FATAL, "SetConfigItems(): value for TIMEOUT is invalid: [%d]", config->timeout); + /* read items: TIMEOUT */ + GetConfigValue("TIMEOUT", items, val); + if (strlen(val) == 0) { + trace(TRACE_DEBUG, + "SetConfigItems(): no value for TIMEOUT in config file"); + config->timeout = 0; + } else if ((config->timeout = atoi(val)) <= 30) + trace(TRACE_FATAL, + "SetConfigItems(): value for TIMEOUT is invalid: [%d]", + config->timeout); - trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", config->timeout); + trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", + config->timeout); - /* read items: PORT */ - GetConfigValue("PORT", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for PORT in config file"); + /* read items: PORT */ + GetConfigValue("PORT", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for PORT in config file"); - if ( (config->port = atoi(val)) <= 0) - trace(TRACE_FATAL, "SetConfigItems(): value for PORT is invalid: [%d]", config->port); + if ((config->port = atoi(val)) <= 0) + trace(TRACE_FATAL, + "SetConfigItems(): value for PORT is invalid: [%d]", + config->port); - trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", config->port); + trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", + config->port); - /* read items: BINDIP */ - GetConfigValue("BINDIP", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for BINDIP in config file"); + /* read items: BINDIP */ + GetConfigValue("BINDIP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for BINDIP in config file"); - strncpy(config->ip, val, IPLEN); - config->ip[IPLEN-1] = '\0'; + strncpy(config->ip, val, IPLEN); + config->ip[IPLEN - 1] = '\0'; - trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", config->ip); + trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", + config->ip); - /* read items: RESOLVE_IP */ - GetConfigValue("RESOLVE_IP", items, val); - if (strlen(val) == 0) - trace(TRACE_DEBUG, "SetConfigItems(): no value for RESOLVE_IP in config file"); + /* read items: RESOLVE_IP */ + GetConfigValue("RESOLVE_IP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, + "SetConfigItems(): no value for RESOLVE_IP in config file"); - config->resolveIP = (strcasecmp(val, "yes") == 0); + config->resolveIP = (strcasecmp(val, "yes") == 0); - trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", config->resolveIP ? "" : "not "); + trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", + config->resolveIP ? "" : "not "); - /* read items: IMAP-BEFORE-SMTP */ - GetConfigValue("TIMS_BEFORE_SMTP", items, val); - if (strlen(val) == 0) - trace(TRACE_DEBUG, "SetConfigItems(): no value for TIMS_BEFORE_SMTP in config file"); + /* read items: IMAP-BEFORE-SMTP */ + GetConfigValue("TIMS_BEFORE_SMTP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, + "SetConfigItems(): no value for TIMS_BEFORE_SMTP in config file"); - tims_before_smtp = (strcasecmp(val, "yes") == 0); + tims_before_smtp = (strcasecmp(val, "yes") == 0); - trace(TRACE_DEBUG, "SetConfigItems(): %s TIMS-before-SMTP", - tims_before_smtp ? "Enabling" : "Disabling"); + trace(TRACE_DEBUG, "SetConfigItems(): %s TIMS-before-SMTP", + tims_before_smtp ? "Enabling" : "Disabling"); - /* read items: EFFECTIVE-USER */ - GetConfigValue("EFFECTIVE_USER", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_USER in config file"); + /* read items: EFFECTIVE-USER */ + GetConfigValue("EFFECTIVE_USER", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for EFFECTIVE_USER in config file"); - strncpy(config->serverUser, val, FIELDSIZE); - config->serverUser[FIELDSIZE-1] = '\0'; + strncpy(config->serverUser, val, FIELDSIZE); + config->serverUser[FIELDSIZE - 1] = '\0'; - trace(TRACE_DEBUG, "SetConfigItems(): effective user shall be [%s]", config->serverUser); + trace(TRACE_DEBUG, + "SetConfigItems(): effective user shall be [%s]", + config->serverUser); - /* read items: EFFECTIVE-GROUP */ - GetConfigValue("EFFECTIVE_GROUP", items, val); - if (strlen(val) == 0) - trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_GROUP in config file"); + /* read items: EFFECTIVE-GROUP */ + GetConfigValue("EFFECTIVE_GROUP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, + "SetConfigItems(): no value for EFFECTIVE_GROUP in config file"); - strncpy(config->serverGroup, val, FIELDSIZE); - config->serverGroup[FIELDSIZE-1] = '\0'; + strncpy(config->serverGroup, val, FIELDSIZE); + config->serverGroup[FIELDSIZE - 1] = '\0'; - trace(TRACE_DEBUG, "SetConfigItems(): effective group shall be [%s]", config->serverGroup); + trace(TRACE_DEBUG, + "SetConfigItems(): effective group shall be [%s]", + config->serverGroup); @@ -48,18 +48,18 @@ char *configFile = DEFAULT_CONFIG_FILE; #define SHADOWFILE "/etc/shadow" -char *getToken(char** str,const char* delims); +char *getToken(char **str, const char *delims); char csalt[] = "........"; -char *bgetpwent (char *filename, char *name); +char *bgetpwent(char *filename, char *name); char *cget_salt(void); /* database login data */ extern db_param_t _db_params; /* valid characters for passwd/username */ -const char ValidChars[] = -"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -"_.!@#$%^&*()-+=~[]{}<>:;\\/"; +const char ValidChars[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "_.!@#$%^&*()-+=~[]{}<>:;\\/"; void show_help(void); int quiet = 0; @@ -78,77 +78,87 @@ int is_valid(const char *name); int main(int argc, char *argv[]) { - struct list sysItems; - int result; - int argidx = 0; - - openlog(PNAME, LOG_PID, LOG_MAIL); - - setvbuf(stdout,0,_IONBF,0); - - if (argc<2) - { - show_help(); - return 0; - } - - if (strcasecmp(argv[1], "quiet") == 0) - { - if (argc < 3) - { - show_help(); - return 0; + struct list sysItems; + int result; + int argidx = 0; + + openlog(PNAME, LOG_PID, LOG_MAIL); + + setvbuf(stdout, 0, _IONBF, 0); + + if (argc < 2) { + show_help(); + return 0; + } + + if (strcasecmp(argv[1], "quiet") == 0) { + if (argc < 3) { + show_help(); + return 0; + } + + quiet = 1; + argidx = 1; + } + + ReadConfig("DBMAIL", configFile, &sysItems); + SetTraceLevel(&sysItems); + GetDBParams(&_db_params, &sysItems); + + quiet_printf("\n*** dbmail-adduser ***\n"); + + /* open database connection */ + quiet_printf("Opening connection to database...\n"); + if (db_connect() != 0) { + quiet_printf + ("Failed. Could not connect to database (check log)\n"); + return -1; } - quiet = 1; - argidx = 1; - } - - ReadConfig("DBMAIL", configFile, &sysItems); - SetTraceLevel(&sysItems); - GetDBParams(&_db_params, &sysItems); - - quiet_printf ("\n*** dbmail-adduser ***\n"); - - /* open database connection */ - quiet_printf ("Opening connection to database...\n"); - if (db_connect() != 0) - { - quiet_printf ("Failed. Could not connect to database (check log)\n"); - return -1; - } - - /* open authentication connection */ - quiet_printf ("Opening connection to authentication...\n"); - if (auth_connect() != 0) - { - quiet_printf ("Failed. Could not connect to authentication (check log)\n"); - return -1; - } - - quiet_printf ("Ok. Connected\n"); - configure_debug(TRACE_ERROR, 1, 0); - - switch (argv[argidx+1][0]) - { - case 'a': result = do_add(argc- (2+argidx),&argv[2+argidx]); break; - case 'c': result = do_change(&argv[2+argidx]); break; - case 'd': result = do_delete(argv[2+argidx]); break; - case 's': result = do_show(argv[2+argidx]); break; - case 'f': result = do_make_alias(&argv[2+argidx]); break; - case 'x': result = do_remove_alias(&argv[2+argidx]); break; - case 'e': result = do_empty(argv[2+argidx]); break; - default: - show_help(); - db_disconnect(); - auth_disconnect(); - return 0; - } - - - db_disconnect(); - auth_disconnect(); - return result; + /* open authentication connection */ + quiet_printf("Opening connection to authentication...\n"); + if (auth_connect() != 0) { + quiet_printf + ("Failed. Could not connect to authentication (check log)\n"); + return -1; + } + + quiet_printf("Ok. Connected\n"); + configure_debug(TRACE_ERROR, 1, 0); + + switch (argv[argidx + 1][0]) { + case 'a': + result = do_add(argc - (2 + argidx), &argv[2 + argidx]); + break; + case 'c': + result = do_change(&argv[2 + argidx]); + break; + case 'd': + result = do_delete(argv[2 + argidx]); + break; + case 's': + result = do_show(argv[2 + argidx]); + break; + case 'f': + result = do_make_alias(&argv[2 + argidx]); + break; + case 'x': + result = do_remove_alias(&argv[2 + argidx]); + break; + case 'e': + result = do_empty(argv[2 + argidx]); + break; + default: + show_help(); + db_disconnect(); + auth_disconnect(); + return 0; + } + + + db_disconnect(); + auth_disconnect(); + return result; } @@ -158,560 +168,579 @@ int main(int argc, char *argv[]) */ int do_make_alias(char *argv[]) { - int result; + int result; - if (!argv[0] || !argv[1]) - { - quiet_printf ("invalid arguments specified. Check the man page\n"); - return -1; - } + if (!argv[0] || !argv[1]) { + quiet_printf + ("invalid arguments specified. Check the man page\n"); + return -1; + } - quiet_printf("Adding alias [%s] --> [%s]...", argv[0], argv[1]); - switch ( (result = db_addalias_ext(argv[0], argv[1], 0)) ) - { - case -1: - quiet_printf("Failed\n\nCheck logs for details\n\n"); - break; + quiet_printf("Adding alias [%s] --> [%s]...", argv[0], argv[1]); + switch ((result = db_addalias_ext(argv[0], argv[1], 0))) { + case -1: + quiet_printf("Failed\n\nCheck logs for details\n\n"); + break; - case 0: - quiet_printf("Ok alias added\n"); - break; + case 0: + quiet_printf("Ok alias added\n"); + break; - case 1: - quiet_printf("Already exists. no extra alias added\n"); - result = -1; /* return error */ - break; + case 1: + quiet_printf("Already exists. no extra alias added\n"); + result = -1; /* return error */ + break; - } + } - return result; + return result; } int do_remove_alias(char *argv[]) { - if (!argv[0] || !argv[1]) - { - quiet_printf ("invalid arguments specified. Check the man page\n"); - return -1; - } - - quiet_printf("Removing alias [%s] --> [%s]...", argv[0], argv[1]); - if (db_removealias_ext(argv[0], argv[1]) != 0) - { - quiet_printf("Failed\n\nCheck logs for details\n\n"); - return -1; - } - - quiet_printf("Ok alias removed\n"); - return 0; + if (!argv[0] || !argv[1]) { + quiet_printf + ("invalid arguments specified. Check the man page\n"); + return -1; + } + + quiet_printf("Removing alias [%s] --> [%s]...", argv[0], argv[1]); + if (db_removealias_ext(argv[0], argv[1]) != 0) { + quiet_printf("Failed\n\nCheck logs for details\n\n"); + return -1; + } + + quiet_printf("Ok alias removed\n"); + return 0; } int do_add(int argc, char *argv[]) { - u64_t useridnr; - int add_user_result; - int i, result; - char pw[50]=""; - - if (argc < 4) - { - quiet_printf ("invalid number of options specified. Check the man page\n"); - return -1; - } - - if (!is_valid(argv[0])) - { - quiet_printf("Error: invalid characters in username [%s] encountered\n",argv[0]); - return -1; - } - - quiet_printf ("Adding user %s with password %s, %s bytes mailbox limit and clientid %s...", - argv[0], argv[1], argv[3], argv[2]); - - /* check if we need to encrypt this pwd */ - if (strncasecmp(argv[1], "{crypt:}", strlen("{crypt:}")) == 0) - { - /* encrypt using crypt() */ - strcat(pw,crypt(&argv[1][strlen("{crypt:}")], cget_salt())); - add_user_result = auth_adduser(argv[0], pw, "crypt", - argv[2],argv[3], &useridnr); - } - else if (strncasecmp(argv[1], "{crypt}", strlen("{crypt}")) == 0) - { - /* assume passwd is encrypted on command line */ - add_user_result = auth_adduser(argv[0], &argv[1][strlen("{crypt}")], - "crypt",argv[2],argv[3], &useridnr); - } - else if (strncasecmp(argv[1], "{md5:}", strlen("{md5:}")) == 0) - { - /* encrypt using md5 crypt() */ - sprintf(pw,"%s%s%s","$1$",cget_salt(),"$"); - strncpy(pw,crypt(&argv[1][strlen("{md5:}")], pw),49); - add_user_result = auth_adduser(argv[0], pw, "md5", - argv[2],argv[3], &useridnr); - } - else if (strncasecmp(argv[1], "{md5}", strlen("{md5}")) == 0) - { - /* assume passwd is encrypted on command line */ - add_user_result = auth_adduser(argv[0], &argv[1][strlen("{md5}")], - "md5",argv[2],argv[3], &useridnr); - } - else if (strncasecmp(argv[1], "{md5sum:}", strlen("{md5sum:}")) == 0) - { - /* encrypt using md5 digest */ - strcat(pw,makemd5(&argv[1][strlen("{md5sum:}")])); - add_user_result = auth_adduser(argv[0], pw, "md5sum",argv[2], - argv[3], &useridnr); - } - else if (strncasecmp(argv[1], "{md5sum}", strlen("{md5sum}")) == 0) - { - /* assume passwd is encrypted on command line */ - add_user_result = auth_adduser(argv[0], &argv[1][strlen("{md5sum}")], - "md5sum",argv[2],argv[3], &useridnr); - } - else - { - add_user_result = auth_adduser(argv[0],argv[1],"", - argv[2],argv[3], &useridnr); - } - - if (add_user_result == -1) { - /* check if existance of another user with the same name caused - the failure */ - if (auth_user_exists(argv[0], &useridnr) == -1) { - quiet_printf("Failed\n\nCheck logs for details\n\n"); - return -1; /* database failure */ - } - if (useridnr != 0) - quiet_printf("Failed: user exists [%llu]\n", useridnr); - else { /* useridnr is 0 ! */ - quiet_printf("Failed\n\nCheck logs for details\n\n"); - useridnr = -1; - } - return -1; - } - - quiet_printf ("Ok, user added id [%llu]\n",useridnr); - - for (i = 4, result = 0; i<argc; i++) - { - quiet_printf ("Adding alias %s...",argv[i]); - switch ( db_addalias(useridnr,argv[i],atoi(argv[2])) ) - { - case -1: - quiet_printf ("Failed\n"); - result = -1; - break; - - case 0: - quiet_printf ("Ok, added\n"); - break; + u64_t useridnr; + int add_user_result; + int i, result; + char pw[50] = ""; + + if (argc < 4) { + quiet_printf + ("invalid number of options specified. Check the man page\n"); + return -1; + } - case 1: - quiet_printf("Already exists. No extra alias added\n"); - result = -1; - break; + if (!is_valid(argv[0])) { + quiet_printf + ("Error: invalid characters in username [%s] encountered\n", + argv[0]); + return -1; } - } - - quiet_printf ("adduser done\n"); - if (result != 0) - quiet_printf("Warning: user added but not all the specified aliases\n"); - return result; + quiet_printf + ("Adding user %s with password %s, %s bytes mailbox limit and clientid %s...", + argv[0], argv[1], argv[3], argv[2]); + + /* check if we need to encrypt this pwd */ + if (strncasecmp(argv[1], "{crypt:}", strlen("{crypt:}")) == 0) { + /* encrypt using crypt() */ + strcat(pw, + crypt(&argv[1][strlen("{crypt:}")], cget_salt())); + add_user_result = + auth_adduser(argv[0], pw, "crypt", argv[2], argv[3], + &useridnr); + } else if (strncasecmp(argv[1], "{crypt}", strlen("{crypt}")) == 0) { + /* assume passwd is encrypted on command line */ + add_user_result = + auth_adduser(argv[0], &argv[1][strlen("{crypt}")], + "crypt", argv[2], argv[3], &useridnr); + } else if (strncasecmp(argv[1], "{md5:}", strlen("{md5:}")) == 0) { + /* encrypt using md5 crypt() */ + sprintf(pw, "%s%s%s", "$1$", cget_salt(), "$"); + strncpy(pw, crypt(&argv[1][strlen("{md5:}")], pw), 49); + add_user_result = auth_adduser(argv[0], pw, "md5", + argv[2], argv[3], + &useridnr); + } else if (strncasecmp(argv[1], "{md5}", strlen("{md5}")) == 0) { + /* assume passwd is encrypted on command line */ + add_user_result = + auth_adduser(argv[0], &argv[1][strlen("{md5}")], "md5", + argv[2], argv[3], &useridnr); + } else if (strncasecmp(argv[1], "{md5sum:}", strlen("{md5sum:}")) + == 0) { + /* encrypt using md5 digest */ + strcat(pw, makemd5(&argv[1][strlen("{md5sum:}")])); + add_user_result = + auth_adduser(argv[0], pw, "md5sum", argv[2], argv[3], + &useridnr); + } else if (strncasecmp(argv[1], "{md5sum}", strlen("{md5sum}")) == + 0) { + /* assume passwd is encrypted on command line */ + add_user_result = + auth_adduser(argv[0], &argv[1][strlen("{md5sum}")], + "md5sum", argv[2], argv[3], &useridnr); + } else { + add_user_result = auth_adduser(argv[0], argv[1], "", + argv[2], argv[3], + &useridnr); + } + + if (add_user_result == -1) { + /* check if existance of another user with the same name caused + the failure */ + if (auth_user_exists(argv[0], &useridnr) == -1) { + quiet_printf + ("Failed\n\nCheck logs for details\n\n"); + return -1; /* database failure */ + } + if (useridnr != 0) + quiet_printf("Failed: user exists [%llu]\n", + useridnr); + else { /* useridnr is 0 ! */ + quiet_printf + ("Failed\n\nCheck logs for details\n\n"); + useridnr = -1; + } + return -1; + } + + quiet_printf("Ok, user added id [%llu]\n", useridnr); + + for (i = 4, result = 0; i < argc; i++) { + quiet_printf("Adding alias %s...", argv[i]); + switch (db_addalias(useridnr, argv[i], atoi(argv[2]))) { + case -1: + quiet_printf("Failed\n"); + result = -1; + break; + + case 0: + quiet_printf("Ok, added\n"); + break; + + case 1: + quiet_printf + ("Already exists. No extra alias added\n"); + result = -1; + break; + } + } + + quiet_printf("adduser done\n"); + if (result != 0) + quiet_printf + ("Warning: user added but not all the specified aliases\n"); + + return result; } int do_change(char *argv[]) { - int i,result = 0, retval=0; - u64_t newsize,userid,newcid; - u64_t client_id; - char *endptr = NULL,*entry = NULL,*passwdfile = NULL; - char pw[50]=""; - - /* verify the existence of this user */ - if (auth_user_exists(argv[0], &userid) == -1) { - quiet_printf("Error verifying existence of user [%s]. Please check the log.\n",argv[0]); - return -1; - } - - if (userid == 0) - { - quiet_printf("Error: user [%s] does not exist.\n",argv[0]); - return -1; - } - - quiet_printf("Performing changes for user [%s]...",argv[0]); - - for (i=1; argv[i]; i++) - { - if (argv[i][0] != '-' && argv[i][0] != '+' && argv[i][0] != 'x' - && argv[i][0] != 'd' && argv[i][0] != 'D') - { - quiet_printf ("Failed: invalid option specified. Check the man page\n"); - return -1; + int i, result = 0, retval = 0; + u64_t newsize, userid, newcid; + u64_t client_id; + char *endptr = NULL, *entry = NULL, *passwdfile = NULL; + char pw[50] = ""; + + /* verify the existence of this user */ + if (auth_user_exists(argv[0], &userid) == -1) { + quiet_printf + ("Error verifying existence of user [%s]. Please check the log.\n", + argv[0]); + return -1; } - - switch (argv[i][1]) - { - case 'u': - /* change the name */ - if (argv[i][0] != '-') - { - quiet_printf ("Failed: invalid option specified. Check the man page\n"); - return -1; - } - if (!is_valid(argv[i+1])) - { - quiet_printf("\nWarning: username contains invalid characters. Username not updated. "); - retval = -1; - } - - if (auth_change_username(userid,argv[i+1]) != 0) - { - quiet_printf("\nWarning: could not change username "); - retval = -1; - } - - i++; - break; - - case 'p': - /* change the password */ - if (!is_valid(argv[i+1])) - { - quiet_printf("\nWarning: password contains invalid characters. Password not updated. "); - retval = -1; - } - - switch (argv[i][0]) - { - case '+': - /* +p will convert clear text into crypt hash value */ - strcat(pw,crypt(argv[i+1], cget_salt())); - result = auth_change_password(userid,pw,"crypt"); - break; - case '-': - strncpy(pw,argv[i+1],49); - result = auth_change_password(userid,pw,""); - break; - case 'x': - /* 'xp' will copy passwd from command line - assuming that the supplied passwd is crypt encrypted - */ - strncpy(pw,argv[i+1],49); - result = auth_change_password(userid,pw,"crypt"); - break; - default: - quiet_printf ("Failed: invalid option specified. Check the man page\n"); - return -1; - } - - if (result != 0) - { - quiet_printf("\nWarning: could not change password "); - retval = -1; - } - - i++; - break; - - case '5': - /* md5 passwords */ - if (!is_valid(argv[i+1])) - { - quiet_printf("\nWarning: password contains invalid characters. Password not updated. "); - retval = -1; - } - switch (argv[i][0]) - { - case '-': - /* -5 takes a md5 hash and saves it */ - strncpy(pw,argv[i+1],49); - result = auth_change_password(userid,pw,"md5"); - break; - case '+': - /* +5 takes a plaintext password and saves as a md5 hash */ - sprintf(pw,"%s%s%s","$1$",cget_salt(),"$"); - strncpy(pw,crypt(argv[i+1], pw),49); - result = auth_change_password(userid,pw,"md5"); - break; - case 'd': - /* d5 takes a md5 digest and saves it */ - strncpy(pw,argv[i+1],49); - result = auth_change_password(userid,pw,"md5sum"); - break; - case 'D': - /* D5 takes a plaintext password and saves as a md5 digest */ - strncat(pw,makemd5(argv[i+1]),49); - result = auth_change_password(userid,pw,"md5sum"); - break; - - default: - quiet_printf ("Failed: invalid option specified. Check the man page\n"); - return -1; - } - - if (result != 0) - { - quiet_printf("\nWarning: could not change password "); - retval = -1; - } - - i++; - break; - - case 'P': - /* -P will copy password from SHADOWFILE */ - /* -P:filename will copy password from filename */ - if (argv[i][0] != '-') - { - quiet_printf ("Failed: invalid option specified. Check the man page\n"); - return -1; - } - if (argv[i][2] == ':') - passwdfile = &argv[i][3]; - else - passwdfile = SHADOWFILE; - - - entry = bgetpwent(passwdfile, argv[0]); - if (!entry) - { - quiet_printf("\nWarning: error finding password from [%s] - are you superuser?\n", - passwdfile); - retval = -1; - break; - } - - strncat(pw,entry,50); - if ( strcmp(pw, "") == 0 ) - { - quiet_printf("\n%s's password not found at \"%s\" !\n", argv[0],passwdfile); - retval = -1; - } - else - { - if ( strncmp(pw, "$1$", 3) ) - { - if (auth_change_password(userid,pw,"crypt") != 0) - { - quiet_printf("\nWarning: could not change password"); - retval = -1; - } - } - else - { - if (auth_change_password(userid,pw,"md5") != 0) - { - quiet_printf("\nWarning: could not change password"); - retval = -1; - } - } - } - break; - case 'c': - if (argv[i][0] != '-') - { - quiet_printf ("Failed: invalid option specified. Check the man page\n"); - return -1; - } - - newcid = strtoull(argv[i+1], 0, 10); - - if (auth_change_clientid(userid, newcid) != 0) - { - quiet_printf("\nWarning: could not change client id "); - retval = -1; - } - - i++; - break; - - case 'q': - if (argv[i][0] != '-') - { - quiet_printf ("Failed: invalid option specified. Check the man page\n"); - return -1; - } - - newsize = strtoull(argv[i+1], &endptr, 10); - switch (*endptr) - { - case 'm': - case 'M': - newsize *= (1024 * 1024); - break; - - case 'k': - case 'K': - newsize *= 1024; - break; - } - - if (auth_change_mailboxsize(userid, newsize) != 0) - { - quiet_printf("\nWarning: could not change max mailboxsize "); - retval = -1; - } - - i++; - break; - - case 'a': - switch (argv[i][0]) - { - case '-': - /* remove alias */ - if (db_removealias(userid, argv[i+1]) < 0) - { - quiet_printf("\nWarning: could not remove alias [%s] ",argv[i+1]); - retval = -1; + if (userid == 0) { + quiet_printf("Error: user [%s] does not exist.\n", + argv[0]); + return -1; + } + + quiet_printf("Performing changes for user [%s]...", argv[0]); + + for (i = 1; argv[i]; i++) { + if (argv[i][0] != '-' && argv[i][0] != '+' + && argv[i][0] != 'x' && argv[i][0] != 'd' + && argv[i][0] != 'D') { + quiet_printf + ("Failed: invalid option specified. Check the man page\n"); + return -1; } - break; - case '+': - /* add alias */ - auth_getclientid(userid, &client_id); - if (db_addalias(userid, argv[i+1], client_id) < 0) - { - quiet_printf("\nWarning: could not add alias [%s]",argv[i+1]); - retval = -1; + + switch (argv[i][1]) { + case 'u': + /* change the name */ + if (argv[i][0] != '-') { + quiet_printf + ("Failed: invalid option specified. Check the man page\n"); + return -1; + } + if (!is_valid(argv[i + 1])) { + quiet_printf + ("\nWarning: username contains invalid characters. Username not updated. "); + retval = -1; + } + + if (auth_change_username(userid, argv[i + 1]) != 0) { + quiet_printf + ("\nWarning: could not change username "); + retval = -1; + } + + i++; + break; + + case 'p': + /* change the password */ + if (!is_valid(argv[i + 1])) { + quiet_printf + ("\nWarning: password contains invalid characters. Password not updated. "); + retval = -1; + } + + switch (argv[i][0]) { + case '+': + /* +p will convert clear text into crypt hash value */ + strcat(pw, + crypt(argv[i + 1], cget_salt())); + result = + auth_change_password(userid, pw, + "crypt"); + break; + case '-': + strncpy(pw, argv[i + 1], 49); + result = + auth_change_password(userid, pw, ""); + break; + case 'x': + /* 'xp' will copy passwd from command line + assuming that the supplied passwd is crypt encrypted + */ + strncpy(pw, argv[i + 1], 49); + result = + auth_change_password(userid, pw, + "crypt"); + break; + default: + quiet_printf + ("Failed: invalid option specified. Check the man page\n"); + return -1; + } + + if (result != 0) { + quiet_printf + ("\nWarning: could not change password "); + retval = -1; + } + + i++; + break; + + case '5': + /* md5 passwords */ + if (!is_valid(argv[i + 1])) { + quiet_printf + ("\nWarning: password contains invalid characters. Password not updated. "); + retval = -1; + } + switch (argv[i][0]) { + case '-': + /* -5 takes a md5 hash and saves it */ + strncpy(pw, argv[i + 1], 49); + result = + auth_change_password(userid, pw, + "md5"); + break; + case '+': + /* +5 takes a plaintext password and saves as a md5 hash */ + sprintf(pw, "%s%s%s", "$1$", cget_salt(), + "$"); + strncpy(pw, crypt(argv[i + 1], pw), 49); + result = + auth_change_password(userid, pw, + "md5"); + break; + case 'd': + /* d5 takes a md5 digest and saves it */ + strncpy(pw, argv[i + 1], 49); + result = + auth_change_password(userid, pw, + "md5sum"); + break; + case 'D': + /* D5 takes a plaintext password and saves as a md5 digest */ + strncat(pw, makemd5(argv[i + 1]), 49); + result = + auth_change_password(userid, pw, + "md5sum"); + break; + + default: + quiet_printf + ("Failed: invalid option specified. Check the man page\n"); + return -1; + } + + if (result != 0) { + quiet_printf + ("\nWarning: could not change password "); + retval = -1; + } + + i++; + break; + + case 'P': + /* -P will copy password from SHADOWFILE */ + /* -P:filename will copy password from filename */ + if (argv[i][0] != '-') { + quiet_printf + ("Failed: invalid option specified. Check the man page\n"); + return -1; + } + if (argv[i][2] == ':') + passwdfile = &argv[i][3]; + else + passwdfile = SHADOWFILE; + + + entry = bgetpwent(passwdfile, argv[0]); + if (!entry) { + quiet_printf + ("\nWarning: error finding password from [%s] - are you superuser?\n", + passwdfile); + retval = -1; + break; + } + + strncat(pw, entry, 50); + if (strcmp(pw, "") == 0) { + quiet_printf + ("\n%s's password not found at \"%s\" !\n", + argv[0], passwdfile); + retval = -1; + } else { + if (strncmp(pw, "$1$", 3)) { + if (auth_change_password + (userid, pw, "crypt") != 0) { + quiet_printf + ("\nWarning: could not change password"); + retval = -1; + } + } else { + if (auth_change_password + (userid, pw, "md5") != 0) { + quiet_printf + ("\nWarning: could not change password"); + retval = -1; + } + } + } + break; + + case 'c': + if (argv[i][0] != '-') { + quiet_printf + ("Failed: invalid option specified. Check the man page\n"); + return -1; + } + + newcid = strtoull(argv[i + 1], 0, 10); + + if (auth_change_clientid(userid, newcid) != 0) { + quiet_printf + ("\nWarning: could not change client id "); + retval = -1; + } + + i++; + break; + + case 'q': + if (argv[i][0] != '-') { + quiet_printf + ("Failed: invalid option specified. Check the man page\n"); + return -1; + } + + newsize = strtoull(argv[i + 1], &endptr, 10); + switch (*endptr) { + case 'm': + case 'M': + newsize *= (1024 * 1024); + break; + + case 'k': + case 'K': + newsize *= 1024; + break; + } + + if (auth_change_mailboxsize(userid, newsize) != 0) { + quiet_printf + ("\nWarning: could not change max mailboxsize "); + retval = -1; + } + + i++; + break; + + case 'a': + switch (argv[i][0]) { + case '-': + /* remove alias */ + if (db_removealias(userid, argv[i + 1]) < + 0) { + quiet_printf + ("\nWarning: could not remove alias [%s] ", + argv[i + 1]); + retval = -1; + } + break; + case '+': + /* add alias */ + auth_getclientid(userid, &client_id); + if (db_addalias + (userid, argv[i + 1], client_id) < 0) { + quiet_printf + ("\nWarning: could not add alias [%s]", + argv[i + 1]); + retval = -1; + } + break; + default: + quiet_printf + ("Failed: invalid option specified. Check the man page\n"); + return -1; + } + i++; + break; + + default: + quiet_printf + ("invalid option specified. Check the man page\n"); + return -1; } - break; - default: - quiet_printf ("Failed: invalid option specified. Check the man page\n"); - return -1; - } - i++; - break; - default: - quiet_printf ("invalid option specified. Check the man page\n"); - return -1; } - - } - quiet_printf("Done\n"); + quiet_printf("Done\n"); - return retval; + return retval; } int do_delete(char *name) { - int result; + int result; - quiet_printf("Deleting user [%s]...",name); + quiet_printf("Deleting user [%s]...", name); - result = auth_delete_user(name); + result = auth_delete_user(name); - if (result < 0) - { - quiet_printf("Failed. Please check the log\n"); - return -1; - } + if (result < 0) { + quiet_printf("Failed. Please check the log\n"); + return -1; + } - quiet_printf("Done\n"); - return 0; + quiet_printf("Done\n"); + return 0; } int do_show(char *name) { - u64_t userid,cid,quotum,quotumused; - struct list userlist; - struct element *tmp; - char *deliver_to; - - if (!name) - { - /* show all users */ - quiet_printf("Existing users:\n"); - - auth_get_known_users(&userlist); - - tmp = list_getstart(&userlist); - while (tmp) - { - quiet_printf("[%s]\n", (char*)tmp->data); - tmp = tmp->nextnode; - } + u64_t userid, cid, quotum, quotumused; + struct list userlist; + struct element *tmp; + char *deliver_to; - if (userlist.start) - list_freelist(&userlist.start); - } - else - { - quiet_printf("Info for user [%s]",name); - - if (auth_user_exists(name, &userid) == -1) { - quiet_printf("\nError verifying existence of user [%s]. Please check the log.\n",name); - return -1; - } - - if (userid == 0) - { - /* 'name' is not a user, try it as an alias */ - quiet_printf("..is not a user, trying as an alias"); - - deliver_to = db_get_deliver_from_alias(name); - - if (!deliver_to) - { - quiet_printf("\nError verifying existence of alias [%s]. Please check the log.\n",name); - return -1; - } - - if (deliver_to[0] == '\0') - { - quiet_printf("..is not an alias.\n"); - return 0; - } - - userid = strtoul(deliver_to, NULL, 10); - if (userid == 0) - { - quiet_printf("\n[%s] is an alias for [%s]\n", name, deliver_to); - my_free(deliver_to); - return 0; - } - - my_free(deliver_to); - quiet_printf("\nFound user for alias [%s]:\n\n", name); - } + if (!name) { + /* show all users */ + quiet_printf("Existing users:\n"); - auth_getclientid(userid, &cid); - auth_getmaxmailsize(userid, "um); - db_get_quotum_used(userid, "umused); - - quiet_printf("\n"); - quiet_printf("User ID : %llu\n", userid); - quiet_printf("Username : %s\n", auth_get_userid(userid)); - quiet_printf("Client ID : %llu\n",cid); - quiet_printf("Max. mailboxsize: %.02f MB\n",(double)quotum/(1024.0*1024.0)); - quiet_printf("Quotum used : %.02f MB (%.01f%%)\n", (double)quotumused/(1024.0*1024.0), - (100.0 * quotumused)/(double)quotum); - quiet_printf("\n"); - - quiet_printf("Aliases:\n"); - db_get_user_aliases(userid, &userlist); - - tmp = list_getstart(&userlist); - while (tmp) - { - quiet_printf("%s\n",(char*)tmp->data); - tmp = tmp->nextnode; - } + auth_get_known_users(&userlist); + + tmp = list_getstart(&userlist); + while (tmp) { + quiet_printf("[%s]\n", (char *) tmp->data); + tmp = tmp->nextnode; + } + + if (userlist.start) + list_freelist(&userlist.start); + } else { + quiet_printf("Info for user [%s]", name); + + if (auth_user_exists(name, &userid) == -1) { + quiet_printf + ("\nError verifying existence of user [%s]. Please check the log.\n", + name); + return -1; + } - quiet_printf("\n"); - if (userlist.start) - list_freelist(&userlist.start); - } + if (userid == 0) { + /* 'name' is not a user, try it as an alias */ + quiet_printf + ("..is not a user, trying as an alias"); + + deliver_to = db_get_deliver_from_alias(name); + + if (!deliver_to) { + quiet_printf + ("\nError verifying existence of alias [%s]. Please check the log.\n", + name); + return -1; + } + + if (deliver_to[0] == '\0') { + quiet_printf("..is not an alias.\n"); + return 0; + } + + userid = strtoul(deliver_to, NULL, 10); + if (userid == 0) { + quiet_printf + ("\n[%s] is an alias for [%s]\n", name, + deliver_to); + my_free(deliver_to); + return 0; + } + + my_free(deliver_to); + quiet_printf("\nFound user for alias [%s]:\n\n", + name); + } + + auth_getclientid(userid, &cid); + auth_getmaxmailsize(userid, "um); + db_get_quotum_used(userid, "umused); + + quiet_printf("\n"); + quiet_printf("User ID : %llu\n", userid); + quiet_printf("Username : %s\n", + auth_get_userid(userid)); + quiet_printf("Client ID : %llu\n", cid); + quiet_printf("Max. mailboxsize: %.02f MB\n", + (double) quotum / (1024.0 * 1024.0)); + quiet_printf("Quotum used : %.02f MB (%.01f%%)\n", + (double) quotumused / (1024.0 * 1024.0), + (100.0 * quotumused) / (double) quotum); + quiet_printf("\n"); + + quiet_printf("Aliases:\n"); + db_get_user_aliases(userid, &userlist); + + tmp = list_getstart(&userlist); + while (tmp) { + quiet_printf("%s\n", (char *) tmp->data); + tmp = tmp->nextnode; + } + + quiet_printf("\n"); + if (userlist.start) + list_freelist(&userlist.start); + } - return 0; + return 0; } @@ -720,125 +749,127 @@ int do_show(char *name) */ int do_empty(char *name) { - u64_t userid; - int result; - - if (auth_user_exists(name, &userid) == -1) { - quiet_printf("Error verifying existence of user [%s]. " - "Please check the log.\n",name); - return -1; - } - - if (userid == 0) - { - quiet_printf("User [%s] does not exist.\n", name); - return -1; - } - - quiet_printf("Emptying mailbox..."); fflush(stdout); - - result = db_empty_mailbox(userid); - if (result != 0) - quiet_printf("Error. Please check the log.\n",name); - else - quiet_printf("Ok.\n"); - - return result; + u64_t userid; + int result; + + if (auth_user_exists(name, &userid) == -1) { + quiet_printf("Error verifying existence of user [%s]. " + "Please check the log.\n", name); + return -1; + } + + if (userid == 0) { + quiet_printf("User [%s] does not exist.\n", name); + return -1; + } + + quiet_printf("Emptying mailbox..."); + fflush(stdout); + + result = db_empty_mailbox(userid); + if (result != 0) + quiet_printf("Error. Please check the log.\n", name); + else + quiet_printf("Ok.\n"); + + return result; } int is_valid(const char *name) { - int i; - - for (i=0; name[i]; i++) - if (strchr(ValidChars, name[i]) == NULL) - return 0; + int i; + + for (i = 0; name[i]; i++) + if (strchr(ValidChars, name[i]) == NULL) + return 0; - return 1; + return 1; } void show_help() { - printf ("\n*** dbmail-adduser ***\n"); - - printf("Use this program to manage the users for your dbmail system.\n"); - printf("See the man page for more info. Summary:\n\n"); - printf("dbmail-adduser [quiet] <a|d|c|s|f|x|e> [username] [options...]\n\n"); + printf("\n*** dbmail-adduser ***\n"); + + printf + ("Use this program to manage the users for your dbmail system.\n"); + printf("See the man page for more info. Summary:\n\n"); + printf + ("dbmail-adduser [quiet] <a|d|c|s|f|x|e> [username] [options...]\n\n"); } int quiet_printf(const char *fmt, ...) { - va_list argp; - int r; + va_list argp; + int r; - if (quiet) - return 0; - - va_start(argp, fmt); - r = vprintf(fmt, argp); - va_end(argp); + if (quiet) + return 0; - return r; + va_start(argp, fmt); + r = vprintf(fmt, argp); + va_end(argp); + + return r; } - + /*eddy This two function was base from "cpu" by Blake Matheny <matheny@dbaseiv.net> bgetpwent : get hash password from /etc/shadow cget_salt : generate salt value for crypt */ -char *bgetpwent(char *filename, char *name) +char *bgetpwent(char *filename, char *name) { - FILE *passfile = NULL; - char pass_char[512]; - int pass_size = 511; - char *pw = NULL; - char *user = NULL; - - if ((passfile = fopen(filename, "r")) == NULL) - return NULL; - - while (fgets(pass_char, pass_size, passfile) != NULL) { - char *m = pass_char; - int num_tok = 0; - char *toks; - - while (m != NULL && *m != 0) { - toks = getToken(&m, ":"); - if (num_tok == 0) - user = toks; - else if (num_tok == 1) - /*result->pw_passwd = toks;*/ - pw = toks; - else - break; - num_tok++; - } - if (strcmp(user, name) == 0) - return pw; - - } - return ""; + FILE *passfile = NULL; + char pass_char[512]; + int pass_size = 511; + char *pw = NULL; + char *user = NULL; + + if ((passfile = fopen(filename, "r")) == NULL) + return NULL; + + while (fgets(pass_char, pass_size, passfile) != NULL) { + char *m = pass_char; + int num_tok = 0; + char *toks; + + while (m != NULL && *m != 0) { + toks = getToken(&m, ":"); + if (num_tok == 0) + user = toks; + else if (num_tok == 1) + /*result->pw_passwd = toks; */ + pw = toks; + else + break; + num_tok++; + } + if (strcmp(user, name) == 0) + return pw; + + } + return ""; } char *cget_salt() { - unsigned long seed[2]; - const char *const seedchars = - "./0123456789ABCDEFGHIJKLMNOPQRST" - "UVWXYZabcdefghijklmnopqrstuvwxyz"; - int i; - - seed[0] = time(NULL); - seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000); - for (i = 0; i < 8; i++) - csalt[i] = seedchars[(seed[i / 5] >> (i % 5) * 6) & 0x3f]; - - return csalt; + unsigned long seed[2]; + const char *const seedchars = + "./0123456789ABCDEFGHIJKLMNOPQRST" + "UVWXYZabcdefghijklmnopqrstuvwxyz"; + int i; + + seed[0] = time(NULL); + seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000); + for (i = 0; i < 8; i++) + csalt[i] = seedchars[(seed[i / 5] >> (i % 5) * 6) & 0x3f]; + + return csalt; } @@ -847,28 +878,26 @@ char *cget_salt() by Blake Matheny <matheny@dbaseiv.net> getToken : break down username and password from a file */ -char *getToken(char** str,const char* delims) +char *getToken(char **str, const char *delims) { - char* token; - - if (*str==NULL) - { - /* No more tokens */ - return NULL; - } - - token=*str; - while (**str!='\0') - { - if (strchr(delims,**str)!=NULL) { - **str='\0'; - (*str)++; - return token; - } - (*str)++; - } + char *token; + + if (*str == NULL) { + /* No more tokens */ + return NULL; + } - /* There is no other token */ - *str=NULL; - return token; + token = *str; + while (**str != '\0') { + if (strchr(delims, **str) != NULL) { + **str = '\0'; + (*str)++; + return token; + } + (*str)++; + } + + /* There is no other token */ + *str = NULL; + return token; } @@ -25,4 +25,3 @@ #endif #define PNAME "dbmail/adduser" - diff --git a/vut2dbmail.c b/vut2dbmail.c index 8cea3d80..0615853a 100644 --- a/vut2dbmail.c +++ b/vut2dbmail.c @@ -46,145 +46,139 @@ int process_piece(char *left, char *right); int main(void) { - int i,result; - char *left, *right, *tmp; - - if (db_connect() != 0) - { - fprintf(stderr, "Could not connect to database\n"); - return 1; - } - - if (auth_connect() != 0) - { - fprintf(stderr, "Could not connect to authentication\n"); - db_disconnect(); - return 1; - } - - do - { - fgets(line, MAXLINESIZE, stdin); - - if (ferror(stdin) || feof(stdin)) - break; - - if (line[0] != '#' && line[0] != '\n' && line[0]) - { - line[strlen(line)-1] = 0; /* remove trailing space */ - - /* get left part of entry */ - for (i=0; line[i] && !isspace(line[i]); i++) ; - - if (!line[i] || line[i] == '\n') - { - if (i > 0) - { - fprintf(stderr, "Found [%*s], don't know what to do with it\n", - i-1, line); - } - continue; - } + int i, result; + char *left, *right, *tmp; - line[i] = 0; - left = line; + if (db_connect() != 0) { + fprintf(stderr, "Could not connect to database\n"); + return 1; + } - while (isspace(line[++i])) ; + if (auth_connect() != 0) { + fprintf(stderr, "Could not connect to authentication\n"); + db_disconnect(); + return 1; + } - right = &line[i]; + do { + fgets(line, MAXLINESIZE, stdin); - do - { - tmp = strchr(right, ','); /* find delimiter */ + if (ferror(stdin) || feof(stdin)) + break; - if (tmp) - *tmp = 0; /* end string on delimiter position */ + if (line[0] != '#' && line[0] != '\n' && line[0]) { + line[strlen(line) - 1] = 0; /* remove trailing space */ - if ((result = process_piece(left, right)) < 0) - { - if (result == -1) - { - fprintf(stderr, "Error processing [%s] [%s]\n",left,right); - } - } + /* get left part of entry */ + for (i = 0; line[i] && !isspace(line[i]); i++); - if (tmp) - { - right = tmp+1; - while (isspace(*right)) right++; - } - } while (tmp && *right); + if (!line[i] || line[i] == '\n') { + if (i > 0) { + fprintf(stderr, + "Found [%*s], don't know what to do with it\n", + i - 1, line); + } + continue; + } - } - } while (!feof(stdin) && !ferror(stdin)); + line[i] = 0; + left = line; + + while (isspace(line[++i])); + + right = &line[i]; + + do { + tmp = strchr(right, ','); /* find delimiter */ + + if (tmp) + *tmp = 0; /* end string on delimiter position */ + + if ((result = + process_piece(left, right)) < 0) { + if (result == -1) { + fprintf(stderr, + "Error processing [%s] [%s]\n", + left, right); + } + } - /* ok everything inserted. - * - * the alias table should be cleaned up now.. - */ + if (tmp) { + right = tmp + 1; + while (isspace(*right)) + right++; + } + } while (tmp && *right); - db_disconnect(); - auth_disconnect(); - return 0; + } + } while (!feof(stdin) && !ferror(stdin)); + + /* ok everything inserted. + * + * the alias table should be cleaned up now.. + */ + + db_disconnect(); + auth_disconnect(); + return 0; } - + int process_piece(char *left, char *right) { - u64_t useridnr,clientidnr; - - /* check what right contains: - * username or email address - */ - - if (strchr(right, '@') || strchr(right,'|')) - { - /* email - * add this alias if it doesn't already exist - */ - - if (db_addalias_ext(left, right, 0) == -1) - return -1; - - printf("alias [%s] --> [%s] created\n",left,right); - return 0; - } - else - { - /* username - * check if this user exists - */ - - if (auth_user_exists(right, &useridnr) < -1) - return -1; - - if (useridnr == 0) - { - /* new user */ - if (auth_adduser(right, "geheim", "", "0", "0", &useridnr) == -1) - { - fprintf(stderr,"Could not add user [%s]\n",right); - return -1; - } - } + u64_t useridnr, clientidnr; + + /* check what right contains: + * username or email address + */ + + if (strchr(right, '@') || strchr(right, '|')) { + /* email + * add this alias if it doesn't already exist + */ + + if (db_addalias_ext(left, right, 0) == -1) + return -1; + + printf("alias [%s] --> [%s] created\n", left, right); + return 0; + } else { + /* username + * check if this user exists + */ + + if (auth_user_exists(right, &useridnr) < -1) + return -1; + + if (useridnr == 0) { + /* new user */ + if (auth_adduser + (right, "geheim", "", "0", "0", + &useridnr) == -1) { + fprintf(stderr, + "Could not add user [%s]\n", + right); + return -1; + } + } - /* this user now exists, add alias */ - if ( auth_getclientid(useridnr, &clientidnr) == -1) - { - fprintf(stderr,"Could not retrieve client id nr for user [%s] [id %llu]\n", - right, useridnr); - return -1; - } + /* this user now exists, add alias */ + if (auth_getclientid(useridnr, &clientidnr) == -1) { + fprintf(stderr, + "Could not retrieve client id nr for user [%s] [id %llu]\n", + right, useridnr); + return -1; + } - if (db_addalias(useridnr, left, clientidnr) == -1) - { - fprintf(stderr,"Could not add alias [%s] for user [%s] [id %llu]\n", - left, right, useridnr); - return -1; - } + if (db_addalias(useridnr, left, clientidnr) == -1) { + fprintf(stderr, + "Could not add alias [%s] for user [%s] [id %llu]\n", + left, right, useridnr); + return -1; + } - printf("alias [%s] --> [%s] created\n",left,right); - return 0; - } + printf("alias [%s] --> [%s] created\n", left, right); + return 0; + } } |