Commit message: imapd: check for isadmin BEFORE parsing sync lines
CVE: CVE-2017-12843
CWE: CWE-20
Vulnerability description: Cyrus IMAP before 3.0.3 allows remote authenticated users to write to arbitrary files via a crafted (1) SYNCAPPLY, (2) SYNCGET or (3) SYNCRESTORE command.

Project: cyrus-imapd
File: imapd.c

static int _metadata_to_annotate(const strarray_t *entries,
                                 strarray_t *newa, strarray_t *newe,
                                 const char *tag, int depth)
{
    int i;
    int have_shared = 0;
    int have_private = 0;

    /* we need to rewrite the entries and attribs to match the way that
     * the old annotation system works. */
    for (i = 0 ; i < entries->count ; i++) {
        char *ent = entries->data[i];
        char entry[MAX_MAILBOX_NAME+1];

        lcase(ent);
        /* there's no way to perfect this - unfortunately - the old style
         * syntax doesn't support everything.  XXX - will be nice to get
         * rid of this... */
        if (!strncmp(ent, "/private", 8) &&
            (ent[8] == '\0' || ent[8] == '/')) {
            xstrncpy(entry, ent + 8, MAX_MAILBOX_NAME);
            have_private = 1;
        }
        else if (!strncmp(ent, "/shared", 7) &&
                 (ent[7] == '\0' || ent[7] == '/')) {
            xstrncpy(entry, ent + 7, MAX_MAILBOX_NAME);
            have_shared = 1;
        }
        else {
            if (tag)
                prot_printf(imapd_out,
                            "%s BAD entry must begin with /shared or /private\r\n",
                            tag);
            return IMAP_NO_NOSUCHMSG;
        }
        strarray_append(newe, entry);
        if (depth == 1) {
            strncat(entry, "/%", MAX_MAILBOX_NAME);
            strarray_append(newe, entry);
        }
        else if (depth == -1) {
            strncat(entry, "/*", MAX_MAILBOX_NAME);
            strarray_append(newe, entry);
        }
    }

    if (have_private) strarray_append(newa, "value.priv");
    if (have_shared) strarray_append(newa, "value.shared");

    return 0;
}

Project: cyrus-imapd
File: imapd.c

static int annot_fetch_cb(annotate_state_t *astate, void *rock)
{
    struct annot_fetch_rock *arock = rock;
    return annotate_state_fetch(astate, arock->entries, arock->attribs,
                                arock->callback, arock->cbrock);
}

Project: cyrus-imapd
File: imapd.c

static int annot_store_cb(annotate_state_t *astate, void *rock)
{
    struct annot_store_rock *arock = rock;
    return annotate_state_store(astate, arock->entryatts);
}

Project: cyrus-imapd
File: imapd.c

static void appendfieldlist(struct fieldlist **l, char *section,
                     strarray_t *fields, char *trail,
                     void *d, size_t size)
{
    struct fieldlist **tail = l;

    while (*tail) tail = &(*tail)->next;

    *tail = (struct fieldlist *)xmalloc(sizeof(struct fieldlist));
    (*tail)->section = xstrdup(section);
    (*tail)->fields = fields;
    (*tail)->trail = xstrdup(trail);
    if(d && size) {
        (*tail)->rock = xmalloc(size);
        memcpy((*tail)->rock, d, size);
    } else {
        (*tail)->rock = NULL;
    }
    (*tail)->next = 0;
}

Project: cyrus-imapd

static int apply_cb(struct findall_data *data, void* rock)
{
    if (!data) return 0;
    struct apply_rock *arock = (struct apply_rock *)rock;
    annotate_state_t *state = arock->state;
    int r;

    /* Suppress any output of a partial match */
    if (!data->mbname)
        return 0;

    strlcpy(arock->lastname, mbname_intname(data->mbname), sizeof(arock->lastname));

    /* NOTE: this is a fricking horrible abuse of layers.  We'll be passing the
     * extname less horribly one day */
    const char *extname = mbname_extname(data->mbname, &imapd_namespace, imapd_userid);
    mbentry_t *backdoor = (mbentry_t *)data->mbentry;
    backdoor->ext_name = xmalloc(strlen(extname)+1);
    strcpy(backdoor->ext_name, extname);

    r = annotate_state_set_mailbox_mbe(state, data->mbentry);
    if (r) return r;

    r = arock->proc(state, arock->data);
    arock->nseen++;

    return r;
}

Project: cyrus-imapd
File: imapd.c

static int apply_mailbox_array(annotate_state_t *state,
                               const strarray_t *mboxes,
                               int (*proc)(annotate_state_t *, void *),
                               void *rock)
{
    int i;
    mbentry_t *mbentry = NULL;
    char *intname = NULL;
    int r = 0;

    for (i = 0 ; i < mboxes->count ; i++) {
        intname = mboxname_from_external(strarray_nth(mboxes, i), &imapd_namespace, imapd_userid);

        r = mboxlist_lookup(intname, &mbentry, NULL);
        if (r)
            break;

        r = annotate_state_set_mailbox_mbe(state, mbentry);
        if (r)
            break;

        r = proc(state, rock);
        if (r)
            break;

        mboxlist_entry_free(&mbentry);
        free(intname);
        intname = NULL;
    }

    mboxlist_entry_free(&mbentry);
    free(intname);

    return r;
}

Project: cyrus-imapd
File: imapd.c

static int apply_mailbox_pattern(annotate_state_t *state,
                                 const char *pattern,
                                 int (*proc)(annotate_state_t *, void *),
                                 void *data)
{
    struct apply_rock arock;
    int r = 0;

    memset(&arock, 0, sizeof(arock));
    arock.state = state;
    arock.proc = proc;
    arock.data = data;

    r = mboxlist_findall(&imapd_namespace,
                         pattern,
                         imapd_userisadmin || imapd_userisproxyadmin,
                         imapd_userid,
                         imapd_authstate,
                         apply_cb, &arock);

    if (!r && !arock.nseen)
        r = IMAP_MAILBOX_NONEXISTENT;

    return r;
}

Project: cyrus-imapd
File: imapd.c

static void authentication_success(void)
{
    int r;
    struct mboxevent *mboxevent;

    /* authstate already created by mysasl_proxy_policy() */
    imapd_userisadmin = global_authisa(imapd_authstate, IMAPOPT_ADMINS);

    /* Create telemetry log */
    imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);

    /* Set namespace */
    r = mboxname_init_namespace(&imapd_namespace,
                                imapd_userisadmin || imapd_userisproxyadmin);

    mboxevent_setnamespace(&imapd_namespace);

    if (r) {
        syslog(LOG_ERR, "%s", error_message(r));
        fatal(error_message(r), EC_CONFIG);
    }

    /* Make a copy of the external userid for use in proxying */
    proxy_userid = xstrdup(imapd_userid);

    /* send a Login event notification */
    if ((mboxevent = mboxevent_new(EVENT_LOGIN))) {
        mboxevent_set_access(mboxevent, saslprops.iplocalport,
                             saslprops.ipremoteport, imapd_userid, NULL, 1);

        mboxevent_notify(&mboxevent);
        mboxevent_free(&mboxevent);
    }

#ifdef USE_AUTOCREATE
    autocreate_inbox();
#endif // USE_AUTOCREATE
}

Project: cyrus-imapd
File: imapd.c

static void autocreate_inbox(void)
{
    if (imapd_userisadmin) return;
    if (imapd_userisproxyadmin) return;

    if (config_getint(IMAPOPT_AUTOCREATE_QUOTA) >= 0) {
        char *inboxname = mboxname_user_mbox(imapd_userid, NULL);
        int r = mboxlist_lookup(inboxname, NULL, NULL);
        free(inboxname);
        if (r != IMAP_MAILBOX_NONEXISTENT) return;
        autocreate_user(&imapd_namespace, imapd_userid);
    }
}

Project: cyrus-imapd
File: imapd.c

static char *canonical_list_pattern(const char *reference, const char *pattern)
{
    int patlen = strlen(pattern);
    int reflen = strlen(reference);

    char *buf = xmalloc(patlen + reflen + 1);
    buf[0] = '\0';

    if (*reference) {
        if (reference[reflen-1] == imapd_namespace.hier_sep &&
                pattern[0] == imapd_namespace.hier_sep)
            --reflen;
        memcpy(buf, reference, reflen);
        buf[reflen] = '\0';
    }
    strcat(buf, pattern);

    return buf;
}

Project: cyrus-imapd
File: imapd.c

static void canonical_list_patterns(const char *reference,
                                    strarray_t *patterns)
{
    static int ignorereference = 0;
    int i;

    /* Ignore the reference argument?
       (the behavior in 1.5.10 & older) */
    if (ignorereference == 0)
        ignorereference = config_getswitch(IMAPOPT_IGNOREREFERENCE);

    for (i = 0 ; i < patterns->count ; i++) {
        char *p = patterns->data[i];
        if (!ignorereference || p[0] == imapd_namespace.hier_sep) {
            strarray_setm(patterns, i,
                          canonical_list_pattern(reference, p));
            p = patterns->data[i];
        }
    }
}

Project: cyrus-imapd
File: imapd.c

static void capa_response(int flags)
{
    const char *sasllist; /* the list of SASL mechanisms */
    int mechcount;
    int need_space = 0;
    int i;

    int lminus = config_getswitch(IMAPOPT_LITERALMINUS);

    for (i = 0; base_capabilities[i].str; i++) {
        const char *capa = base_capabilities[i].str;
        /* Filter capabilities if requested */
        if (capa_is_disabled(capa))
            continue;
        /* Don't show "MAILBOX-REFERRALS" if disabled by config */
        if (config_getswitch(IMAPOPT_PROXYD_DISABLE_MAILBOX_REFERRALS) &&
            !strcmp(capa, "MAILBOX-REFERRALS"))
            continue;
        /* Don't show if they're not shown at this level of login */
        if (!(base_capabilities[i].mask & flags))
            continue;
        /* cheap and nasty version of LITERAL- support - just say so */
        if (lminus && !strcmp(capa, "LITERAL+"))
            capa = "LITERAL-";
        /* print the capability */
        if (need_space) prot_putc(' ', imapd_out);
        else need_space = 1;
        prot_printf(imapd_out, "%s", base_capabilities[i].str);
    }

    if (config_mupdate_server) {
        prot_printf(imapd_out, " MUPDATE=mupdate://%s/", config_mupdate_server);
    }

    if (apns_enabled) {
        prot_printf(imapd_out, " XAPPLEPUSHSERVICE");
    }

    if (tls_enabled() && !imapd_starttls_done && !imapd_authstate) {
        prot_printf(imapd_out, " STARTTLS");
    }
    if (imapd_tls_required || imapd_authstate ||
        (!imapd_starttls_done && (extprops_ssf < 2) &&
         !config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
        prot_printf(imapd_out, " LOGINDISABLED");
    }

    /* add the SASL mechs */
    if (!imapd_tls_required && (!imapd_authstate || saslprops.ssf) &&
        sasl_listmech(imapd_saslconn, NULL,
                      "AUTH=", " AUTH=",
                      !imapd_authstate ? " SASL-IR" : "", &sasllist,
                      NULL, &mechcount) == SASL_OK && mechcount > 0) {
        prot_printf(imapd_out, " %s", sasllist);
    } else {
        /* else don't show anything */
    }

    if (!(flags & CAPA_POSTAUTH)) return;

    if (config_getswitch(IMAPOPT_CONVERSATIONS))
        prot_printf(imapd_out, " XCONVERSATIONS");

#ifdef HAVE_ZLIB
    if (!imapd_compress_done && !imapd_tls_comp) {
        prot_printf(imapd_out, " COMPRESS=DEFLATE");
    }
#endif // HAVE_ZLIB

    for (i = 0 ; i < QUOTA_NUMRESOURCES ; i++)
        prot_printf(imapd_out, " X-QUOTA=%s", quota_names[i]);

    if (idle_enabled()) {
        prot_printf(imapd_out, " IDLE");
    }
}

Project: cyrus-imapd
File: imapd.c

static int catenate_url(const char *s, const char *cur_name, FILE *f,
                        unsigned *totalsize, const char **parseerr)
{
    struct imapurl url;
    struct index_state *state;
    uint32_t msgno;
    int r = 0, doclose = 0;
    unsigned long size = 0;

    r = imapurl_fromURL(&url, s);

    if (r) {
        *parseerr = "Improperly specified URL";
        r = IMAP_BADURL;
    } else if (url.server) {
        *parseerr = "Only relative URLs are supported";
        r = IMAP_BADURL;
#if 0
    } else if (url.server && strcmp(url.server, config_servername)) {
        *parseerr = "Cannot catenate messages from another server";
        r = IMAP_BADURL;
#endif
    } else if (!url.mailbox && !imapd_index && !cur_name) {
        *parseerr = "No mailbox is selected or specified";
        r = IMAP_BADURL;
    } else if (url.mailbox || (url.mailbox = cur_name)) {
        mbentry_t *mbentry = NULL;

        /* lookup the location of the mailbox */
        char *intname = mboxname_from_external(url.mailbox, &imapd_namespace, imapd_userid);
        r = mlookup(NULL, NULL, intname, &mbentry);

        if (!r && (mbentry->mbtype & MBTYPE_REMOTE)) {
            /* remote mailbox */
            struct backend *be;

            be = proxy_findserver(mbentry->server, &imap_protocol,
                                 proxy_userid, &backend_cached,
                                 &backend_current, &backend_inbox, imapd_in);
            if (be) {
                r = proxy_catenate_url(be, &url, f, &size, parseerr);
                if (*totalsize > UINT_MAX - size)
                    r = IMAP_MESSAGE_TOO_LARGE;
                else
                    *totalsize += size;
            }
            else
                r = IMAP_SERVER_UNAVAILABLE;

            free(url.freeme);
            mboxlist_entry_free(&mbentry);
            free(intname);

            return r;
        }

        mboxlist_entry_free(&mbentry);

        /* local mailbox */
        if (!r) {
            struct index_init init;
            memset(&init, 0, sizeof(init));
            init.userid = imapd_userid;
            init.authstate = imapd_authstate;
            init.out = imapd_out;
            r = index_open(intname, &init, &state);
            if (init.vanishedlist) seqset_free(init.vanishedlist);
        }
        if (!r) doclose = 1;

        if (!r && !(state->myrights & ACL_READ))
            r = (imapd_userisadmin || (state->myrights & ACL_LOOKUP)) ?
                IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;

        if (r) {
            *parseerr = error_message(r);
            r = IMAP_BADURL;
        }

        free(intname);
    } else {
        state = imapd_index;
    }

    if (r) {
        /* nothing to do, handled up top */
    } else if (url.uidvalidity &&
               (state->mailbox->i.uidvalidity != url.uidvalidity)) {
        *parseerr = "Uidvalidity of mailbox has changed";
        r = IMAP_BADURL;
    } else if (!url.uid || !(msgno = index_finduid(state, url.uid)) ||
               (index_getuid(state, msgno) != url.uid)) {
        *parseerr = "No such message in mailbox";
        r = IMAP_BADURL;
    } else {
        /* Catenate message part to stage */
        struct protstream *s = prot_new(fileno(f), 1);

        r = index_urlfetch(state, msgno, 0, url.section,
                           url.start_octet, url.octet_count, s, &size);
        if (r == IMAP_BADURL)
            *parseerr = "No such message part";
        else if (!r) {
            if (*totalsize > UINT_MAX - size)
                r = IMAP_MESSAGE_TOO_LARGE;
            else
                *totalsize += size;
        }

        prot_flush(s);
        prot_free(s);

        /* XXX  do we want to try and validate the message like
           we do in message_copy_strict()? */
    }

    free(url.freeme);

    if (doclose) index_close(&state);

    return r;
}

Project: cyrus-imapd
File: imapd.c

static int checklimits(const char *tag)
{
    struct proc_limits limits;

    limits.procname = "imapd";
    limits.clienthost = imapd_clienthost;
    limits.userid = imapd_userid;

    if (proc_checklimits(&limits)) {
        const char *sep = "";
        prot_printf(imapd_out, "%s NO Too many open connections (", tag);
        if (limits.maxhost) {
            prot_printf(imapd_out, "%s%d of %d from %s", sep,
                        limits.host, limits.maxhost, imapd_clienthost);
            sep = ", ";
        }
        if (limits.maxuser) {
            prot_printf(imapd_out, "%s%d of %d for %s", sep,
                        limits.user, limits.maxuser, imapd_userid);
        }
        prot_printf(imapd_out, ")\r\n");
        free(imapd_userid);
        imapd_userid = NULL;
        auth_freestate(imapd_authstate);
        imapd_authstate = NULL;
        return 1;
    }
    return 0;
}

Project: cyrus-imapd
File: imapd.c

static int checkmboxname(const mbentry_t *mbentry, void *rock)
{
    struct renrock *text = (struct renrock *)rock;
    int r;

    text->found++;

    if((text->nl + strlen(mbentry->name + text->ol)) >= MAX_MAILBOX_BUFFER)
        return IMAP_MAILBOX_BADNAME;

    strcpy(text->newmailboxname + text->nl, mbentry->name + text->ol);

    /* force create, but don't ignore policy.  This is a filthy hack that
       will go away when we refactor this code */
    r = mboxlist_createmailboxcheck(text->newmailboxname, 0, text->partition, 1,
                                    imapd_userid, imapd_authstate, NULL, NULL, 2);
    return r;
}

Project: cyrus-imapd
File: imapd.c

static void cmd_authenticate(char *tag, char *authtype, char *resp)
{
    int sasl_result;

    const void *val;
    const char *ssfmsg = NULL;
    char replybuf[MAX_MAILBOX_BUFFER];
    const char *reply = NULL;

    const char *canon_user;

    int r;
    int failedloginpause;

    if (imapd_tls_required) {
        prot_printf(imapd_out,
                    "%s NO Authenticate only available under a layer\r\n", tag);
        return;
    }

    r = saslserver(imapd_saslconn, authtype, resp, "", "+ ", "",
                   imapd_in, imapd_out, &sasl_result, NULL);

    if (r) {
        const char *errorstring = NULL;

        switch (r) {
        case IMAP_SASL_CANCEL:
            prot_printf(imapd_out,
                        "%s BAD Client canceled authentication\r\n", tag);
            break;
        case IMAP_SASL_PROTERR:
            errorstring = prot_error(imapd_in);

            prot_printf(imapd_out,
                        "%s NO Error reading client response: %s\r\n",
                        tag, errorstring ? errorstring : "");
            break;
        default:
            /* failed authentication */
            syslog(LOG_NOTICE, "badlogin: %s %s [%s]",
                   imapd_clienthost, authtype, sasl_errdetail(imapd_saslconn));

            snmp_increment_args(AUTHENTICATION_NO, 1,
                                VARIABLE_AUTH, 0, /* hash_simple(authtype) */
                                VARIABLE_LISTEND);
            failedloginpause = config_getint(IMAPOPT_FAILEDLOGINPAUSE);
            if (failedloginpause != 0) {
                sleep(failedloginpause);
            }

            /* Don't allow user probing */
            if (sasl_result == SASL_NOUSER) sasl_result = SASL_BADAUTH;

            errorstring = sasl_errstring(sasl_result, NULL, NULL);
            if (errorstring) {
                prot_printf(imapd_out, "%s NO %s\r\n", tag, errorstring);
            } else {
                prot_printf(imapd_out, "%s NO Error authenticating\r\n", tag);
            }
        }

        reset_saslconn(&imapd_saslconn);
        return;
    }

    /* successful authentication */

    /* get the userid from SASL --- already canonicalized from
     * mysasl_proxy_policy()
     */
    sasl_result = sasl_getprop(imapd_saslconn, SASL_USERNAME, &val);
    if (sasl_result != SASL_OK) {
        prot_printf(imapd_out, "%s NO weird SASL error %d SASL_USERNAME\r\n",
                    tag, sasl_result);
        syslog(LOG_ERR, "weird SASL error %d getting SASL_USERNAME",
               sasl_result);
        reset_saslconn(&imapd_saslconn);
        return;
    }
    canon_user = (const char *) val;

    /* If we're proxying, the authzid may contain a magic plus,
       so re-canonify it */
    if (config_getswitch(IMAPOPT_IMAPMAGICPLUS) && strchr(canon_user, '+')) {
        char userbuf[MAX_MAILBOX_BUFFER];
        unsigned userlen;

        sasl_result = imapd_canon_user(imapd_saslconn, NULL, canon_user, 0,
                                       SASL_CU_AUTHID | SASL_CU_AUTHZID,
                                       NULL, userbuf, sizeof(userbuf), &userlen);
        if (sasl_result != SASL_OK) {
            prot_printf(imapd_out,
                        "%s NO SASL canonification error %d\r\n",
                        tag, sasl_result);
            reset_saslconn(&imapd_saslconn);
            return;
        }

        imapd_userid = xstrdup(userbuf);
    } else {
        imapd_userid = xstrdup(canon_user);
    }

    snprintf(replybuf, sizeof(replybuf),
        "User logged in SESSIONID=<%s>", session_id());
    reply = replybuf;
    syslog(LOG_NOTICE, "login: %s %s%s %s%s %s", imapd_clienthost,
           imapd_userid, imapd_magicplus ? imapd_magicplus : "",
           authtype, imapd_starttls_done ? "+TLS" : "", reply);

    sasl_getprop(imapd_saslconn, SASL_SSF, &val);
    saslprops.ssf = *((sasl_ssf_t *) val);

    /* really, we should be doing a sasl_getprop on SASL_SSF_EXTERNAL,
       but the current libsasl doesn't allow that. */
    if (imapd_starttls_done) {
        switch(saslprops.ssf) {
        case 0: ssfmsg = "tls protection"; break;
        case 1: ssfmsg = "tls plus integrity protection"; break;
        default: ssfmsg = "tls plus privacy protection"; break;
        }
    } else {
        switch(saslprops.ssf) {
        case 0: ssfmsg = "no protection"; break;
        case 1: ssfmsg = "integrity protection"; break;
        default: ssfmsg = "privacy protection"; break;
        }
    }

    snmp_increment_args(AUTHENTICATION_YES, 1,
                        VARIABLE_AUTH, 0, /* hash_simple(authtype) */
                        VARIABLE_LISTEND);

    if (checklimits(tag)) {
        reset_saslconn(&imapd_saslconn);
        return;
    }

    if (!saslprops.ssf) {
        prot_printf(imapd_out, "%s OK [CAPABILITY ", tag);
        capa_response(CAPA_PREAUTH|CAPA_POSTAUTH);
        prot_printf(imapd_out, "] Success (%s) SESSIONID=<%s>\r\n",
                    ssfmsg, session_id());
    } else {
        prot_printf(imapd_out, "%s OK Success (%s) SESSIONID=<%s>\r\n",
                    tag, ssfmsg, session_id());
    }

    prot_setsasl(imapd_in,  imapd_saslconn);
    prot_setsasl(imapd_out, imapd_saslconn);

    authentication_success();
}

Project: cyrus-imapd
File: imapd.c

static void cmd_capability(char *tag)
{
    imapd_check(NULL, 0);

    prot_printf(imapd_out, "* CAPABILITY ");

    capa_response(CAPA_PREAUTH|CAPA_POSTAUTH);

    prot_printf(imapd_out, "\r\n%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
}

Project: cyrus-imapd
File: imapd.c

static void cmd_changesub(char *tag, char *namespace, char *name, int add)
{
    const char *cmd = add ? "Subscribe" : "Unsubscribe";
    int r = 0;
    int force = config_getswitch(IMAPOPT_ALLOWALLSUBSCRIBE);

    if (backend_inbox || (backend_inbox = proxy_findinboxserver(imapd_userid))) {
        /* remote INBOX */
        if (add) {
            char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);
            r = mlookup(NULL, NULL, intname, NULL);
            free(intname);

            /* Doesn't exist on murder */
        }

        imapd_check(backend_inbox, 0);

        if (!r) {
            if (namespace) {
                prot_printf(backend_inbox->out,
                            "%s %s {" SIZE_T_FMT "+}\r\n%s"
                            " {" SIZE_T_FMT "+}\r\n%s\r\n",
                            tag, cmd,
                            strlen(namespace), namespace,
                            strlen(name), name);
            } else {
                prot_printf(backend_inbox->out, "%s %s {" SIZE_T_FMT "+}\r\n%s\r\n",
                            tag, cmd,
                            strlen(name), name);
            }
            pipe_including_tag(backend_inbox, tag, 0);
        }
        else {
            prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        }

        return;
    }

    /* local INBOX */
    if (namespace) lcase(namespace);
    if (!namespace || !strcmp(namespace, "mailbox")) {
        size_t len = strlen(name);
        if (force && imapd_namespace.isalt &&
            (((len == strlen(imapd_namespace.prefix[NAMESPACE_USER]) - 1) &&
              !strncmp(name, imapd_namespace.prefix[NAMESPACE_USER], len)) ||
             ((len == strlen(imapd_namespace.prefix[NAMESPACE_SHARED]) - 1) &&
              !strncmp(name, imapd_namespace.prefix[NAMESPACE_SHARED], len)))) {
            r = 0;
        }
        else {
            char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);
            r = mboxlist_changesub(intname, imapd_userid, imapd_authstate, add, force, 1);
            free(intname);
        }
    }
    else if (!strcmp(namespace, "bboard")) {
        r = add ? IMAP_MAILBOX_NONEXISTENT : 0;
    }
    else {
        prot_printf(imapd_out, "%s BAD Invalid %s subcommand\r\n", tag, cmd);
        return;
    }

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s: %s\r\n", tag, cmd, error_message(r));
    }
    else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }
}

