X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fimap%2Fimap_tools.c;fp=citadel%2Fmodules%2Fimap%2Fimap_tools.c;h=0000000000000000000000000000000000000000;hb=f6fcf350671e3661f8f22696eb35133014ab6a14;hp=7d7c0805cfebf6f8babc5d81a83e4a0b5c8d7877;hpb=2e4e67a1f7f65568abace99d13a71024ad06ebde;p=citadel.git diff --git a/citadel/modules/imap/imap_tools.c b/citadel/modules/imap/imap_tools.c deleted file mode 100644 index 7d7c0805c..000000000 --- a/citadel/modules/imap/imap_tools.c +++ /dev/null @@ -1,992 +0,0 @@ -/* - * Utility functions for the IMAP module. - * - * Copyright (c) 2001-2017 by the citadel.org team and others, except for - * most of the UTF7 and UTF8 handling code which was lifted from Evolution. - * - * This program is open source software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define SHOW_ME_VAPPEND_PRINTF -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "sysdep_decls.h" -#include "internet_addressing.h" -#include "serv_imap.h" -#include "imap_tools.h" -#include "ctdl_module.h" - -/* String handling helpers */ - -/* This code uses some pretty nasty string manipulation. To make everything - * manageable, we use this semi-high-level string manipulation API. Strings are - * always \0-terminated, despite the fact that we keep track of the size. - */ -struct string { - char* buffer; - int maxsize; - int size; -}; - -static void string_init(struct string* s, char* buf, int bufsize) -{ - s->buffer = buf; - s->maxsize = bufsize-1; - s->size = strlen(buf); -} - -static char* string_end(struct string* s) -{ - return s->buffer + s->size; -} - -/* Append a UTF8 string of a particular length (in bytes). -1 to autocalculate. */ - -static void string_append_sn(struct string* s, char* p, int len) -{ - if (len == -1) - len = strlen(p); - if ((s->size+len) > s->maxsize) - len = s->maxsize - s->size; - memcpy(s->buffer + s->size, p, len); - s->size += len; - s->buffer[s->size] = '\0'; -} - -/* As above, always autocalculate. */ - -#define string_append_s(s, p) string_append_sn((s), (p), -1) - -/* Appends a UTF8 character --- which may make the size change by more than 1! - * If the string overflows, the last character may become invalid. */ - -static void string_append_c(struct string* s, int c) -{ - char UmlChar[5]; - int len = 0; - - /* Don't do anything if there's no room. */ - - if (s->size == s->maxsize) - return; - - if (c <= 0x7F) - { - /* This is the most common case, so we optimise it. */ - - s->buffer[s->size++] = c; - s->buffer[s->size] = 0; - return; - } - else if (c <= 0x7FF) - { - UmlChar[0] = 0xC0 | (c >> 6); - UmlChar[1] = 0x80 | (c & 0x3F); - len = 2; - } - else if (c <= 0xFFFF) - { - UmlChar[0] = 0xE0 | (c >> 12); - UmlChar[1] = 0x80 | ((c >> 6) & 0x3f); - UmlChar[2] = 0x80 | (c & 0x3f); - len = 3; - } - else - { - UmlChar[0] = 0xf0 | c >> 18; - UmlChar[1] = 0x80 | ((c >> 12) & 0x3f); - UmlChar[2] = 0x80 | ((c >> 6) & 0x3f); - UmlChar[3] = 0x80 | (c & 0x3f); - len = 4; - } - - string_append_sn(s, UmlChar, len); -} - -/* Reads a UTF8 character from a char*, advancing the pointer. */ - -int utf8_getc(char** ptr) -{ - unsigned char* p = (unsigned char*) *ptr; - unsigned char c, r; - int v, m; - - for (;;) - { - r = *p++; - loop: - if (r < 0x80) - { - *ptr = (char*) p; - v = r; - break; - } - else if (r < 0xf8) - { - /* valid start char? (max 4 octets) */ - v = r; - m = 0x7f80; /* used to mask out the length bits */ - do { - c = *p++; - if ((c & 0xc0) != 0x80) - { - r = c; - goto loop; - } - v = (v<<6) | (c & 0x3f); - r<<=1; - m<<=5; - } while (r & 0x40); - - *ptr = (char*)p; - - v &= ~m; - break; - } - } - - return v; -} - -/* IMAP name safety */ - -/* IMAP has certain special requirements in its character set, which means we - * have to do a fair bit of work to convert Citadel's UTF8 strings to IMAP - * strings. The next two routines (and their data tables) do that. - */ - -static char *utf7_alphabet = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; - -static unsigned char utf7_rank[256] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3E,0x3F,0xFF,0xFF,0xFF, - 0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, - 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, - 0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -}; - -/* Base64 helpers. */ - -static void utf7_closeb64(struct string* out, int v, int i) -{ - int x; - - if (i > 0) - { - x = (v << (6-i)) & 0x3F; - string_append_c(out, utf7_alphabet[x]); - } - string_append_c(out, '-'); -} - -/* Convert from a Citadel name to an IMAP-safe name. Returns the end - * of the destination. - */ -static char* toimap(char* destp, char* destend, char* src) -{ - struct string dest; - int state = 0; - int v = 0; - int i = 0; - - *destp = 0; - string_init(&dest, destp, destend-destp); - /* syslog(LOG_DEBUG, "toimap %s", src); */ - - for (;;) - { - int c = utf8_getc(&src); - if (c == '\0') - break; - - if (c >= 0x20 && c <= 0x7e) - { - if (state == 1) - { - utf7_closeb64(&dest, v, i); - state = 0; - i = 0; - } - - switch (c) - { - case '&': - string_append_sn(&dest, "&-", 2); - break; - - case '/': - /* Citadel extension: / becomes |, because / - * isn't valid as part of an IMAP name. */ - - c = '|'; - goto defaultcase; - - case '\\': - /* Citadel extension: backslashes mark folder - * seperators in the IMAP subfolder emulation - * hack. We turn them into / characters, - * *except* if it's the last character in the - * string. */ - - if (*src != '\0') - c = '/'; - /* fall through */ - - default: - defaultcase: - string_append_c(&dest, c); - } - } - else - { - if (state == 0) - { - string_append_c(&dest, '&'); - state = 1; - } - v = (v << 16) | c; - i += 16; - while (i >= 6) - { - int x = (v >> (i-6)) & 0x3f; - string_append_c(&dest, utf7_alphabet[x]); - i -= 6; - } - } - } - - if (state == 1) - utf7_closeb64(&dest, v, i); - /* syslog(LOG_DEBUG, " -> %s", destp); */ - return string_end(&dest); -} - -/* Convert from an IMAP-safe name back into a Citadel name. Returns the end of the destination. */ - -static int cfrommap(int c); -static char* fromimap(char* destp, char* destend, const char* src) -{ - struct string dest; - unsigned const char *p = (unsigned const char*) src; - int v = 0; - int i = 0; - int state = 0; - int c; - - *destp = 0; - string_init(&dest, destp, destend-destp); - /* syslog(LOG_DEBUG, "fromimap %s", src); */ - - do { - c = *p++; - switch (state) - { - case 0: - /* US-ASCII characters. */ - - if (c == '&') - state = 1; - else - string_append_c(&dest, cfrommap(c)); - break; - - case 1: - if (c == '-') - { - string_append_c(&dest, '&'); - state = 0; - } - else if (utf7_rank[c] != 0xff) - { - v = utf7_rank[c]; - i = 6; - state = 2; - } - else - { - /* invalid char */ - string_append_sn(&dest, "&-", 2); - state = 0; - } - break; - - case 2: - if (c == '-') - state = 0; - else if (utf7_rank[c] != 0xFF) - { - v = (v<<6) | utf7_rank[c]; - i += 6; - if (i >= 16) - { - int x = (v >> (i-16)) & 0xFFFF; - string_append_c(&dest, cfrommap(x)); - i -= 16; - } - } - else - { - string_append_c(&dest, cfrommap(c)); - state = 0; - } - break; - } - } while (c != '\0'); - - /* syslog(LOG_DEBUG, " -> %s", destp); */ - return string_end(&dest); -} - -/* Undoes the special character conversion. */ -static int cfrommap(int c) -{ - switch (c) - { - case '|': return '/'; - case '/': return '\\'; - } - return c; -} - - -/* Break a command down into tokens, unquoting any escaped characters. */ -void MakeStringOf(StrBuf *Buf, int skip) -{ - int i; - citimap_command *Cmd = &IMAP->Cmd; - - for (i=skip; inum_parms; ++i) { - StrBufAppendBufPlain(Buf, Cmd->Params[i].Key, Cmd->Params[i].len, 0); - if (i < (Cmd->num_parms-1)) StrBufAppendBufPlain(Buf, HKEY(" "), 0); - } -} - - -void TokenCutRight(citimap_command *Cmd, - ConstStr *CutMe, - int n) -{ - const char *CutAt; - - if (CutMe->len < n) { - CutAt = CutMe->Key; - CutMe->len = 0; - } - else { - CutAt = CutMe->Key + CutMe->len - n; - CutMe->len -= n; - } - StrBufPeek(Cmd->CmdBuf, CutAt, -1, '\0'); -} - -void TokenCutLeft(citimap_command *Cmd, - ConstStr *CutMe, - int n) -{ - if (CutMe->len < n) { - CutMe->Key += CutMe->len; - CutMe->len = 0; - } - else { - CutMe->Key += n; - CutMe->len -= n; - } -} - - - -int CmdAdjust(citimap_command *Cmd, - int nArgs, - int Realloc) -{ - ConstStr *Params; - if (nArgs > Cmd->avail_parms) { - Params = (ConstStr*) malloc(sizeof(ConstStr) * nArgs); - if (Realloc) { - memcpy(Params, - Cmd->Params, - sizeof(ConstStr) * Cmd->avail_parms); - - memset(Cmd->Params + - sizeof(ConstStr) * Cmd->avail_parms, - 0, - sizeof(ConstStr) * nArgs - - sizeof(ConstStr) * Cmd->avail_parms - ); - } - else { - Cmd->num_parms = 0; - memset(Params, 0, - sizeof(ConstStr) * nArgs); - } - Cmd->avail_parms = nArgs; - if (Cmd->Params != NULL) - free (Cmd->Params); - Cmd->Params = Params; - } - else { - if (!Realloc) { - memset(Cmd->Params, - 0, - sizeof(ConstStr) * Cmd->avail_parms); - Cmd->num_parms = 0; - } - } - return Cmd->avail_parms; -} - -int imap_parameterize(citimap_command *Cmd) -{ - int nArgs; - const char *In, *End; - - In = ChrPtr(Cmd->CmdBuf); - End = In + StrLength(Cmd->CmdBuf); - - /* we start with 10 chars per arg, maybe we need to realloc later. */ - nArgs = StrLength(Cmd->CmdBuf) / 10 + 10; - nArgs = CmdAdjust(Cmd, nArgs, 0); - while (In < End) - { - /* Skip whitespace. */ - while (isspace(*In)) - In++; - if (*In == '\0') - break; - - /* Found the start of a token. */ - - Cmd->Params[Cmd->num_parms].Key = In; - - /* Read in the token. */ - - for (;;) - { - if (isspace(*In)) - break; - - if (*In == '\"') - { - /* Found a quoted section. */ - - Cmd->Params[Cmd->num_parms].Key++; - //In++; - for (;;) - { - In++; - if (*In == '\"') { - StrBufPeek(Cmd->CmdBuf, In, -1, '\0'); - break; - } - else if (*In == '\\') - In++; - - if (*In == '\0') { - Cmd->Params[Cmd->num_parms].len = - In - Cmd->Params[Cmd->num_parms].Key; - Cmd->num_parms++; - return Cmd->num_parms; - } - } - break; - } - else if (*In == '\\') - { - In++; - } - - if (*In == '\0') { - Cmd->Params[Cmd->num_parms].len = - In - Cmd->Params[Cmd->num_parms].Key; - Cmd->num_parms++; - return Cmd->num_parms; - } - In++; - } - StrBufPeek(Cmd->CmdBuf, In, -1, '\0'); - Cmd->Params[Cmd->num_parms].len = - In - Cmd->Params[Cmd->num_parms].Key; - if (Cmd->num_parms + 1 >= Cmd->avail_parms) { - nArgs = CmdAdjust(Cmd, nArgs * 2, 1); - } - Cmd->num_parms ++; - In++; - } - return Cmd->num_parms; -} - - -/* Convert a struct ctdlroom to an IMAP-compatible mailbox name. */ -long imap_mailboxname(char *buf, int bufsize, struct ctdlroom *qrbuf) -{ - char* bufend = buf+bufsize; - struct floor *fl; - char* p = buf; - const char *pend; - - /* For mailboxes, just do it straight. - * Do the Cyrus-compatible thing: all private folders are - * subfolders of INBOX. */ - - if (qrbuf->QRflags & QR_MAILBOX) - { - if (strcasecmp(qrbuf->QRname+11, MAILROOM) == 0) - { - pend = toimap(p, bufend, "INBOX"); - return pend - buf; - } - else - { - p = toimap(p, bufend, "INBOX"); - if (p < bufend) - *p++ = '/'; - pend = toimap(p, bufend, qrbuf->QRname+11); - return pend - buf; - } - } - else - { - /* Otherwise, prefix the floor name as a "public folders" moniker. */ - - fl = CtdlGetCachedFloor(qrbuf->QRfloor); - p = toimap(p, bufend, fl->f_name); - if (p < bufend) - *p++ = '/'; - pend = toimap(p, bufend, qrbuf->QRname); - return pend - buf; - } -} - -/* - * Convert an inputted folder name to our best guess as to what an equivalent - * room name should be. - * - * If an error occurs, it returns -1. Otherwise... - * - * The lower eight bits of the return value are the floor number on which the - * room most likely resides. The upper eight bits may contain flags, - * including IR_MAILBOX if we're dealing with a personal room. - * - */ -int imap_roomname(char *rbuf, int bufsize, const char *foldername) -{ - int levels; - char floorname[ROOMNAMELEN*2]; - char roomname[ROOMNAMELEN]; - int i; - struct floor *fl; - int ret = (-1); - - if (foldername == NULL) - return(-1); - - /* Unmunge the entire string into the output buffer. */ - - fromimap(rbuf, rbuf+bufsize, foldername); - - /* Is this an IMAP inbox? */ - - if (strncasecmp(rbuf, "INBOX", 5) == 0) - { - if (rbuf[5] == 0) - { - /* It's the system inbox. */ - - safestrncpy(rbuf, MAILROOM, bufsize); - ret = (0 | IR_MAILBOX); - goto exit; - } - else if (rbuf[5] == FDELIM) - { - /* It's another personal mail folder. */ - - safestrncpy(rbuf, rbuf+6, bufsize); - ret = (0 | IR_MAILBOX); - goto exit; - } - - /* If we get here, the folder just happens to start with INBOX - * --- fall through. */ - } - - /* Is this a multi-level room name? */ - - levels = num_tokens(rbuf, FDELIM); - if (levels > 1) - { - long len; - /* Extract the main room name. */ - - len = extract_token(floorname, rbuf, 0, FDELIM, sizeof floorname); - if (len < 0) len = 0; - safestrncpy(roomname, &rbuf[len + 1], sizeof(roomname)); - - /* Try and find it on any floor. */ - - for (i = 0; i < MAXFLOORS; ++i) - { - fl = CtdlGetCachedFloor(i); - if (fl->f_flags & F_INUSE) - { - if (strcasecmp(floorname, fl->f_name) == 0) - { - /* Got it! */ - - safestrncpy(rbuf, roomname, bufsize); - ret = i; - goto exit; - } - } - } - } - - /* Meh. It's either not a multi-level room name, or else we - * couldn't find it. - */ - ret = (0 | IR_MAILBOX); - -exit: - syslog(LOG_DEBUG, "(That translates to \"%s\")", rbuf); - return(ret); -} - - -/* - * Determine whether the supplied string is a valid message set. - * If the string contains only numbers, colons, commas, and asterisks, - * return 1 for a valid message set. If any other character is found, - * return 0. - */ -int imap_is_message_set(const char *buf) -{ - int i; - - if (buf == NULL) - return (0); /* stupidity checks */ - if (IsEmptyStr(buf)) - return (0); - - if (!strcasecmp(buf, "ALL")) - return (1); /* macro? why? */ - - for (i = 0; buf[i]; ++i) { /* now start the scan */ - if ( - (!isdigit(buf[i])) - && (buf[i] != ':') - && (buf[i] != ',') - && (buf[i] != '*') - ) - return (0); - } - - return (1); /* looks like we're good */ -} - - -/* - * imap_match.c, based on wildmat.c from INN - * hacked for Citadel/IMAP by Daniel Malament - */ - -/* note: not all return statements use these; don't change them */ -#define WILDMAT_TRUE 1 -#define WILDMAT_FALSE 0 -#define WILDMAT_ABORT -1 -#define WILDMAT_DELIM '/' - -/* - * Match text and p, return TRUE, FALSE, or ABORT. - */ -static int do_imap_match(const char *supplied_text, const char *supplied_p) -{ - int matched, i; - char lcase_text[SIZ], lcase_p[SIZ]; - char *text; - char *p; - - /* Copy both strings and lowercase them, in order to - * make this entire operation case-insensitive. - */ - for (i=0; - ((supplied_text[i] != '\0') && - (i < sizeof(lcase_text))); - ++i) - lcase_text[i] = tolower(supplied_text[i]); - lcase_text[i] = '\0'; - - for (i=0; - ((supplied_p[i] != '\0') && - (i < sizeof(lcase_p))); - ++i) - lcase_p[i] = tolower(supplied_p[i]); - lcase_p[i] = '\0'; - - /* Start matching */ - for (p = lcase_p, text = lcase_text; - !IsEmptyStr(p) && !IsEmptyStr(text); - text++, p++) { - if ((*text == '\0') && (*p != '*') && (*p != '%')) { - return WILDMAT_ABORT; - } - switch (*p) { - default: - if (*text != *p) { - return WILDMAT_FALSE; - } - continue; - case '*': -star: - while (++p, ((*p == '*') || (*p == '%'))) { - /* Consecutive stars or %'s act - * just like one star. - */ - continue; - } - if (*p == '\0') { - /* Trailing star matches everything. */ - return WILDMAT_TRUE; - } - while (*text) { - if ((matched = do_imap_match(text++, p)) - != WILDMAT_FALSE) { - return matched; - } - } - return WILDMAT_ABORT; - case '%': - while (++p, (!IsEmptyStr(p) && ((*p == '*') || (*p == '%')))) - { - /* Consecutive %'s act just like one, but even - * a single star makes the sequence act like - * one star, instead. - */ - if (*p == '*') { - goto star; - } - continue; - } - if (*p == '\0') { - /* - * Trailing % matches everything - * without a delimiter. - */ - while (!IsEmptyStr(text)) { - if (*text == WILDMAT_DELIM) { - return WILDMAT_FALSE; - } - text++; - } - return WILDMAT_TRUE; - } - while (!IsEmptyStr(text) && - /* make sure text - 1 isn't before lcase_p */ - ((text == lcase_text) || (*(text - 1) != WILDMAT_DELIM))) - { - if ((matched = do_imap_match(text++, p)) - != WILDMAT_FALSE) { - return matched; - } - } - return WILDMAT_ABORT; - } - } - - if ((*text == '\0') && (*p == '\0')) return WILDMAT_TRUE; - else return WILDMAT_FALSE; -} - - -/* - * Support function for mailbox pattern name matching in LIST and LSUB - * Returns nonzero if the supplied mailbox name matches the supplied pattern. - */ -int imap_mailbox_matches_pattern(const char *pattern, char *mailboxname) -{ - /* handle just-star case quickly */ - if ((pattern[0] == '*') && (pattern[1] == '\0')) { - return WILDMAT_TRUE; - } - return (do_imap_match(mailboxname, pattern) == WILDMAT_TRUE); -} - - - -/* - * Compare an IMAP date string (date only, no time) to the date found in - * a Unix timestamp. - */ -int imap_datecmp(const char *datestr, time_t msgtime) { - char daystr[256]; - char monthstr[256]; - char yearstr[256]; - int i; - int day, month, year; - int msgday, msgmonth, msgyear; - struct tm msgtm; - - char *imap_datecmp_ascmonths[12] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - - if (datestr == NULL) return(0); - - /* Expecting a date in the form dd-Mmm-yyyy */ - extract_token(daystr, datestr, 0, '-', sizeof daystr); - extract_token(monthstr, datestr, 1, '-', sizeof monthstr); - extract_token(yearstr, datestr, 2, '-', sizeof yearstr); - - day = atoi(daystr); - year = atoi(yearstr); - month = 0; - for (i=0; i<12; ++i) { - if (!strcasecmp(monthstr, imap_datecmp_ascmonths[i])) { - month = i; - } - } - - /* Extract day/month/year from message timestamp */ - localtime_r(&msgtime, &msgtm); - msgday = msgtm.tm_mday; - msgmonth = msgtm.tm_mon; - msgyear = msgtm.tm_year + 1900; - - /* Now start comparing */ - - if (year < msgyear) return(+1); - if (year > msgyear) return(-1); - - if (month < msgmonth) return(+1); - if (month > msgmonth) return(-1); - - if (day < msgday) return(+1); - if (day > msgday) return(-1); - - return(0); -} - - -void IAPrintf(const char *Format, ...) -{ - va_list arg_ptr; - - va_start(arg_ptr, Format); - StrBufVAppendPrintf(IMAP->Reply, Format, arg_ptr); - va_end(arg_ptr); -} - - -void iaputs(const char *Str, long Len) -{ - StrBufAppendBufPlain(IMAP->Reply, Str, Len, 0); -} - - -void ireply(const char *Msg, long len) -{ - citimap *Imap = IMAP; - - StrBufAppendBufPlain(Imap->Reply, - CKEY(Imap->Cmd.Params[0]), 0); - StrBufAppendBufPlain(Imap->Reply, - HKEY(" "), 0); - StrBufAppendBufPlain(Imap->Reply, - Msg, len, 0); - - StrBufAppendBufPlain(Imap->Reply, - HKEY("\r\n"), 0); - -} - - -void IReplyPrintf(const char *Format, ...) -{ - citimap *Imap = IMAP; - va_list arg_ptr; - - - StrBufAppendBufPlain(Imap->Reply, - CKEY(Imap->Cmd.Params[0]), 0); - - StrBufAppendBufPlain(Imap->Reply, - HKEY(" "), 0); - - va_start(arg_ptr, Format); - StrBufVAppendPrintf(IMAP->Reply, Format, arg_ptr); - va_end(arg_ptr); - - StrBufAppendBufPlain(Imap->Reply, - HKEY("\r\n"), 0); - -} - - -/* Output a string to the IMAP client, either as a literal or quoted. - * (We do a literal if it has any double-quotes or backslashes.) */ -void IPutStr(const char *Msg, long Len) -{ - int i; - int is_literal = 0; - citimap *Imap = IMAP; - - - if ((Msg == NULL) || (Len == 0)) - { /* yeah, we handle this */ - StrBufAppendBufPlain(Imap->Reply, HKEY("NIL"), 0); - return; - } - - for (i = 0; i < Len; ++i) { - if ((Msg[i] == '\"') || (Msg[i] == '\\')) - is_literal = 1; - } - - if (is_literal) { - StrBufAppendPrintf(Imap->Reply, "{%ld}\r\n", Len); - StrBufAppendBufPlain(Imap->Reply, Msg, Len, 0); - } else { - StrBufAppendBufPlain(Imap->Reply, - HKEY("\""), 0); - StrBufAppendBufPlain(Imap->Reply, - Msg, Len, 0); - StrBufAppendBufPlain(Imap->Reply, - HKEY("\""), 0); - } -} - -void IUnbuffer (void) -{ - citimap *Imap = IMAP; - - cputbuf(Imap->Reply); - FlushStrBuf(Imap->Reply); -}