"Fossies" - the Fresh Open Source Software Archive

Member "imapfilter-2.8.2/src/namespace.c" (26 Dec 2023, 9397 Bytes) of package /linux/privat/imapfilter-2.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "namespace.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8.1_vs_2.8.2.

    1 #include <stdio.h>
    2 #include <string.h>
    3 #include <errno.h>
    4 
    5 #include "imapfilter.h"
    6 #include "session.h"
    7 #include "buffer.h"
    8 
    9 
   10 buffer nbuf;            /* Namespace buffer. */
   11 buffer cbuf;            /* Conversion buffer. */
   12 
   13 
   14 static const char base64[] =
   15     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
   16 
   17 
   18 const char *apply_conversion(const char *mbox);
   19 const char *reverse_conversion(const char *mbox);
   20 
   21 
   22 /*
   23  * Convert the names of personal mailboxes, using the namespace specified
   24  * by the mail server, from internal to mail server format.
   25  */
   26 const char *
   27 apply_namespace(const char *mbox, session *ssn)
   28 {
   29     int n;
   30     char *c;
   31     const char *m;
   32 
   33     if (!strcasecmp(mbox, "INBOX"))
   34         return mbox;
   35 
   36     m = mbox;
   37     if (!ssn->utf8)
   38         m = apply_conversion(mbox);
   39 
   40     if ((ssn->ns.prefix == NULL && ssn->ns.delim == '\0') ||
   41         (ssn->ns.prefix == NULL && ssn->ns.delim == '/'))
   42         return m;
   43 
   44     buffer_reset(&nbuf);
   45 
   46     n = snprintf(nbuf.data, nbuf.size + 1, "%s%s",
   47         (ssn->ns.prefix ? ssn->ns.prefix : ""), m);
   48     if (n > (int)nbuf.size) {
   49         buffer_check(&nbuf, n);
   50         snprintf(nbuf.data, nbuf.size + 0, "%s%s",
   51             (ssn->ns.prefix ? ssn->ns.prefix : ""), m);
   52     }
   53     for (c = nbuf.data; (c = strchr(c, '/')) != NULL; *(c++) = ssn->ns.delim);
   54 
   55     debug("namespace: '%s' -> '%s'\n", m, nbuf.data);
   56 
   57     return nbuf.data;
   58 }
   59 
   60 
   61 /*
   62  * Convert the names of personal mailboxes, using the namespace specified by
   63  * the mail server, from mail server format to internal format.
   64  */
   65 const char *
   66 reverse_namespace(const char *mbox, session *ssn)
   67 {
   68     int n, o;
   69     char *c;
   70 
   71     if (!strcasecmp(mbox, "INBOX"))
   72         return mbox;
   73 
   74     if ((ssn->ns.prefix == NULL && ssn->ns.delim == '\0') ||
   75         (ssn->ns.prefix == NULL && ssn->ns.delim == '/')) {
   76         if (!ssn->utf8)
   77             return reverse_conversion(mbox);
   78         return mbox;
   79     }
   80 
   81     buffer_reset(&nbuf);
   82 
   83     o = strlen(ssn->ns.prefix ? ssn->ns.prefix : "");
   84     if (strncasecmp(mbox, (ssn->ns.prefix ? ssn->ns.prefix : ""), o))
   85         o = 0;
   86 
   87     n = snprintf(nbuf.data, nbuf.size + 1, "%s", mbox + o);
   88     if (n > (int)nbuf.size) {
   89         buffer_check(&nbuf, n);
   90         snprintf(nbuf.data, nbuf.size + 1, "%s", mbox + o);
   91     }
   92     for (c = nbuf.data; (c = strchr(c, ssn->ns.delim)) != NULL; *(c++) = '/');
   93 
   94     debug("namespace: '%s' <- '%s'\n", mbox, nbuf.data);
   95 
   96     return reverse_conversion(nbuf.data);
   97 }
   98 
   99 
  100 /*
  101  * Convert a mailbox name to the modified UTF-7 encoding, according to RFC 3501
  102  * Section 5.1.3.
  103  */
  104 const char *
  105 apply_conversion(const char *mbox)
  106 {
  107     unsigned char *c, *out;
  108     unsigned char ucp[4], ucplast, ucptemp;
  109     int padding, shift;
  110 
  111     buffer_check(&nbuf, strlen(mbox));
  112     buffer_reset(&nbuf);
  113     xstrncpy(nbuf.data, mbox, nbuf.size);
  114     nbuf.len = strlen(nbuf.data);
  115     buffer_check(&cbuf, nbuf.len * 4);
  116     buffer_reset(&cbuf);
  117 
  118     c = (unsigned char *)nbuf.data;
  119     out = (unsigned char *)cbuf.data;
  120 
  121     memset((void *)ucp, 0, sizeof(ucp));
  122     ucplast = ucptemp = 0;
  123     padding = shift = 0;
  124 
  125     while (*c != '\0' || shift > 0) {
  126         if (shift > 0 && *c <= 0x7F) {
  127             /* Last character so do Base64 padding. */
  128             if (padding == 2) {
  129                 *out++ = base64[ucplast << 2 & 0x3C];
  130             } else if (padding == 4) {
  131                 *out++ = base64[ucplast << 4 & 0x30];
  132             }
  133             *out++ = '-';
  134             padding = 0;
  135             shift = 0;
  136             continue;
  137         }
  138 
  139         /* Escape shift character for modified UTF-7. */
  140         if (*c == '&') {
  141             *out++ = '&';
  142             *out++ = '-';
  143             c++;
  144             continue;
  145 
  146         /* Copy all ASCII printable characters. */
  147         } else if ((*c >= 0x20 && *c <= 0x7e)) {
  148             *out++ = *c;
  149             c++;
  150             continue;
  151         }
  152 
  153         /* Non-ASCII UTF-8 characters follow. */
  154         if (shift == 0)
  155             *out++ = '&';
  156         /* Convert UTF-8 characters to Unicode code point. */
  157         if ((*c & 0xE0) == 0xC0) {
  158             shift = 2;
  159             ucp[0] = 0x07 & *c >> 2;
  160             ucp[1] = (*c << 6 & 0xC0) | (*(c + 1) & 0x3F);
  161             c += 2;
  162         } else if ((*c & 0xF0) == 0xE0) {
  163             shift = 3;
  164             ucp[0] = (*c << 4 & 0xF0) | (*(c + 1) >> 2 & 0x0F);
  165             ucp[1] = (*(c + 1) << 6 & 0xC0) | (*(c + 2) & 0x3F);
  166             c += 3;
  167         } else if ((*c & 0xF8) == 0xF0) {
  168             shift = 4;
  169             ucptemp = ((*c << 2 & 0x1C) | (*(c + 1) >> 4 & 0x03)) -
  170                 0x01;
  171             ucp[0] = (ucptemp >> 2 & 0x03) | 0xD8;
  172             ucp[1] = (ucptemp << 6 & 0xC0) |
  173                 (*(c + 1) << 2 & 0x3C) | (*(c + 2) >> 4 & 0x03);
  174             ucp[2] = (*(c + 2) >> 2 & 0x03) | 0xDC;
  175             ucp[3] = (*(c + 2) << 6 & 0xC0) | (*(c + 3) & 0x3F);
  176             c += 4;
  177         }
  178 
  179         /* Convert Unicode characters to UTF-7. */
  180         if (padding == 0) {
  181             *out++ = base64[ucp[0] >> 2 & 0x3F];
  182             *out++ = base64[(ucp[0] << 4 & 0x30) |
  183                 (ucp[1] >> 4 & 0x0F)];
  184             if (shift == 4) {
  185                 ucplast = ucp[3];
  186                 *out++ = base64[(ucp[1] << 2 & 0x3C) |
  187                     (ucp[2] >> 6 & 0x03)];
  188                 *out++ = base64[ucp[2] & 0x3F];
  189                 *out++ = base64[ucp[3] >> 2 & 0x3F];
  190                 padding = 4;
  191             } else {
  192                 ucplast = ucp[1];
  193                 padding = 2;
  194             }
  195         } else if (padding == 2) {
  196             *out++ = base64[(ucplast << 2 & 0x3C) |
  197                 (ucp[0] >> 6 & 0x03)];
  198             *out++ = base64[ucp[0] & 0x3F];
  199             *out++ = base64[ucp[1] >> 2 & 0x3F];
  200             if (shift == 4) {
  201                 *out++ = base64[(ucp[1] << 4 & 0x30) |
  202                     (ucp[2] >> 4 & 0x0F)];
  203                 *out++ = base64[(ucp[2] << 2 & 0x3C) |
  204                     (ucp[3] >> 6 & 0x03)];
  205                 *out++ = base64[ucp[3] & 0x3F];
  206                 padding = 0;
  207             } else {
  208                 ucplast = ucp[1];
  209                 padding = 4;
  210             }
  211         } else if (padding == 4) {
  212             *out++ = base64[(ucplast << 4 & 0x30) |
  213                 (ucp[0] >> 4 & 0x0F)];
  214             *out++ = base64[(ucp[0] << 2 & 0x3C) |
  215                 (ucp[1] >> 6 & 0x03)];
  216             if (shift == 4) {
  217                 ucplast = ucp[3];
  218                 *out++ = base64[ucp[1] & 0x3F];
  219                 *out++ = base64[ucp[2] >> 2 & 0x3F];
  220                 *out++ = base64[(ucp[2] << 4 & 0x30) |
  221                     (ucp[3] >> 4 & 0x0F)];
  222                 padding = 2;
  223             } else {
  224                 *out++ = base64[ucp[1] & 0x3F];
  225                 padding = 0;
  226             }
  227         }
  228     }
  229     *out = '\0';
  230 
  231     debug("conversion: '%s' -> '%s'\n", nbuf.data, cbuf.data);
  232 
  233     return cbuf.data;
  234 }
  235 
  236 /*
  237  * Convert a mailbox name from the modified UTF-7 encoding, according to RFC
  238  * 3501 Section 5.1.3.
  239  */
  240 const char *
  241 reverse_conversion(const char *mbox)
  242 {
  243     unsigned char *c, *out;
  244     unsigned char ucp[4], ucptemp;
  245     unsigned char b64[6], b64last;
  246     int padding;
  247     
  248     buffer_check(&cbuf, strlen(mbox));
  249     buffer_reset(&cbuf);
  250     xstrncpy(cbuf.data, mbox, cbuf.size);
  251     cbuf.len = strlen(cbuf.data);
  252     buffer_check(&nbuf, cbuf.len);
  253     buffer_reset(&nbuf);
  254 
  255     c = (unsigned char *)cbuf.data;
  256     out = (unsigned char *)nbuf.data;
  257 
  258     memset((void *)ucp, 0, sizeof(ucp));
  259     memset((void *)b64, 0, sizeof(b64));
  260     ucptemp = b64last = 0;
  261     padding = 0;
  262 
  263     while (*c != '\0') {
  264         /* Copy all ASCII printable characters. */
  265         if (*c >= 0x20 && *c <= 0x7e) {
  266             if (*c != '&') {
  267                 *out++ = *c++;
  268                 continue;
  269             } else {
  270                 c++;
  271             }
  272         }
  273 
  274         /* Write shift character for modified UTF-7. */
  275         if (*c == '-') {
  276             *out++ = '&';
  277             c++;
  278             continue;
  279         }
  280 
  281         /* UTF-7 characters follow. */
  282         padding = 0;
  283         do {
  284             /* Read Base64 characters. */
  285             b64[0] = strchr(base64, *c) - base64;
  286             b64[1] = strchr(base64, *(c + 1)) - base64;
  287             if (padding == 0 || padding == 2) {
  288                 b64[2] = strchr(base64, *(c + 2)) - base64;
  289                 c += 3;
  290             } else {
  291                 c += 2;
  292             }
  293             /* Convert from Base64 to Unicode code point. */
  294             if (padding == 0) {
  295                 ucp[0] = (b64[0] << 2 & 0xFC) |
  296                     (b64[1] >> 4 & 0x03);
  297                 ucp[1] = (b64[1] << 4 & 0xF0) |
  298                     (b64[2] >> 2 & 0x0F);
  299                 b64last = b64[2];
  300                 padding = 2;
  301             } else if (padding == 2) {
  302                 ucp[0] = (b64last << 6 & 0xC0) |
  303                     (b64[0] & 0x3F);
  304                 ucp[1] = (b64[1] << 2 & 0xFC) |
  305                     (b64[2] >> 4 & 0x03);
  306                 b64last = b64[2];
  307                 padding = 4;
  308             } else if (padding == 4) {
  309                 ucp[0] = (b64last << 4 & 0xF0) |
  310                     (b64[0] >> 2 & 0x0F);
  311                 ucp[1] = (b64[0] << 6 & 0xC0) |
  312                     (b64[1] & 0x3F);
  313                 padding = 0;
  314             }
  315 
  316             /* Convert from Unicode to UTF-8. */
  317             if (ucp[0] <= 0x07) {
  318                 *out++ = 0xC0 | (ucp[0] << 2 & 0x1C) |
  319                     (ucp[1] >> 6 & 0x03);
  320                 *out++ = 0x80 | (ucp[1] & 0x3F);
  321             } else if ((ucp[0] >= 0x08 && ucp[0] <= 0xD7) ||
  322                 ucp[0] >= 0xE0) {
  323                 *out++ = 0xE0 | (ucp[0] >> 4 & 0x0F);
  324                 *out++ = 0x80 | (ucp[0] << 2 & 0x1C) |
  325                     (ucp[1] >> 6 & 0x03);
  326                 *out++ = 0x80 | (ucp[1] & 0x3F);
  327             } else if (ucp[0] >= 0xD8 && ucp[0] <= 0xDF) {
  328                 b64[3] = strchr(base64, *c) - base64;
  329                 b64[4] = strchr(base64, *(c + 1)) - base64;
  330                 if (padding == 0 || padding == 2) {
  331                     b64[5] = strchr(base64, *(c + 2)) -
  332                         base64;
  333                     c += 3;
  334                 } else {
  335                     c += 2;
  336                 }
  337 
  338                 if (padding == 0) {
  339                     ucp[2] = (b64[3] << 2 & 0xFC) |
  340                         (b64[4] >> 4 & 0x03);
  341                     ucp[3] = (b64[4] << 4 & 0xF0) |
  342                         (b64[5] >> 2 & 0x0F);
  343                     b64last = b64[5];
  344                     padding = 2;
  345                 } else if (padding == 2) {
  346                     ucp[2] = (b64last << 6 & 0xC0) |
  347                         (b64[3] & 0x3F);
  348                     ucp[3] = (b64[4] << 2 & 0xFC) |
  349                         (b64[5] >> 4 & 0x03);
  350                     b64last = b64[5];
  351                     padding = 4;
  352                 } else if (padding == 4) {
  353                     ucp[2] = (b64last << 4 & 0xF0) |
  354                         (b64[3] >> 2 & 0x0F);
  355                     ucp[3] = (b64[3] << 6 & 0xC0) |
  356                         (b64[4] & 0x3F);
  357                     padding = 0;
  358                 }
  359 
  360                 ucp[0] &= 0xFF - 0xDF;
  361                 ucptemp = ((ucp[0] << 2 & 0x0C) |
  362                     (ucp[1] >> 6 & 0x03)) + 0x1;
  363                 ucp[2] &= 0xFF - 0xDC;
  364 
  365                 *out++ = 0xF0 | (ucptemp >> 2 & 0x03);
  366                 *out++ = 0x80 | (ucptemp << 4 & 0x30) |
  367                     (ucp[1] >> 2 & 0x0F);
  368                 *out++ = 0x80 | (ucp[1] << 4 & 0x30) |
  369                     (ucp[2] << 2 & 0x0C) |
  370                     (ucp[3] >> 6 & 0x03);
  371                 *out++ = 0x80 | (ucp[3] & 0x3F);
  372             }
  373             if (*c == '-') {
  374                 c++;
  375                 break;
  376             }
  377         } while (*c != '-');
  378     }
  379     *out = '\0';
  380 
  381     debug("conversion: '%s' <- '%s'\n", nbuf.data, cbuf.data);
  382 
  383     return nbuf.data;
  384 }