Project: cyrus-imapd
File: imapd.c

static void cmd_close(char *tag, char *cmd)
{
    if (backend_current) {
        /* remote mailbox */
        prot_printf(backend_current->out, "%s %s\r\n", tag, cmd);
        /* xxx do we want this to say OK if the connection is gone?
         * saying NO is clearly wrong, hense the fatal request. */
        pipe_including_tag(backend_current, tag, 0);

        /* remove backend_current from the protgroup */
        protgroup_delete(protin, backend_current->in);

        backend_current = NULL;
        return;
    }

    /* local mailbox */
    if ((cmd[0] == 'C') && index_hasrights(imapd_index, ACL_EXPUNGE)) {
        index_expunge(imapd_index, NULL, 1);
        /* don't tell changes here */
    }

    index_close(&imapd_index);

    /* http://www.rfc-editor.org/errata_search.php?rfc=5162
     * Errata ID: 1808 - don't send HIGHESTMODSEQ to a close
     * command, because it can lose synchronisation */
    prot_printf(imapd_out, "%s OK %s\r\n",
                tag, error_message(IMAP_OK_COMPLETED));
}

Project: cyrus-imapd
File: imapd.c

static void cmd_copy(char *tag, char *sequence, char *name, int usinguid, int ismove)
{
    int r, myrights;
    char *copyuid = NULL;
    mbentry_t *mbentry = NULL;

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);
    r = mlookup(NULL, NULL, intname, &mbentry);

    if (!r) myrights = cyrus_acl_myrights(imapd_authstate, mbentry->acl);

    if (!r && backend_current) {
        /* remote mailbox -> local or remote mailbox */

        /* xxx  start of separate proxy-only code
           (remove when we move to a unified environment) */
        struct backend *s = NULL;

        s = proxy_findserver(mbentry->server, &imap_protocol,
                             proxy_userid, &backend_cached,
                             &backend_current, &backend_inbox, imapd_in);
        mboxlist_entry_free(&mbentry);
        if (!s) {
            r = IMAP_SERVER_UNAVAILABLE;
            goto done;
        }

        if (s != backend_current) {
            /* this is the hard case; we have to fetch the messages and append
               them to the other mailbox */

            proxy_copy(tag, sequence, name, myrights, usinguid, s);
            goto cleanup;
        }
        /* xxx  end of separate proxy-only code */

        /* simply send the COPY to the backend */
        prot_printf(
                backend_current->out,
                "%s %s %s {" SIZE_T_FMT "+}\r\n%s\r\n",
                tag,
                usinguid ? (ismove ? "UID Move" : "UID Copy") : (ismove ? "Move" : "Copy"),
                sequence,
                strlen(name),
                name
            );

        pipe_including_tag(backend_current, tag, 0);

        goto cleanup;
    }
    else if (!r && (mbentry->mbtype & MBTYPE_REMOTE)) {
        /* local mailbox -> remote mailbox
         *
         * fetch the messages and APPEND them to the backend
         *
         * xxx  completely untested
         */
        struct backend *s = NULL;
        int res;

        s = proxy_findserver(mbentry->server, &imap_protocol,
                             proxy_userid, &backend_cached,
                             &backend_current, &backend_inbox, imapd_in);
        mboxlist_entry_free(&mbentry);
        if (!s) r = IMAP_SERVER_UNAVAILABLE;
        else if (!CAPA(s, CAPA_MULTIAPPEND)) {
            /* we need MULTIAPPEND for atomicity */
            r = IMAP_REMOTE_NO_MULTIAPPEND;
        }

        if (r) goto done;

        assert(!ismove); /* XXX - support proxying moves */

        /* start the append */
        prot_printf(s->out, "%s Append {" SIZE_T_FMT "+}\r\n%s",
                    tag, strlen(name), name);

        /* append the messages */
        r = index_copy_remote(imapd_index, sequence, usinguid, s->out);

        if (!r) {
            /* ok, finish the append; we need the UIDVALIDITY and UIDs
               to return as part of our COPYUID response code */
            char *appenduid, *b;

            prot_printf(s->out, "\r\n");

            res = pipe_until_tag(s, tag, 0);

            if (res == PROXY_OK) {
                if (myrights & ACL_READ) {
                    appenduid = strchr(s->last_result.s, '[');
                    /* skip over APPENDUID */
                    if (appenduid) {
                        appenduid += strlen("[appenduid ");
                        b = strchr(appenduid, ']');
                        if (b) *b = '\0';
                        prot_printf(imapd_out, "%s OK [COPYUID %s] %s\r\n", tag,
                                    appenduid, error_message(IMAP_OK_COMPLETED));
                    } else
                        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                                    error_message(IMAP_OK_COMPLETED));
                } else {
                    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                                error_message(IMAP_OK_COMPLETED));
                }
            } else {
                prot_printf(imapd_out, "%s %s", tag, s->last_result.s);
            }
        } else {
            /* abort the append */
            prot_printf(s->out, " {0}\r\n");
            pipe_until_tag(s, tag, 0);

            /* report failure */
            prot_printf(imapd_out, "%s NO inter-server COPY failed\r\n", tag);
        }

        goto cleanup;
    }

    /* need permission to delete from source if it's a move */
    if (!r && ismove && !(imapd_index->myrights & ACL_EXPUNGE))
        r = IMAP_PERMISSION_DENIED;

    /* local mailbox -> local mailbox */
    if (!r) {
        r = index_copy(imapd_index, sequence, usinguid, intname,
                       &copyuid, !config_getswitch(IMAPOPT_SINGLEINSTANCESTORE),
                       &imapd_namespace,
                       (imapd_userisadmin || imapd_userisproxyadmin), ismove,
                       ignorequota);
    }

    if (ismove && copyuid && !r) {
        prot_printf(imapd_out, "* OK [COPYUID %s] %s\r\n",
                    copyuid, error_message(IMAP_OK_COMPLETED));
        free(copyuid);
        copyuid = NULL;
    }

    imapd_check(NULL, ismove || usinguid);

  done:

    if (r && !(usinguid && r == IMAP_NO_NOSUCHMSG)) {
        prot_printf(imapd_out, "%s NO %s%s\r\n", tag,
                    (r == IMAP_MAILBOX_NONEXISTENT &&
                     mboxlist_createmailboxcheck(intname, 0, 0,
                                                 imapd_userisadmin,
                                                 imapd_userid, imapd_authstate,
                                                 NULL, NULL, 0) == 0)
                    ? "[TRYCREATE] " : "", error_message(r));
    }
    else if (copyuid) {
            prot_printf(imapd_out, "%s OK [COPYUID %s] %s\r\n", tag,
                        copyuid, error_message(IMAP_OK_COMPLETED));
            free(copyuid);
    }
    else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }

cleanup:
    mboxlist_entry_free(&mbentry);
    free(intname);
}

Project: cyrus-imapd

static void cmd_create(char *tag, char *name, struct dlist *extargs, int localonly)
{
    int r = 0;
    int mbtype = 0;
    const char *partition = NULL;
    const char *server = NULL;
    struct buf specialuse = BUF_INITIALIZER;
    struct dlist *use;

    /* We don't care about trailing hierarchy delimiters. */
    if (name[0] && name[strlen(name)-1] == imapd_namespace.hier_sep) {
        name[strlen(name)-1] = '\0';
    }

    mbname_t *mbname = mbname_from_extname(name, &imapd_namespace, imapd_userid);

    dlist_getatom(extargs, "PARTITION", &partition);
    dlist_getatom(extargs, "SERVER", &server);

    const char *type = NULL;

    dlist_getatom(extargs, "PARTITION", &partition);
    dlist_getatom(extargs, "SERVER", &server);
    if (dlist_getatom(extargs, "TYPE", &type)) {
        if (!strcasecmp(type, "CALENDAR")) mbtype |= MBTYPE_CALENDAR;
        else if (!strcasecmp(type, "COLLECTION")) mbtype |= MBTYPE_COLLECTION;
        else if (!strcasecmp(type, "ADDRESSBOOK")) mbtype |= MBTYPE_ADDRESSBOOK;
        else {
            r = IMAP_MAILBOX_BADTYPE;
            goto err;
        }
    }
    use = dlist_getchild(extargs, "USE");
    if (use) {
        /* only user mailboxes can have specialuse, and they must be user toplevel folders */
        if (!mbname_userid(mbname) || strarray_size(mbname_boxes(mbname)) != 1) {
            r = IMAP_MAILBOX_SPECIALUSE;
            goto err;
        }
        /* I would much prefer to create the specialuse annotation FIRST
         * and do the sanity check on the values, so we can return the
         * correct error.  Sadly, that's a pain - so we compromise by
         * "normalising" first */
        struct dlist *item;
        char *raw;
        strarray_t *su = strarray_new();
        for (item = use->head; item; item = item->next) {
            strarray_append(su, dlist_cstring(item));
        }
        raw = strarray_join(su, " ");
        strarray_free(su);
        r = specialuse_validate(imapd_userid, raw, &specialuse);
        free(raw);
        if (r) {
            prot_printf(imapd_out, "%s NO [USEATTR] %s\r\n", tag, error_message(r));
            goto done;
        }
    }

    if ((server || partition) && !imapd_userisadmin) {
        if (config_mupdate_config == IMAP_ENUM_MUPDATE_CONFIG_STANDARD ||
            config_mupdate_config == IMAP_ENUM_MUPDATE_CONFIG_UNIFIED) {

            if (!config_getstring(IMAPOPT_PROXYSERVERS)) {
                r = IMAP_PERMISSION_DENIED;
                goto err;
            }
        }
    }

    /* check for INBOX.INBOX creation by broken Apple clients */
    const strarray_t *boxes = mbname_boxes(mbname);
    if (strarray_size(boxes) > 1
        && !strcasecmp(strarray_nth(boxes, 0), "INBOX")
        && !strcasecmp(strarray_nth(boxes, 1), "INBOX"))
        r = IMAP_MAILBOX_BADNAME;

    if (r) {
    err:
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        goto done;
    }

    if (!localonly) {

        if (config_mupdate_server) {

            if (
                    config_mupdate_config == IMAP_ENUM_MUPDATE_CONFIG_STANDARD ||
                    config_mupdate_config == IMAP_ENUM_MUPDATE_CONFIG_UNIFIED
                ) {

                if (!config_getstring(IMAPOPT_PROXYSERVERS)) {
                    mbentry_t *parent = NULL;

                    r = mboxlist_findparent(mbname_intname(mbname), &parent);

                    if (r) {
                        if (r != IMAP_MAILBOX_NONEXISTENT) {
                            prot_printf(imapd_out, "%s NO %s (%s:%d)\r\n", tag, error_message(r), __FILE__, __LINE__);
                            goto done;
                        }
                    }

                    if (!server && !partition) {
                        if (!parent) {
                            server = find_free_server();

                            if (!server) {
                                prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(IMAP_SERVER_UNAVAILABLE));
                                goto done;
                            }

                        } else {
                            server = parent->server;
                            /* DO NOT set the partition:
                               only admins are allowed to do this
                               and the backend will use the partition
                               of the parent by default anyways.

                            partition = parent->partition;
                            */
                        }
                    }

                    struct backend *s_conn = NULL;

                    s_conn = proxy_findserver(
                            server,
                            &imap_protocol,
                            proxy_userid,
                            &backend_cached,
                            &backend_current,
                            &backend_inbox,
                            imapd_in
                        );

                    if (!s_conn) {
                        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(IMAP_SERVER_UNAVAILABLE));
                        goto done;
                    }

                    if (imapd_userisadmin && supports_referrals) {
                        imapd_refer(tag, server, name);
                        referral_kick = 1;
                        return;
                    }

                    if (!CAPA(s_conn, CAPA_MUPDATE)) {
                        syslog(LOG_WARNING, "backend %s is not advertising any MUPDATE capability (%s:%d)", server, __FILE__, __LINE__);
                    }

                    prot_printf(s_conn->out, "%s CREATE ", tag);
                    prot_printastring(s_conn->out, name);

                    if (specialuse.len) {
                        prot_printf(s_conn->out, "(USE (%s)", buf_cstring(&specialuse));

                        if (partition) {
                            prot_printf(s_conn->out, " PARTITION ");
                            prot_printastring(s_conn->out, partition);
                        }

                        prot_putc(')', s_conn->out);
                    }

                    else if (partition) {
                        prot_putc(' ', s_conn->out);
                        prot_printastring(s_conn->out, partition);
                    }

                    prot_printf(s_conn->out, "\r\n");

                    int res = pipe_until_tag(s_conn, tag, 0);

                    if (!CAPA(s_conn, CAPA_MUPDATE)) {
                        syslog(LOG_WARNING, "backend %s is not advertising any MUPDATE capability (%s:%d)", server, __FILE__, __LINE__);
                    }

                    /* make sure we've seen the update */
                    if (ultraparanoid && res == PROXY_OK) kick_mupdate();

                    imapd_check(s_conn, 0);

                    prot_printf(imapd_out, "%s %s", tag, s_conn->last_result.s);

                    goto done;

                } else { // (!config_getstring(IMAPOPT_PROXYSERVERS))
                    goto localcreate;

                } // (!config_getstring(IMAPOPT_PROXYSERVERS))

            } // (config_mupdate_config == IMAP_ENUM_MUPDATE_CONFIG_STANDARD)

            else if (config_mupdate_config == IMAP_ENUM_MUPDATE_CONFIG_REPLICATED) {
                goto localcreate;
            } // (config_mupdate_config == IMAP_ENUM_MUPDATE_CONFIG_REPLICATED)

            else {
                syslog(LOG_ERR, "murder configuration I cannot deal with");
                prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(IMAP_SERVER_UNAVAILABLE));
                goto done;
            }

        } else { // (config_mupdate_server)
            goto localcreate;
        } // (config_mupdate_server)

    } else { // (!localonly)
        goto localcreate;
    }

localcreate:
    r = mboxlist_createmailbox(
            mbname_intname(mbname),                             // const char name
            mbtype,                                             // int mbtype
            partition,                                          // const char partition
            imapd_userisadmin || imapd_userisproxyadmin,        // int isadmin
            imapd_userid,                                       // const char userid
            imapd_authstate,                                    // struct auth_state auth_state
            localonly,                                          // int localonly
            localonly,                                          // int forceuser
            0,                                                  // int dbonly
            1,                                                  // int notify
            NULL                                                // struct mailbox mailboxptr
        );

#ifdef USE_AUTOCREATE
    if (r == IMAP_PERMISSION_DENIED) {
        if (!strcasecmp(name, "INBOX")) {
            int autocreatequotastorage = config_getint(IMAPOPT_AUTOCREATE_QUOTA);

            if (autocreatequotastorage > 0) {
                r = mboxlist_createmailbox(
                        mbname_intname(mbname),
                        0,
                        partition,
                        1,
                        imapd_userid,
                        imapd_authstate,
                        0,
                        0,
                        0,
                        1,
                        NULL
                    );

                if (r) {
                    prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
                    goto done;
                }

                int autocreatequotamessage = config_getint(IMAPOPT_AUTOCREATE_QUOTA_MESSAGES);

                if ((autocreatequotastorage > 0) || (autocreatequotamessage > 0)) {
                    quota_t newquotas[QUOTA_NUMRESOURCES];
                    int res;

                    for (res = 0; res < QUOTA_NUMRESOURCES; res++) {
                        newquotas[res] = QUOTA_UNLIMITED;
                    }

                    newquotas[QUOTA_STORAGE] = autocreatequotastorage;
                    newquotas[QUOTA_MESSAGE] = autocreatequotamessage;

                    (void) mboxlist_setquotas(mbname_intname(mbname), newquotas, 0);
                } // (autocreatequotastorage > 0) || (autocreatequotamessage > 0)

            } else { // (autocreatequotastorage = config_getint(IMAPOPT_AUTOCREATEQUOTA))
                prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(IMAP_PERMISSION_DENIED));
                goto done;

            } // (autocreatequotastorage = config_getint(IMAPOPT_AUTOCREATEQUOTA))

        } else { // (!strcasecmp(name, "INBOX"))
            prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(IMAP_PERMISSION_DENIED));
            goto done;
        } // (!strcasecmp(name, "INBOX"))

    } else if (r) { // (r == IMAP_PERMISSION_DENIED)
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        goto done;

    } else { // (r == IMAP_PERMISSION_DENIED)
        /* no error: carry on */
    } // (r == IMAP_PERMISSION_DENIED)

#else // USE_AUTOCREATE
    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        goto done;

    } // (r)
#endif // USE_AUTOCREATE

    if (specialuse.len) {
        r = annotatemore_write(mbname_intname(mbname), "/specialuse", mbname_userid(mbname), &specialuse);
        if (r) {
            /* XXX - failure here SHOULD cause a cleanup of the created mailbox */
            syslog(
                    LOG_ERR,
                    "IOERROR: failed to write specialuse for %s on %s (%s) (%s:%d)",
                    imapd_userid,
                    mbname_intname(mbname),
                    buf_cstring(&specialuse),
                    __FILE__,
                    __LINE__
                );

            prot_printf(imapd_out, "%s NO %s (%s:%d)\r\n", tag, error_message(r), __FILE__, __LINE__);
            goto done;
        }
    }

    prot_printf(imapd_out, "%s OK Completed\r\n", tag);

    imapd_check(NULL, 0);

