Группа :: Система/Серверы
Пакет: dbmail
Главная Изменения Спек Патчи Загрузить Bugs and FR
Патч: dbmail-2.0.5_0.6-folders.patch
diff -urN dbmail-2.0.5/README.folders dbmail-2.0.5-folders/README.folders
--- dbmail-2.0.5/README.folders 1969-12-31 19:00:00.000000000 -0500
+++ dbmail-2.0.5-folders/README.folders 2005-08-16 15:47:51.000000000 -0400
@@ -0,0 +1,126 @@
+DBMail user+folder@domain.name Patch
+Patch Name: dbmail-2.0.5_0.6-folders.patch
+
+Author: <niblettda at gru dot com>
+Patch version: v0.6
+
+This patch allows the use of the common form: user+folder@domain.name.
+
+I wrote this patch because I wanted to sort Email out from Amavis such
+that it will be sent to a users Spam folder based on their Amavis/
+SpamAssassin settings.
+
+Currently this patch version only permits dbmail-lmtpd to sort based on
+the folder.
+
+There is a config option line CREATE_FOLDERS that takes the form of:
+
+ CREATE_FOLDERS=:FOLDER:FOLDER:FOLDER:
+
+These are folders that are allowed to be created if they don't exist.
+If a supplied folder to the LMTP Daemon doesn't exist is not in the
+CREATE_FOLDERS list, the email will delivered to the users INBOX.
+
+There is no need to include INBOX in the folder list, as the server
+should always be able to create that folder.
+
+
+
+* A NOTE ABOUT CASE *
+
+Without a doubt the biggest problem I've encountered has been surrounding
+case sensitivity. For example, if Amavis is supposed to deliver the
+message to user+SPAM, and the user has a mailbox for spam, but it's called
+"Spam", then many things could happen.
+
+ - Deliver to the "Spam" box (this is what I do).
+ - Create a new box called "Spam", and deliver to it.
+ - Say that Spam isn't in the CREATE_FOLDERS list and dump it to INBOX.
+
+Each have their positives and negatives. My approach has been based on
+what I expect my "general population" of users to expect. I believe that
+most people are not going to make "Spam", "SPAM", "SpAm", etc. mailboxes.
+If your experience is different, then by all means, please feel free to
+alter my patch to suit your needs.
+
+
+
+* TO DO *
+- Currently there is a minor bug with delivery to multiple recipients
+ via aliases. For example, if you have user1@domain and user2@domain,
+ then an alias alias@domain with a deliver_to BOTH user1@domain AND
+ user2@domain. If either user has say mailbox XYZ, and a message is
+ delivered to alias+XYZ@domain, even if XYZ is not in the auto create
+ list, because one of the two users has the mailbox, the other user
+ will get one created as well.
+
+ The only way to fix the above problem would be a major change to the
+ dsnuser structure in DBMail and that is beyond the scope of this patch.
+ So for the time being this is one bug that will have to exist.
+
+
+
+* CHANGE LOG *
+
+dbmail-2.0.5_0.6-folder:
+- Renamed the patch to 2.0.5 since it is now based on the 2.0.5 code.
+
+- Removed code from sort/sort.c, now we will create the folder in the
+ db.c (db_find_create_mailbox) function per request from Paul.
+
+- Moved valid_folder checking in lmtp.c to after verification that the
+ username is valid before bothering to check if the folder is valid.
+
+- Changed valid_folder to recieve a userids list so that I can check
+ by user_idnr rather than the address to deliver. This is important
+ to fix an issue where delivery to an alias, as the alias wouldn't
+ have any folders to deliver to.
+
+- Modified db_find_create_mailbox function to also IMAP subscribe the
+ mailbox to the user if it has to be created.
+
+- I no longer only check for subscribed mailboxes for delivery, so be
+ aware that if a user unscribes, but still has the box, that it may
+ be able to continue to grow in size.
+
+
+dbmail-2.0.4_0.5-folders:
+- Updated the README, which was forgotten in v0.4
+
+
+dbmail-2.0.4_0.4-folders:
+- Fixed a problem with creating the mailbox if it didn't exist. This would
+ cause LMTPD to crash. Mainly just changed order of events.
+
+- Found and fixed error with determining if the folder could be created.
+ Was appending to string rather than overwriting.
+
+- Added the feature that if the mailbox is created for the user they are
+ also automatically subscribed to the mailbox.
+
+
+dbmail-2.0.4_0.3-folders:
+- Found problems with code should a folder not exist. This patch version
+ was never released.
+
+
+dbmail-2.0.4_0.2-folders:
+- Removed case insensitivity DB search that was valid only for PostgreSQL.
+ (Thanks to Paul J. Stevens <paul at nfg dot nl>)
+
+- Added bound limits to strncpy() in misc.c to prevent excessive folder
+ length from over writing memory.
+ (Thanks to Paul J. Stevens <paul at nfg dot nl>)
+
+- Changed misc.c, valid_folders() function to use db_findfolder_by_regex().
+ (Thanks to Wolfram)
+
+- Changed misc.c, valid_folders() function to use the folder name as stored
+ in the database, which prevents us from creating two folders with same
+ name but different case. (See above above)
+
+
+dbmail-2.0.4-folders:
+- Changed my_free() function in lmtp.c to dm_free() since my_free() was
+ renamed in v2.0.4 of DBMail
+
diff -urN dbmail-2.0.5/db.c dbmail-2.0.5-folders/db.c
--- dbmail-2.0.5/db.c 2005-04-22 09:03:31.000000000 -0400
+++ dbmail-2.0.5-folders/db.c 2005-08-16 15:36:45.000000000 -0400
@@ -2952,10 +2952,17 @@
"%s, %s: seriously could not create mailbox [%s]",
__FILE__, __func__, name);
return -1;
+ } else {
+ /* Since we had to create the mailbox, subscribe to it too. */
+ trace(TRACE_DEBUG,
+ "%s, %s: mailbox [%s] created on the fly", __FILE__,
+ __func__, name);
+
+ /* No reason to output an error since db_subscribe does it. */
+ /* Also, as long as the box was created, even if we have a */
+ /* problem subscribing we assume message delivery will work. */
+ db_subscribe(mboxidnr, owner_idnr);
}
- trace(TRACE_DEBUG,
- "%s, %s: mailbox [%s] created on the fly", __FILE__,
- __func__, name);
}
trace(TRACE_DEBUG, "%s, %s: mailbox [%s] found",
__FILE__, __func__, name);
diff -urN dbmail-2.0.5/dbmail.conf dbmail-2.0.5-folders/dbmail.conf
--- dbmail-2.0.5/dbmail.conf 2005-04-22 09:03:31.000000000 -0400
+++ dbmail-2.0.5-folders/dbmail.conf 2005-08-16 15:34:47.000000000 -0400
@@ -19,6 +19,7 @@
pass= # password for user to database
db= # name of database
POSTMASTER= # postmaster's email address.
+CREATE_FOLDER=:INBOX:SPAM:
# trace level for dbmail-util
TRACE_LEVEL=2
diff -urN dbmail-2.0.5/lmtp.c dbmail-2.0.5-folders/lmtp.c
--- dbmail-2.0.5/lmtp.c 2005-04-22 09:03:31.000000000 -0400
+++ dbmail-2.0.5-folders/lmtp.c 2005-08-16 13:07:31.000000000 -0400
@@ -525,10 +525,14 @@
} else {
size_t tmplen = 0, tmppos = 0;
char *tmpaddr = NULL;
+ char *tmpfolder = NULL;
find_bounded(value, '<', '>', &tmpaddr,
&tmplen, &tmppos);
+ /* Remove the folder if there is one. */
+ remove_folder(&tmpaddr, &tmplen);
+
if (tmplen < 1) {
ci_write((FILE *) stream,
"500 No address found.\r\n");
@@ -556,6 +560,16 @@
/* Class 2 means the address was deliverable in some way. */
switch (dsnuser.dsn.class) {
case DSN_CLASS_OK:
+ /* Determine if there is a folder involved for this address. */
+ if (! find_bounded(value, '+', '@', &tmpfolder, &tmplen, &tmppos)) {
+ /* Is it a valid mailbox for this address? */
+ if (valid_folder(dsnuser.userids, tmpfolder)) {
+ dsnuser.mailbox = tmpfolder;
+ } else {
+ /* Free the memory from find_bounded */
+ dm_free(tmpfolder);
+ }
+ }
ci_write((FILE *) stream,
"250 Recipient <%s> OK\r\n",
dsnuser.address);
diff -urN dbmail-2.0.5/misc.c dbmail-2.0.5-folders/misc.c
--- dbmail-2.0.5/misc.c 2005-04-22 09:03:31.000000000 -0400
+++ dbmail-2.0.5-folders/misc.c 2005-08-16 15:38:28.000000000 -0400
@@ -491,3 +491,138 @@
return 0;
}
}
+
+/* Finds the folder if included in an address between a '+' and '@'.
+ * Does not allocate memory since that should already be done prior to
+ * calling this function. The string must be shorter if anything.
+ * retchar will have the new string or the original value if there is
+ * no folder to remove.
+ *
+ * Return values are:
+ * 0 on success (found)
+ * -1 on failure (not found)
+ *
+ * */
+int remove_folder(char **retchar, size_t * retsize)
+{
+ char *value;
+ char *tmpleft;
+ char *tmpright;
+ size_t tmplen;
+
+ char left = '+';
+ char right = '@';
+
+ value = *retchar;
+ 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: No folder found.",
+ __FILE__, __func__);
+ *retsize = strlen(*retchar);
+ return -1;
+ } else {
+ tmplen = strlen(value) - (strlen(tmpleft) - strlen(tmpright));
+ strncpy(*retchar, value, (strlen(value) - strlen(tmpleft)));
+ (*retchar)[(strlen(value) - strlen(tmpleft))] = '\0';
+ strncat(*retchar, tmpright, strlen(tmpright));
+ (*retchar)[tmplen] = '\0';
+ *retsize = tmplen;
+ trace(TRACE_INFO,
+ "%s, %s: Found [%s] of length [%zd] around '%c' and '%c'.",
+ __FILE__, __func__, *retchar, *retsize, left,
+ right);
+ return 0;
+ }
+}
+
+/* Function to determine if the requested mailbox exists or is valid to
+ * be created for the specified userid
+ *
+ * Return values are:
+ * 1 on success (existing or allowed to be created)
+ * 0 on failure (does not exist not allowed to be created)
+ *
+ * */
+
+int valid_folder(struct list *userids, char *folder)
+{
+ int result;
+ field_t val;
+ char tmp[IMAP_MAX_MAILBOX_NAMELEN+2] = "";
+ u64_t *children = NULL;
+ unsigned nchildren;
+ struct element *element;
+
+ /* Create the pattern to search on the folder list. */
+ tmp[0] = '^';
+ strncat(&tmp[1], folder, IMAP_MAX_MAILBOX_NAMELEN-3);
+ strcat(tmp, "$");
+
+ /* We need to check all the user_idnr's */
+ for (element = list_getstart(userids); element != NULL;
+ element = element->nextnode) {
+ /* Save the current useridnr in something more useful. */
+ u64_t useridnr = *(u64_t *) element->data;
+
+ /* Search folders for delivery. */
+ result = db_findmailbox_by_regex(useridnr, tmp, &children, &nchildren, 1);
+
+ /* Invalid response, deal with it. */
+ if (result != 0) {
+ trace(TRACE_INFO, "%s, %s: Folder [%s] regex failure for id [%llu].",
+ __FILE__, __func__, folder, useridnr);
+ return 0;
+ }
+
+ /* If we got some children back we are home free. */
+ if (nchildren > 0) {
+
+ u64_t mailboxidnr = children[0]; /* Save the mailboxid for later. */
+ dm_free(children); /* Done with the children. */
+
+ /* Set the folder name to what is in the database, this is */
+ /* to avoid mixed case differences. See README.folders. */
+ result = db_getmailboxname(mailboxidnr, useridnr, folder);
+
+ /* No success, then bail out and assume INBOX */
+ if (result == -1) {
+ trace(TRACE_INFO, "%s, %s: Folder [%s] lookup failure for id [%llu].",
+ __FILE__, __func__, folder, useridnr);
+ return 0;
+ }
+
+ /* Otherwise we now have the foldername as appears in the DB. */
+ trace(TRACE_INFO, "%s, %s: mailbox [%s] exists for id [%llu].",
+ __FILE__, __func__, folder, useridnr);
+ return 1;
+ }
+
+ /* No existing folder, are we allowed to create it? */
+ GetConfigValue("CREATE_FOLDERS", "DBMAIL", val);
+
+ /* Reset the tmp string and get our search item. */
+ /* we can cheat and just modify our initial search string some */
+ tmp[0] = ':';
+ tmp[strlen(tmp)-1] = ':';
+
+ if (strcasestr(val, tmp) != NULL) {
+ trace(TRACE_INFO, "%s,%s: folder [%s] is in create list [%s]",
+ __FILE__, __func__, tmp, val);
+ return 1;
+ }
+
+ trace(TRACE_INFO, "%s,%s: failed to find or create folder [%s] for id [%llu], using INBOX",
+ __FILE__, __func__, folder, useridnr);
+ }
+
+ /* Either user doesn't exist, or not allowed to create. */
+ return 0;
+}
diff -urN dbmail-2.0.5/misc.h dbmail-2.0.5-folders/misc.h
--- dbmail-2.0.5/misc.h 2005-04-22 09:03:31.000000000 -0400
+++ dbmail-2.0.5-folders/misc.h 2005-08-16 13:04:17.000000000 -0400
@@ -105,6 +105,8 @@
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 remove_folder(char **retchar, size_t * retsize);
+int valid_folder(struct list *userids, char *folder);
int base64_grow_ret(char ***inchar, size_t ** inint, size_t newcount,
size_t newchar);