diff -Naur cyrus-imapd-2.2.10/imap/imapd.c cyrus-imapd-2.2.10.autocreate.uncompiled/imap/imapd.c --- cyrus-imapd-2.2.10/imap/imapd.c 2004-11-18 00:29:03.000000000 +0200 +++ cyrus-imapd-2.2.10.autocreate.uncompiled/imap/imapd.c 2004-11-24 12:36:54.000000000 +0200 @@ -158,6 +158,7 @@ void motd_file(int fd); void shut_down(int code); void fatal(const char *s, int code); +void autocreate_inbox(void); void cmdloop(void); void cmd_login(char *tag, char *user); @@ -1694,6 +1695,43 @@ } /* + * Autocreate Inbox and subfolders upon login + */ +void autocreate_inbox() +{ + char inboxname[MAX_MAILBOX_NAME+1]; + int autocreatequota; + int r; + + /* + * Exlude admin's accounts + */ + if (imapd_userisadmin || imapd_userisproxyadmin) + return; + + /* + * Exclude anonymous + */ + if (!strcmp(imapd_userid, "anonymous")) + return; + + + if ((autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA))) { + /* This is actyally not required + as long as the lenght of userid is ok */ + r = (*imapd_namespace.mboxname_tointernal) (&imapd_namespace, + "INBOX", imapd_userid, inboxname); + if (!r) + r = mboxlist_lookup(inboxname, NULL, NULL, NULL); + + if (r == IMAP_MAILBOX_NONEXISTENT) + mboxlist_autocreateinbox(&imapd_namespace, imapd_userid, + imapd_authstate, inboxname, autocreatequota); + } +} + + +/* * Perform a LOGIN command */ void cmd_login(char *tag, char *user) @@ -1849,6 +1887,9 @@ strcspn(imapd_userid, "@") : 0); freebuf(&passwdbuf); + + autocreate_inbox(); + return; } @@ -1994,6 +2035,8 @@ config_virtdomains ? strcspn(imapd_userid, "@") : 0); + autocreate_inbox(); + return; } diff -Naur cyrus-imapd-2.2.10/imap/lmtpd.c cyrus-imapd-2.2.10.autocreate.uncompiled/imap/lmtpd.c --- cyrus-imapd-2.2.10/imap/lmtpd.c 2004-09-09 19:21:26.000000000 +0300 +++ cyrus-imapd-2.2.10.autocreate.uncompiled/imap/lmtpd.c 2004-11-24 12:36:54.000000000 +0200 @@ -106,6 +106,8 @@ static FILE *spoolfile(message_data_t *msgdata); static void removespool(message_data_t *msgdata); +static int autocreate_inbox(char *rcpt_userid); + /* current namespace */ static struct namespace lmtpd_namespace; @@ -505,10 +507,52 @@ exit(code); } +/* + * Autocreate Inbox and subfolders upon login + */ +int autocreate_inbox(char *rcpt_userid) +{ + struct auth_state *authstate; + char inboxname[MAX_MAILBOX_NAME+1]; + int rcptisadmin ; + int autocreatequota; + int r; + + /* + * Exclude anonymous + */ + if (!strcmp(rcpt_userid, "anonymous")) + return IMAP_MAILBOX_NONEXISTENT; + + /* + * Check for autocreatequota and createonpost + */ + if (!(autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA)) || + !(config_getswitch(IMAPOPT_CREATEONPOST))) + return IMAP_MAILBOX_NONEXISTENT; + + /* + * Exclude admin's accounts + */ + authstate = auth_newstate(rcpt_userid); + rcptisadmin = global_authisa(authstate, IMAPOPT_ADMINS); + if (rcptisadmin) + return IMAP_MAILBOX_NONEXISTENT; + + r = (*lmtpd_namespace.mboxname_tointernal) (&lmtpd_namespace, + "INBOX", rcpt_userid, inboxname); + if (!r) + r = mboxlist_autocreateinbox(&lmtpd_namespace, rcpt_userid, + authstate, inboxname, autocreatequota); + return r; +} + + static int verify_user(const char *user, const char *domain, const char *mailbox, long quotacheck, struct auth_state *authstate) { char namebuf[MAX_MAILBOX_NAME+1] = ""; + char *userinbox = NULL; int r = 0; if ((!user && !mailbox) || @@ -546,6 +590,23 @@ */ r = append_check(namebuf, MAILBOX_FORMAT_NORMAL, authstate, !user ? ACL_POST : 0, quotacheck > 0 ? 0 : quotacheck); + if (r == IMAP_MAILBOX_NONEXISTENT) { + if(domain) { + int k; + userinbox = (char *)xmalloc((strlen(user)+strlen(domain)+2)*sizeof(char)); + k = strlcpy(userinbox, user, strlen(user)+1); + *(userinbox + k) = '@'; + strlcpy(userinbox+k+1, domain, strlen(domain)+1); + } + else userinbox = user; + r = autocreate_inbox(userinbox); + if(userinbox != user) + free(userinbox); + if (!r) + r = append_check(namebuf, MAILBOX_FORMAT_NORMAL, authstate, + 0, quotacheck > 0 ? 0 : quotacheck); + } + } if (r) syslog(LOG_DEBUG, "verify_user(%s) failed: %s", namebuf, diff -Naur cyrus-imapd-2.2.10/imap/mboxlist.c cyrus-imapd-2.2.10.autocreate.uncompiled/imap/mboxlist.c --- cyrus-imapd-2.2.10/imap/mboxlist.c 2004-07-26 21:08:03.000000000 +0300 +++ cyrus-imapd-2.2.10.autocreate.uncompiled/imap/mboxlist.c 2004-11-24 12:36:54.000000000 +0200 @@ -98,6 +98,10 @@ static int mboxlist_changequota(const char *name, int matchlen, int maycreate, void *rock); +static int mboxlist_autosubscribe_sharedfolders(struct namespace *namespace, + char *userid, + struct auth_state *auth_state); + struct change_rock { struct quota *quota; struct txn **tid; @@ -3124,3 +3128,209 @@ return DB->abort(mbdb, tid); } + + +#define SEP '|' + +/* + * Automatically subscribe user to a shared folder. + * Subscription is done successfully, if the shared + * folder exists and the user has the necessary + * permissions. + */ +static int mboxlist_autosubscribe_sharedfolders(struct namespace *namespace, + char *userid, + struct auth_state *auth_state) { + + const char *sub ; + char *p, *q, *next_sub; + char folder [MAX_MAILBOX_NAME+1], name[MAX_MAILBOX_NAME+1], mailboxname[MAX_MAILBOX_NAME+1]; + int len; + int r = 0; + + if ((sub=config_getstring(IMAPOPT_AUTOSUBSCRIBESHAREDFOLDERS)) == NULL) + return r; + + next_sub = (char *) sub; + while (*next_sub) { + for (p = next_sub ; isspace((int) *p) || *p == SEP ; p++); + for (next_sub = p ; *next_sub && *next_sub != SEP ; next_sub++); + for (q = next_sub ; q > p && (isspace((int) *q) || *q == SEP || !*q) ; q--); + if (!*p ) continue; + + len = q - p + 1; + /* Check for folder length */ + if (len > sizeof(folder)-1) + continue; + + if (!r) { + strncpy(folder, p, len); + folder[len] = NULL; + + strlcpy(name, namespace->prefix[NAMESPACE_SHARED], sizeof(name)); + len = strlcat(name, folder, sizeof(name)); + + r = (namespace->mboxname_tointernal) (namespace, name, userid, + mailboxname); + } + + if (!r) + r = mboxlist_changesub(mailboxname, userid, auth_state, 1, 0); + + if (!r) { + syslog(LOG_DEBUG,"autosubscribe: User %s to %s succeeded", + userid, folder); + } else { + syslog(LOG_ERR, "autosubscribe: User %s to %s failed: %s", + userid, folder, error_message(r)); + r = 0; + } + } + + return r; +} + + + +int mboxlist_autocreateinbox(struct namespace *namespace, + char *userid, + struct auth_state *auth_state, + char *mailboxname, int autocreatequota) { + char name [MAX_MAILBOX_NAME+1]; + char folder [MAX_MAILBOX_NAME+1]; + char *partition = NULL; + const char *crt; + const char *sub; + char *p, *q, *next_crt, *next_sub; + int len; + int r = 0; + int numcrt = 0; + int numsub = 0; + +#if 0 + /* + * Get Partition info or return. + * (Here you should propably use + * you own "get_partition(char *userid)" + * function. Otherwise all new INBOXes will be + * created into whatever partition has been declared + * as default in your imapd.conf) + */ + + partition = get_partition(userid); + + if (partition == NULL) { + /* + * Couldn't get partition info + */ + syslog(LOG_WARNING, + "Could not get imapPartition info for user %s", userid); + return IMAP_PARTITION_UNKNOWN; + } +#endif + + + r = mboxlist_createmailbox(mailboxname, MAILBOX_FORMAT_NORMAL, NULL, + 1, userid, auth_state, 0, 0, 0); + + if (!r && autocreatequota > 0) + r = mboxlist_setquota(mailboxname, autocreatequota, 0); + + if (!r) + r = mboxlist_changesub(mailboxname, userid, + auth_state, 1, 1); + + if (!r) + syslog(LOG_NOTICE, "autocreateinbox: User %s, INBOX was successfully created in partition %s", + userid, partition == NULL ? "default" : partition); + else { + syslog(LOG_ERR, "autocreateinbox: User %s, INBOX failed. %s", + userid, error_message(r)); + return r; + } + + /* INBOX's subfolders */ + if ((crt=config_getstring(IMAPOPT_AUTOCREATEINBOXFOLDERS))) + sub=config_getstring(IMAPOPT_AUTOSUBSCRIBEINBOXFOLDERS); + + /* Roll through crt */ + next_crt = (char *) crt; + while (next_crt!=NULL && *next_crt) { + for (p = next_crt ; isspace((int) *p) || *p == SEP ; p++); + for (next_crt = p ; *next_crt && *next_crt != SEP ; next_crt++); + for (q = next_crt ; q > p && (isspace((int) *q) || *q == SEP || !*q); q--); + + if (!*p) continue; + + len = q - p + 1; + + /* First time we check for length */ + if (len > sizeof(folder) - 5) + r = IMAP_MAILBOX_BADNAME; + + if (!r) { + strncpy(folder, p, len); + folder[len] = '\0'; + + strlcpy(name, namespace->prefix[NAMESPACE_INBOX], sizeof(name)); + len = strlcat(name, folder, sizeof(name)); + } + + if (!r) + r = (namespace->mboxname_tointernal) (namespace, name, userid, + mailboxname); + if (!r) + r = mboxlist_createmailbox(mailboxname, MAILBOX_FORMAT_NORMAL, NULL, + 1, userid, auth_state, 0, 0, 0); + + + if (!r) { + numcrt++; + syslog(LOG_DEBUG, "autocreateinbox: User %s, subfolder %s creation succeeded.", + userid, name); + } else { + syslog(LOG_ERR, "autocreateinbox: User %s, subfolder %s creation failed. %s", + userid, name, error_message(r)); + r=0; + continue; + } + + /* Roll through sub */ + next_sub = (char *) sub; + while (next_sub!=NULL && *next_sub) { + for (p = next_sub ; isspace((int) *p) || *p == SEP ; p++); + for (next_sub = p ; *next_sub && *next_sub != SEP ; next_sub++); + for (q = next_sub ; q > p && (isspace((int) *q) || *q == SEP || !*q) ; q--); + if (!*p ) continue; + + len = q - p + 1; + + if (len != strlen(folder) || strncmp(folder, p, len)) + continue; + + r = mboxlist_changesub(mailboxname, userid, auth_state, 1, 1); + + if (!r) { + numsub++; + syslog(LOG_DEBUG,"autocreateinbox: User %s, subscription to %s succeeded", + userid, name); + } else + syslog(LOG_ERR, "autocreateinbox: User %s, subscription to %s failed. %s", + userid, name, error_message(r)); + + break; + } + } + + if (crt!=NULL && *crt) + syslog(LOG_INFO, "User %s, Inbox subfolders, created %d, subscribed %d", + userid, numcrt, numsub); + + /* + * Check if shared folders are available for subscription. + */ + mboxlist_autosubscribe_sharedfolders(namespace, userid, auth_state); + + return r; +} + diff -Naur cyrus-imapd-2.2.10/imap/mboxlist.h cyrus-imapd-2.2.10.autocreate.uncompiled/imap/mboxlist.h --- cyrus-imapd-2.2.10/imap/mboxlist.h 2004-03-17 20:07:49.000000000 +0200 +++ cyrus-imapd-2.2.10.autocreate.uncompiled/imap/mboxlist.h 2004-11-24 12:36:54.000000000 +0200 @@ -197,4 +197,10 @@ int mboxlist_commit(struct txn *tid); int mboxlist_abort(struct txn *tid); +int mboxlist_autocreateinbox(struct namespace *namespace, + char *userid, + struct auth_state *auth_state, + char *mailboxname, int autocreatequota); + + #endif diff -Naur cyrus-imapd-2.2.10/imap/pop3d.c cyrus-imapd-2.2.10.autocreate.uncompiled/imap/pop3d.c --- cyrus-imapd-2.2.10/imap/pop3d.c 2004-09-09 19:21:26.000000000 +0300 +++ cyrus-imapd-2.2.10.autocreate.uncompiled/imap/pop3d.c 2004-11-24 12:36:55.000000000 +0200 @@ -152,6 +152,8 @@ static char popd_apop_chal[45 + MAXHOSTNAMELEN + 1]; /* */ static void cmd_apop(char *response); +static int autocreate_inbox(char *inboxname, char *userid); + static void cmd_auth(char *arg); static void cmd_capa(void); static void cmd_pass(char *pass); @@ -1085,6 +1087,7 @@ popd_userid = xstrdup(p); prot_printf(popd_out, "+OK Name is a valid mailbox\r\n"); } + } void cmd_pass(char *pass) @@ -1329,6 +1332,43 @@ } /* + * Autocreate Inbox and subfolders upon login + */ +int autocreate_inbox(char *inboxname, char *userid) +{ + struct auth_state *authstate; + int userisadmin ; + int autocreatequota; + int r; + + /* + * Exclude anonymous + */ + if (!strcmp(popd_userid, "anonymous")) + return IMAP_MAILBOX_NONEXISTENT; + + /* + * Check for autocreatequota + */ + if (!(autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA))) + return IMAP_MAILBOX_NONEXISTENT; + + /* + * Exclude admin's accounts + */ + + authstate = auth_newstate(popd_userid); + userisadmin = global_authisa(authstate, IMAPOPT_ADMINS); + if (userisadmin) + return IMAP_MAILBOX_NONEXISTENT; + + r = mboxlist_autocreateinbox(&popd_namespace, userid, + authstate, inboxname, autocreatequota); + return r; +} + + +/* * Complete the login process by opening and locking the user's inbox */ int openinbox(void) @@ -1350,6 +1390,10 @@ userid, inboxname); if (!r) r = mboxlist_detail(inboxname, &type, NULL, &server, &acl, NULL); + /* Try once again after autocreate_inbox */ + if (r == IMAP_MAILBOX_NONEXISTENT && !(r = autocreate_inbox(inboxname, userid))) + r = mboxlist_detail(inboxname, &type, NULL, &server, &acl, NULL); + if (!r && (config_popuseacl = config_getswitch(IMAPOPT_POPUSEACL)) && (!acl || !((myrights = cyrus_acl_myrights(popd_authstate, acl)) & ACL_READ))) { diff -Naur cyrus-imapd-2.2.10/lib/imapoptions cyrus-imapd-2.2.10.autocreate.uncompiled/lib/imapoptions --- cyrus-imapd-2.2.10/lib/imapoptions 2004-07-21 22:07:45.000000000 +0300 +++ cyrus-imapd-2.2.10.autocreate.uncompiled/lib/imapoptions 2004-11-24 12:36:55.000000000 +0200 @@ -169,6 +169,29 @@ /* Number of seconds to wait before returning a timeout failure when performing a client connection (e.g. in a murder enviornment) */ +{ "createonpost", 0, SWITCH } +/* If yes, when lmtpd receives an incoming mail for an INBOX that does not exist, + then the INBOX is automatically created by lmtpd. */ + +{ "autocreateinboxfolders", NULL, STRING } +/* If a user does not have an INBOX created then the INBOX as well as some INBOX subfolders are + created under two conditions. + 1. The user logins via the IMAP or the POP3 protocol. (autocreatequota option must have a nonzero value) + 2. A message arrives for the user through the LMTPD protocol.(createonpost option must yes) + autocreateinboxfolders is a list of INBOX's subfolders separated by a "|", that are automatically created by the server + under the previous two situations. */ + +{ "autosubscribeinboxfolders", NULL, STRING } +/* A list of folder names, separated by "|" that the users get automatically subscribed to, when their INBOX + is created. + These folder names must have been included in the autocreateinboxfolders option of the imapd.conf. */ + +{ "autosubscribesharedfolders", NULL, STRING } +/* A list of shared folders (bulletin boards), separated by "|" that the users get + automatically subscribed to, after their INBOX + is created. The shared folder must have been created and the user must have the + required permissions to get subscribed to the it. Otherwise the subscription fails. */ + { "configdirectory", NULL, STRING } /* The pathname of the IMAP configuration directory. This field is required. */