done:
    buf_free(&specialuse);
    mbname_free(&mbname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_delete(char *tag, char *name, int localonly, int force)
{
    int r;
    mbentry_t *mbentry = NULL;
    struct mboxevent *mboxevent = NULL;

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);
    r = mlookup(NULL, NULL, intname, &mbentry);

    if (!r && (mbentry->mbtype & MBTYPE_REMOTE)) {
        /* remote mailbox */
        struct backend *s = NULL;
        int res;

        if (supports_referrals) {
            imapd_refer(tag, mbentry->server, name);
            referral_kick = 1;
            mboxlist_entry_free(&mbentry);
            free(intname);
            return;
        }

        s = proxy_findserver(mbentry->server, &imap_protocol,
                             proxy_userid, &backend_cached,
                             &backend_current, &backend_inbox, imapd_in);
        mboxlist_entry_free(&mbentry);
        if (!s) r = IMAP_SERVER_UNAVAILABLE;

        if (!r) {
            prot_printf(s->out, "%s DELETE {" SIZE_T_FMT "+}\r\n%s\r\n",
                        tag, strlen(name), name);
            res = pipe_until_tag(s, tag, 0);

            if (!CAPA(s, CAPA_MUPDATE) && res == PROXY_OK) {
                /* do MUPDATE delete operations */
            }

            /* make sure we've seen the update */
            if (ultraparanoid && res == PROXY_OK) kick_mupdate();
        }

        imapd_check(s, 0);

        if (r) {
            prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        } else {
            /* we're allowed to reference last_result since the noop, if
               sent, went to a different server */
            prot_printf(imapd_out, "%s %s", tag, s->last_result.s);
        }

        free(intname);
        return;
    }
    mboxlist_entry_free(&mbentry);

    mboxevent = mboxevent_new(EVENT_MAILBOX_DELETE);

    /* local mailbox */
    if (!r) {
        if (localonly || !mboxlist_delayed_delete_isenabled()) {
            r = mboxlist_deletemailbox(intname,
                                       imapd_userisadmin || imapd_userisproxyadmin,
                                       imapd_userid, imapd_authstate, mboxevent,
                                       1-force, localonly, 0);
        } else if ((imapd_userisadmin || imapd_userisproxyadmin) &&
                   mboxname_isdeletedmailbox(intname, NULL)) {
            r = mboxlist_deletemailbox(intname,
                                       imapd_userisadmin || imapd_userisproxyadmin,
                                       imapd_userid, imapd_authstate, mboxevent,
                                       0 /* checkacl */, localonly, 0);
        } else {
            r = mboxlist_delayed_deletemailbox(intname,
                                               imapd_userisadmin || imapd_userisproxyadmin,
                                               imapd_userid, imapd_authstate, mboxevent,
                                               1-force, 0, 0);
        }
    }

    /* send a MailboxDelete event notification */
    if (!r)
        mboxevent_notify(&mboxevent);
    mboxevent_free(&mboxevent);

    /* was it a top-level user mailbox? */
    /* localonly deletes are only per-mailbox */
    if (!r && !localonly && mboxname_isusermailbox(intname, 1)) {
        char *userid = mboxname_to_userid(intname);
        if (userid) {
            r = mboxlist_usermboxtree(userid, delmbox, NULL, 0);
            if (!r) r = user_deletedata(userid, 1);
            free(userid);
        }
    }

    if (!r && config_getswitch(IMAPOPT_DELETE_UNSUBSCRIBE)) {
        mboxlist_changesub(intname, imapd_userid, imapd_authstate,
                           /* add */ 0, /* force */ 0, /* notify? */ 1);
    }

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    }
    else {
        if (config_mupdate_server)
            kick_mupdate();

        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }
    free(intname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_dump(char *tag, char *name, int uid_start)
{
    int r = 0;
    struct mailbox *mailbox = NULL;

    /* administrators only please */
    if (!imapd_userisadmin)
        r = IMAP_PERMISSION_DENIED;

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);

    if (!r) r = mailbox_open_irl(intname, &mailbox);

    if (!r) r = dump_mailbox(tag, mailbox, uid_start, MAILBOX_MINOR_VERSION,
                             imapd_in, imapd_out, imapd_authstate);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    } else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }

    if (mailbox) mailbox_close(&mailbox);
    free(intname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_fetch(char *tag, char *sequence, int usinguid)
{
    const char *cmd = usinguid ? "UID Fetch" : "Fetch";
    struct fetchargs fetchargs;
    int fetchedsomething, r;
    clock_t start = clock();
    char mytime[100];

    if (backend_current) {
        /* remote mailbox */
        prot_printf(backend_current->out, "%s %s %s ", tag, cmd, sequence);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }

    /* local mailbox */
    memset(&fetchargs, 0, sizeof(struct fetchargs));

    r = parse_fetch_args(tag, cmd,
                         (usinguid && (client_capa & CAPA_QRESYNC)),
                         &fetchargs);
    if (r)
        goto freeargs;

    if (usinguid)
        fetchargs.fetchitems |= FETCH_UID;

    r = index_fetch(imapd_index, sequence, usinguid, &fetchargs,
                &fetchedsomething);

    snprintf(mytime, sizeof(mytime), "%2.3f",
             (clock() - start) / (double) CLOCKS_PER_SEC);

    if (r) {
        prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
                    error_message(r), mytime);
    } else if (fetchedsomething || usinguid) {
        prot_printf(imapd_out, "%s OK %s (%s sec)\r\n", tag,
                    error_message(IMAP_OK_COMPLETED), mytime);
    } else {
        /* normal FETCH, nothing came back */
        prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
                    error_message(IMAP_NO_NOSUCHMSG), mytime);
    }

 freeargs:
    fetchargs_fini(&fetchargs);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_genurlauth(char *tag)
{
    struct mboxkey *mboxkey_db;
    int first = 1;
    int c, r;
    static struct buf arg1, arg2;
    struct imapurl url;
    char newkey[MBOX_KEY_LEN];
    char *urlauth = NULL;
    const char *key;
    size_t keylen;
    unsigned char token[EVP_MAX_MD_SIZE+1]; /* +1 for algorithm */
    unsigned int token_len;
    mbentry_t *mbentry = NULL;
    time_t now = time(NULL);

    r = mboxkey_open(imapd_userid, MBOXKEY_CREATE, &mboxkey_db);
    if (r) {
        prot_printf(imapd_out,
                   "%s NO Cannot open mailbox key db for %s: %s\r\n",
                   tag, imapd_userid, error_message(r));
        return;
    }

    do {
        char *intname = NULL;

        c = getastring(imapd_in, imapd_out, &arg1);
        if (c != ' ') {
            prot_printf(imapd_out,
                        "%s BAD Missing required argument to Genurlauth\r\n",
                        tag);
            eatline(imapd_in, c);
            return;
        }
        c = getword(imapd_in, &arg2);
        if (strcasecmp(arg2.s, "INTERNAL")) {
            prot_printf(imapd_out,
                        "%s BAD Unknown auth mechanism to Genurlauth %s\r\n",
                        tag, arg2.s);
            eatline(imapd_in, c);
            return;
        }

        r = imapurl_fromURL(&url, arg1.s);

        /* validate the URL */
        if (r || !url.user || !url.server || !url.mailbox || !url.uid ||
            (url.section && !*url.section) || !url.urlauth.access) {
            r = IMAP_BADURL;
        } else if (strcmp(url.user, imapd_userid)) {
            /* not using currently authorized user's namespace */
            r = IMAP_BADURL;
        } else if (strcmp(url.server, config_servername)) {
            /* wrong server */
            r = IMAP_BADURL;
        } else if (url.urlauth.expire &&
                   url.urlauth.expire < mktime(gmtime(&now))) {
            /* already expired */
            r = IMAP_BADURL;
        }
        if (r) goto err;

        intname = mboxname_from_external(url.mailbox, &imapd_namespace, imapd_userid);
        r = mlookup(NULL, NULL, intname, &mbentry);

        if (r) {
            prot_printf(imapd_out,
                        "%s BAD Poorly specified URL to Genurlauth %s\r\n",
                        tag, arg1.s);
            eatline(imapd_in, c);
            free(url.freeme);
            free(intname);
            return;
        }

        if (mbentry->mbtype & MBTYPE_REMOTE) {
            /* XXX  proxy to backend */
            mboxlist_entry_free(&mbentry);
            free(url.freeme);
            free(intname);
            continue;
        }

        mboxlist_entry_free(&mbentry);

        /* lookup key */
        r = mboxkey_read(mboxkey_db, intname, &key, &keylen);
        if (r) {
            syslog(LOG_ERR, "DBERROR: error fetching mboxkey: %s",
                   cyrusdb_strerror(r));
        }
        else if (!key) {
            /* create a new key */
            RAND_bytes((unsigned char *) newkey, MBOX_KEY_LEN);
            key = newkey;
            keylen = MBOX_KEY_LEN;
            r = mboxkey_write(mboxkey_db, intname, key, keylen);
            if (r) {
                syslog(LOG_ERR, "DBERROR: error writing new mboxkey: %s",
                       cyrusdb_strerror(r));
            }
        }

        if (r) {
        err:
            eatline(imapd_in, c);
            prot_printf(imapd_out,
                        "%s NO Error authorizing %s: %s\r\n",
                        tag, arg1.s, cyrusdb_strerror(r));
            free(url.freeme);
            free(intname);
            return;
        }

        /* first byte is the algorithm used to create token */
        token[0] = URLAUTH_ALG_HMAC_SHA1;
        HMAC(EVP_sha1(), key, keylen, (unsigned char *) arg1.s, strlen(arg1.s),
             token+1, &token_len);
        token_len++;

        urlauth = xrealloc(urlauth, strlen(arg1.s) + 10 +
                           2 * (EVP_MAX_MD_SIZE+1) + 1);
        strcpy(urlauth, arg1.s);
        strcat(urlauth, ":internal:");
        bin_to_hex(token, token_len, urlauth+strlen(urlauth), BH_LOWER);

        if (first) {
            prot_printf(imapd_out, "* GENURLAUTH");
            first = 0;
        }
        (void)prot_putc(' ', imapd_out);
        prot_printstring(imapd_out, urlauth);
        free(intname);
        free(url.freeme);
    } while (c == ' ');

    if (!first) prot_printf(imapd_out, "\r\n");

    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to GENURLAUTH\r\n", tag);
        eatline(imapd_in, c);
    }
    else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }

    free(urlauth);

    mboxkey_close(mboxkey_db);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_getacl(const char *tag, const char *name)
{
    int r, access;
    char *acl;
    char *rights, *nextid;
    char *freeme = NULL;
    mbentry_t *mbentry = NULL;

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);

    r = mlookup(tag, name, intname, &mbentry);
    if (r == IMAP_MAILBOX_MOVED) return;

    if (!r) {
        access = cyrus_acl_myrights(imapd_authstate, mbentry->acl);

        if (!(access & ACL_ADMIN) &&
            !imapd_userisadmin &&
            !mboxname_userownsmailbox(imapd_userid, intname)) {
            r = (access & ACL_LOOKUP) ?
              IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
        }
    }

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        mboxlist_entry_free(&mbentry);
        free(intname);
        return;
    }

    prot_printf(imapd_out, "* ACL ");
    prot_printastring(imapd_out, name);

    freeme = acl = xstrdupnull(mbentry->acl);

    while (acl) {
        rights = strchr(acl, '\t');
        if (!rights) break;
        *rights++ = '\0';

        nextid = strchr(rights, '\t');
        if (!nextid) break;
        *nextid++ = '\0';

        prot_printf(imapd_out, " ");
        prot_printastring(imapd_out, acl);
        prot_printf(imapd_out, " ");
        prot_printastring(imapd_out, rights);
        acl = nextid;
    }
    prot_printf(imapd_out, "\r\n");
    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
    free(freeme);
    mboxlist_entry_free(&mbentry);
    free(intname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_getannotation(const char *tag, char *mboxpat)
{
    int c, r = 0;
    strarray_t entries = STRARRAY_INITIALIZER;
    strarray_t attribs = STRARRAY_INITIALIZER;
    annotate_state_t *astate = NULL;

    c = parse_annotate_fetch_data(tag, /*permessage_flag*/0, &entries, &attribs);
    if (c == EOF) {
        eatline(imapd_in, c);
        goto freeargs;
    }

    /* check for CRLF */
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to Getannotation\r\n",
                    tag);
        eatline(imapd_in, c);
        goto freeargs;
    }

    astate = annotate_state_new();
    annotate_state_set_auth(astate,
                            imapd_userisadmin || imapd_userisproxyadmin,
                            imapd_userid, imapd_authstate);
    if (!*mboxpat) {
        r = annotate_state_set_server(astate);
        if (!r)
            r = annotate_state_fetch(astate, &entries, &attribs,
                                     getannotation_response, NULL);
    }
    else {
        struct annot_fetch_rock arock;
        arock.entries = &entries;
        arock.attribs = &attribs;
        arock.callback = getannotation_response;
        arock.cbrock = NULL;
        r = apply_mailbox_pattern(astate, mboxpat, annot_fetch_cb, &arock);
    }
    /* we didn't write anything */
    annotate_state_abort(&astate);

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    } else {
        prot_printf(imapd_out, "%s OK %s\r\n",
                    tag, error_message(IMAP_OK_COMPLETED));
    }

 freeargs:
    strarray_fini(&entries);
    strarray_fini(&attribs);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_getquota(const char *tag, const char *name)
{
    int r;
    char quotarootbuf[MAX_MAILBOX_BUFFER];
    mbentry_t *mbentry = NULL;
    struct quota q;
    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);

    quota_init(&q, intname);

    imapd_check(NULL, 0);

    if (!imapd_userisadmin && !imapd_userisproxyadmin) {
        r = IMAP_PERMISSION_DENIED;
        goto done;
    }

    r = mlookup(NULL, NULL, intname, &mbentry);
    if (!r && (mbentry->mbtype & MBTYPE_REMOTE)) {
        /* remote mailbox */

        snprintf(quotarootbuf, sizeof(quotarootbuf), "%s.", intname);

        r = mboxlist_allmbox(quotarootbuf, quota_cb, (void *)mbentry->server, 0);
        if (r) goto done;

        struct backend *s;
        s = proxy_findserver(mbentry->server, &imap_protocol,
                             proxy_userid, &backend_cached,
                             &backend_current, &backend_inbox, imapd_in);
        if (!s) {
            r = IMAP_SERVER_UNAVAILABLE;
            goto done;
        }

        imapd_check(s, 0);

        prot_printf(s->out, "%s Getquota {" SIZE_T_FMT "+}\r\n%s\r\n",
                    tag, strlen(name), name);
        pipe_including_tag(s, tag, 0);

        goto done;
    }

    /* local mailbox */

    r = quota_read(&q, NULL, 0);
    if (r) goto done;

    prot_printf(imapd_out, "* QUOTA ");
    prot_printastring(imapd_out, name);
    prot_printf(imapd_out, " ");
    print_quota_used(imapd_out, &q);
    prot_printf(imapd_out, "\r\n");

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));

 done:
    if (r) prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    mboxlist_entry_free(&mbentry);
    quota_free(&q);
    free(intname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_getquotaroot(const char *tag, const char *name)
{
    mbentry_t *mbentry = NULL;
    struct mailbox *mailbox = NULL;
    int myrights;
    int r, doclose = 0;

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);
    r = mlookup(tag, name, intname, &mbentry);
    if (r == IMAP_MAILBOX_MOVED) {
        free(intname);
        return;
    }

    if (!r && (mbentry->mbtype & MBTYPE_REMOTE)) {
        /* remote mailbox */
        struct backend *s;

        s = proxy_findserver(mbentry->server, &imap_protocol,
                             proxy_userid, &backend_cached,
                             &backend_current, &backend_inbox, imapd_in);
        if (!s) r = IMAP_SERVER_UNAVAILABLE;

        imapd_check(s, 0);

        if (!r) {
            prot_printf(s->out, "%s Getquotaroot {" SIZE_T_FMT "+}\r\n%s\r\n",
                        tag, strlen(name), name);
            pipe_including_tag(s, tag, 0);
        } else {
            prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        }

        mboxlist_entry_free(&mbentry);
        free(intname);

        return;
    }

    mboxlist_entry_free(&mbentry);

    /* local mailbox */
    if (!r) {
        r = mailbox_open_irl(intname, &mailbox);
        if (!r) {
            doclose = 1;
            myrights = cyrus_acl_myrights(imapd_authstate, mailbox->acl);
        }
    }

    if (!r) {
        if (!imapd_userisadmin && !(myrights & ACL_READ)) {
            r = (myrights & ACL_LOOKUP) ?
              IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
        }
    }

    if (!r) {
        prot_printf(imapd_out, "* QUOTAROOT ");
        prot_printastring(imapd_out, name);
        if (mailbox->quotaroot) {
            struct quota q;
            char *extname = mboxname_to_external(mailbox->quotaroot, &imapd_namespace, imapd_userid);
            prot_printf(imapd_out, " ");
            prot_printastring(imapd_out, extname);
            quota_init(&q, mailbox->quotaroot);
            r = quota_read(&q, NULL, 0);
            if (!r) {
                prot_printf(imapd_out, "\r\n* QUOTA ");
                prot_printastring(imapd_out, extname);
                prot_putc(' ', imapd_out);
                print_quota_used(imapd_out, &q);
            }
            quota_free(&q);
            free(extname);
        }
        prot_printf(imapd_out, "\r\n");
    }

    if (doclose) mailbox_close(&mailbox);

    free(intname);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        return;
    }

    imapd_check(NULL, 0);

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
}

Project: cyrus-imapd
File: imapd.c

static void cmd_id(char *tag)
{
    int c = EOF, npair = 0;
    static struct buf arg, field;

    /* check if we've already had an ID in non-authenticated state */
    if (!imapd_userid && imapd_id.did_id) {
        prot_printf(imapd_out, "%s OK NIL\r\n", tag);
        eatline(imapd_in, c);
        return;
    }

    clear_id();

    /* ok, accept parameter list */
    c = getword(imapd_in, &arg);
    /* check for "NIL" or start of parameter list */
    if (strcasecmp(arg.s, "NIL") && c != '(') {
        prot_printf(imapd_out, "%s BAD Invalid parameter list in Id\r\n", tag);
        eatline(imapd_in, c);
        return;
    }

    /* parse parameter list */
    if (c == '(') {
        for (;;) {
            if (c == ')') {
                /* end of string/value pairs */
                break;
            }

            /* get field name */
            c = getstring(imapd_in, imapd_out, &field);
            if (c != ' ') {
                prot_printf(imapd_out,
                            "%s BAD Invalid/missing field name in Id\r\n",
                            tag);
                eatline(imapd_in, c);
                return;
            }

            /* get field value */
            c = getnstring(imapd_in, imapd_out, &arg);
            if (c != ' ' && c != ')') {
                prot_printf(imapd_out,
                            "%s BAD Invalid/missing value in Id\r\n",
                            tag);
                eatline(imapd_in, c);
                return;
            }

            /* ok, we're anal, but we'll still process the ID command */
            if (strlen(field.s) > MAXIDFIELDLEN) {
                prot_printf(imapd_out,
                            "%s BAD field longer than %u octets in Id\r\n",
                            tag, MAXIDFIELDLEN);
                eatline(imapd_in, c);
                return;
            }
            if (arg.len > MAXIDVALUELEN) {
                prot_printf(imapd_out,
                            "%s BAD value longer than %u octets in Id\r\n",
                            tag, MAXIDVALUELEN);
                eatline(imapd_in, c);
                return;
            }
            if (++npair > MAXIDPAIRS) {
                prot_printf(imapd_out,
                            "%s BAD too many (%u) field-value pairs in ID\r\n",
                            tag, MAXIDPAIRS);
                eatline(imapd_in, c);
                return;
            }

            if (!strcmp(field.s, "os") && !strcmp(arg.s, "iOS")) {
                imapd_id.quirks |= QUIRK_SEARCHFUZZY;
            }

            /* ok, we're happy enough */
            appendattvalue(&imapd_id.params, field.s, &arg);
        }

        if (c != ')') {
            /* erp! */
            prot_printf(imapd_out, "%s BAD trailing junk\r\n", tag);
            eatline(imapd_in, c);
            return;
        }
        c = prot_getc(imapd_in);
    }

    /* check for CRLF */
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out, "%s BAD Unexpected extra arguments to Id\r\n", tag);
        eatline(imapd_in, c);
        return;
    }

    /* log the client's ID string.
       eventually this should be a callback or something. */
    if (npair) {
        struct buf logbuf = BUF_INITIALIZER;
        struct attvaluelist *pptr;

        for (pptr = imapd_id.params; pptr; pptr = pptr->next) {
            const char *val = buf_cstring(&pptr->value);

            /* should we check for and format literals here ??? */
            buf_printf(&logbuf, " \"%s\" ", pptr->attrib);
            if (!val || !strcmp(val, "NIL"))
                buf_printf(&logbuf, "NIL");
            else
                buf_printf(&logbuf, "\"%s\"", val);
        }

        syslog(LOG_INFO, "client id sessionid=<%s>:%s", session_id(), buf_cstring(&logbuf));
        buf_free(&logbuf);
    }

    /* spit out our ID string.
       eventually this might be configurable. */
    if (config_getswitch(IMAPOPT_IMAPIDRESPONSE) &&
        (imapd_authstate || (config_serverinfo == IMAP_ENUM_SERVERINFO_ON))) {
        id_response(imapd_out);
        prot_printf(imapd_out, ")\r\n");
    }
    else
        prot_printf(imapd_out, "* ID NIL\r\n");

    imapd_check(NULL, 0);

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));

    imapd_id.did_id = 1;
}

Project: cyrus-imapd
File: imapd.c

static void cmd_idle(char *tag)
{
    int c = EOF;
    int flags;
    static struct buf arg;
    static int idle_period = -1;
    static time_t idle_timeout = -1;
    struct timespec deadline = { 0, 0 };

    if (idle_timeout == -1) {
        idle_timeout = config_getint(IMAPOPT_IMAPIDLETIMEOUT);
        if (idle_timeout <= 0) {
            idle_timeout = config_getint(IMAPOPT_TIMEOUT);
        }
        idle_timeout *= 60; /* unit is minutes */
    }

    if (idle_timeout > 0) {
        errno = 0;
        if (clock_gettime(CLOCK_MONOTONIC, &deadline) == -1) {
            syslog(LOG_ERR, "clock_gettime (%d %m): error reading clock",
                   errno);
        } else {
            deadline.tv_sec += idle_timeout;
        }
    }

    if (!backend_current) {  /* Local mailbox */

        /* Tell client we are idling and waiting for end of command */
        prot_printf(imapd_out, "+ idling\r\n");
        prot_flush(imapd_out);

        /* Start doing mailbox updates */
        index_check(imapd_index, 1, 0);
        idle_start(index_mboxname(imapd_index));
        /* use this flag so if getc causes a shutdown due to
         * connection abort we tell idled about it */
        idling = 1;

        index_release(imapd_index);
        while ((flags = idle_wait(imapd_in->fd))) {
            if (deadline_exceeded(&deadline)) {
                syslog(LOG_DEBUG, "timeout for user '%s' while idling",
                       imapd_userid);
                shut_down(0);
                break;
            }

            if (flags & IDLE_INPUT) {
                /* Get continuation data */
                c = getword(imapd_in, &arg);
                break;
            }

            /* Send unsolicited untagged responses to the client */
            if (flags & IDLE_MAILBOX)
                index_check(imapd_index, 1, 0);

            if (flags & IDLE_ALERT) {
                char shut[MAX_MAILBOX_PATH+1];
                if (! imapd_userisadmin &&
                    (shutdown_file(shut, sizeof(shut)) ||
                     (imapd_userid &&
                      userdeny(imapd_userid, config_ident, shut, sizeof(shut))))) {
                    char *p;
                    for (p = shut; *p == '['; p++); /* can't have [ be first char */
                    prot_printf(imapd_out, "* BYE [ALERT] %s\r\n", p);
                    shut_down(0);
                }
            }

            index_release(imapd_index);
            prot_flush(imapd_out);
        }

        /* Stop updates and do any necessary cleanup */
        idling = 0;
        idle_stop(index_mboxname(imapd_index));
    }
    else {  /* Remote mailbox */
        int done = 0;
        enum { shutdown_skip, shutdown_bye, shutdown_silent } shutdown = shutdown_skip;
        char buf[2048];

        /* get polling period */
        if (idle_period == -1) {
            idle_period = config_getint(IMAPOPT_IMAPIDLEPOLL);
        }

        if (CAPA(backend_current, CAPA_IDLE)) {
            /* Start IDLE on backend */
            prot_printf(backend_current->out, "%s IDLE\r\n", tag);
            if (!prot_fgets(buf, sizeof(buf), backend_current->in)) {

                /* If we received nothing from the backend, fail */
                prot_printf(imapd_out, "%s NO %s\r\n", tag,
                            error_message(IMAP_SERVER_UNAVAILABLE));
                return;
            }
            if (buf[0] != '+') {
                /* If we received anything but a continuation response,
                   spit out what we received and quit */
                prot_write(imapd_out, buf, strlen(buf));
                return;
            }
        }

        /* Tell client we are idling and waiting for end of command */
        prot_printf(imapd_out, "+ idling\r\n");
        prot_flush(imapd_out);

        /* Pipe updates to client while waiting for end of command */
        while (!done) {
            if (deadline_exceeded(&deadline)) {
                syslog(LOG_DEBUG,
                       "timeout for user '%s' while idling on remote mailbox",
                       imapd_userid);
                shutdown = shutdown_silent;
                goto done;
            }

            /* Flush any buffered output */
            prot_flush(imapd_out);

            /* Check for shutdown file */
            if (!imapd_userisadmin &&
                (shutdown_file(buf, sizeof(buf)) ||
                 (imapd_userid &&
                  userdeny(imapd_userid, config_ident, buf, sizeof(buf))))) {
                done = 1;
                shutdown = shutdown_bye;
                goto done;
            }

            done = proxy_check_input(protin, imapd_in, imapd_out,
                                     backend_current->in, NULL, idle_period);

            /* If not running IDLE on backend, poll the mailbox for updates */
            if (!CAPA(backend_current, CAPA_IDLE)) {
                imapd_check(NULL, 0);
            }
        }

        /* Get continuation data */
        c = getword(imapd_in, &arg);

      done:
        if (CAPA(backend_current, CAPA_IDLE)) {
            /* Either the client timed out, or ended the command.
               In either case we're done, so terminate IDLE on backend */
            prot_printf(backend_current->out, "Done\r\n");
            pipe_until_tag(backend_current, tag, 0);
        }

        switch (shutdown) {
        case shutdown_bye:
            ;
            char *p;

            for (p = buf; *p == '['; p++); /* can't have [ be first char */
            prot_printf(imapd_out, "* BYE [ALERT] %s\r\n", p);
            /* fallthrough */
        case shutdown_silent:
            shut_down(0);
            break;
        case shutdown_skip:
        default:
            break;
        }
    }

    imapd_check(NULL, 1);

    if (c != EOF) {
        if (!strcasecmp(arg.s, "Done") &&
            (c = (c == '\r') ? prot_getc(imapd_in) : c) == '\n') {
            prot_printf(imapd_out, "%s OK %s\r\n", tag,
                        error_message(IMAP_OK_COMPLETED));
        }
        else {
            prot_printf(imapd_out,
                        "%s BAD Invalid Idle continuation\r\n", tag);
            eatline(imapd_in, c);
        }
    }
}

Project: cyrus-imapd
File: imapd.c

