Back to index

courier  0.68.2
encode.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2003-2004 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 /*
00007 */
00008 #include      "encode.h"
00009 #include      <string.h>
00010 #include      <stdlib.h>
00011 
00012 static int quoted_printable(struct libmail_encode_info *,
00013                          const char *, size_t);
00014 static int base64(struct libmail_encode_info *,
00015                 const char *, size_t);
00016 static int eflush(struct libmail_encode_info *,
00017                const char *, size_t);
00018 
00019 void libmail_encode_start(struct libmail_encode_info *info,
00020                        const char *transfer_encoding,
00021                        int (*callback_func)(const char *, size_t, void *),
00022                        void *callback_arg)
00023 {
00024        info->output_buf_cnt=0;
00025        info->input_buf_cnt=0;
00026 
00027        switch (*transfer_encoding) {
00028        case 'q':
00029        case 'Q':
00030               info->encoding_func=quoted_printable;
00031               info->input_buffer[0]=0; /* Recycle for qp encoding */
00032               break;
00033        case 'b':
00034        case 'B':
00035               info->encoding_func=base64;
00036               break;
00037        default:
00038               info->encoding_func=eflush;
00039               break;
00040        }
00041        info->callback_func=callback_func;
00042        info->callback_arg=callback_arg;
00043 }
00044 
00045 int libmail_encode(struct libmail_encode_info *info,
00046                  const char *ptr,
00047                  size_t cnt)
00048 {
00049        return ((*info->encoding_func)(info, ptr, cnt));
00050 }
00051 
00052 int libmail_encode_end(struct libmail_encode_info *info)
00053 {
00054        int rc=(*info->encoding_func)(info, NULL, 0);
00055 
00056        if (rc == 0 && info->output_buf_cnt > 0)
00057        {
00058               rc= (*info->callback_func)(info->output_buffer,
00059                                       info->output_buf_cnt,
00060                                       info->callback_arg);
00061               info->output_buf_cnt=0;
00062        }
00063 
00064        return rc;
00065 }
00066 
00067 static int eflush(struct libmail_encode_info *info, const char *ptr, size_t n)
00068 {
00069        while (n > 0)
00070        {
00071               size_t i;
00072 
00073               if (info->output_buf_cnt == sizeof(info->output_buffer))
00074               {
00075                      int rc= (*info->callback_func)(info->output_buffer,
00076                                                  info->output_buf_cnt,
00077                                                  info->callback_arg);
00078 
00079                      info->output_buf_cnt=0;
00080                      if (rc)
00081                             return rc;
00082               }
00083 
00084               i=n;
00085 
00086               if (i > sizeof(info->output_buffer) - info->output_buf_cnt)
00087                      i=sizeof(info->output_buffer) - info->output_buf_cnt;
00088 
00089               memcpy(info->output_buffer + info->output_buf_cnt, ptr, i);
00090               info->output_buf_cnt += i;
00091               ptr += i;
00092               n -= i;
00093        }
00094        return 0;
00095 }
00096 
00097 static int base64_flush(struct libmail_encode_info *);
00098 
00099 static int base64(struct libmail_encode_info *info,
00100                 const char *buf, size_t n)
00101 {
00102        if (!buf)
00103        {
00104               int rc=0;
00105 
00106               if (info->input_buf_cnt > 0)
00107                      rc=base64_flush(info);
00108 
00109               return rc;
00110        }
00111 
00112        while (n)
00113        {
00114               size_t i;
00115 
00116               if (info->input_buf_cnt == sizeof(info->input_buffer))
00117               {
00118                      int rc=base64_flush(info);
00119 
00120                      if (rc != 0)
00121                             return rc;
00122               }
00123 
00124               i=n;
00125               if (i > sizeof(info->input_buffer) - info->input_buf_cnt)
00126                      i=sizeof(info->input_buffer) - info->input_buf_cnt;
00127 
00128               memcpy(info->input_buffer + info->input_buf_cnt,
00129                      buf, i);
00130               info->input_buf_cnt += i;
00131               buf += i;
00132               n -= i;
00133        }
00134        return 0;
00135 }
00136 
00137 static const char base64tab[]=
00138 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00139 
00140 static int base64_flush(struct libmail_encode_info *info)
00141 {
00142        int    a=0,b=0,c=0;
00143        int    i, j;
00144        int    d, e, f, g;
00145        char   output_buf[ sizeof(info->input_buffer) / 3 * 4+1];
00146 
00147        for (j=i=0; i<info->input_buf_cnt; i += 3)
00148        {
00149               a=(unsigned char)info->input_buffer[i];
00150               b= i+1 < info->input_buf_cnt ?
00151                      (unsigned char)info->input_buffer[i+1]:0;
00152               c= i+2 < info->input_buf_cnt ?
00153                      (unsigned char)info->input_buffer[i+2]:0;
00154 
00155               d=base64tab[ a >> 2 ];
00156               e=base64tab[ ((a & 3 ) << 4) | (b >> 4)];
00157               f=base64tab[ ((b & 15) << 2) | (c >> 6)];
00158               g=base64tab[ c & 63 ];
00159               if (i + 1 >= info->input_buf_cnt)  f='=';
00160               if (i + 2 >= info->input_buf_cnt) g='=';
00161               output_buf[j++]=d;
00162               output_buf[j++]=e;
00163               output_buf[j++]=f;
00164               output_buf[j++]=g;
00165        }
00166 
00167        info->input_buf_cnt=0;
00168 
00169        output_buf[j++]='\n';
00170        return eflush(info, output_buf, j);
00171 }
00172 
00173 static const char xdigit[]="0123456789ABCDEF";
00174 
00175 static int quoted_printable(struct libmail_encode_info *info,
00176                          const char *p, size_t n)
00177 {
00178        char local_buf[256];
00179        int local_buf_cnt=0;
00180 
00181 #define QPUT(c) do { if (local_buf_cnt == sizeof(local_buf)) \
00182                      { int rc=eflush(info, local_buf, local_buf_cnt); \
00183                      local_buf_cnt=0; if (rc) return (rc); } \
00184                      local_buf[local_buf_cnt]=(c); ++local_buf_cnt; } while(0)
00185 
00186        if (!p)
00187               return (0);
00188 
00189        while (n)
00190        {
00191 
00192 
00193               /*
00194               ** Repurpose input_buffer[0] as a flag whether the previous
00195               ** character was a space.
00196               **
00197               ** A space before a newline gets escaped.
00198               */
00199 
00200               if (info->input_buffer[0])
00201               {
00202                      if (*p == '\n')
00203                      {
00204                             QPUT('=');
00205                             QPUT('2');
00206                             QPUT('0');
00207                      }
00208                      else
00209                      {
00210                             QPUT(' ');
00211                      }
00212                      ++info->input_buf_cnt;
00213               }
00214 
00215               info->input_buffer[0]=0;
00216 
00217               if (*p == ' ')
00218               {
00219                      info->input_buffer[0]=1;
00220                      p++;
00221                      --n;
00222                      continue;
00223               }
00224 
00225               if (info->input_buf_cnt > 72 && *p != '\n')
00226               {
00227                      QPUT('=');
00228                      QPUT('\n');
00229                      info->input_buf_cnt=0;
00230               }
00231 
00232               if ( *p == '\n')
00233                      info->input_buf_cnt=0;
00234               else if (*p < ' ' || *p == '=' || *p >= 0x7F)
00235               {
00236                      QPUT('=');
00237                      QPUT(xdigit[ (*p >> 4) & 15]);
00238                      QPUT(xdigit[ *p & 15 ]);
00239                      info->input_buf_cnt += 3;
00240                      p++;
00241                      --n;
00242                      continue;
00243               }
00244               else info->input_buf_cnt++;
00245 
00246               QPUT( *p);
00247               p++;
00248               --n;
00249        }
00250 
00251        if (local_buf_cnt > 0)
00252               return eflush(info, local_buf, local_buf_cnt);
00253 
00254        return 0;
00255 }