nanohttp-mime.c

Go to the documentation of this file.
00001 /******************************************************************
00002 *  _  _   _   _  _   __
00003 * | \/ | | | | \/ | | _/
00004 * |_''_| |_| |_''_| |_'/  PARSER
00005 *
00006 *  $Id: nanohttp-mime.c,v 1.19 2006/12/16 15:55:24 m0gg Exp $
00007 *
00008 * CSOAP Project:  A http client/server library in C
00009 * Copyright (C) 2003-2004  Ferhat Ayaz
00010 *
00011 * This library is free software; you can redistribute it and/or
00012 * modify it under the terms of the GNU Library General Public
00013 * License as published by the Free Software Foundation; either
00014 * version 2 of the License, or (at your option) any later version.
00015 *
00016 * This library is distributed in the hope that it will be useful,
00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 * Library General Public License for more details.
00020 *
00021 * You should have received a copy of the GNU Library General Public
00022 * License along with this library; if not, write to the
00023 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00024 * Boston, MA  02111-1307, USA.
00025 *
00026 * Email: ferhatayaz@yahoo.com
00027 ******************************************************************/
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #ifdef HAVE_STDIO_H
00033 #include <stdio.h>
00034 #endif
00035 
00036 #ifdef HAVE_STDLIB_H
00037 #include <stdlib.h>
00038 #endif
00039 
00040 #ifdef HAVE_STRING_H
00041 #include <string.h>
00042 #endif
00043 
00044 #ifdef HAVE_ERRNO_H
00045 #include <errno.h>
00046 #endif
00047 
00048 #ifdef HAVE_NETINET_IN_H
00049 #include <netinet/in.h>
00050 #endif
00051 
00052 /*----------------------------------------------------------------
00053 Buffered Reader. A helper object to read bytes from a source
00054 ----------------------------------------------------------------*/
00055 
00056 #include "nanohttp-logging.h"
00057 #include "nanohttp-error.h"
00058 #include "nanohttp-common.h"
00059 #include "nanohttp-socket.h"
00060 #include "nanohttp-stream.h"
00061 #include "nanohttp-mime.h"
00062 
00063 
00064 /* ------------------------------------------------------------------
00065   MIME Parser
00066  ------------------------------------------------------------------*/
00067 typedef void (*MIME_part_begin) (void *);
00068 typedef void (*MIME_part_end) (void *);
00069 typedef void (*MIME_parse_begin) (void *);
00070 typedef void (*MIME_parse_end) (void *);
00071 typedef void (*MIME_ERROR_bytes) (void *, const unsigned char *, int);
00072 
00073 typedef enum _MIME_parser_status
00074 {
00075   MIME_PARSER_INCOMPLETE_MESSAGE,
00076   MIME_PARSER_READ_ERROR,
00077   MIME_PARSER_OK
00078 } MIME_parser_status;
00079 
00080 typedef enum _MIME_read_status
00081 {
00082   MIME_READ_OK,
00083   MIME_READ_EOF,
00084   MIME_READ_ERROR
00085 } MIME_read_status;
00086 
00087 #define MIME_READER_MAX_BUFFER_SIZE  1054
00088 #define MIME_PARSER_BUFFER_SIZE 1054
00089 
00090 
00091 typedef MIME_read_status(*MIME_read_function) (void *, unsigned char *,
00092                                                int *);
00093 
00094 
00099 typedef struct _MIME_reader
00100 {
00101   int size;
00102   int marker;
00103   int current;
00104   MIME_read_function read_function;
00105   char buffer[MIME_READER_MAX_BUFFER_SIZE];
00106   void *userdata;
00107 } MIME_reader;
00108 
00109 
00110 MIME_read_status MIME_filereader_function(void *userdata,
00111                                           unsigned char *dest, int *size);
00112 
00113 typedef struct _MIME_callbacks
00114 {
00115   MIME_part_begin part_begin_cb;
00116   MIME_part_end part_end_cb;
00117   MIME_parse_begin parse_begin_cb;
00118   MIME_parse_end parse_end_cb;
00119   MIME_ERROR_bytes received_bytes_cb;
00120 } MIME_callbacks;
00121 
00122 
00123 MIME_parser_status MIME_parse(MIME_read_function reader_function,
00124                               void *reader_userdata,
00125                               const char *user_boundary,
00126                               const MIME_callbacks * callbacks,
00127                               void *callbacks_userdata);
00128 
00129 
00133 void
00134 MIME_reader_init(MIME_reader * reader,
00135                  MIME_read_function reader_function, void *userdata)
00136 {
00137   reader->size = 0;
00138   reader->marker = -1;
00139   reader->current = 0;
00140   reader->userdata = userdata;
00141   reader->read_function = reader_function;
00142 
00143 }
00144 
00148 MIME_read_status
00149 MIME_reader_read(MIME_reader * reader, unsigned char *buffer, int size)
00150 {
00151   MIME_read_status status;
00152   int len;
00153   unsigned char tempBuffer[MIME_READER_MAX_BUFFER_SIZE];
00154   int rest_size;
00155 
00156   /* Check if buffer is full */
00157   if (reader->size == reader->current)
00158   {
00159     /* Yes, so read some data */
00160 
00161     /* First handle marker */
00162     if (reader->marker > -1)
00163     {
00164       if (reader->marker != 0)
00165       {
00166         memcpy(tempBuffer, reader->buffer + reader->marker,
00167                reader->size - reader->marker);
00168         memcpy(reader->buffer, tempBuffer, reader->size - reader->marker);
00169         reader->current = reader->size - reader->marker;
00170       }
00171       else if (reader->current == MIME_READER_MAX_BUFFER_SIZE - 1)
00172       {
00173         fprintf(stderr, "Marker error");
00174         return MIME_READ_ERROR;
00175       }
00176       reader->marker = 0;
00177     }
00178     else
00179       reader->current = 0;
00180 
00181     len = MIME_READER_MAX_BUFFER_SIZE - reader->current - 1;
00182     status = reader->read_function(reader->userdata,
00183                                    reader->buffer + reader->current,
00184                                    &len);
00185 
00186     if (status == MIME_READ_OK)
00187     {
00188       reader->size = len + reader->current;
00189     }
00190     else
00191       return status;
00192   }
00193 
00194   if (size <= reader->size - reader->current)
00195   {
00196     memcpy(buffer, reader->buffer + reader->current, size);
00197     reader->current += size;
00198     return MIME_READ_OK;
00199   }
00200   else
00201   {
00202     /* Fill rest data */
00203     rest_size = reader->size - reader->current;
00204     memcpy(buffer, reader->buffer + reader->current, rest_size);
00205 
00206     reader->current = reader->size;
00207     return MIME_reader_read(reader, buffer + rest_size, size - rest_size);
00208   }
00209 }
00210 
00211 
00212 void
00213 MIME_reader_set_marker(MIME_reader * reader)
00214 {
00215   reader->marker = reader->current;
00216 }
00217 
00218 void
00219 MIME_reader_unset_marker(MIME_reader * reader)
00220 {
00221   reader->marker = -1;
00222 }
00223 
00224 void
00225 MIME_reader_jump_marker(MIME_reader * reader)
00226 {
00227   reader->current = reader->marker;
00228 }
00229 
00230 
00231 
00232 typedef struct _MIME_buffer
00233 {
00234   unsigned char data[MIME_PARSER_BUFFER_SIZE];
00235   int size;
00236 } MIME_buffer;
00237 
00238 
00239 void
00240 MIME_buffer_init(MIME_buffer * buffer)
00241 {
00242   buffer->size = 0;
00243 }
00244 
00245 void
00246 MIME_buffer_add(MIME_buffer * buffer, unsigned char ch)
00247 {
00248   buffer->data[buffer->size++] = ch;
00249 }
00250 
00251 void
00252 MIME_buffer_add_bytes(MIME_buffer * buffer, unsigned char *bytes, int size)
00253 {
00254   memcpy(buffer->data, bytes, size);
00255   buffer->size += size;
00256 }
00257 
00258 int
00259 MIME_buffer_is_full(MIME_buffer * buffer)
00260 {
00261   return buffer->size + 150 >= MIME_PARSER_BUFFER_SIZE;
00262 }
00263 
00264 int
00265 MIME_buffer_is_empty(MIME_buffer * buffer)
00266 {
00267   return buffer->size == 0;
00268 }
00269 
00270 void
00271 MIME_buffer_clear(MIME_buffer * buffer)
00272 {
00273   buffer->size = 0;
00274 }
00275 
00276 
00277 MIME_parser_status
00278 MIME_parse(MIME_read_function reader_function,
00279            void *reader_userdata,
00280            const char *user_boundary,
00281            const MIME_callbacks * callbacks, void *callbacks_userdata)
00282 {
00283   char boundary[150];
00284   unsigned char ch[153];
00285   int boundary_length, n, ignore = 0;
00286   MIME_reader reader;
00287   MIME_buffer buffer;
00288   MIME_read_status status;
00289 
00290   /* Init reader */
00291   MIME_reader_init(&reader, reader_function, reader_userdata);
00292 
00293   /* Init buffer */
00294   MIME_buffer_init(&buffer);
00295 
00296   /* Set boundary related stuff */
00297   sprintf(boundary, "\n--%s", user_boundary);
00298   boundary_length = strlen(boundary);
00299 
00300   /* Call parse begin callback */
00301   callbacks->parse_begin_cb(callbacks_userdata);
00302 
00303   while (1)
00304   {
00305   set_marker:
00306 
00307     /* Set marker */
00308     MIME_reader_set_marker(&reader);
00309 
00310   read_byte:
00311 
00312     /* Read 1 byte */
00313     status = MIME_reader_read(&reader, ch, 1);
00314     if (status == MIME_READ_EOF)
00315       return MIME_PARSER_INCOMPLETE_MESSAGE;
00316     else if (status == MIME_READ_ERROR)
00317       return MIME_PARSER_READ_ERROR;
00318 
00319     if (ch[0] == '\r' && !ignore)
00320     {
00321       n = 0;
00322       while (n < boundary_length)
00323       {
00324         /* Read 1 byte */
00325         status = MIME_reader_read(&reader, ch, 1);
00326         if (status == MIME_READ_EOF)
00327           return MIME_PARSER_INCOMPLETE_MESSAGE;
00328         else if (status == MIME_READ_ERROR)
00329           return MIME_PARSER_READ_ERROR;
00330 
00331         /* Check if byte is in boundary */
00332         if (ch[0] == boundary[n])
00333         {
00334           n = n + 1;
00335           continue;
00336         }
00337         else
00338         {
00339           MIME_reader_jump_marker(&reader);
00340           ignore = 1;
00341           goto read_byte;
00342         }
00343 
00344       }                         /* while n < boundary_length */
00345 
00346       /* Read 1 byte */
00347       status = MIME_reader_read(&reader, ch, 1);
00348 
00349 
00350       if (status == MIME_READ_EOF)
00351         return MIME_PARSER_INCOMPLETE_MESSAGE;
00352       else if (status == MIME_READ_ERROR)
00353         return MIME_PARSER_READ_ERROR;
00354 
00355       /* Show if byte is '\r' */
00356       if (ch[0] == '\r')
00357       {
00358         /* Read 1 byte */
00359         status = MIME_reader_read(&reader, ch, 1);
00360 
00361 
00362         if (status == MIME_READ_EOF)
00363           return MIME_PARSER_INCOMPLETE_MESSAGE;
00364         else if (status == MIME_READ_ERROR)
00365           return MIME_PARSER_READ_ERROR;
00366 
00367         /* Check if byte is '\n' */
00368         if (ch[0] == '\n')
00369         {
00370           if (!MIME_buffer_is_empty(&buffer))
00371           {
00372             /* Invoke callback */
00373             callbacks->received_bytes_cb(callbacks_userdata, buffer.data,
00374                                          buffer.size);
00375 
00376             /* Empty the buffer */
00377             MIME_buffer_clear(&buffer);
00378 
00379             /* Invoke End Part */
00380             callbacks->part_end_cb(callbacks_userdata);
00381           }
00382 
00383           /* Invoke start new Part */
00384           callbacks->part_begin_cb(callbacks_userdata);
00385           goto set_marker;
00386 
00387         }                       /* if (ch[0] == '\n') */
00388         else
00389         {
00390           /* Jump to marker and read bytes */
00391           MIME_reader_jump_marker(&reader);
00392           MIME_reader_read(&reader, ch, boundary_length + 2);
00393 
00394           MIME_buffer_add_bytes(&buffer, ch, boundary_length + 2);
00395 
00396           if (MIME_buffer_is_full(&buffer))
00397           {
00398             /* Invoke callback */
00399             callbacks->received_bytes_cb(callbacks_userdata, buffer.data,
00400                                          buffer.size);
00401 
00402 
00403             /* Empty the buffer */
00404             MIME_buffer_clear(&buffer);
00405           }
00406         }                       /* else of if (ch[0] == '\n') */
00407 
00408       }                         /* if (ch[0] == '\r') */
00409       else
00410       {
00411         if (ch[0] == '-')
00412         {
00413           /* Read 1 byte */
00414           status = MIME_reader_read(&reader, ch, 1);
00415 
00416           if (status == MIME_READ_EOF)
00417             return MIME_PARSER_INCOMPLETE_MESSAGE;
00418           else if (status == MIME_READ_ERROR)
00419             return MIME_PARSER_READ_ERROR;
00420 
00421           if (ch[0] == '-')
00422           {
00423             if (!MIME_buffer_is_empty(&buffer))
00424             {
00425               /* Invoke callback */
00426               callbacks->received_bytes_cb(callbacks_userdata, buffer.data,
00427                                            buffer.size);
00428 
00429               /* Empty the buffer */
00430               MIME_buffer_clear(&buffer);
00431 
00432               /* Invoke End Part */
00433               callbacks->part_end_cb(callbacks_userdata);
00434             }
00435 
00436             /* Invoke start new Part */
00437             callbacks->parse_end_cb(callbacks_userdata);
00438 
00439             /* Finish parsing */
00440             /* TODO (#1#): We assume that after -- comes \r\n This is not
00441                always correct */
00442 
00443             return MIME_PARSER_OK;
00444 
00445           }                     /* if (ch[0] == '-') */
00446           else
00447           {
00448             MIME_reader_jump_marker(&reader);
00449             ignore = 1;
00450             goto read_byte;
00451           }                     /* else of if (ch[0] == '-') */
00452 
00453         }                       /* if (ch[0] == '-') */
00454         else
00455         {
00456           MIME_reader_jump_marker(&reader);
00457           ignore = 1;
00458           goto read_byte;
00459         }                       /* else of if (ch[0] == '-') */
00460 
00461       }                         /* else of if (ch[0] == '\r') */
00462 
00463     }                           /* if ch[0] == '\r' && !ignore */
00464     else
00465     {
00466       ignore = 0;
00467       MIME_buffer_add(&buffer, ch[0]);
00468 
00469       /* Chec if buffer is full */
00470       if (MIME_buffer_is_full(&buffer))
00471       {
00472         /* Invoke callback */
00473         callbacks->received_bytes_cb(callbacks_userdata, buffer.data,
00474                                      buffer.size);
00475 
00476         /* Empty the buffer */
00477         MIME_buffer_clear(&buffer);
00478       }
00479     }                           /* else of if ch[0] == '\r' && !ignore */
00480   }                             /* while (1) */
00481 }
00482 
00483 MIME_read_status
00484 MIME_filereader_function(void *userdata, unsigned char *dest, int *size)
00485 {
00486   FILE *f = (FILE *) userdata;
00487 
00488   if (feof(f))
00489     return MIME_READ_EOF;
00490 
00491   *size = fread(dest, 1, *size, f);
00492   return MIME_READ_OK;
00493 }
00494 
00495 
00496 /* ------------------------------------------------------------------
00497   "multipart/related"  MIME Message Builder
00498  ------------------------------------------------------------------*/
00499 
00500 /*
00501   Callback data to use internally
00502 */
00503 typedef struct _mime_callback_data
00504 {
00505   int part_id;
00506   struct attachments_t *message;
00507   struct part_t *current_part;
00508   int buffer_capacity;
00509   char header[4064];
00510   char root_id[256];
00511   int header_index;
00512   int header_search;
00513   FILE *current_fd;
00514   char root_dir[512];
00515 } mime_callback_data_t;
00516 
00517 
00518 MIME_read_status
00519 mime_streamreader_function(void *userdata, unsigned char *dest, int *size)
00520 {
00521   int len = 0;
00522   struct http_input_stream_t *in = (struct http_input_stream_t *) userdata;
00523 
00524   if (!http_input_stream_is_ready(in))
00525     return MIME_READ_EOF;
00526 
00527   len = http_input_stream_read(in, dest, *size);
00528   /* 
00529      log_info1("http_input_stream_read() returned 0"); */
00530   if (len == -1)
00531   {
00532     log_error4("[%d] %s():%s ", herror_code(in->err), herror_func(in->err),
00533                herror_message(in->err));
00534   }
00535 
00536   *size = len;
00537   if (*size != -1)
00538   {
00539     return MIME_READ_OK;
00540   }
00541   return MIME_READ_ERROR;
00542 }
00543 
00544 
00545 /*
00546   Start Callback functions
00547 */
00548 static void
00549 _mime_parse_begin(void *data)
00550 {
00551 /* Nothing to do
00552   mime_callback_data_t *cbdata = (mime_callback_data_t)data;
00553  */
00554   log_verbose2("Begin parse (%p)", data);
00555 
00556   return;
00557 }
00558 
00559 
00560 static void
00561 _mime_parse_end(void *data)
00562 {
00563 /* Nothing to do
00564   mime_callback_data_t *cbdata = (mime_callback_data_t)data;
00565  */
00566   log_verbose2("End parse (%p)", data);
00567 
00568   return;
00569 }
00570 
00571 
00572 static void
00573 _mime_part_begin(void *data)
00574 {
00575   char buffer[1054];
00576   struct part_t *part;
00577   mime_callback_data_t *cbdata;
00578  
00579   cbdata = (mime_callback_data_t *) data;
00580   log_verbose2("Begin Part (%p)", data);
00581   if (!(part = (struct part_t *) malloc(sizeof(struct part_t))))
00582   {
00583     log_error2("malloc failed (%s)", strerror(errno));
00584     return;
00585   }
00586   part->next = NULL;
00587 
00588 
00589   if (cbdata->current_part)
00590     cbdata->current_part->next = part;
00591 
00592   cbdata->current_part = part;
00593 
00594   if (!cbdata->message->parts)
00595     cbdata->message->parts = part;
00596 
00597   cbdata->header[0] = '\0';
00598   cbdata->header_index = 0;
00599   cbdata->header_search = 0;
00600 
00601 #ifdef WIN32
00602   sprintf(buffer, "%s\\mime_%p_%d.part", cbdata->root_dir,
00603           cbdata, cbdata->part_id++);
00604 #else
00605   sprintf(buffer, "%s/mime_%p_%d.part", cbdata->root_dir,
00606           cbdata, cbdata->part_id++);
00607 #endif
00608 
00609 /*  log_info2("Creating FILE ('%s') deleteOnExit=1", buffer);*/
00610   part->deleteOnExit = 1;
00611   cbdata->current_fd = fopen(buffer, "wb");
00612   if (cbdata->current_fd)
00613     strcpy(cbdata->current_part->filename, buffer);
00614   else
00615     log_error2("Can not open file for write '%s'", buffer);
00616 }
00617 
00618 
00619 static void
00620 _mime_part_end(void *data)
00621 {
00622   mime_callback_data_t *cbdata = (mime_callback_data_t *) data;
00623   log_verbose2("End Part (%p)", data);
00624   if (cbdata->current_fd)
00625   {
00626     fclose(cbdata->current_fd);
00627     cbdata->current_fd = NULL;
00628   }
00629 
00630   return;
00631 }
00632 
00633 
00634 static hpair_t *
00635 _mime_process_header(char *buffer)
00636 {
00637   int i = 0, c = 0, proc_key, begin = 0;
00638   hpair_t *first = NULL, *last = NULL;
00639   char key[1054], value[1054];
00640 
00641   key[0] = '\0';
00642   value[0] = '\0';
00643   proc_key = 1;
00644 
00645   while (buffer[i] != '\0')
00646   {
00647     if (buffer[i] == '\r' && buffer[i + 1] == '\n')
00648     {
00649       value[c] = '\0';
00650       if (last)
00651       {
00652         last->next = hpairnode_new(key, value, NULL);
00653         last = last->next;
00654       }
00655       else
00656       {
00657         first = last = hpairnode_new(key, value, NULL);
00658       }
00659       proc_key = 1;
00660       c = 0;
00661       i++;
00662     }
00663     else if (buffer[i] == ':')
00664     {
00665       key[c] = '\0';
00666       c = 0;
00667       begin = 0;
00668       proc_key = 0;
00669     }
00670     else
00671     {
00672       if (proc_key)
00673         key[c++] = buffer[i];
00674       else
00675       {
00676         if (buffer[i] != ' ')
00677           begin = 1;
00678         if (begin)
00679           value[c++] = buffer[i];
00680       }
00681     }
00682     i++;
00683   }
00684   return first;
00685 }
00686 
00687 
00688 static void
00689 _mime_received_bytes(void *data, const unsigned char *bytes, int size)
00690 {
00691   int i = 0;
00692   char *id, *type, *location;
00693   mime_callback_data_t *cbdata = (mime_callback_data_t *) data;
00694 
00695   if (!cbdata)
00696   {
00697     log_error1
00698       ("MIME transport error Called <received bytes> without initializing\n");
00699     return;
00700   }
00701   if (!cbdata->current_part)
00702   {
00703     log_error1
00704       ("MIME transport error Called <received bytes> without initializing\n");
00705     return;
00706   }
00707 /*  log_verbose4("Received %d bytes (%p), header_search = %d", 
00708     size, data, cbdata->header_search);
00709 */
00710   if (cbdata->header_search < 4)
00711   {
00712     /* Find \r\n\r\n in bytes */
00713     for (i = 0; i < size; i++)
00714     {
00715       if (cbdata->header_search == 0)
00716       {
00717         if (bytes[i] == '\r')
00718           cbdata->header_search++;
00719         else
00720         {
00721           cbdata->header[cbdata->header_index++] = bytes[i];
00722           cbdata->header_search = 0;
00723         }
00724       }
00725 
00726       else if (cbdata->header_search == 1)
00727       {
00728         if (bytes[i] == '\n')
00729           cbdata->header_search++;
00730         else
00731         {
00732           cbdata->header[cbdata->header_index++] = '\r';
00733           cbdata->header[cbdata->header_index++] = bytes[i];
00734           cbdata->header_search = 0;
00735         }
00736       }
00737 
00738       else if (cbdata->header_search == 2)
00739       {
00740         if (bytes[i] == '\r')
00741           cbdata->header_search++;
00742         else
00743         {
00744           cbdata->header[cbdata->header_index++] = '\r';
00745           cbdata->header[cbdata->header_index++] = '\n';
00746           cbdata->header[cbdata->header_index++] = bytes[i];
00747           cbdata->header_search = 0;
00748         }
00749       }
00750 
00751       else if (cbdata->header_search == 3)
00752       {
00753         if (bytes[i] == '\n')
00754         {
00755           cbdata->header[cbdata->header_index++] = '\r';
00756           cbdata->header[cbdata->header_index++] = '\n';
00757           cbdata->header[cbdata->header_index++] = '\0';
00758           cbdata->header_search = 4;
00759           cbdata->current_part->header = _mime_process_header(cbdata->header);
00760           hpairnode_dump_deep(cbdata->current_part->header);
00761           /* set id */
00762           id = hpairnode_get(cbdata->current_part->header, HEADER_CONTENT_ID);
00763           if (id != NULL)
00764           {
00765             strcpy(cbdata->current_part->id, id);
00766             if (!strcmp(id, cbdata->root_id))
00767               cbdata->message->root_part = cbdata->current_part;
00768           }
00769           location =
00770             hpairnode_get(cbdata->current_part->header,
00771                           HEADER_CONTENT_LOCATION);
00772           if (location != NULL)
00773           {
00774             strcpy(cbdata->current_part->location, location);
00775           }
00776           type =
00777             hpairnode_get(cbdata->current_part->header, HEADER_CONTENT_TYPE);
00778           if (type != NULL)
00779           {
00780             strcpy(cbdata->current_part->content_type, type);
00781           }
00782           i++;
00783           break;
00784         }
00785         else
00786         {
00787           cbdata->header[cbdata->header_index++] = '\r';
00788           cbdata->header[cbdata->header_index++] = '\n';
00789           cbdata->header[cbdata->header_index++] = '\r';
00790           cbdata->header[cbdata->header_index++] = bytes[i];
00791           cbdata->header_search = 0;
00792         }
00793       }
00794       /* TODO (#1#): Check for cbdata->header overflow */
00795 
00796     }                           /* for (i=0;i<size;i++) */
00797   }                             /* if (cbdata->header_search < 4) */
00798 
00799   if (i >= size - 1)
00800     return;
00801 
00802   /* Write remaining bytes into the file or buffer (if root) (buffer is
00803      disabled in this version) */
00804   if (cbdata->current_fd)
00805     fwrite(&(bytes[i]), 1, size - i, cbdata->current_fd);
00806 
00807   return;
00808 }
00809 
00810 
00811 /*
00812   The mime message parser
00813 */
00814 
00815 struct attachments_t *
00816 mime_message_parse(struct http_input_stream_t * in, const char *root_id,
00817                    const char *boundary, const char *dest_dir)
00818 {
00819   MIME_parser_status status;
00820   MIME_callbacks callbacks;
00821   struct attachments_t *message;
00822 
00823   mime_callback_data_t *cbdata;
00824  
00825   if (!(cbdata = (mime_callback_data_t *) malloc(sizeof(mime_callback_data_t))))
00826   {
00827     log_error2("malloc failed (%s)", strerror(errno));
00828     return NULL;
00829   }
00830 
00831   cbdata->part_id = 100;
00832   cbdata->buffer_capacity = 0;
00833   cbdata->current_fd = NULL;
00834   cbdata->current_part = NULL;
00835   cbdata->header_index = 0;
00836   cbdata->header_search = 0;
00837   strcpy(cbdata->root_id, root_id);
00838   strcpy(cbdata->root_dir, dest_dir);
00839 
00840   if (!(message = (struct attachments_t *) malloc(sizeof(struct attachments_t))))
00841   {
00842     log_error2("malloc failed (%s)", strerror(errno));
00843     free(cbdata);
00844     return NULL;
00845   }
00846   cbdata->message = message;
00847   cbdata->message->parts = NULL;
00848   cbdata->message->root_part = NULL;
00849 
00850   callbacks.parse_begin_cb = _mime_parse_begin;
00851   callbacks.parse_end_cb = _mime_parse_end;
00852   callbacks.part_begin_cb = _mime_part_begin;
00853   callbacks.part_end_cb = _mime_part_end;
00854   callbacks.received_bytes_cb = _mime_received_bytes;
00855 
00856   status = MIME_parse(mime_streamreader_function,
00857                       in, boundary, &callbacks, cbdata);
00858 
00859   if (status == MIME_PARSER_OK)
00860   {
00861     free(cbdata);
00862     return message;
00863   }
00864   else
00865   {
00866     log_error2("MIME parser error '%s'!",
00867                status ==
00868                MIME_PARSER_READ_ERROR ? "read error" : "Incomplete message");
00869     return NULL;
00870   }
00871 }
00872 
00873 struct attachments_t *
00874 mime_message_parse_from_file(FILE * in, const char *root_id,
00875                              const char *boundary, const char *dest_dir)
00876 {
00877   MIME_parser_status status;
00878   MIME_callbacks callbacks;
00879   struct attachments_t *message;
00880 
00881   mime_callback_data_t *cbdata;
00882  
00883   if (!(cbdata = (mime_callback_data_t *) malloc(sizeof(mime_callback_data_t))))
00884   {
00885     log_error2("malloc failed (%s)", strerror(errno));
00886     return NULL;
00887   }
00888 
00889   cbdata->part_id = 100;
00890   cbdata->buffer_capacity = 0;
00891   cbdata->current_fd = NULL;
00892   cbdata->current_part = NULL;
00893   cbdata->header_index = 0;
00894   cbdata->header_search = 0;
00895   strcpy(cbdata->root_id, root_id);
00896   strcpy(cbdata->root_dir, dest_dir);
00897 
00898   if (!(message = (struct attachments_t *) malloc(sizeof(struct attachments_t))))
00899   {
00900     log_error2("malloc failed (%s)", strerror(errno));
00901     free(cbdata);
00902     return NULL;
00903   }
00904 
00905   cbdata->message = message;
00906   cbdata->message->parts = NULL;
00907   cbdata->message->root_part = NULL;
00908 
00909   callbacks.parse_begin_cb = _mime_parse_begin;
00910   callbacks.parse_end_cb = _mime_parse_end;
00911   callbacks.part_begin_cb = _mime_part_begin;
00912   callbacks.part_end_cb = _mime_part_end;
00913   callbacks.received_bytes_cb = _mime_received_bytes;
00914 
00915   status = MIME_parse(MIME_filereader_function,
00916                       in, boundary, &callbacks, cbdata);
00917 
00918   if (status == MIME_PARSER_OK)
00919   {
00920     free(cbdata);
00921     return message;
00922   }
00923   else
00924   {
00925     /* TODO (#1#): Free objects */
00926 
00927     log_error2("MIME parser error '%s'!",
00928                status ==
00929                MIME_PARSER_READ_ERROR ? "general error" :
00930                "Incomplete message");
00931     return NULL;
00932   }
00933 }
00934 
00935 herror_t
00936 mime_get_attachments(content_type_t * ctype, struct http_input_stream_t * in,
00937                      struct attachments_t ** dest)
00938 {
00939   /* MIME variables */
00940   struct attachments_t *mimeMessage;
00941   struct part_t *part, *tmp_part = NULL;
00942   char *boundary, *root_id;
00943 
00944   /* Check for MIME message */
00945   if (!(ctype && !strcmp(ctype->type, "multipart/related")))
00946     return herror_new("mime_get_attachments", MIME_ERROR_NOT_MIME_MESSAGE,
00947                       "Not a MIME message '%s'", ctype->type);
00948 
00949   boundary = hpairnode_get(ctype->params, "boundary");
00950   root_id = hpairnode_get(ctype->params, "start");
00951   if (boundary == NULL)
00952   {
00953     /* TODO (#1#): Handle Error in http form */
00954     log_error1("'boundary' not set for multipart/related");
00955     return herror_new("mime_get_attachments", MIME_ERROR_NO_BOUNDARY_PARAM,
00956                       "'boundary' not set for multipart/related");
00957   }
00958 
00959   if (root_id == NULL)
00960   {
00961     /* TODO (#1#): Handle Error in http form */
00962     log_error1("'start' not set for multipart/related");
00963     return herror_new("mime_get_attachments", MIME_ERROR_NO_START_PARAM,
00964                       "'start' not set for multipart/related");
00965   }
00966 
00967   mimeMessage = mime_message_parse(in, root_id, boundary, ".");
00968   if (mimeMessage == NULL)
00969   {
00970     /* TODO (#1#): Handle Error in http form */
00971     log_error1("MIME Parse Error");
00972     return herror_new("mime_get_attachments", MIME_ERROR_PARSE_ERROR,
00973                       "MIME Parse Error");
00974   }
00975 
00976   /* Find root */
00977   if (!mimeMessage->root_part)
00978   {
00979     attachments_free(mimeMessage);
00980     return herror_new("mime_get_attachments", MIME_ERROR_NO_ROOT_PART,
00981                       "No root part found!");
00982   }
00983 
00984   /* delete root_part from list */
00985   part = mimeMessage->parts;
00986   while (part)
00987   {
00988     if (part == mimeMessage->root_part)
00989     {
00990       if (tmp_part)
00991         tmp_part->next = part->next;
00992       else
00993         mimeMessage->parts = part->next;
00994 
00995       break;
00996     }
00997     tmp_part = part;
00998     part = part->next;
00999   }
01000   *dest = mimeMessage;
01001   return H_OK;
01002 }

Generated on Thu Jan 25 23:36:03 2007 for csoap by  doxygen 1.4.6