static void cmd_listrights(char *tag, char *name, char *identifier)
{
    int r, rights;
    mbentry_t *mbentry = NULL;
    struct auth_state *authstate;
    const char *canon_identifier;
    int implicit;
    char rightsdesc[100], optional[33];

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);
    r = mlookup(tag, name, intname, &mbentry);
    if (r == IMAP_MAILBOX_MOVED) return;

    if (!r) {
        rights = cyrus_acl_myrights(imapd_authstate, mbentry->acl);

        if (!rights && !imapd_userisadmin &&
            !mboxname_userownsmailbox(imapd_userid, intname)) {
            r = IMAP_MAILBOX_NONEXISTENT;
        }
    }

    mboxlist_entry_free(&mbentry);

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        return;
    }

    authstate = auth_newstate(identifier);
    if (global_authisa(authstate, IMAPOPT_ADMINS))
        canon_identifier = identifier; /* don't canonify global admins */
    else
        canon_identifier = canonify_userid(identifier, imapd_userid, NULL);
    auth_freestate(authstate);

    if (!canon_identifier) {
        implicit = 0;
    }
    else if (mboxname_userownsmailbox(canon_identifier, intname)) {
        /* identifier's personal mailbox */
        implicit = config_implicitrights;
    }
    else if (mboxname_isusermailbox(intname, 1)) {
        /* anyone can post to an INBOX */
        implicit = ACL_POST;
    }
    else {
        implicit = 0;
    }

    /* calculate optional rights */
    cyrus_acl_masktostr(implicit ^ (canon_identifier ? ACL_FULL : 0),
                        optional);

    /* build the rights string */
    if (implicit) {
        cyrus_acl_masktostr(implicit, rightsdesc);
    }
    else {
        strcpy(rightsdesc, "\"\"");
    }

    if (*optional) {
        int i, n = strlen(optional);
        char *p = rightsdesc + strlen(rightsdesc);

        for (i = 0; i < n; i++) {
            *p++ = ' ';
            *p++ = optional[i];
        }
        *p = '\0';
    }

    prot_printf(imapd_out, "* LISTRIGHTS ");
    prot_printastring(imapd_out, name);
    (void)prot_putc(' ', imapd_out);
    prot_printastring(imapd_out, identifier);
    prot_printf(imapd_out, " %s", rightsdesc);

    prot_printf(imapd_out, "\r\n%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
    free(intname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_login(char *tag, char *user)
{
    char userbuf[MAX_MAILBOX_BUFFER];
    char replybuf[MAX_MAILBOX_BUFFER];
    unsigned userlen;
    const char *canon_user = userbuf;
    const void *val;
    int c;
    struct buf passwdbuf;
    char *passwd;
    const char *reply = NULL;
    int r;
    int failedloginpause;

    if (imapd_userid) {
        eatline(imapd_in, ' ');
        prot_printf(imapd_out, "%s BAD Already logged in\r\n", tag);
        return;
    }

    r = imapd_canon_user(imapd_saslconn, NULL, user, 0,
                         SASL_CU_AUTHID | SASL_CU_AUTHZID, NULL,
                         userbuf, sizeof(userbuf), &userlen);

    if (r) {
        eatline(imapd_in, ' ');
        syslog(LOG_NOTICE, "badlogin: %s plaintext %s invalid user",
               imapd_clienthost, beautify_string(user));
        prot_printf(imapd_out, "%s NO %s\r\n", tag,
                    error_message(IMAP_INVALID_USER));
        return;
    }

    /* possibly disallow login */
    if (imapd_tls_required ||
        (!imapd_starttls_done && (extprops_ssf < 2) &&
         !config_getswitch(IMAPOPT_ALLOWPLAINTEXT) &&
         !is_userid_anonymous(canon_user))) {
        eatline(imapd_in, ' ');
        prot_printf(imapd_out, "%s NO Login only available under a layer\r\n",
                    tag);
        return;
    }

    memset(&passwdbuf,0,sizeof(struct buf));
    c = getastring(imapd_in, imapd_out, &passwdbuf);

    if(c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        buf_free(&passwdbuf);
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to LOGIN\r\n",
                    tag);
        eatline(imapd_in, c);
        return;
    }

    passwd = passwdbuf.s;

    if (is_userid_anonymous(canon_user)) {
        if (config_getswitch(IMAPOPT_ALLOWANONYMOUSLOGIN)) {
            passwd = beautify_string(passwd);
            if (strlen(passwd) > 500) passwd[500] = '\0';
            syslog(LOG_NOTICE, "login: %s anonymous %s",
                   imapd_clienthost, passwd);
            reply = "Anonymous access granted";
            imapd_userid = xstrdup("anonymous");
        }
        else {
            syslog(LOG_NOTICE, "badlogin: %s anonymous login refused",
                   imapd_clienthost);
            prot_printf(imapd_out, "%s NO %s\r\n", tag,
                   error_message(IMAP_ANONYMOUS_NOT_PERMITTED));
            buf_free(&passwdbuf);
            return;
        }
    }
    else if ( nosaslpasswdcheck ) {
        snprintf(replybuf, sizeof(replybuf),
            "User logged in SESSIONID=<%s>", session_id());
        reply = replybuf;
        imapd_userid = xstrdup(canon_user);
        imapd_authstate = auth_newstate(canon_user);
        syslog(LOG_NOTICE, "login: %s %s%s nopassword%s %s", imapd_clienthost,
               imapd_userid, imapd_magicplus ? imapd_magicplus : "",
               imapd_starttls_done ? "+TLS" : "", reply);
    }
    else if ((r = sasl_checkpass(imapd_saslconn,
                                 canon_user,
                                 strlen(canon_user),
                                 passwd,
                                 strlen(passwd))) != SASL_OK) {
        syslog(LOG_NOTICE, "badlogin: %s plaintext %s %s",
               imapd_clienthost, canon_user, sasl_errdetail(imapd_saslconn));

        failedloginpause = config_getint(IMAPOPT_FAILEDLOGINPAUSE);
        if (failedloginpause != 0) {
            sleep(failedloginpause);
        }

        /* Don't allow user probing */
        if (r == SASL_NOUSER) r = SASL_BADAUTH;

        if ((reply = sasl_errstring(r, NULL, NULL)) != NULL) {
            prot_printf(imapd_out, "%s NO Login failed: %s\r\n", tag, reply);
        } else {
            prot_printf(imapd_out, "%s NO Login failed: %d\r\n", tag, r);
        }

        snmp_increment_args(AUTHENTICATION_NO, 1,
                            VARIABLE_AUTH, 0 /* hash_simple("LOGIN") */,
                            VARIABLE_LISTEND);
        buf_free(&passwdbuf);
        return;
    }
    else {
        r = sasl_getprop(imapd_saslconn, SASL_USERNAME, &val);

        if(r != SASL_OK) {
            if ((reply = sasl_errstring(r, NULL, NULL)) != NULL) {
                prot_printf(imapd_out, "%s NO Login failed: %s\r\n",
                            tag, reply);
            } else {
                prot_printf(imapd_out, "%s NO Login failed: %d\r\n", tag, r);
            }

            snmp_increment_args(AUTHENTICATION_NO, 1,
                                VARIABLE_AUTH, 0 /* hash_simple("LOGIN") */,
                                VARIABLE_LISTEND);
            buf_free(&passwdbuf);
            return;
        }

        snprintf(replybuf, sizeof(replybuf),
            "User logged in SESSIONID=<%s>", session_id());
        reply = replybuf;
        imapd_userid = xstrdup((const char *) val);
        snmp_increment_args(AUTHENTICATION_YES, 1,
                            VARIABLE_AUTH, 0 /*hash_simple("LOGIN") */,
                            VARIABLE_LISTEND);
        syslog(LOG_NOTICE, "login: %s %s%s plaintext%s %s", imapd_clienthost,
               imapd_userid, imapd_magicplus ? imapd_magicplus : "",
               imapd_starttls_done ? "+TLS" : "",
               reply ? reply : "");

        /* Apply penalty only if not under layer */
        if (!imapd_starttls_done) {
            int plaintextloginpause = config_getint(IMAPOPT_PLAINTEXTLOGINPAUSE);
            if (plaintextloginpause) {
                sleep(plaintextloginpause);
            }

            /* Fetch plaintext login nag message */
            plaintextloginalert = config_getstring(IMAPOPT_PLAINTEXTLOGINALERT);
        }
    }

    buf_free(&passwdbuf);

    if (checklimits(tag)) return;

    prot_printf(imapd_out, "%s OK [CAPABILITY ", tag);
    capa_response(CAPA_PREAUTH|CAPA_POSTAUTH);
    prot_printf(imapd_out, "] %s\r\n", reply);

    authentication_success();
}

Project: cyrus-imapd
File: imapd.c

static void cmd_mupdatepush(char *tag, char *name)
{
    int r = 0, retry = 0;
    mbentry_t *mbentry = NULL;
    char buf[MAX_PARTITION_LEN + HOSTNAME_SIZE + 2];
    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);

    if (!imapd_userisadmin) {
        r = IMAP_PERMISSION_DENIED;
        goto done;
    }
    if (!config_mupdate_server) {
        r = IMAP_SERVER_UNAVAILABLE;
        goto done;
    }

    r = mlookup(tag, name, intname, &mbentry);
    if (r) goto done;

    /* Push mailbox to mupdate server */
    if (!mupdate_h) {
        syslog(LOG_INFO, "XFER: connecting to mupdate '%s'",
               config_mupdate_server);

        r = mupdate_connect(config_mupdate_server, NULL, &mupdate_h, NULL);
        retry = 1;
        if (r) {
            syslog(LOG_INFO, "Failed to connect to mupdate '%s'",
                   config_mupdate_server);
            goto done;
        }
    }

    snprintf(buf, sizeof(buf), "%s!%s",
             config_servername, mbentry->partition);

  retry:
    r = mupdate_activate(mupdate_h, intname, buf, mbentry->acl);

    if (r && !retry) {
        syslog(LOG_INFO, "MUPDATE: lost connection, retrying");
        mupdate_disconnect(&mupdate_h);
        r = mupdate_connect(config_mupdate_server, NULL, &mupdate_h, NULL);
        if (r) {
            syslog(LOG_INFO, "Failed to connect to mupdate '%s'",
                   config_mupdate_server);
        }
        else {
            retry = 1;
            goto retry;
        }
    }

done:
    mboxlist_entry_free(&mbentry);
    free(intname);
    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    }
    else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }
}

Project: cyrus-imapd
File: imapd.c

static void cmd_myrights(const char *tag, const char *name)
{
    mbentry_t *mbentry = NULL;
    int r;
    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);

    r = mlookup(tag, name, intname, &mbentry);
    if (r == IMAP_MAILBOX_MOVED) return;

    if (!r) r = printmyrights(name, mbentry);

    mboxlist_entry_free(&mbentry);

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        return;
    }

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
    free(intname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_namespace(char* tag)
{
    int sawone[3] = {0, 0, 0};
    char* pattern;

    if (SLEEZY_NAMESPACE) {
        if (strlen(imapd_userid) + 5 >= MAX_MAILBOX_BUFFER)
            sawone[NAMESPACE_INBOX] = 0;
        else {
            char *inbox = mboxname_user_mbox(imapd_userid, NULL);
            sawone[NAMESPACE_INBOX] =
                !mboxlist_lookup(inbox, NULL, NULL);
            free(inbox);
        }
        sawone[NAMESPACE_USER] = imapd_userisadmin ? 1 : imapd_namespace.accessible[NAMESPACE_USER];
        sawone[NAMESPACE_SHARED] = imapd_userisadmin ? 1 : imapd_namespace.accessible[NAMESPACE_SHARED];
    } else {
        pattern = xstrdup("%");
        /* now find all the exciting toplevel namespaces -
         * we're using internal names here
         */
        mboxlist_findall(NULL, pattern, imapd_userisadmin, imapd_userid,
                         imapd_authstate, namespacedata, (void*) sawone);
        free(pattern);
    }

    prot_printf(imapd_out, "* NAMESPACE");
    if (sawone[NAMESPACE_INBOX]) {
        prot_printf(imapd_out, " ((\"%s\" \"%c\"))",
                    imapd_namespace.prefix[NAMESPACE_INBOX],
                    imapd_namespace.hier_sep);
    } else {
        prot_printf(imapd_out, " NIL");
    }
    if (sawone[NAMESPACE_USER]) {
        prot_printf(imapd_out, " ((\"%s\" \"%c\"))",
                    imapd_namespace.prefix[NAMESPACE_USER],
                    imapd_namespace.hier_sep);
    } else {
        prot_printf(imapd_out, " NIL");
    }
    if (sawone[NAMESPACE_SHARED]) {
        prot_printf(imapd_out, " ((\"%s\" \"%c\"))",
                    imapd_namespace.prefix[NAMESPACE_SHARED],
                    imapd_namespace.hier_sep);
    } else {
        prot_printf(imapd_out, " NIL");
    }
    prot_printf(imapd_out, "\r\n");

    imapd_check(NULL, 0);

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
}

Project: cyrus-imapd
File: imapd.c

static void cmd_noop(char *tag, char *cmd)
{
    if (backend_current) {
        /* remote mailbox */
        prot_printf(backend_current->out, "%s %s\r\n", tag, cmd);
        pipe_including_tag(backend_current, tag, 0);

        return;
    }

    index_check(imapd_index, 1, 0);

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
}

Project: cyrus-imapd
File: imapd.c

static void cmd_reconstruct(const char *tag, const char *name, int recursive)
{
    int r = 0;
    char quotaroot[MAX_MAILBOX_BUFFER];
    mbentry_t *mbentry = NULL;
    struct mailbox *mailbox = NULL;

    /* administrators only please */
    if (!imapd_userisadmin)
        r = IMAP_PERMISSION_DENIED;

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);

    if (!r && !strcmpsafe(intname, index_mboxname(imapd_index)))
        r = IMAP_MAILBOX_LOCKED;

    if (!r) {
        r = mlookup(tag, name, intname, &mbentry);
    }
    if (r == IMAP_MAILBOX_MOVED) {
        free(intname);
        return;
    }

    if (!r && (mbentry->mbtype & MBTYPE_REMOTE)) {
        /* remote mailbox */
        imapd_refer(tag, mbentry->server, name);
        mboxlist_entry_free(&mbentry);
        free(intname);
        return;
    }

    mboxlist_entry_free(&mbentry);

    /* local mailbox */
    if (!r) {
        int pid;

        /* Reconstruct it */

        pid = fork();
        if (pid == -1) {
            r = IMAP_SYS_ERROR;
        } else if (pid == 0) {
            char buf[4096];
            int ret;

            /* Child - exec reconstruct*/
            syslog(LOG_NOTICE, "Reconstructing '%s' (%s) for user '%s'",
                   intname, recursive ? "recursive" : "not recursive",
                   imapd_userid);

            fclose(stdin);
            fclose(stdout);
            fclose(stderr);

            ret = snprintf(buf, sizeof(buf), "%s/reconstruct", SBIN_DIR);
            if(ret < 0 || ret >= (int) sizeof(buf)) {
                /* in child, so fatailing won't disconnect our user */
                fatal("reconstruct buffer not sufficiently big", EC_CONFIG);
            }

            if(recursive) {
                execl(buf, buf, "-C", config_filename, "-r", "-f",
                      intname, NULL);
            } else {
                execl(buf, buf, "-C", config_filename, intname, NULL);
            }

            /* if we are here, we have a problem */
            exit(-1);
        } else {
            int status;

            /* Parent, wait on child */
            if(waitpid(pid, &status, 0) < 0) r = IMAP_SYS_ERROR;

            /* Did we fail? */
            if(WEXITSTATUS(status) != 0) r = IMAP_SYS_ERROR;
        }
    }

    /* Still in parent, need to re-quota the mailbox*/

    /* Find its quota root */
    if (!r)
        r = mailbox_open_irl(intname, &mailbox);

    if(!r) {
        if(mailbox->quotaroot) {
            strcpy(quotaroot, mailbox->quotaroot);
        } else {
            strcpy(quotaroot, intname);
        }
        mailbox_close(&mailbox);
    }

    /* Run quota -f */
    if (!r) {
        int pid;

        pid = fork();
        if(pid == -1) {
            r = IMAP_SYS_ERROR;
        } else if(pid == 0) {
            char buf[4096];
            int ret;

            /* Child - exec reconstruct*/
            syslog(LOG_NOTICE,
                   "Regenerating quota roots starting with '%s' for user '%s'",
                   intname, imapd_userid);

            fclose(stdin);
            fclose(stdout);
            fclose(stderr);

            ret = snprintf(buf, sizeof(buf), "%s/quota", SBIN_DIR);
            if(ret < 0 || ret >= (int) sizeof(buf)) {
                /* in child, so fatailing won't disconnect our user */
                fatal("quota buffer not sufficiently big", EC_CONFIG);
            }

            execl(buf, buf, "-C", config_filename, "-f", quotaroot, NULL);

            /* if we are here, we have a problem */
            exit(-1);
        } else {
            int status;

            /* Parent, wait on child */
            if(waitpid(pid, &status, 0) < 0) r = IMAP_SYS_ERROR;

            /* Did we fail? */
            if(WEXITSTATUS(status) != 0) r = IMAP_SYS_ERROR;
        }
    }

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    } else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }

    free(intname);
}

Project: cyrus-imapd

static void cmd_rename(char *tag, char *oldname, char *newname, char *location)
{
    int r = 0;
    char *c;
    char oldmailboxname[MAX_MAILBOX_BUFFER];
    char newmailboxname[MAX_MAILBOX_BUFFER];
    char oldmailboxname2[MAX_MAILBOX_BUFFER];
    char newmailboxname2[MAX_MAILBOX_BUFFER];
    char *oldextname = NULL;
    char *newextname = NULL;
    char *oldintname = NULL;
    char *newintname = NULL;
    char *olduser = NULL;
    char *newuser = NULL;
    int omlen, nmlen;
    int subcount = 0; /* number of sub-folders found */
    int recursive_rename = 1;
    int rename_user = 0;
    mbentry_t *mbentry = NULL;
    struct renrock rock;

    if (location && !imapd_userisadmin) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(IMAP_PERMISSION_DENIED));
        return;
    }

    if (location && strcmp(oldname, newname)) {
        prot_printf(imapd_out,
                    "%s NO Cross-server or cross-partition move w/rename not supported\r\n",
                    tag);
        return;
    }

    oldintname = mboxname_from_external(oldname, &imapd_namespace, imapd_userid);
    strncpy(oldmailboxname, oldintname, MAX_MAILBOX_NAME);
    free(oldintname);

    newintname = mboxname_from_external(newname, &imapd_namespace, imapd_userid);
    strncpy(newmailboxname, newintname, MAX_MAILBOX_NAME);
    free(newintname);

    olduser = mboxname_to_userid(oldmailboxname);
    newuser = mboxname_to_userid(newmailboxname);

    /* Keep temporary copy: master is trashed */
    strcpy(oldmailboxname2, oldmailboxname);
    strcpy(newmailboxname2, newmailboxname);

    r = mlookup(NULL, NULL, oldmailboxname, &mbentry);

    if (!r && mbentry->mbtype & MBTYPE_REMOTE) {
        /* remote mailbox */
        struct backend *s = NULL;
        int res;

        s = proxy_findserver(mbentry->server, &imap_protocol,
                             proxy_userid, &backend_cached,
                             &backend_current, &backend_inbox, imapd_in);

        if (!s) {
            prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(IMAP_SERVER_UNAVAILABLE));
            goto done;
        }

        if (location) {
            char *destserver = NULL;
            char *destpart = NULL;

            c = strchr(location, '!');
            if (c) {
                destserver = xstrndup(location, c - location);
                destpart = xstrdup(c + 1);
            } else {
                destpart = xstrdup(location);
            }

            if (*destpart == '\0') {
                free(destpart);
                destpart = NULL;
            }

            if (!destserver || !strcmp(destserver, mbentry->server)) {
                /* same server: proxy a rename */
                prot_printf(s->out,
                        "%s RENAME \"%s\" \"%s\" %s\r\n",
                        tag,
                        oldname,
                        newname,
                        location);
            } else {
                /* different server: proxy an xfer */
                prot_printf(s->out,
                        "%s XFER \"%s\" %s%s%s\r\n",
                        tag,
                        oldname,
                        destserver,
                        destpart ? " " : "",
                        destpart ? destpart : "");
            }

            if (destserver) free(destserver);
            if (destpart) free(destpart);

            res = pipe_until_tag(s, tag, 0);

            /* make sure we've seen the update */
            if (ultraparanoid && res == PROXY_OK) kick_mupdate();

        } else { // (location)
            if (!strcmp(oldname, newname)) {
                prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(IMAP_SERVER_UNAVAILABLE));
                goto done;
            }

            prot_printf(s->out,
                    "%s RENAME \"%s\" \"%s\"\r\n",
                    tag,
                    oldname,
                    newname
                );

            res = pipe_until_tag(s, tag, 0);

            /* make sure we've seen the update */
            if (ultraparanoid && res == PROXY_OK) kick_mupdate();
        }

        imapd_check(s, 0);

        if (r) {
            prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        } else {
            /* we're allowed to reference last_result since the noop, if
               sent, went to a different server */
            prot_printf(imapd_out, "%s %s", tag, s->last_result.s);
        }

        goto done;
    }

    /* local mailbox */

    if (location && !config_partitiondir(location)) {
        /* invalid partition, assume its a server (remote destination) */
        char *server;
        char *partition;

        /* dest partition? */
        server = location;
        partition = strchr(location, '!');
        if (partition) *partition++ = '\0';

        cmd_xfer(tag, oldname, server, partition);

        goto done;
    }

    /* local rename: it's OK if the mailbox doesn't exist, we'll check
     * if sub mailboxes can be renamed */
    if (r == IMAP_MAILBOX_NONEXISTENT)
        r = 0;

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        goto done;
    }

    /* local destination */

    /* if this is my inbox, don't do recursive renames */
    if (!strcasecmp(oldname, "inbox")) {
        recursive_rename = 0;
    }
    /* check if we're an admin renaming a user */
    else if (config_getswitch(IMAPOPT_ALLOWUSERMOVES) &&
             mboxname_isusermailbox(oldmailboxname, 1) &&
             mboxname_isusermailbox(newmailboxname, 1) &&
             strcmp(oldmailboxname, newmailboxname) && /* different user */
             imapd_userisadmin) {
        rename_user = 1;
    }

    /* if we're renaming something inside of something else,
       don't recursively rename stuff */
    omlen = strlen(oldmailboxname);
    nmlen = strlen(newmailboxname);
    if (omlen < nmlen) {
        if (!strncmp(oldmailboxname, newmailboxname, omlen) &&
            newmailboxname[omlen] == '.') {
            recursive_rename = 0;
        }
    } else {
        if (!strncmp(oldmailboxname, newmailboxname, nmlen) &&
            oldmailboxname[nmlen] == '.') {
            recursive_rename = 0;
        }
    }

    oldextname = mboxname_to_external(oldmailboxname, &imapd_namespace, imapd_userid);
    newextname = mboxname_to_external(newmailboxname, &imapd_namespace, imapd_userid);

    /* rename all mailboxes matching this */
    if (recursive_rename && strcmp(oldmailboxname, newmailboxname)) {
        int ol = omlen + 1;
        int nl = nmlen + 1;
        char ombn[MAX_MAILBOX_BUFFER];
        char nmbn[MAX_MAILBOX_BUFFER];

        strcpy(ombn, oldmailboxname);
        strcpy(nmbn, newmailboxname);
        strcat(ombn, ".");
        strcat(nmbn, ".");

        /* setup the rock */
        rock.namespace = &imapd_namespace;
        rock.found = 0;
        rock.newmailboxname = nmbn;
        rock.ol = ol;
        rock.nl = nl;
        rock.olduser = olduser;
        rock.newuser = newuser;
        rock.partition = location;
        rock.rename_user = rename_user;

        /* Check mboxnames to ensure we can write them all BEFORE we start */
        r = mboxlist_allmbox(ombn, checkmboxname, &rock, 0);

        subcount = rock.found;
    }

    /* attempt to rename the base mailbox */
    if (!r) {
        struct mboxevent *mboxevent = NULL;
        uint32_t uidvalidity = mbentry ? mbentry->uidvalidity : 0;

        /* don't send rename notification if we only change the partition */
        if (strcmp(oldmailboxname, newmailboxname))
            mboxevent = mboxevent_new(EVENT_MAILBOX_RENAME);

        /* check if a previous deleted mailbox existed */
        mbentry_t *newmbentry = NULL;
        r = mboxlist_lookup_allow_all(newmailboxname, &newmbentry, NULL);
        /* XXX - otherwise we should probably reject now, but meh, save it for
         * a real cleanup */
        if (!r && newmbentry->mbtype == MBTYPE_DELETED) {
            /* changing the unique id since last time? */
            if (!mbentry || strcmpsafe(mbentry->uniqueid, newmbentry->uniqueid)) {
                /* then the UIDVALIDITY must be higher than before */
                if (uidvalidity <= newmbentry->uidvalidity)
                    uidvalidity = newmbentry->uidvalidity+1;
            }
        }
        mboxlist_entry_free(&newmbentry);

        r = mboxlist_renamemailbox(oldmailboxname, newmailboxname, location,
                                   0 /* uidvalidity */, imapd_userisadmin,
                                   imapd_userid, imapd_authstate, mboxevent,
                                   0, 0, rename_user);

        /* it's OK to not exist if there are subfolders */
        if (r == IMAP_MAILBOX_NONEXISTENT && subcount && !rename_user &&
           mboxname_userownsmailbox(imapd_userid, oldmailboxname) &&
           mboxname_userownsmailbox(imapd_userid, newmailboxname)) {

            mboxevent_free(&mboxevent);

            goto submboxes;
        }

        /* send a MailboxRename event notification if enabled */
        if (!r)
            mboxevent_notify(&mboxevent);
        mboxevent_free(&mboxevent);
    }

    /* If we're renaming a user, take care of changing quotaroot, ACL,
       seen state, subscriptions and sieve scripts */
    if (!r && rename_user) {
        user_copyquotaroot(oldmailboxname, newmailboxname);
        user_renameacl(&imapd_namespace, newmailboxname, olduser, newuser);
        user_renamedata(olduser, newuser);

        /* XXX report status/progress of meta-data */
    }

    /* rename all mailboxes matching this */
    if (!r && recursive_rename) {
        prot_printf(imapd_out, "* OK rename %s %s\r\n",
                    oldextname, newextname);
        prot_flush(imapd_out);

submboxes:
        strcat(oldmailboxname, ".");
        strcat(newmailboxname, ".");

        /* setup the rock */
        rock.namespace = &imapd_namespace;
        rock.newmailboxname = newmailboxname;
        rock.ol = omlen + 1;
        rock.nl = nmlen + 1;
        rock.olduser = olduser;
        rock.newuser = newuser;
        rock.partition = location;
        rock.rename_user = rename_user;

        /* add submailboxes; we pretend we're an admin since we successfully
           renamed the parent - we're using internal names here */
        r = mboxlist_allmbox(oldmailboxname, renmbox, &rock, 0);
    }

    /* take care of deleting old ACLs, subscriptions, seen state and quotas */
    if (!r && rename_user) {
        user_deletedata(olduser, 1);
        /* allow the replica to get the correct new quotaroot
         * and acls copied across */
        sync_log_user(newuser);
        /* allow the replica to clean up the old meta files */
        sync_log_unuser(olduser);
    }

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    } else {
        if (config_mupdate_server)
            kick_mupdate();

        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
        if (rename_user) sync_log_user(newuser);
    }

done:
    mboxlist_entry_free(&mbentry);
    free(oldextname);
    free(newextname);
    free(olduser);
    free(newuser);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_resetkey(char *tag, char *name,
                  char *mechanism __attribute__((unused)))
/* XXX we don't support any external mechanisms, so we ignore it */
{
    int r;

    if (name) {
        /* delete key for specified mailbox */
        struct mboxkey *mboxkey_db;
        mbentry_t *mbentry = NULL;

        char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);
        r = mlookup(NULL, NULL, intname, &mbentry);
        if (r) {
            prot_printf(imapd_out, "%s NO Error removing key: %s\r\n",
                        tag, error_message(r));
            free(intname);
            return;
        }

        if (mbentry->mbtype & MBTYPE_REMOTE) {
            /* XXX  proxy to backend */
            mboxlist_entry_free(&mbentry);
            free(intname);
            return;
        }

        mboxlist_entry_free(&mbentry);

        r = mboxkey_open(imapd_userid, MBOXKEY_CREATE, &mboxkey_db);
        if (!r) {
            r = mboxkey_write(mboxkey_db, intname, NULL, 0);
            mboxkey_close(mboxkey_db);
        }

        if (r) {
            prot_printf(imapd_out, "%s NO Error removing key: %s\r\n",
                        tag, cyrusdb_strerror(r));
        } else {
            prot_printf(imapd_out,
                        "%s OK [URLMECH INTERNAL] key removed\r\n", tag);
        }
        free(intname);
    }
    else {
        /* delete ALL keys */
        /* XXX  what do we do about multiple backends? */
        r = mboxkey_delete_user(imapd_userid);
        if (r) {
            prot_printf(imapd_out, "%s NO Error removing keys: %s\r\n",
                        tag, cyrusdb_strerror(r));
        } else {
            prot_printf(imapd_out, "%s OK All keys removed\r\n", tag);
        }
    }
}

Project: cyrus-imapd
File: imapd.c

static void cmd_search(char *tag, int usinguid)
{
    int c;
    struct searchargs *searchargs;
    clock_t start = clock();
    char mytime[100];
    int n;

    if (backend_current) {
        /* remote mailbox */
        const char *cmd = usinguid ? "UID Search" : "Search";

        prot_printf(backend_current->out, "%s %s ", tag, cmd);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }

    /* local mailbox */
    searchargs = new_searchargs(tag, GETSEARCH_CHARSET_KEYWORD|GETSEARCH_RETURN,
                                &imapd_namespace, imapd_userid, imapd_authstate,
                                imapd_userisadmin || imapd_userisproxyadmin);

    /* special case quirk for iPhones */
    if (imapd_id.quirks & QUIRK_SEARCHFUZZY)
        searchargs->fuzzy_depth++;

    c = get_search_program(imapd_in, imapd_out, searchargs);
    if (c == EOF) {
        eatline(imapd_in, ' ');
        freesearchargs(searchargs);
        return;
    }

    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out, "%s BAD Unexpected extra arguments to Search\r\n", tag);
        eatline(imapd_in, c);
        freesearchargs(searchargs);
        return;
    }

    if (searchargs->charset == CHARSET_UNKNOWN_CHARSET) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag,
               error_message(IMAP_UNRECOGNIZED_CHARSET));
    }
    else {
        n = index_search(imapd_index, searchargs, usinguid);
        snprintf(mytime, sizeof(mytime), "%2.3f",
                 (clock() - start) / (double) CLOCKS_PER_SEC);
        prot_printf(imapd_out, "%s OK %s (%d msgs in %s secs)\r\n", tag,
                    error_message(IMAP_OK_COMPLETED), n, mytime);
    }

    freesearchargs(searchargs);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_select(char *tag, char *cmd, char *name)
{
    int c;
    int r = 0;
    int doclose = 0;
    mbentry_t *mbentry = NULL;
    struct backend *backend_next = NULL;
    struct index_init init;
    int wasopen = 0;
    struct vanished_params *v = &init.vanished;

    memset(&init, 0, sizeof(struct index_init));

    c = prot_getc(imapd_in);
    if (c == ' ') {
        static struct buf arg, parm1, parm2;

        c = prot_getc(imapd_in);
        if (c != '(') goto badlist;

        c = getword(imapd_in, &arg);
        if (arg.s[0] == '\0') goto badlist;
        for (;;) {
            ucase(arg.s);
            if (!strcmp(arg.s, "CONDSTORE")) {
                client_capa |= CAPA_CONDSTORE;
            }
            else if ((client_capa & CAPA_QRESYNC) &&
                     !strcmp(arg.s, "QRESYNC")) {
                char *p;

                if (c != ' ') goto badqresync;
                c = prot_getc(imapd_in);
                if (c != '(') goto badqresync;
                c = getastring(imapd_in, imapd_out, &arg);
                v->uidvalidity = strtoul(arg.s, &p, 10);
                if (*p || !v->uidvalidity || v->uidvalidity == ULONG_MAX) goto badqresync;
                if (c != ' ') goto badqresync;
                c = getmodseq(imapd_in, &v->modseq);
                if (c == EOF) goto badqresync;
                if (c == ' ') {
                    c = prot_getc(imapd_in);
                    if (c != '(') {
                        /* optional UID sequence */
                        prot_ungetc(c, imapd_in);
                        c = getword(imapd_in, &arg);
                        if (!imparse_issequence(arg.s)) goto badqresync;
                        v->sequence = arg.s;
                        if (c == ' ') {
                            c = prot_getc(imapd_in);
                            if (c != '(') goto badqresync;
                        }
                    }
                    if (c == '(') {
                        /* optional sequence match data */
                        c = getword(imapd_in, &parm1);
                        if (!imparse_issequence(parm1.s)) goto badqresync;
                        v->match_seq = parm1.s;
                        if (c != ' ') goto badqresync;
                        c = getword(imapd_in, &parm2);
                        if (!imparse_issequence(parm2.s)) goto badqresync;
                        v->match_uid = parm2.s;
                        if (c != ')') goto badqresync;
                        c = prot_getc(imapd_in);
                    }
                }
                if (c != ')') goto badqresync;
                c = prot_getc(imapd_in);
            }
            else if (!strcmp(arg.s, "ANNOTATE")) {
                /*
                 * RFC5257 requires us to parse this keyword, which
                 * indicates that the client wants unsolicited
                 * ANNOTATION responses in this session, but we don't
                 * actually have to do anything with it, so we won't.
                 */
                ;
            }
            else {
                prot_printf(imapd_out, "%s BAD Invalid %s modifier %s\r\n",
                            tag, cmd, arg.s);
                eatline(imapd_in, c);
                return;
            }

            if (c == ' ') c = getword(imapd_in, &arg);
            else break;
        }

        if (c != ')') {
            prot_printf(imapd_out,
                        "%s BAD Missing close parenthesis in %s\r\n", tag, cmd);
            eatline(imapd_in, c);
            return;
        }

        c = prot_getc(imapd_in);
    }
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to %s\r\n", tag, cmd);
        eatline(imapd_in, c);
        return;
    }

    if (imapd_index) {
        index_close(&imapd_index);
        wasopen = 1;
    }

    if (backend_current) {
        /* remove backend_current from the protgroup */
        protgroup_delete(protin, backend_current->in);
        wasopen = 1;
    }

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);
    r = mlookup(tag, name, intname, &mbentry);
    if (r == IMAP_MAILBOX_MOVED) {
        free(intname);
        return;
    }

    if (!r && (mbentry->mbtype & MBTYPE_REMOTE)) {
        char mytag[128];

        if (supports_referrals) {
            imapd_refer(tag, mbentry->server, name);
            mboxlist_entry_free(&mbentry);
            free(intname);
            return;
        }

        backend_next = proxy_findserver(mbentry->server, &imap_protocol,
                                        proxy_userid, &backend_cached,
                                        &backend_current, &backend_inbox,
                                        imapd_in);
        if (!backend_next) r = IMAP_SERVER_UNAVAILABLE;

        if (backend_current && backend_current != backend_next) {
            /* switching servers; flush old server output */
            proxy_gentag(mytag, sizeof(mytag));
            prot_printf(backend_current->out, "%s Unselect\r\n", mytag);
            /* do not fatal() here, because we don't really care about this
             * server anymore anyway */
            pipe_until_tag(backend_current, mytag, 1);
        }
        backend_current = backend_next;

        if (r) {
            prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
            mboxlist_entry_free(&mbentry);
            free(intname);
            return;
        }

        if (client_capa) {
            /* Enable client capabilities on new backend */
            proxy_gentag(mytag, sizeof(mytag));
            prot_printf(backend_current->out, "%s Enable", mytag);
            if (client_capa & CAPA_QRESYNC)
                prot_printf(backend_current->out, " Qresync");
            else if (client_capa & CAPA_CONDSTORE)
                prot_printf(backend_current->out, " Condstore");
            prot_printf(backend_current->out, "\r\n");
            pipe_until_tag(backend_current, mytag, 0);
        }

        /* Send SELECT command to backend */
        prot_printf(backend_current->out, "%s %s {" SIZE_T_FMT "+}\r\n%s",
                    tag, cmd, strlen(name), name);
        if (v->uidvalidity) {
            prot_printf(backend_current->out, " (QRESYNC (%lu " MODSEQ_FMT,
                        v->uidvalidity, v->modseq);
            if (v->sequence) {
                prot_printf(backend_current->out, " %s", v->sequence);
            }
            if (v->match_seq && v->match_uid) {
                prot_printf(backend_current->out, " (%s %s)",
                            v->match_seq, v->match_uid);
            }
            prot_printf(backend_current->out, "))");
        }
        prot_printf(backend_current->out, "\r\n");

        switch (pipe_including_tag(backend_current, tag, 0)) {
        case PROXY_OK:
            syslog(LOG_DEBUG, "open: user %s opened %s on %s",
                   imapd_userid, name, mbentry->server);

            /* add backend_current to the protgroup */
            protgroup_insert(protin, backend_current->in);
            break;
        default:
            syslog(LOG_DEBUG, "open: user %s failed to open %s", imapd_userid,
                   name);
            /* not successfully selected */
            backend_current = NULL;
            break;
        }

        mboxlist_entry_free(&mbentry);
        free(intname);

        return;
    }

    mboxlist_entry_free(&mbentry);

    /* local mailbox */
    if (backend_current) {
      char mytag[128];

      /* switching servers; flush old server output */
      proxy_gentag(mytag, sizeof(mytag));
      prot_printf(backend_current->out, "%s Unselect\r\n", mytag);
      /* do not fatal() here, because we don't really care about this
       * server anymore anyway */
      pipe_until_tag(backend_current, mytag, 1);
    }
    backend_current = NULL;

    if (wasopen) prot_printf(imapd_out, "* OK [CLOSED] Ok\r\n");

    init.userid = imapd_userid;
    init.authstate = imapd_authstate;
    init.out = imapd_out;
    init.examine_mode = cmd[0] == 'E';
    init.select = 1;
    if (!strcasecmpsafe(imapd_magicplus, "+dav")) init.want_dav = 1;

    r = index_open(intname, &init, &imapd_index);
    if (!r) doclose = 1;

    if (!r && !index_hasrights(imapd_index, ACL_READ)) {
        r = (imapd_userisadmin || index_hasrights(imapd_index, ACL_LOOKUP)) ?
          IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
    }

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        if (init.vanishedlist) seqset_free(init.vanishedlist);
        init.vanishedlist = NULL;
        if (doclose) index_close(&imapd_index);
        free(intname);
        return;
    }

    if (index_hasrights(imapd_index, ACL_EXPUNGE))
        warn_about_quota(imapd_index->mailbox->quotaroot);

    index_select(imapd_index, &init);

    if (init.vanishedlist) seqset_free(init.vanishedlist);
    init.vanishedlist = NULL;

    prot_printf(imapd_out, "%s OK [READ-%s] %s\r\n", tag,
                index_hasrights(imapd_index, ACL_READ_WRITE) ?
                "WRITE" : "ONLY", error_message(IMAP_OK_COMPLETED));

    syslog(LOG_DEBUG, "open: user %s opened %s", imapd_userid, name);
    free(intname);
    return;

 badlist:
    prot_printf(imapd_out, "%s BAD Invalid modifier list in %s\r\n", tag, cmd);
    eatline(imapd_in, c);
    return;

 badqresync:
    prot_printf(imapd_out, "%s BAD Invalid QRESYNC parameter list in %s\r\n",
                tag, cmd);
    eatline(imapd_in, c);
    return;
}

Project: cyrus-imapd
File: imapd.c

static void cmd_setacl(char *tag, const char *name,
                const char *identifier, const char *rights)
{
    int r;
    mbentry_t *mbentry = NULL;

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);

    /* is it remote? */
    r = mlookup(tag, name, intname, &mbentry);
    if (r == IMAP_MAILBOX_MOVED) return;

    if (!r && (mbentry->mbtype & MBTYPE_REMOTE)) {
        /* remote mailbox */
        struct backend *s = NULL;
        int res;

        s = proxy_findserver(mbentry->server, &imap_protocol,
                             proxy_userid, &backend_cached,
                             &backend_current, &backend_inbox, imapd_in);
        if (!s) r = IMAP_SERVER_UNAVAILABLE;

        if (!r && imapd_userisadmin && supports_referrals) {
            /* They aren't an admin remotely, so let's refer them */
            imapd_refer(tag, mbentry->server, name);
            referral_kick = 1;
            mboxlist_entry_free(&mbentry);
            return;
        }

        mboxlist_entry_free(&mbentry);

        if (!r) {
            if (rights) {
                prot_printf(s->out,
                            "%s Setacl {" SIZE_T_FMT "+}\r\n%s"
                            " {" SIZE_T_FMT "+}\r\n%s {" SIZE_T_FMT "+}\r\n%s\r\n",
                            tag, strlen(name), name,
                            strlen(identifier), identifier,
                            strlen(rights), rights);
            } else {
                prot_printf(s->out,
                            "%s Deleteacl {" SIZE_T_FMT "+}\r\n%s"
                            " {" SIZE_T_FMT "+}\r\n%s\r\n",
                            tag, strlen(name), name,
                            strlen(identifier), identifier);
            }
            res = pipe_until_tag(s, tag, 0);

            if (!CAPA(s, CAPA_MUPDATE) && res == PROXY_OK) {
                /* setup new ACL in MUPDATE */
            }
            /* make sure we've seen the update */
            if (ultraparanoid && res == PROXY_OK) kick_mupdate();
        }

        imapd_check(s, 0);

        if (r) {
            prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        } else {
            /* we're allowed to reference last_result since the noop, if
               sent, went to a different server */
            prot_printf(imapd_out, "%s %s", tag, s->last_result.s);
        }

        free(intname);
        return;
    }

    mboxlist_entry_free(&mbentry);

    /* local mailbox */
    if (!r) {
        char *err;

        /* send BAD response if rights string contains unrecognised chars */
        if (rights && *rights) {
            r = cyrus_acl_checkstr(rights, &err);
            if (r) {
                prot_printf(imapd_out, "%s BAD %s\r\n", tag, err);
                free(err);
                free(intname);
                return;
            }
        }

        r = mboxlist_setacl(&imapd_namespace, intname, identifier, rights,
                            imapd_userisadmin || imapd_userisproxyadmin,
                            proxy_userid, imapd_authstate);
    }

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    } else {
        if (config_mupdate_server)
            kick_mupdate();

        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }
    free(intname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_setmetadata(const char *tag, char *mboxpat)
{
    int c, r = 0;
    struct entryattlist *entryatts = NULL;
    annotate_state_t *astate = NULL;

    c = parse_metadata_store_data(tag, &entryatts);
    if (c == EOF) {
        eatline(imapd_in, c);
        goto freeargs;
    }

    /* check for CRLF */
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to Setmetadata\r\n",
                    tag);
        eatline(imapd_in, c);
        goto freeargs;
    }

    astate = annotate_state_new();
    annotate_state_set_auth(astate, imapd_userisadmin,
                            imapd_userid, imapd_authstate);
    if (!r) {
        if (!*mboxpat) {
            r = annotate_state_set_server(astate);
            if (!r)
                r = annotate_state_store(astate, entryatts);
        }
        else {
            struct annot_store_rock arock;
            arock.entryatts = entryatts;
            r = apply_mailbox_pattern(astate, mboxpat, annot_store_cb, &arock);
        }
    }
    if (!r)
        r = annotate_state_commit(&astate);
    else
        annotate_state_abort(&astate);

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    } else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }

  freeargs:
    if (entryatts) freeentryatts(entryatts);
    return;
}

Project: cyrus-imapd
File: imapd.c

void cmd_setquota(const char *tag, const char *quotaroot)
{
    quota_t newquotas[QUOTA_NUMRESOURCES];
    int res;
    int c;
    int force = 0;
    static struct buf arg;
    int r;
    mbentry_t *mbentry = NULL;
    char *intname = NULL;

    if (!imapd_userisadmin && !imapd_userisproxyadmin) {
        /* need to allow proxies so that mailbox moves can set initial quota
         * roots */
        r = IMAP_PERMISSION_DENIED;
        goto out;
    }

    /* are we forcing the creation of a quotaroot by having a leading +? */
    if (quotaroot[0] == '+') {
        force = 1;
        quotaroot++;
    }

    intname = mboxname_from_external(quotaroot, &imapd_namespace, imapd_userid);

    r = mlookup(NULL, NULL, intname, &mbentry);
    if (r == IMAP_MAILBOX_NONEXISTENT)
        r = 0;      /* will create a quotaroot anyway */
    if (r)
        goto out;

    if (mbentry && (mbentry->mbtype & MBTYPE_REMOTE)) {
        /* remote mailbox */
        struct backend *s;
        char quotarootbuf[MAX_MAILBOX_BUFFER];

        snprintf(quotarootbuf, sizeof(quotarootbuf), "%s.", intname);

        r = mboxlist_allmbox(quotarootbuf, quota_cb, (void *)mbentry->server, 0);
        if (r)
            goto out;

        imapd_check(NULL, 0);

        s = proxy_findserver(mbentry->server, &imap_protocol,
                             proxy_userid, &backend_cached,
                             &backend_current, &backend_inbox, imapd_in);
        if (!s) {
            r = IMAP_SERVER_UNAVAILABLE;
            goto out;
        }

        imapd_check(s, 0);

        prot_printf(s->out, "%s Setquota ", tag);
        prot_printstring(s->out, quotaroot);
        prot_putc(' ', s->out);
        pipe_command(s, 0);
        pipe_including_tag(s, tag, 0);

        free(intname);
        return;

    }
    mboxlist_entry_free(&mbentry);

    /* local mailbox */

    /* Now parse the arguments as a setquota_list */
    c = prot_getc(imapd_in);
    if (c != '(') goto badlist;

    for (res = 0 ; res < QUOTA_NUMRESOURCES ; res++)
        newquotas[res] = QUOTA_UNLIMITED;

    for (;;) {
        /* XXX - limit is actually stored in an int value */
        int32_t limit = 0;

        c = getword(imapd_in, &arg);
        if ((c == ')') && !arg.s[0]) break;
        if (c != ' ') goto badlist;
        res = quota_name_to_resource(arg.s);
        if (res < 0) {
            r = IMAP_UNSUPPORTED_QUOTA;
            goto out;
        }

        c = getsint32(imapd_in, &limit);
        /* note: we accept >= 0 according to rfc2087,
         * and also -1 to fix Bug #3559 */
        if (limit < -1) goto badlist;
        newquotas[res] = limit;
        if (c == ')') break;
        else if (c != ' ') goto badlist;
    }
    c = prot_getc(imapd_in);
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out, "%s BAD Unexpected extra arguments to SETQUOTA\r\n", tag);
        eatline(imapd_in, c);
        return;
    }

    r = mboxlist_setquotas(intname, newquotas, force);

    imapd_check(NULL, 0);
out:
    mboxlist_entry_free(&mbentry);
    free(intname);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
        return;
    }

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
    return;

 badlist:
    prot_printf(imapd_out, "%s BAD Invalid quota list in Setquota\r\n", tag);
    eatline(imapd_in, c);
    free(intname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_sort(char *tag, int usinguid)
{
    int c;
    struct sortcrit *sortcrit = NULL;
    struct searchargs *searchargs = NULL;
    clock_t start = clock();
    char mytime[100];
    int n;

    if (backend_current) {
        /* remote mailbox */
        const char *cmd = usinguid ? "UID Sort" : "Sort";

        prot_printf(backend_current->out, "%s %s ", tag, cmd);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }

    /* local mailbox */
    c = getsortcriteria(tag, &sortcrit);
    if (c == EOF) goto error;

    searchargs = new_searchargs(tag, GETSEARCH_CHARSET_FIRST,
                                &imapd_namespace, imapd_userid, imapd_authstate,
                                imapd_userisadmin || imapd_userisproxyadmin);
    if (imapd_id.quirks & QUIRK_SEARCHFUZZY)
        searchargs->fuzzy_depth++;
    c = get_search_program(imapd_in, imapd_out, searchargs);
    if (c == EOF) goto error;

    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to Sort\r\n", tag);
        goto error;
    }

    n = index_sort(imapd_index, sortcrit, searchargs, usinguid);
    snprintf(mytime, sizeof(mytime), "%2.3f",
             (clock() - start) / (double) CLOCKS_PER_SEC);
    if (CONFIG_TIMING_VERBOSE) {
        char *s = sortcrit_as_string(sortcrit);
        syslog(LOG_DEBUG, "SORT (%s) processing time: %d msg in %s sec",
               s, n, mytime);
        free(s);
    }
    prot_printf(imapd_out, "%s OK %s (%d msgs in %s secs)\r\n", tag,
                error_message(IMAP_OK_COMPLETED), n, mytime);

    freesortcrit(sortcrit);
    freesearchargs(searchargs);
    return;

error:
    eatline(imapd_in, (c == EOF ? ' ' : c));
    freesortcrit(sortcrit);
    freesearchargs(searchargs);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_starttls(char *tag, int imaps)
{
    int result;
    int *layerp;

    char *auth_id;
    sasl_ssf_t ssf;

    /* SASL and openssl have different ideas about whether ssf is signed */
    layerp = (int *) &ssf;

    if (imapd_starttls_done == 1)
    {
        prot_printf(imapd_out, "%s NO TLS already active\r\n", tag);
        return;
    }

    result=tls_init_serverengine("imap",
                                 5,        /* depth to verify */
                                 !imaps,   /* can client auth? */
                                 NULL);

    if (result == -1) {

        syslog(LOG_ERR, "error initializing TLS");

        if (imaps == 0) {
            prot_printf(imapd_out, "%s NO Error initializing TLS\r\n", tag);
        } else {
            shut_down(0);
        }

        return;
    }

    if (imaps == 0)
    {
        prot_printf(imapd_out, "%s OK Begin TLS negotiation now\r\n", tag);
        /* must flush our buffers before starting tls */
        prot_flush(imapd_out);
    }

    result=tls_start_servertls(0, /* read */
                               1, /* write */
                               imaps ? 180 : imapd_timeout,
                               layerp,
                               &auth_id,
                               &tls_conn);

    /* if error */
    if (result==-1) {
        if (imaps == 0) {
            prot_printf(imapd_out, "%s NO Starttls negotiation failed\r\n", tag);
            syslog(LOG_NOTICE, "STARTTLS negotiation failed: %s", imapd_clienthost);
            return;
        } else {
            syslog(LOG_NOTICE, "imaps TLS negotiation failed: %s", imapd_clienthost);
            shut_down(0);
        }
    }

    /* tell SASL about the negotiated layer */
    result = sasl_setprop(imapd_saslconn, SASL_SSF_EXTERNAL, &ssf);
    if (result == SASL_OK) {
        saslprops.ssf = ssf;

        result = sasl_setprop(imapd_saslconn, SASL_AUTH_EXTERNAL, auth_id);
    }
    if (result != SASL_OK) {
        syslog(LOG_NOTICE, "sasl_setprop() failed: cmd_starttls()");
        if (imaps == 0) {
            fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
        } else {
            shut_down(0);
        }
    }

    if(saslprops.authid) {
        free(saslprops.authid);
        saslprops.authid = NULL;
    }
    if(auth_id)
        saslprops.authid = xstrdup(auth_id);

    /* tell the prot layer about our new layers */
    prot_settls(imapd_in, tls_conn);
    prot_settls(imapd_out, tls_conn);

    imapd_starttls_done = 1;
    imapd_tls_required = 0;

#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
    imapd_tls_comp = (void *) SSL_get_current_compression(tls_conn);
#endif
}

Project: cyrus-imapd
File: imapd.c

void cmd_starttls(char *tag __attribute__((unused)),
                  int imaps __attribute__((unused)))
{
    fatal("cmd_starttls() executed, but starttls isn't implemented!",
          EC_SOFTWARE);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_status(char *tag, char *name)
{
    int c;
    unsigned statusitems = 0;
    const char *errstr = "Bad status string";
    mbentry_t *mbentry = NULL;
    struct statusdata sdata = STATUSDATA_INIT;
    int r = 0;

    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);
    r = mlookup(tag, name, intname, &mbentry);
    if (r == IMAP_MAILBOX_MOVED) {
        /* Eat the argument */
        eatline(imapd_in, prot_getc(imapd_in));
        free(intname);
        return;
    }

    if (!r && (mbentry->mbtype & MBTYPE_REMOTE)) {
        /* remote mailbox */

        if (supports_referrals
            && config_getswitch(IMAPOPT_PROXYD_ALLOW_STATUS_REFERRAL)) {
            imapd_refer(tag, mbentry->server, name);
            /* Eat the argument */
            eatline(imapd_in, prot_getc(imapd_in));
        }
        else {
            struct backend *s;

            s = proxy_findserver(mbentry->server, &imap_protocol,
                                 proxy_userid, &backend_cached,
                                 &backend_current, &backend_inbox, imapd_in);
            if (!s) r = IMAP_SERVER_UNAVAILABLE;

            imapd_check(s, 0);

            if (!r) {
                prot_printf(s->out, "%s Status {" SIZE_T_FMT "+}\r\n%s ", tag,
                            strlen(name), name);
                if (!pipe_command(s, 65536)) {
                    pipe_including_tag(s, tag, 0);
                }
            } else {
                eatline(imapd_in, prot_getc(imapd_in));
                prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
            }
        }

        goto done;
    }

    /* local mailbox */

    imapd_check(NULL, 0);

    c = parse_statusitems(&statusitems, &errstr);
    if (c == EOF) {
        prot_printf(imapd_out, "%s BAD %s\r\n", tag, errstr);
        goto done;
    }

    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to Status\r\n", tag);
        eatline(imapd_in, c);
        goto done;
    }

    /* check permissions */
    if (!r) {
        int myrights = cyrus_acl_myrights(imapd_authstate, mbentry->acl);

        if (!(myrights & ACL_READ)) {
            r = (imapd_userisadmin || (myrights & ACL_LOOKUP)) ?
                IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
        }
    }

    if (!r) r = imapd_statusdata(intname, statusitems, &sdata);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag,
                    error_message(r));
    }
    else {
        print_statusline(name, statusitems, &sdata);
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }

 done:
    if (global_conversations) {
        conversations_abort(&global_conversations);
        global_conversations = NULL;
    }
    mboxlist_entry_free(&mbentry);
    free(intname);
    return;
}

Project: cyrus-imapd
File: imapd.c

static void cmd_store(char *tag, char *sequence, int usinguid)
{
    const char *cmd = usinguid ? "UID Store" : "Store";
    struct storeargs storeargs;
    static struct buf operation, flagname;
    int len, c;
    int flagsparsed = 0, inlist = 0;
    char *modified = NULL;
    int r;

    if (backend_current) {
        /* remote mailbox */
        prot_printf(backend_current->out, "%s %s %s ",
                    tag, cmd, sequence);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }

    /* local mailbox */
    memset(&storeargs, 0, sizeof storeargs);
    storeargs.unchangedsince = ~0ULL;
    storeargs.usinguid = usinguid;
    strarray_init(&storeargs.flags);

    c = prot_getc(imapd_in);
    if (c == '(') {
        /* Grab/parse the modifier(s) */
        static struct buf storemod;

        do {
            c = getword(imapd_in, &storemod);
            ucase(storemod.s);
            if (!strcmp(storemod.s, "UNCHANGEDSINCE")) {
                if (c != ' ') {
                    prot_printf(imapd_out,
                                "%s BAD Missing required argument to %s %s\r\n",
                                tag, cmd, storemod.s);
                    eatline(imapd_in, c);
                    return;
                }
                c = getmodseq(imapd_in, &storeargs.unchangedsince);
                if (c == EOF) {
                    prot_printf(imapd_out,
                                "%s BAD Invalid argument to %s UNCHANGEDSINCE\r\n",
                                tag, cmd);
                    eatline(imapd_in, c);
                    return;
                }
            }
            else {
                prot_printf(imapd_out, "%s BAD Invalid %s modifier %s\r\n",
                            tag, cmd, storemod.s);
                eatline(imapd_in, c);
                return;
            }
        } while (c == ' ');
        if (c != ')') {
            prot_printf(imapd_out,
                        "%s BAD Missing close paren in store modifier entry \r\n",
                        tag);
            eatline(imapd_in, c);
            return;
        }
        c = prot_getc(imapd_in);
        if (c != ' ') {
            prot_printf(imapd_out,
                        "%s BAD Missing required argument to %s\r\n",
                        tag, cmd);
            eatline(imapd_in, c);
            return;
        }
    }
    else
        prot_ungetc(c, imapd_in);

    c = getword(imapd_in, &operation);
    if (c != ' ') {
        prot_printf(imapd_out,
                    "%s BAD Missing required argument to %s\r\n", tag, cmd);
        eatline(imapd_in, c);
        return;
    }
    lcase(operation.s);

    len = strlen(operation.s);
    if (len > 7 && !strcmp(operation.s+len-7, ".silent")) {
        storeargs.silent = 1;
        operation.s[len-7] = '\0';
    }

    if (!strcmp(operation.s, "+flags")) {
        storeargs.operation = STORE_ADD_FLAGS;
    }
    else if (!strcmp(operation.s, "-flags")) {
        storeargs.operation = STORE_REMOVE_FLAGS;
    }
    else if (!strcmp(operation.s, "flags")) {
        storeargs.operation = STORE_REPLACE_FLAGS;
    }
    else if (!strcmp(operation.s, "annotation")) {
        storeargs.operation = STORE_ANNOTATION;
        /* ANNOTATION has implicit .SILENT behaviour */
        storeargs.silent = 1;

        c = parse_annotate_store_data(tag, /*permessage_flag*/1,
                                      &storeargs.entryatts);
        if (c == EOF) {
            eatline(imapd_in, c);
            goto freeflags;
        }
        storeargs.namespace = &imapd_namespace;
        storeargs.isadmin = imapd_userisadmin;
        storeargs.userid = imapd_userid;
        storeargs.authstate = imapd_authstate;
        goto notflagsdammit;
    }
    else {
        prot_printf(imapd_out, "%s BAD Invalid %s attribute\r\n", tag, cmd);
        eatline(imapd_in, ' ');
        return;
    }

    for (;;) {
        c = getword(imapd_in, &flagname);
        if (c == '(' && !flagname.s[0] && !flagsparsed && !inlist) {
            inlist = 1;
            continue;
        }

        if (!flagname.s[0]) break;

        if (flagname.s[0] == '\\') {
            lcase(flagname.s);
            if (!strcmp(flagname.s, "\\seen")) {
                storeargs.seen = 1;
            }
            else if (!strcmp(flagname.s, "\\answered")) {
                storeargs.system_flags |= FLAG_ANSWERED;
            }
            else if (!strcmp(flagname.s, "\\flagged")) {
                storeargs.system_flags |= FLAG_FLAGGED;
            }
            else if (!strcmp(flagname.s, "\\deleted")) {
                storeargs.system_flags |= FLAG_DELETED;
            }
            else if (!strcmp(flagname.s, "\\draft")) {
                storeargs.system_flags |= FLAG_DRAFT;
            }
            else {
                prot_printf(imapd_out, "%s BAD Invalid system flag in %s command\r\n",
                       tag, cmd);
                eatline(imapd_in, c);
                goto freeflags;
            }
        }
        else if (!imparse_isatom(flagname.s)) {
            prot_printf(imapd_out, "%s BAD Invalid flag name %s in %s command\r\n",
                   tag, flagname.s, cmd);
            eatline(imapd_in, c);
            goto freeflags;
        }
        else
            strarray_append(&storeargs.flags, flagname.s);

        flagsparsed++;
        if (c != ' ') break;
    }

    if (!inlist && !flagsparsed) {
        prot_printf(imapd_out, "%s BAD Missing required argument to %s\r\n", tag, cmd);
        eatline(imapd_in, c);
        return;
    }
    if (inlist && c == ')') {
        inlist = 0;
        c = prot_getc(imapd_in);
    }
    if (inlist) {
        prot_printf(imapd_out, "%s BAD Missing close parenthesis in %s\r\n", tag, cmd);
        eatline(imapd_in, c);
        goto freeflags;
    }
notflagsdammit:
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out, "%s BAD Unexpected extra arguments to %s\r\n", tag, cmd);
        eatline(imapd_in, c);
        goto freeflags;
    }

    if ((storeargs.unchangedsince != ULONG_MAX) &&
        !(client_capa & CAPA_CONDSTORE)) {
        client_capa |= CAPA_CONDSTORE;
        prot_printf(imapd_out, "* OK [HIGHESTMODSEQ " MODSEQ_FMT "]  \r\n",
                    index_highestmodseq(imapd_index));
    }

    r = index_store(imapd_index, sequence, &storeargs);

    /* format the MODIFIED response code */
    if (storeargs.modified) {
        char *seqstr = seqset_cstring(storeargs.modified);
        assert(seqstr);
        modified = strconcat("[MODIFIED ", seqstr, "] ", (char *)NULL);
        free(seqstr);
    }
    else {
        modified = xstrdup("");
    }

    if (r) {
        prot_printf(imapd_out, "%s NO %s%s\r\n",
                    tag, modified, error_message(r));
    }
    else {
        prot_printf(imapd_out, "%s OK %s%s\r\n",
                    tag, modified, error_message(IMAP_OK_COMPLETED));
    }

 freeflags:
    strarray_fini(&storeargs.flags);
    freeentryatts(storeargs.entryatts);
    seqset_free(storeargs.modified);
    free(modified);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_syncapply(const char *tag, struct dlist *kin, struct sync_reserve_list *reserve_list)
{
    struct sync_state sync_state = {
        imapd_userid,
        imapd_userisadmin || imapd_userisproxyadmin,
        imapd_authstate,
        &imapd_namespace,
        imapd_out,
        0 /* local_only */
    };

    /* administrators only please */
    if (!imapd_userisadmin) {
        syslog(LOG_ERR, "SYNCERROR: invalid user %s trying to sync", imapd_userid);
        prot_printf(imapd_out, "%s NO only admininstrators may use sync commands\r\n", tag);
        return;
    }

    const char *resp = sync_apply(kin, reserve_list, &sync_state);
    prot_printf(imapd_out, "%s %s\r\n", tag, resp);

    /* Reset inactivity timer in case we spent a long time processing data */
    prot_resettimeout(imapd_in);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_syncget(const char *tag, struct dlist *kin)
{
    struct sync_state sync_state = {
        imapd_userid,
        imapd_userisadmin || imapd_userisproxyadmin,
        imapd_authstate,
        &imapd_namespace,
        imapd_out,
        0 /* local_only */
    };

    /* administrators only please */
    if (!imapd_userisadmin) {
        syslog(LOG_ERR, "SYNCERROR: invalid user %s trying to sync", imapd_userid);
        prot_printf(imapd_out, "%s NO only admininstrators may use sync commands\r\n", tag);
        return;
    }

    const char *resp = sync_get(kin, &sync_state);
    prot_printf(imapd_out, "%s %s\r\n", tag, resp);

    /* Reset inactivity timer in case we spent a long time processing data */
    prot_resettimeout(imapd_in);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_syncrestart(const char *tag, struct sync_reserve_list **reserve_listp, int re_alloc)
{
    struct sync_reserve *res;
    struct sync_reserve_list *l = *reserve_listp;
    struct sync_msgid *msg;
    int hash_size = l->hash_size;
    struct partition_list *p, *pl = NULL;

    for (res = l->head; res; res = res->next) {
        for (msg = res->list->head; msg; msg = msg->next) {
            if (!msg->fname) continue;
            pl = partition_list_add(res->part, pl);

            unlink(msg->fname);
        }
    }
    sync_reserve_list_free(reserve_listp);

    /* Remove all <partition>/sync./<pid> directories referred to above */
    for (p=pl; p ; p = p->next) {
        static char buf[MAX_MAILBOX_PATH];

        snprintf(buf, MAX_MAILBOX_PATH, "%s/sync./%lu",
                 config_partitiondir(p->name), (unsigned long)getpid());
        rmdir(buf);

        /* and the archive partition too */
        snprintf(buf, MAX_MAILBOX_PATH, "%s/sync./%lu",
                 config_archivepartitiondir(p->name), (unsigned long)getpid());
        rmdir(buf);
    }
    partition_list_free(pl);

    if (re_alloc) {
        *reserve_listp = sync_reserve_list_create(hash_size);
        prot_printf(imapd_out, "%s OK Restarting\r\n", tag);
    }
    else
        *reserve_listp = NULL;
}

Project: cyrus-imapd
File: imapd.c

static void cmd_syncrestore(const char *tag, struct dlist *kin,
                            struct sync_reserve_list *reserve_list)
{
    struct sync_state sync_state = {
        imapd_userid,
        imapd_userisadmin || imapd_userisproxyadmin,
        imapd_authstate,
        &imapd_namespace,
        imapd_out,
        0 /* local_only */
    };

    /* administrators only please */
    if (!imapd_userisadmin) {
        syslog(LOG_ERR, "SYNCERROR: invalid user %s trying to sync", imapd_userid);
        prot_printf(imapd_out, "%s NO only admininstrators may use sync commands\r\n", tag);
        return;
    }

    const char *resp = sync_restore(kin, reserve_list, &sync_state);
    prot_printf(imapd_out, "%s %s\r\n", tag, resp);

    /* Reset inactivity timer in case we spent a long time processing data */
    prot_resettimeout(imapd_in);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_thread(char *tag, int usinguid)
{
    static struct buf arg;
    int c;
    int alg;
    struct searchargs *searchargs;
    clock_t start = clock();
    char mytime[100];
    int n;

    if (backend_current) {
        /* remote mailbox */
        const char *cmd = usinguid ? "UID Thread" : "Thread";

        prot_printf(backend_current->out, "%s %s ", tag, cmd);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }

    /* local mailbox */
    /* get algorithm */
    c = getword(imapd_in, &arg);
    if (c != ' ') {
        prot_printf(imapd_out, "%s BAD Missing algorithm in Thread\r\n", tag);
        eatline(imapd_in, c);
        return;
    }

    if ((alg = find_thread_algorithm(arg.s)) == -1) {
        prot_printf(imapd_out, "%s BAD Invalid Thread algorithm %s\r\n",
                    tag, arg.s);
        eatline(imapd_in, c);
        return;
    }

    searchargs = new_searchargs(tag, GETSEARCH_CHARSET_FIRST,
                                &imapd_namespace, imapd_userid, imapd_authstate,
                                imapd_userisadmin || imapd_userisproxyadmin);
    c = get_search_program(imapd_in, imapd_out, searchargs);
    if (c == EOF) {
        eatline(imapd_in, ' ');
        freesearchargs(searchargs);
        return;
    }

    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to Thread\r\n", tag);
        eatline(imapd_in, c);
        freesearchargs(searchargs);
        return;
    }

    n = index_thread(imapd_index, alg, searchargs, usinguid);
    snprintf(mytime, sizeof(mytime), "%2.3f",
             (clock() - start) / (double) CLOCKS_PER_SEC);
    prot_printf(imapd_out, "%s OK %s (%d msgs in %s secs)\r\n", tag,
                error_message(IMAP_OK_COMPLETED), n, mytime);

    freesearchargs(searchargs);
    return;
}

Project: cyrus-imapd
File: imapd.c

static void cmd_undump(char *tag, char *name)
{
    int r = 0;
    char *intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);

    /* administrators only please */
    if (!imapd_userisadmin)
        r = IMAP_PERMISSION_DENIED;

    if (!r) r = mlookup(tag, name, intname, NULL);

    if (!r) r = undump_mailbox(intname, imapd_in, imapd_out, imapd_authstate);

    if (r) {
        prot_printf(imapd_out, "%s NO %s%s\r\n",
                    tag,
                    (r == IMAP_MAILBOX_NONEXISTENT &&
                     mboxlist_createmailboxcheck(intname, 0, 0,
                                                 imapd_userisadmin,
                                                 imapd_userid, imapd_authstate,
                                                 NULL, NULL, 0) == 0)
                    ? "[TRYCREATE] " : "", error_message(r));
    } else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }
    free(intname);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_urlfetch(char *tag)
{
    struct mboxkey *mboxkey_db;
    int c, r, doclose;
    static struct buf arg, param;
    struct imapurl url;
    struct index_state *state;
    uint32_t msgno;
    mbentry_t *mbentry = NULL;
    time_t now = time(NULL);
    unsigned extended, params;

    prot_printf(imapd_out, "* URLFETCH");

    do {
        char *intname = NULL;
        extended = params = 0;

        /* See if its an extended URLFETCH */
        c = prot_getc(imapd_in);
        if (c == '(') extended = 1;
        else prot_ungetc(c, imapd_in);

        c = getastring(imapd_in, imapd_out, &arg);
        (void)prot_putc(' ', imapd_out);
        prot_printstring(imapd_out, arg.s);

        if (extended) {
            while (c == ' ') {
                c = getword(imapd_in, &param);

                ucase(param.s);
                if (!strcmp(param.s, "BODY")) {
                    if (params & (URLFETCH_BODY | URLFETCH_BINARY)) goto badext;
                    params |= URLFETCH_BODY;
                } else if (!strcmp(param.s, "BINARY")) {
                    if (params & (URLFETCH_BODY | URLFETCH_BINARY)) goto badext;
                    params |= URLFETCH_BINARY;
                } else if (!strcmp(param.s, "BODYPARTSTRUCTURE")) {
                    if (params & URLFETCH_BODYPARTSTRUCTURE) goto badext;
                    params |= URLFETCH_BODYPARTSTRUCTURE;
                } else {
                    goto badext;
                }
            }

            if (c != ')') goto badext;
            c = prot_getc(imapd_in);
        }

        doclose = 0;
        r = imapurl_fromURL(&url, arg.s);

        /* validate the URL */
        if (r || !url.user || !url.server || !url.mailbox || !url.uid ||
            (url.section && !*url.section) ||
            (url.urlauth.access && !(url.urlauth.mech && url.urlauth.token))) {
            /* missing info */
            r = IMAP_BADURL;
        } else if (strcmp(url.server, config_servername)) {
            /* wrong server */
            r = IMAP_BADURL;
        } else if (url.urlauth.expire &&
                   url.urlauth.expire < mktime(gmtime(&now))) {
            /* expired */
            r = IMAP_BADURL;
        } else if (url.urlauth.access) {
            /* check mechanism & authorization */
            int authorized = 0;

            if (!strcasecmp(url.urlauth.mech, "INTERNAL")) {
                if (!strncasecmp(url.urlauth.access, "submit+", 7) &&
                    global_authisa(imapd_authstate, IMAPOPT_SUBMITSERVERS)) {
                    /* authorized submit server */
                    authorized = 1;
                } else if (!strncasecmp(url.urlauth.access, "user+", 5) &&
                           !strcmp(url.urlauth.access+5, imapd_userid)) {
                    /* currently authorized user */
                    authorized = 1;
                } else if (!strcasecmp(url.urlauth.access, "authuser") &&
                           strcmp(imapd_userid, "anonymous")) {
                    /* any non-anonymous authorized user */
                    authorized = 1;
                } else if (!strcasecmp(url.urlauth.access, "anonymous")) {
                    /* anyone */
                    authorized = 1;
                }
            }

            if (!authorized) r = IMAP_BADURL;
        }

        if (r) goto err;

        intname = mboxname_from_external(url.mailbox, &imapd_namespace, url.user);
        r = mlookup(NULL, NULL, intname, &mbentry);
        if (r) goto err;

        if ((mbentry->mbtype & MBTYPE_REMOTE)) {
            /* remote mailbox */
            struct backend *be;

            be = proxy_findserver(mbentry->server, &imap_protocol,
                                  proxy_userid, &backend_cached,
                                  &backend_current, &backend_inbox, imapd_in);
            if (!be) {
                r = IMAP_SERVER_UNAVAILABLE;
            } else {
                /* XXX  proxy command to backend */
            }

            free(url.freeme);

            mboxlist_entry_free(&mbentry);
            free(intname);

            continue;
        }

        mboxlist_entry_free(&mbentry);

        /* local mailbox */
        if (url.urlauth.token) {
            /* validate the URLAUTH token */

            /* yes, this is evil, in-place conversion from hex
             * to binary */
            if (hex_to_bin(url.urlauth.token, 0,
                (unsigned char *) url.urlauth.token) < 1) {
                r = IMAP_BADURL;
                break;
            }

            /* first byte is the algorithm used to create token */
            switch (url.urlauth.token[0]) {
            case URLAUTH_ALG_HMAC_SHA1: {
                const char *key;
                size_t keylen;
                unsigned char vtoken[EVP_MAX_MD_SIZE];
                unsigned int vtoken_len;

                r = mboxkey_open(url.user, 0, &mboxkey_db);
                if (r) break;

                r = mboxkey_read(mboxkey_db, intname, &key, &keylen);
                if (r) break;

                HMAC(EVP_sha1(), key, keylen, (unsigned char *) arg.s,
                     url.urlauth.rump_len, vtoken, &vtoken_len);
                mboxkey_close(mboxkey_db);

                if (memcmp(vtoken, url.urlauth.token+1, vtoken_len)) {
                    r = IMAP_BADURL;
                }

                break;
            }
            default:
                r = IMAP_BADURL;
                break;
            }
        }
        if (r) goto err;

        if (!strcmp(index_mboxname(imapd_index), intname)) {
            state = imapd_index;
        }
        else {
            /* not the currently selected mailbox, so try to open it */

            r = index_open(intname, NULL, &state);
            if (!r)
                doclose = 1;

            if (!r && !url.urlauth.access &&
                !(state->myrights & ACL_READ)) {
                r = (imapd_userisadmin ||
                     (state->myrights & ACL_LOOKUP)) ?
                    IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
            }
        }
        if (r) goto err;

        if (url.uidvalidity &&
           (state->mailbox->i.uidvalidity != url.uidvalidity)) {
            r = IMAP_BADURL;
        } else if (!url.uid || !(msgno = index_finduid(state, url.uid)) ||
                   (index_getuid(state, msgno) != url.uid)) {
            r = IMAP_BADURL;
        } else {
            r = index_urlfetch(state, msgno, params, url.section,
                               url.start_octet, url.octet_count,
                               imapd_out, NULL);
        }

        if (doclose)
            index_close(&state);

    err:
        free(url.freeme);

        if (r) prot_printf(imapd_out, " NIL");
        free(intname);

    } while (c == ' ');

    prot_printf(imapd_out, "\r\n");

    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to URLFETCH\r\n", tag);
        eatline(imapd_in, c);
    }
    else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }
    return;

  badext:
    prot_printf(imapd_out, " NIL\r\n");
    prot_printf(imapd_out,
                "%s BAD Invalid extended URLFETCH parameters\r\n", tag);
    eatline(imapd_in, c);
}

Project: cyrus-imapd

static void cmd_xapplepushservice(const char *tag,
                                  struct applepushserviceargs *applepushserviceargs)
{
    int r = 0;
    strarray_t notif_mailboxes = STRARRAY_INITIALIZER;
    int i;
    mbentry_t *mbentry = NULL;

    const char *aps_topic = config_getstring(IMAPOPT_APS_TOPIC);
    if (!aps_topic) {
        syslog(LOG_ERR,
               "aps_topic not configured, can't complete XAPPLEPUSHSERVICE response");
        prot_printf(imapd_out, "%s NO Server configuration error\r\n", tag);
        return;
    }

    if (!buf_len(&applepushserviceargs->aps_account_id)) {
        prot_printf(imapd_out, "%s NO Missing APNS account ID\r\n", tag);
        return;
    }
    if (!buf_len(&applepushserviceargs->aps_device_token)) {
        prot_printf(imapd_out, "%s NO Missing APNS device token\r\n", tag);
        return;
    }
    if (!buf_len(&applepushserviceargs->aps_subtopic)) {
        prot_printf(imapd_out, "%s NO Missing APNS sub-topic\r\n", tag);
        return;
    }

    if (applepushserviceargs->aps_version == 1) {
        strarray_truncate(&applepushserviceargs->mailboxes, 0);
        strarray_push(&applepushserviceargs->mailboxes, "INBOX");
        applepushserviceargs->aps_version = 1;
    }
    else {
        applepushserviceargs->aps_version = 2;
    }

    for (i = 0; i < strarray_size(&applepushserviceargs->mailboxes); i++) {
        const char *name = strarray_nth(&applepushserviceargs->mailboxes, i);
        char *intname =
            mboxname_from_external(name, &imapd_namespace, imapd_userid);
        r = mlookup(tag, name, intname, &mbentry);
        if (!r && mbentry->mbtype == 0) {
            strarray_push(&notif_mailboxes, name);
            if (applepushserviceargs->aps_version >= 2) {
                prot_puts(imapd_out, "* XAPPLEPUSHSERVICE \"mailbox\" ");
                prot_printstring(imapd_out, name);
                prot_puts(imapd_out, "\r\n");
            }
        }
        mboxlist_entry_free(&mbentry);
        free(intname);
    }

    prot_printf(imapd_out,
                "* XAPPLEPUSHSERVICE \"aps-version\" \"%d\" \"aps-topic\" \"%s\"\r\n",
                applepushserviceargs->aps_version, aps_topic);
    prot_printf(imapd_out, "%s OK XAPPLEPUSHSERVICE completed.\r\n", tag);

    struct mboxevent *mboxevent = mboxevent_new(EVENT_APPLEPUSHSERVICE);
    mboxevent_set_applepushservice(mboxevent, applepushserviceargs,
                                   &notif_mailboxes, imapd_userid);
    mboxevent_notify(&mboxevent);
    mboxevent_free(&mboxevent);

    buf_release(&applepushserviceargs->aps_account_id);
    buf_release(&applepushserviceargs->aps_device_token);
    buf_release(&applepushserviceargs->aps_subtopic);
    strarray_fini(&applepushserviceargs->mailboxes);
    strarray_fini(&notif_mailboxes);
}

Project: cyrus-imapd
File: imapd.c

void cmd_xbackup(const char *tag,
                 const char *mailbox,
                 const char *channel)
{
    ptrarray_t list = PTRARRAY_INITIALIZER;
    int i, r;

    /* admins only please */
    if (!imapd_userisadmin && !imapd_userisproxyadmin) {
        r = IMAP_PERMISSION_DENIED;
        goto done;
    }

    if (!config_getswitch(IMAPOPT_XBACKUP_ENABLED)) {
        /* shouldn't get here, but just in case */
        r = IMAP_PERMISSION_DENIED;
        goto done;
    }

    mboxlist_findall(NULL, mailbox, 1, NULL, NULL, xbackup_addmbox, &list);

    if (list.count) {
        r = do_xbackup(channel, &list);

        for (i = 0; i < list.count; i++) {
            mbname_t *mbname = ptrarray_nth(&list, i);
            if (mbname)
                mbname_free(&mbname);
        }
        ptrarray_fini(&list);
    }
    else {
        r = IMAP_MAILBOX_NONEXISTENT;
    }

done:
    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
    } else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }
}

Project: cyrus-imapd
File: imapd.c

void cmd_xconvfetch(const char *tag)
{
    int c = ' ';
    struct fetchargs fetchargs;
    int r;
    clock_t start = clock();
    modseq_t ifchangedsince = 0;
    char mytime[100];
    struct dlist *cidlist = NULL;
    struct dlist *item;

    if (backend_current) {
        /* remote mailbox */
        prot_printf(backend_current->out, "%s XCONVFETCH ", tag);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }

    if (!config_getswitch(IMAPOPT_CONVERSATIONS)) {
        prot_printf(imapd_out, "%s BAD Unrecognized command\r\n", tag);
        eatline(imapd_in, c);
        return;
    }

    /* local mailbox */
    memset(&fetchargs, 0, sizeof(struct fetchargs));

    c = dlist_parse_asatomlist(&cidlist, 0, imapd_in);
    if (c != ' ')
        goto syntax_error;

    /* check CIDs */
    for (item = cidlist->head; item; item = item->next) {
        if (!dlist_ishex64(item)) {
            prot_printf(imapd_out, "%s BAD Invalid CID\r\n", tag);
            eatline(imapd_in, c);
            goto freeargs;
        }
    }

    c = getmodseq(imapd_in, &ifchangedsince);
    if (c != ' ')
        goto syntax_error;

    r = parse_fetch_args(tag, "Xconvfetch", 0, &fetchargs);
    if (r)
        goto freeargs;
    fetchargs.fetchitems |= (FETCH_UIDVALIDITY|FETCH_FOLDER);
    fetchargs.namespace = &imapd_namespace;
    fetchargs.userid = imapd_userid;

    r = do_xconvfetch(cidlist, ifchangedsince, &fetchargs);

    snprintf(mytime, sizeof(mytime), "%2.3f",
             (clock() - start) / (double) CLOCKS_PER_SEC);

    if (r) {
        prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
                    error_message(r), mytime);
    } else {
        prot_printf(imapd_out, "%s OK Completed (%s sec)\r\n",
                    tag, mytime);
    }

freeargs:
    dlist_free(&cidlist);
    fetchargs_fini(&fetchargs);
    return;

syntax_error:
    prot_printf(imapd_out, "%s BAD Syntax error\r\n", tag);
    eatline(imapd_in, c);
    dlist_free(&cidlist);
    fetchargs_fini(&fetchargs);
}

Project: cyrus-imapd
File: imapd.c

void cmd_xconvmeta(const char *tag)
{
    int r;
    int c = ' ';
    struct conversations_state *state = NULL;
    struct dlist *cidlist = NULL;
    struct dlist *itemlist = NULL;

    if (backend_current) {
        /* remote mailbox */
        prot_printf(backend_current->out, "%s XCONVMETA ", tag);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }

    if (!config_getswitch(IMAPOPT_CONVERSATIONS)) {
        prot_printf(imapd_out, "%s BAD Unrecognized command\r\n", tag);
        eatline(imapd_in, c);
        goto done;
    }

    c = dlist_parse_asatomlist(&cidlist, 0, imapd_in);
    if (c != ' ') {
        prot_printf(imapd_out, "%s BAD Failed to parse CID list\r\n", tag);
        eatline(imapd_in, c);
        goto done;
    }

    c = dlist_parse_asatomlist(&itemlist, 0, imapd_in);
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out, "%s BAD Failed to parse item list\r\n", tag);
        eatline(imapd_in, c);
        goto done;
    }

    r = conversations_open_user(imapd_userid, &state);
    if (r) {
        prot_printf(imapd_out, "%s BAD failed to open db: %s\r\n",
                    tag, error_message(r));
        goto done;
    }

    do_xconvmeta(tag, state, cidlist, itemlist);

 done:

    dlist_free(&itemlist);
    dlist_free(&cidlist);
    conversations_commit(&state);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_xconvmultisort(char *tag)
{
    int c;
    struct sortcrit *sortcrit = NULL;
    struct searchargs *searchargs = NULL;
    struct windowargs *windowargs = NULL;
    struct conversations_state *cstate = NULL;
    clock_t start = clock();
    char mytime[100];
    int r;

    if (backend_current) {
        /* remote mailbox */
        const char *cmd = "Xconvmultisort";

        prot_printf(backend_current->out, "%s %s ", tag, cmd);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }
    assert(imapd_index);

    if (!config_getswitch(IMAPOPT_CONVERSATIONS)) {
        prot_printf(imapd_out, "%s BAD Unrecognized command\r\n", tag);
        eatline(imapd_in, ' ');
        return;
    }

    c = getsortcriteria(tag, &sortcrit);
    if (c == EOF) goto error;

    if (c != ' ') {
        prot_printf(imapd_out, "%s BAD Missing window args in XConvMultiSort\r\n",
                    tag);
        goto error;
    }

    c = parse_windowargs(tag, &windowargs, /*updates*/0);
    if (c != ' ')
        goto error;

    /* open the conversations state first - we don't care if it fails,
     * because that probably just means it's already open */
    conversations_open_mbox(index_mboxname(imapd_index), &cstate);

    /* need index loaded to even parse searchargs! */
    searchargs = new_searchargs(tag, GETSEARCH_CHARSET_FIRST,
                                &imapd_namespace, imapd_userid, imapd_authstate,
                                imapd_userisadmin || imapd_userisproxyadmin);
    c = get_search_program(imapd_in, imapd_out, searchargs);
    if (c == EOF) goto error;

    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to XconvMultiSort\r\n", tag);
        goto error;
    }

    r = index_convmultisort(imapd_index, sortcrit, searchargs, windowargs);

    if (r < 0) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag,
                    error_message(r));
        goto error;
    }

    snprintf(mytime, sizeof(mytime), "%2.3f",
             (clock() - start) / (double) CLOCKS_PER_SEC);
    if (CONFIG_TIMING_VERBOSE) {
        char *s = sortcrit_as_string(sortcrit);
        syslog(LOG_DEBUG, "XCONVMULTISORT (%s) processing time %s sec",
               s, mytime);
        free(s);
    }
    prot_printf(imapd_out, "%s OK %s (in %s secs)\r\n", tag,
                error_message(IMAP_OK_COMPLETED), mytime);

out:
    if (cstate) conversations_commit(&cstate);
    freesortcrit(sortcrit);
    freesearchargs(searchargs);
    free_windowargs(windowargs);
    return;

error:
    if (cstate) conversations_commit(&cstate);
    eatline(imapd_in, (c == EOF ? ' ' : c));
    goto out;
}

Project: cyrus-imapd
File: imapd.c

void cmd_xconvsort(char *tag, int updates)
{
    int c;
    struct sortcrit *sortcrit = NULL;
    struct searchargs *searchargs = NULL;
    struct windowargs *windowargs = NULL;
    struct index_init init;
    struct index_state *oldstate = NULL;
    struct conversations_state *cstate = NULL;
    clock_t start = clock();
    char mytime[100];
    int r;

    if (backend_current) {
        /* remote mailbox */
        const char *cmd = "Xconvsort";

        prot_printf(backend_current->out, "%s %s ", tag, cmd);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }
    assert(imapd_index);

    if (!config_getswitch(IMAPOPT_CONVERSATIONS)) {
        prot_printf(imapd_out, "%s BAD Unrecognized command\r\n", tag);
        eatline(imapd_in, ' ');
        return;
    }

    c = getsortcriteria(tag, &sortcrit);
    if (c == EOF) goto error;

    if (c != ' ') {
        prot_printf(imapd_out, "%s BAD Missing window args in XConvSort\r\n",
                    tag);
        goto error;
    }

    c = parse_windowargs(tag, &windowargs, updates);
    if (c != ' ')
        goto error;

    /* open the conversations state first - we don't care if it fails,
     * because that probably just means it's already open */
    conversations_open_mbox(index_mboxname(imapd_index), &cstate);

    if (updates) {
        /* in XCONVUPDATES, need to force a re-read from scratch into
         * a new index, because we ask for deleted messages */

        oldstate = imapd_index;
        imapd_index = NULL;

        memset(&init, 0, sizeof(struct index_init));
        init.userid = imapd_userid;
        init.authstate = imapd_authstate;
        init.out = imapd_out;
        init.want_expunged = 1;

        r = index_open(index_mboxname(oldstate), &init, &imapd_index);
        if (r) {
            prot_printf(imapd_out, "%s NO %s\r\n", tag,
                        error_message(r));
            goto error;
        }

        index_checkflags(imapd_index, 0, 0);
    }

    /* need index loaded to even parse searchargs! */
    searchargs = new_searchargs(tag, GETSEARCH_CHARSET_FIRST,
                                &imapd_namespace, imapd_userid, imapd_authstate,
                                imapd_userisadmin || imapd_userisproxyadmin);
    c = get_search_program(imapd_in, imapd_out, searchargs);
    if (c == EOF) goto error;

    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to Xconvsort\r\n", tag);
        goto error;
    }

    if (updates)
        r = index_convupdates(imapd_index, sortcrit, searchargs, windowargs);
    else
        r = index_convsort(imapd_index, sortcrit, searchargs, windowargs);

    if (oldstate) {
        index_close(&imapd_index);
        imapd_index = oldstate;
    }

    if (r < 0) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag,
                    error_message(r));
        goto error;
    }

    snprintf(mytime, sizeof(mytime), "%2.3f",
             (clock() - start) / (double) CLOCKS_PER_SEC);
    if (CONFIG_TIMING_VERBOSE) {
        char *s = sortcrit_as_string(sortcrit);
        syslog(LOG_DEBUG, "XCONVSORT (%s) processing time %s sec",
               s, mytime);
        free(s);
    }
    prot_printf(imapd_out, "%s OK %s (in %s secs)\r\n", tag,
                error_message(IMAP_OK_COMPLETED), mytime);

out:
    if (cstate) conversations_commit(&cstate);
    freesortcrit(sortcrit);
    freesearchargs(searchargs);
    free_windowargs(windowargs);
    return;

error:
    if (cstate) conversations_commit(&cstate);
    if (oldstate) {
        if (imapd_index) index_close(&imapd_index);
        imapd_index = oldstate;
    }
    eatline(imapd_in, (c == EOF ? ' ' : c));
    goto out;
}

Project: cyrus-imapd
File: imapd.c

static void cmd_xfer(const char *tag, const char *name,
                     const char *toserver, const char *topart)
{
    int r = 0, partial_success = 0, mbox_count = 0;
    struct xfer_header *xfer = NULL;
    struct xfer_list list = { &imapd_namespace, imapd_userid, NULL, 0, NULL };
    struct xfer_item *item, *next;
    char *intname = NULL;

    /* administrators only please */
    /* however, proxys can do this, if their authzid is an admin */
    if (!imapd_userisadmin && !imapd_userisproxyadmin) {
        r = IMAP_PERMISSION_DENIED;
        goto done;
    }

    if (!strcmp(toserver, config_servername)) {
        r = IMAP_BAD_SERVER;
        goto done;
    }

    /* Build list of users/mailboxes to transfer */
    if (config_partitiondir(name)) {
        /* entire partition */
        list.part = name;
        mboxlist_findall(NULL, "*", 1, NULL, NULL, xfer_addmbox, &list);
    } else {
        /* mailbox pattern */
        mbname_t *mbname;

        intname = mboxname_from_external(name, &imapd_namespace, imapd_userid);

        mbname = mbname_from_intname(intname);
        if (mbname_localpart(mbname) &&
            (mbname_isdeleted(mbname) || strarray_size(mbname_boxes(mbname)))) {
            /* targeted a user submailbox */
            list.allow_usersubs = 1;
        }
        mbname_free(&mbname);

        mboxlist_findall(NULL, intname, 1, NULL, NULL, xfer_addmbox, &list);
        free(intname);
    }

    r = xfer_init(toserver, &xfer);
    if (r) goto done;

    for (item = list.mboxes; item; item = next) {
        mbentry_t *mbentry = item->mbentry;

        /* NOTE: Since XFER can only be used by an admin, and we always connect
         * to the destination backend as an admin, we take advantage of the fact
         * that admins *always* use a consistent mailbox naming scheme.
         * So, 'name' should be used in any command we send to a backend, and
         * 'intname' is the internal name to be used for mupdate and findall.
         */

        r = 0;
        intname = mbentry->name;
        xfer->topart = xstrdup(topart ? topart : mbentry->partition);

        /* if we are not moving a user, just move the one mailbox */
        if (item->state != XFER_MOVING_USER) {

            syslog(LOG_INFO, "XFER: mailbox '%s' -> %s!%s",
                   mbentry->name, xfer->toserver, xfer->topart);

            /* is the selected mailbox the one we're moving? */
            if (!strcmpsafe(intname, index_mboxname(imapd_index))) {
                r = IMAP_MAILBOX_LOCKED;
                goto next;
            }

            /* we're moving this mailbox */
            xfer_addusermbox(mbentry, xfer);
            mbox_count++;

            r = do_xfer(xfer);
        } else {
            xfer->userid = mboxname_to_userid(intname);

            syslog(LOG_INFO, "XFER: user '%s' -> %s!%s",
                   xfer->userid, xfer->toserver, xfer->topart);

            if (!config_getswitch(IMAPOPT_ALLOWUSERMOVES)) {
                /* not configured to allow user moves */
                r = IMAP_MAILBOX_NOTSUPPORTED;
            } else if (!strcmp(xfer->userid, imapd_userid)) {
                /* don't move your own inbox, that could be troublesome */
                r = IMAP_MAILBOX_NOTSUPPORTED;
            } else if (!strncmpsafe(intname, index_mboxname(imapd_index),
                             strlen(intname))) {
                /* selected mailbox is in the namespace we're moving */
                r = IMAP_MAILBOX_LOCKED;
            }
            if (r) goto next;

            if (!xfer->use_replication) {
                /* set the quotaroot if needed */
                r = xfer_setquotaroot(xfer, intname);
                if (r) goto next;

                /* backport the seen file if needed */
                if (xfer->remoteversion < 12) {
                    r = seen_open(xfer->userid, SEEN_CREATE, &xfer->seendb);
                    if (r) goto next;
                }
            }

            r = mboxlist_usermboxtree(xfer->userid, xfer_addusermbox,
                                      xfer, MBOXTREE_DELETED);

            /* NOTE: mailboxes were added in reverse, so the inbox is
             * done last */
            r = do_xfer(xfer);
            if (r) goto next;

            /* this was a successful user move, and we need to delete
               certain user meta-data (but not seen state!) */
            syslog(LOG_INFO, "XFER: deleting user metadata");
            user_deletedata(xfer->userid, 0);
        }

      next:
        if (r) {
            if (xfer->userid)
                prot_printf(imapd_out, "* NO USER %s (%s)\r\n",
                            xfer->userid, error_message(r));
            else
                prot_printf(imapd_out, "* NO MAILBOX \"%s\" (%s)\r\n",
                            item->extname, error_message(r));
        } else {
            partial_success = 1;

            if (xfer->userid)
                prot_printf(imapd_out, "* OK USER %s\r\n", xfer->userid);
            else
                prot_printf(imapd_out, "* OK MAILBOX \"%s\"\r\n", item->extname);
        }
        prot_flush(imapd_out);

        mboxlist_entry_free(&mbentry);
        next = item->next;
        free(item);

        if (xfer->userid || mbox_count > 1000) {
            /* RESTART after each user or after every 1000 mailboxes */
            mbox_count = 0;

            sync_send_restart(xfer->be->out);
            r = sync_parse_response("RESTART", xfer->be->in, NULL);
            if (r) goto done;
        }

        xfer_cleanup(xfer);

        if (partial_success) r = 0;
    }

done:
    if (xfer) xfer_done(&xfer);

    imapd_check(NULL, 0);

    if (r) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag,
                    error_message(r));
    } else {
        prot_printf(imapd_out, "%s OK %s\r\n", tag,
                    error_message(IMAP_OK_COMPLETED));
    }

    return;
}

Project: cyrus-imapd
File: imapd.c

static void cmd_xforever(const char *tag)
{
    unsigned n = 1;
    int r = 0;

    while (!r) {
        sleep(1);
        prot_printf(imapd_out, "* FOREVER %u\r\n", n++);
        prot_flush(imapd_out);
        r = cmd_cancelled();
    }

    prot_printf(imapd_out, "%s OK %s\r\n", tag, error_message(r));
}

Project: cyrus-imapd
File: imapd.c

static void cmd_xkillmy(const char *tag, const char *cmdname)
{
    char *cmd = xstrdup(cmdname);
    char *p;

    /* normalise to imapd conventions */
    if (Uislower(cmd[0]))
        cmd[0] = toupper((unsigned char) cmd[0]);
    for (p = cmd+1; *p; p++) {
        if (Uisupper(*p)) *p = tolower((unsigned char) *p);
    }

    proc_killusercmd(imapd_userid, cmd, SIGUSR2);

    free(cmd);

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
}

Project: cyrus-imapd
File: imapd.c

static void cmd_xmeid(const char *tag, const char *id)
{
    mboxevent_set_client_id(id);

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
}

Project: cyrus-imapd
File: imapd.c

static void cmd_xrunannotator(const char *tag, const char *sequence,
                              int usinguid)
{
    const char *cmd = usinguid ? "UID Xrunannotator" : "Xrunannotator";
    clock_t start = clock();
    char mytime[100];
    int c, r = 0;

    if (backend_current) {
        /* remote mailbox */
        prot_printf(backend_current->out, "%s %s %s ", tag, cmd, sequence);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }

    /* local mailbox */

    /* we're expecting no more arguments */
    c = prot_getc(imapd_in);
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out, "%s BAD Unexpected extra arguments to %s\r\n", tag, cmd);
        eatline(imapd_in, c);
        return;
    }

    r = index_run_annotator(imapd_index, sequence, usinguid,
                            &imapd_namespace, imapd_userisadmin);

    snprintf(mytime, sizeof(mytime), "%2.3f",
             (clock() - start) / (double) CLOCKS_PER_SEC);

    if (r)
        prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
                    error_message(r), mytime);
    else
        prot_printf(imapd_out, "%s OK %s (%s sec)\r\n", tag,
                    error_message(IMAP_OK_COMPLETED), mytime);
}

Project: cyrus-imapd
File: imapd.c

static void cmd_xsnippets(char *tag)
{
    int c;
    struct searchargs *searchargs = NULL;
    struct snippetargs *snippetargs = NULL;
    clock_t start = clock();
    char mytime[100];
    int r;

    if (backend_current) {
        /* remote mailbox */
        const char *cmd = "Xsnippets";

        prot_printf(backend_current->out, "%s %s ", tag, cmd);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }
    assert(imapd_index);

    c = get_snippetargs(&snippetargs);
    if (c == EOF) {
        prot_printf(imapd_out, "%s BAD Syntax error in snippet arguments\r\n", tag);
        goto error;
    }
    if (c != ' ') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected arguments in Xsnippets\r\n", tag);
        goto error;
    }

    /* need index loaded to even parse searchargs! */
    searchargs = new_searchargs(tag, GETSEARCH_CHARSET_FIRST,
                                &imapd_namespace, imapd_userid, imapd_authstate,
                                imapd_userisadmin || imapd_userisproxyadmin);
    c = get_search_program(imapd_in, imapd_out, searchargs);
    if (c == EOF) goto error;

    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to Xsnippets\r\n", tag);
        goto error;
    }

    r = index_snippets(imapd_index, snippetargs, searchargs);

    if (r < 0) {
        prot_printf(imapd_out, "%s NO %s\r\n", tag,
                    error_message(r));
        goto error;
    }

    snprintf(mytime, sizeof(mytime), "%2.3f",
             (clock() - start) / (double) CLOCKS_PER_SEC);
    prot_printf(imapd_out, "%s OK %s (in %s secs)\r\n", tag,
                error_message(IMAP_OK_COMPLETED), mytime);

out:
    freesearchargs(searchargs);
    free_snippetargs(&snippetargs);
    return;

error:
    eatline(imapd_in, (c == EOF ? ' ' : c));
    goto out;
}

Project: cyrus-imapd
File: imapd.c

static void cmd_xstats(char *tag, int c)
{
    int metric;

    if (backend_current) {
        /* remote mailbox */
        const char *cmd = "Xstats";

        prot_printf(backend_current->out, "%s %s ", tag, cmd);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        return;
    }

    if (c == EOF) {
        prot_printf(imapd_out, "%s BAD Syntax error in Xstats arguments\r\n", tag);
        goto error;
    }
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') {
        prot_printf(imapd_out,
                    "%s BAD Unexpected extra arguments to Xstats\r\n", tag);
        goto error;
    }

    prot_printf(imapd_out, "* XSTATS");
    for (metric = 0 ; metric < XSTATS_NUM_METRICS ; metric++)
        prot_printf(imapd_out, " %s %u", xstats_names[metric], xstats[metric]);
    prot_printf(imapd_out, "\r\n");

    prot_printf(imapd_out, "%s OK %s\r\n", tag,
                error_message(IMAP_OK_COMPLETED));
    return;

error:
    eatline(imapd_in, (c == EOF ? ' ' : c));
}

Project: cyrus-imapd
File: imapd.c

static void cmd_xwarmup(const char *tag)
{
    const char *cmd = "Xwarmup";
    clock_t start = clock();
    char mytime[100];
    struct buf arg = BUF_INITIALIZER;
    int warmup_flags = 0;
    struct seqset *uids = NULL;
    /* We deal with the mboxlist API instead of the index_state API or
     * mailbox API to avoid the overhead of index_open(), which will
     * block while reading all the cyrus.index...we want to be
     * non-blocking */
    struct mboxlist_entry *mbentry = NULL;
    int myrights;
    int c, r = 0;
    char *intname = NULL;

    /* parse arguments: expect <mboxname> '('<warmup-items>')' */

    c = getastring(imapd_in, imapd_out, &arg);
    if (c != ' ') {
syntax_error:
        prot_printf(imapd_out, "%s BAD syntax error in %s\r\n", tag, cmd);
        eatline(imapd_in, c);
        goto out_noprint;
    }

    intname = mboxname_from_external(arg.s, &imapd_namespace, imapd_userid);
    r = mboxlist_lookup(intname, &mbentry, NULL);
    if (r) goto out;

    /* Do a permissions check to avoid server DoS opportunity.  But we
     * only need read permission to warmup a mailbox.  Also, be careful
     * to avoid telling the client about the existance of mailboxes to
     * which he doesn't have LOOKUP rights. */
    r = IMAP_PERMISSION_DENIED;
    myrights = (mbentry->acl ? cyrus_acl_myrights(imapd_authstate, mbentry->acl) : 0);
    if (imapd_userisadmin)
        r = 0;
    else if (!(myrights & ACL_LOOKUP))
        r = IMAP_MAILBOX_NONEXISTENT;
    else if (myrights & ACL_READ)
        r = 0;
    if (r) goto out;

    if (mbentry->mbtype & MBTYPE_REMOTE) {
        /* remote mailbox */
        struct backend *be;

        be = proxy_findserver(mbentry->server, &imap_protocol,
                              proxy_userid, &backend_cached,
                              &backend_current, &backend_inbox, imapd_in);
        if (!be) {
            r = IMAP_SERVER_UNAVAILABLE;
            goto out;
        }

        prot_printf(be->out, "%s %s %s ", tag, cmd, arg.s);
        if (!pipe_command(backend_current, 65536)) {
            pipe_including_tag(backend_current, tag, 0);
        }
        goto out;
    }
    /* local mailbox */

    /* parse the arguments after the mailbox */

    c = prot_getc(imapd_in);
    if (c != '(') goto syntax_error;

    for (;;) {
        c = getword(imapd_in, &arg);
        if (arg.len) {
            if (!strcasecmp(arg.s, "index"))
                warmup_flags |= WARMUP_INDEX;
            else if (!strcasecmp(arg.s, "conversations"))
                warmup_flags |= WARMUP_CONVERSATIONS;
            else if (!strcasecmp(arg.s, "annotations"))
                warmup_flags |= WARMUP_ANNOTATIONS;
            else if (!strcasecmp(arg.s, "folderstatus"))
                warmup_flags |= WARMUP_FOLDERSTATUS;
            else if (!strcasecmp(arg.s, "search"))
                warmup_flags |= WARMUP_SEARCH;
            else if (!strcasecmp(arg.s, "uids")) {
                if (c != ' ') goto syntax_error;
                c = getword(imapd_in, &arg);
                if (c == EOF) goto syntax_error;
                if (!imparse_issequence(arg.s)) goto syntax_error;
                uids = seqset_parse(arg.s, NULL, /*maxval*/0);
                if (!uids) goto syntax_error;
            }
            else if (!strcasecmp(arg.s, "all"))
                warmup_flags |= WARMUP_ALL;
            else
                goto syntax_error;
        }
        if (c == ')')
            break;
        if (c != ' ') goto syntax_error;
    }

    /* we're expecting no more arguments */
    c = prot_getc(imapd_in);
    if (c == '\r') c = prot_getc(imapd_in);
    if (c != '\n') goto syntax_error;

    r = index_warmup(mbentry, warmup_flags, uids);

out:
    snprintf(mytime, sizeof(mytime), "%2.3f",
             (clock() - start) / (double) CLOCKS_PER_SEC);

    if (r)
        prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
                    error_message(r), mytime);
    else
        prot_printf(imapd_out, "%s OK %s (%s sec)\r\n", tag,
                    error_message(IMAP_OK_COMPLETED), mytime);

out_noprint:
    mboxlist_entry_free(&mbentry);
    free(intname);
    buf_free(&arg);
    if (uids) seqset_free(uids);
}

Project: cyrus-imapd
File: imapd.c

static void copy_to_array(const char *key, void *data, void *void_rock)
{
    uint32_t *attributes = (uint32_t *)data;
    struct list_rock_recursivematch *rock =
        (struct list_rock_recursivematch *)void_rock;
    assert(rock->count > 0);
    rock->array[--rock->count].name = key;
    rock->array[rock->count].attributes = *attributes;
}

Project: cyrus-imapd
File: imapd.c

static bool deadline_exceeded(const struct timespec *d)
{
    struct timespec now;

    if (d->tv_sec <= 0) {
        /* No deadline configured */
        return false;
    }

    errno = 0;
    if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
        syslog(LOG_ERR, "clock_gettime (%d %m): error reading clock", errno);
        return false;
    }

    return now.tv_sec > d->tv_sec ||
           (now.tv_sec == d->tv_sec && now.tv_nsec > d->tv_nsec);
}

Project: cyrus-imapd
File: imapd.c

static int delmbox(const mbentry_t *mbentry, void *rock __attribute__((unused)))
{
    int r;

    if (!mboxlist_delayed_delete_isenabled()) {
        r = mboxlist_deletemailbox(mbentry->name,
                                   imapd_userisadmin || imapd_userisproxyadmin,
                                   imapd_userid, imapd_authstate, NULL,
                                   0, 0, 0);
    } else if ((imapd_userisadmin || imapd_userisproxyadmin) &&
               mboxname_isdeletedmailbox(mbentry->name, NULL)) {
        r = mboxlist_deletemailbox(mbentry->name,
                                   imapd_userisadmin || imapd_userisproxyadmin,
                                   imapd_userid, imapd_authstate, NULL,
                                   0, 0, 0);
    } else {
        r = mboxlist_delayed_deletemailbox(mbentry->name,
                                           imapd_userisadmin || imapd_userisproxyadmin,
                                           imapd_userid, imapd_authstate, NULL,
                                           0, 0, 0);
    }

    if (r) {
        prot_printf(imapd_out, "* NO delete %s: %s\r\n",
                    mbentry->name, error_message(r));
    }

    return 0;
}

Project: cyrus-imapd
File: imapd.c

static void do_one_xconvmeta(struct conversations_state *state,
                             conversation_id_t cid,
                             conversation_t *conv,
                             struct dlist *itemlist)
{
    struct dlist *item = dlist_newpklist(NULL, "");
    struct dlist *fl;

    assert(conv);
    assert(itemlist);

    for (fl = itemlist->head; fl; fl = fl->next) {
        const char *key = dlist_cstring(fl);

        /* xxx - parse to a fetchitems? */
        if (!strcasecmp(key, "MODSEQ"))
            dlist_setnum64(item, "MODSEQ", conv->modseq);
        else if (!strcasecmp(key, "EXISTS"))
            dlist_setnum32(item, "EXISTS", conv->exists);
        else if (!strcasecmp(key, "UNSEEN"))
            dlist_setnum32(item, "UNSEEN", conv->unseen);
        else if (!strcasecmp(key, "SIZE"))
            dlist_setnum32(item, "SIZE", conv->size);
        else if (!strcasecmp(key, "COUNT")) {
            struct dlist *flist = dlist_newlist(item, "COUNT");
            fl = fl->next;
            if (dlist_isatomlist(fl)) {
                struct dlist *tmp;
                for (tmp = fl->head; tmp; tmp = tmp->next) {
                    const char *lookup = dlist_cstring(tmp);
                    int i = strarray_find_case(state->counted_flags, lookup, 0);
                    if (i >= 0) {
                        dlist_setflag(flist, "FLAG", lookup);
                        dlist_setnum32(flist, "COUNT", conv->counts[i]);
                    }
                }
            }
        }
        else if (!strcasecmp(key, "SENDERS")) {
            conv_sender_t *sender;
            struct dlist *slist = dlist_newlist(item, "SENDERS");
            for (sender = conv->senders; sender; sender = sender->next) {
                struct dlist *sli = dlist_newlist(slist, "");
                dlist_setatom(sli, "NAME", sender->name);
                dlist_setatom(sli, "ROUTE", sender->route);
                dlist_setatom(sli, "MAILBOX", sender->mailbox);
                dlist_setatom(sli, "DOMAIN", sender->domain);
            }
        }
        /* XXX - maybe rename FOLDERCOUNTS or something? */
        else if (!strcasecmp(key, "FOLDEREXISTS")) {
            struct dlist *flist = dlist_newlist(item, "FOLDEREXISTS");
            conv_folder_t *folder;
            fl = fl->next;
            if (dlist_isatomlist(fl)) {
                struct dlist *tmp;
                for (tmp = fl->head; tmp; tmp = tmp->next) {
                    const char *extname = dlist_cstring(tmp);
                    char *intname = mboxname_from_external(extname, &imapd_namespace, imapd_userid);
                    folder = conversation_find_folder(state, conv, intname);
                    free(intname);
                    dlist_setatom(flist, "MBOXNAME", extname);
                    /* ok if it's not there */
                    dlist_setnum32(flist, "EXISTS", folder ? folder->exists : 0);
                }
            }
        }
        else if (!strcasecmp(key, "FOLDERUNSEEN")) {
            struct dlist *flist = dlist_newlist(item, "FOLDERUNSEEN");
            conv_folder_t *folder;
            fl = fl->next;
            if (dlist_isatomlist(fl)) {
                struct dlist *tmp;
                for (tmp = fl->head; tmp; tmp = tmp->next) {
                    const char *extname = dlist_cstring(tmp);
                    char *intname = mboxname_from_external(extname, &imapd_namespace, imapd_userid);
                    folder = conversation_find_folder(state, conv, intname);
                    free(intname);
                    dlist_setatom(flist, "MBOXNAME", extname);
                    /* ok if it's not there */
                    dlist_setnum32(flist, "UNSEEN", folder ? folder->unseen : 0);
                }
            }
        }
        else {
            dlist_setatom(item, key, NULL); /* add a NIL response */
        }
    }

    prot_printf(imapd_out, "* XCONVMETA %s ", conversation_id_encode(cid));
    dlist_print(item, 0, imapd_out);
    prot_printf(imapd_out, "\r\n");

    dlist_free(&item);
}

Project: cyrus-imapd
File: imapd.c

static int do_xbackup(const char *channel,
                      const ptrarray_t *list)
{
    sasl_callback_t *cb = NULL;
    struct backend *backend = NULL;
    const char *hostname;
    const char *port;
    unsigned sync_flags = 0; // FIXME ??
    int partial_success = 0;
    int mbox_count = 0;
    int i, r;

    hostname = sync_get_config(channel, "sync_host");
    if (!hostname) {
        syslog(LOG_ERR, "XBACKUP: couldn't find hostname for channel '%s'", channel);
        return IMAP_BAD_SERVER;
    }

    port = sync_get_config(channel, "sync_port");
    if (port) csync_protocol.service = port;

    cb = mysasl_callbacks(NULL,
                          sync_get_config(channel, "sync_authname"),
                          sync_get_config(channel, "sync_realm"),
                          sync_get_config(channel, "sync_password"));

    syslog(LOG_INFO, "XBACKUP: connecting to server '%s' for channel '%s'",
                     hostname, channel);

    backend = backend_connect(NULL, hostname, &csync_protocol, NULL, cb, NULL, -1);
    if (!backend) {
        syslog(LOG_ERR, "XBACKUP: failed to connect to server '%s' for channel '%s'",
                        hostname, channel);
        return IMAP_SERVER_UNAVAILABLE;
    }

    free_callbacks(cb);
    cb = NULL;

    for (i = 0; i < list->count; i++) {
        const mbname_t *mbname = ptrarray_nth(list, i);
        if (!mbname) continue;
        const char *userid = mbname_userid(mbname);
        const char *intname = mbname_intname(mbname);

        if (userid) {
            syslog(LOG_INFO, "XBACKUP: replicating user %s", userid);

            r = sync_do_user(userid, NULL, backend, /*channelp*/ NULL, sync_flags);
        }
        else {
            struct sync_name_list *mboxname_list = sync_name_list_create();

            syslog(LOG_INFO, "XBACKUP: replicating mailbox %s", intname);
            sync_name_list_add(mboxname_list, intname);

            r = sync_do_mailboxes(mboxname_list, NULL, backend,
                                  /*channelp*/ NULL, sync_flags);
            mbox_count++;
            sync_name_list_free(&mboxname_list);
        }

        if (r) {
            prot_printf(imapd_out, "* NO %s %s (%s)\r\n",
                        userid ? "USER" : "MAILBOX",
                        userid ? userid : intname,
                        error_message(r));
        }
        else {
            partial_success++;
            prot_printf(imapd_out, "* OK %s %s\r\n",
                        userid ? "USER" : "MAILBOX",
                        userid ? userid : intname);
        }
        prot_flush(imapd_out);

        /* send RESTART after each user, or 1000 mailboxes */
        if (!r && i < list->count - 1 && (userid || mbox_count >= 1000)) {
            mbox_count = 0;

            sync_send_restart(backend->out);
            r = sync_parse_response("RESTART", backend->in, NULL);
            if (r) goto done;
        }
    }

    /* send a final RESTART */
    sync_send_restart(backend->out);
    sync_parse_response("RESTART", backend->in, NULL);

    if (partial_success) r = 0;

done:
    backend_disconnect(backend);
    free(backend);

    return r;
}

Project: cyrus-imapd
File: imapd.c

static int do_xconvfetch(struct dlist *cidlist,
                         modseq_t ifchangedsince,
                         struct fetchargs *fetchargs)
{
    struct conversations_state *state = NULL;
    int r = 0;
    struct index_state *index_state = NULL;
    struct dlist *dl;
    hash_table wanted_cids = HASH_TABLE_INITIALIZER;
    strarray_t folder_list = STRARRAY_INITIALIZER;
    struct index_init init;
    int i;

    r = conversations_open_user(imapd_userid, &state);
    if (r) goto out;

    construct_hash_table(&wanted_cids, 1024, 0);

    for (dl = cidlist->head; dl; dl = dl->next) {
        r = xconvfetch_lookup(state, dlist_num(dl), ifchangedsince,
                              &wanted_cids, &folder_list);
        if (r) goto out;
    }

    /* unchanged, woot */
    if (!folder_list.count)
        goto out;

    fetchargs->cidhash = &wanted_cids;

    memset(&init, 0, sizeof(struct index_init));
    init.userid = imapd_userid;
    init.authstate = imapd_authstate;
    init.out = imapd_out;

    for (i = 0; i < folder_list.count; i++) {
        const char *mboxname = folder_list.data[i];

        r = index_open(mboxname, &init, &index_state);
        if (r == IMAP_MAILBOX_NONEXISTENT)
            continue;
        if (r)
            goto out;

        index_checkflags(index_state, 0, 0);

        /* make sure \Deleted messages are expunged.  Will also lock the
         * mailbox state and read any new information */
        r = index_expunge(index_state, NULL, 1);

        if (!r)
            index_fetchresponses(index_state, NULL, /*usinguid*/1,
                                 fetchargs, NULL);

        index_close(&index_state);

        if (r) goto out;
    }

    r = 0;

out:
    index_close(&index_state);
    conversations_commit(&state);
    free_hash_table(&wanted_cids, NULL);
    strarray_fini(&folder_list);
    return r;
}

Project: cyrus-imapd
File: imapd.c

static void do_xconvmeta(const char *tag,
                         struct conversations_state *state,
                         struct dlist *cidlist,
                         struct dlist *itemlist)
{
    conversation_id_t cid;
    struct dlist *dl;
    int r;

    for (dl = cidlist->head; dl; dl = dl->next) {
        const char *cidstr = dlist_cstring(dl);
        conversation_t *conv = NULL;

        if (!conversation_id_decode(&cid, cidstr) || !cid) {
            prot_printf(imapd_out, "%s BAD Invalid CID %s\r\n", tag, cidstr);
            return;
        }

        r = conversation_load(state, cid, &conv);
        if (r) {
            prot_printf(imapd_out, "%s BAD Failed to read %s\r\n", tag, cidstr);
            conversation_free(conv);
            return;
        }

        if (conv && conv->exists)
            do_one_xconvmeta(state, cid, conv, itemlist);

        conversation_free(conv);
    }

    prot_printf(imapd_out, "%s OK Completed\r\n", tag);
}

Project: cyrus-imapd
File: imapd.c

static int do_xfer(struct xfer_header *xfer)
{
    int r = 0;

    if (xfer->use_replication) {
        /* Initial non-blocking sync */
        r = xfer_initialsync(xfer);
        if (r) return r;
    }

    r = xfer_deactivate(xfer);

    if (!r) {
        if (xfer->use_replication) {
            /* Final sync with write locks on mailboxes */
            r = xfer_finalsync(xfer);
        }
        else {
            r = xfer_localcreate(xfer);
            if (!r) r = xfer_undump(xfer);
        }
    }

    if (r) {
        /* Something failed, revert back to local server */
        xfer_recover(xfer);
        return r;
    }

    /* Successful dump of all mailboxes to remote server.
     * Remove them locally and activate them on remote.
     * Note - we don't report errors if this fails! */
    xfer_delete(xfer);
    xfer_reactivate(xfer);

    return 0;
}

Project: cyrus-imapd
File: imapd.c

static int dumpacl(struct protstream *pin, struct protstream *pout,
                   const char *mboxname, const char *acl_in)
{
    int r = 0;
    char tag[128];
    int tagnum = 1;
    char *rights, *nextid;
    char *acl_safe = acl_in ? xstrdup(acl_in) : NULL;
    char *acl = acl_safe;

    while (acl) {
        rights = strchr(acl, '\t');
        if (!rights) break;
        *rights++ = '\0';

        nextid = strchr(rights, '\t');
        if (!nextid) break;
        *nextid++ = '\0';

        snprintf(tag, sizeof(tag), "SACL%d", tagnum++);

        prot_printf(pout, "%s SETACL {" SIZE_T_FMT "+}\r\n%s"
                    " {" SIZE_T_FMT "+}\r\n%s {" SIZE_T_FMT "+}\r\n%s\r\n",
                    tag,
                    strlen(mboxname), mboxname,
                    strlen(acl), acl,
                    strlen(rights), rights);

        r = getresult(pin, tag);
        if (r) break;

        acl = nextid;
    }

    if(acl_safe) free(acl_safe);

    return r;
}

Project: cyrus-imapd
File: imapd.c

EXPORTED void fatal(const char *s, int code)
{
    static int recurse_code = 0;

    if (recurse_code) {
        /* We were called recursively. Just give up */
        proc_cleanup();
        snmp_increment(ACTIVE_CONNECTIONS, -1);
        exit(recurse_code);
    }
    recurse_code = code;
    if (imapd_out) {
        prot_printf(imapd_out, "* BYE Fatal error: %s\r\n", s);
        prot_flush(imapd_out);
    }
    if (stages.count) {
        /* Cleanup the stage(s) */
        struct appendstage *curstage;
        while ((curstage = ptrarray_pop(&stages))) {
            if (curstage->f != NULL) fclose(curstage->f);
            append_removestage(curstage->stage);
            strarray_fini(&curstage->flags);
            freeentryatts(curstage->annotations);
            free(curstage);
        }
        ptrarray_fini(&stages);
    }

    syslog(LOG_ERR, "Fatal error: %s", s);
    shut_down(code);
}