Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

wap_push_pap_mime.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * Implementation of a gateway oriented mime parser for pap module. This 
00059  * parser follows proxy rules stated in Push Message, chapter 7.
00060  *
00061  * By Aarno Syvänen for Wiral Ltd and Global Networks Inc.
00062  */
00063 
00064 #include "wap_push_pap_mime.h"
00065 
00066 /*****************************************************************************
00067  *
00068  * Prototypes for internal functions
00069  */
00070 
00071 static int is_cr(int c);
00072 static int is_lf(int c);
00073 static int islwspchar(int c);
00074 static long octstr_drop_leading_blanks(Octstr **header_value);
00075 static void drop_separator(Octstr **header_value, long *pos);
00076 static int parse_preamble(Octstr **mime_content, Octstr *boundary);
00077 static long parse_transport_padding(Octstr *mime_content, long pos);
00078 static long parse_terminator(Octstr *mime_content, long pos);
00079 static int parse_body_part(Octstr **multipart, Octstr *boundary, 
00080                             Octstr **body_part);
00081 static int parse_encapsulation(Octstr **mime_content, Octstr *boundary, 
00082                                Octstr **push_data, List **content_headers,
00083                    Octstr **rdf_content);
00084 static int check_control_headers(Octstr **body_part);
00085 static int check_control_content_type_header(Octstr **body_part, Octstr *boundary);
00086 static int drop_optional_header(Octstr **body_part, char *name, Octstr *boundary);
00087 static int drop_header_true(Octstr **body_part, long content_pos);
00088 static int drop_extension_headers(Octstr **mime_content, Octstr *boundary);
00089 static long parse_field_value(Octstr *pap_content, long pos);
00090 static long parse_field_name(Octstr *pap_content, long pos);
00091 static void octstr_split_by_pos(Octstr **mime_content, Octstr **pap_content, 
00092                                 long boundary_pos);
00093 static Octstr *make_close_delimiter(Octstr *boundary);
00094 static Octstr *make_part_delimiter(Octstr *boundary);
00095 static Octstr *make_start_delimiter(Octstr *dash_boundary);
00096 static int pass_data_headers(Octstr **body_part, List **data_headers);
00097 static int check_data_content_type_header(Octstr **body_part, List **data_headers, Octstr *boundary);
00098 static int pass_optional_header(Octstr **body_part, char *name, List **content_headers,
00099                                 Octstr *boundary);
00100 static int pass_extension_headers(Octstr **body_part, List **data_headers, Octstr *boundary);
00101 static long pass_field_name(Octstr **body_part, Octstr **content_header, 
00102                 long pos);
00103 static long pass_field_value(Octstr **body_part, Octstr **content_header, 
00104                              long pos);
00105 static int parse_epilogue(Octstr **mime_content);
00106 static int parse_tail(Octstr **multipart, Octstr *part_delimiter, 
00107                       long boundary_pos, long *next_part_pos);
00108 
00109 /*****************************************************************************
00110  *
00111  * Implementation of the external function, PAP uses MIME type multipart/
00112  * related to communicate a push message and related control information from 
00113  * pi to ppg. Mime_parse separates parts of message and in addition returns
00114  * MIME-part-headers of the content entity. Preamble and epilogue of are dis-
00115  * carded from control messages, but not from a multipart content entity. 
00116  * Already parsed parts of mime content are removed. 
00117  * Multipart/related content type is defined in rfc 2046, chapters 5.1, 5.1.1, 
00118  * and 5.1.7. Grammar is capitulated in rfc 2046 appendix A and in rfc 822, 
00119  * appendix D. PAP, chapter 8 defines how MIME multipart message is used by PAP
00120  * protocol. Functions called by mime_parse remove parsed parts from the mime
00121  * content. 
00122  * Input: pointer to mime boundary and mime content
00123  * Output: Pointer to pap control document and push data, if parsable, NULL
00124  * otherwise. If there is a capabilities document, pointer to this is return-
00125  * ed, too. If there is none, pointer to NULL instead. Neither prologue nor 
00126  * epilogue is returned. 
00127  * In addition, return 1 if parsing was succesfull, 0 otherwise.
00128  */
00129 
00130 int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content, 
00131                Octstr **push_data, List **content_headers, 
00132                Octstr **rdf_content)
00133 {
00134     int ret;
00135 
00136     *pap_content = NULL;
00137     *push_data = NULL;
00138     *content_headers = NULL;
00139     *rdf_content = NULL;
00140 
00141     if (parse_preamble(&mime_content, boundary) < 0) {
00142         warning(0, "erroneous preamble");
00143         return 0;
00144     }
00145     if (parse_body_part(&mime_content, boundary, pap_content) <= 0) {
00146         warning(0, "erroneous control entity");
00147         return 0;
00148     }
00149     if (check_control_headers(pap_content) == 0) {
00150         warning(0, "erroneous control headers");
00151         return 0;
00152     }
00153 
00154     ret = -1;
00155     if ((ret = parse_encapsulation(&mime_content, boundary, push_data, 
00156                                    content_headers, rdf_content)) < 0) {
00157         warning(0, "erroneous content entity (push message)");
00158         return 0;
00159     } else if (ret == 0) {
00160         gw_assert(*rdf_content == NULL);
00161         if (octstr_len(mime_content) != 0)
00162             parse_epilogue(&mime_content);
00163         return 1;
00164     }
00165 
00166     if (check_control_headers(rdf_content) == 0) {
00167         warning(0, "erroneous capacity (rdf) headers");
00168         return 0;
00169     }
00170 
00171     if (octstr_len(mime_content) != 0)
00172         parse_epilogue(&mime_content);
00173     gw_assert(octstr_len(mime_content) == 0);
00174     
00175     return 1;
00176 }
00177 
00178 /*****************************************************************************
00179  *
00180  * Implementation of internal functions
00181  */
00182 
00183 static int is_cr(int c)
00184 {
00185     return c == '\r';
00186 }
00187 
00188 static int is_lf(int c)
00189 {
00190     return c == '\n';
00191 }
00192 
00193 /*
00194  * Lwspchar is defined in rfc 822, appendix D.
00195  */
00196 static int islwspchar(int c)
00197 {
00198     return c == '\t' || c == ' ';
00199 }
00200 
00201 /* These thingies we after normally have after delimiters. */
00202 static int parse_tail(Octstr **multipart, Octstr *delimiter, 
00203                       long boundary_pos, long *next_part_pos)
00204 {
00205     *next_part_pos = parse_transport_padding(*multipart, 
00206          boundary_pos + octstr_len(delimiter));
00207 
00208     if ((*next_part_pos = parse_terminator(*multipart, *next_part_pos)) < 0)
00209         return -1;
00210     
00211     return 0;
00212 }
00213 
00214 
00215 /*
00216  * Boundary misses crlf here. This is intentional: Kannel header parsing pro-
00217  * cess drops this terminator.
00218  */
00219 static int parse_preamble(Octstr **mime_content, Octstr *boundary)
00220 {
00221     long boundary_pos,
00222          next_part_pos;
00223     Octstr *dash_boundary;
00224 
00225     boundary_pos = next_part_pos = -1;
00226     dash_boundary = make_start_delimiter(boundary);
00227     
00228     if ((boundary_pos = octstr_search(*mime_content, dash_boundary, 0)) < 0)
00229         goto error;
00230 
00231     if (parse_tail(mime_content, dash_boundary, boundary_pos, 
00232             &next_part_pos) < 0) 
00233         goto error;
00234 
00235     octstr_delete(*mime_content, 0, next_part_pos);
00236     octstr_destroy(dash_boundary);
00237 
00238     return 0;
00239 
00240 error:
00241     octstr_destroy(dash_boundary);
00242     return -1;
00243 }
00244     
00245 static long parse_terminator(Octstr *mime_content, long pos)
00246 {
00247     if (is_cr(octstr_get_char(mime_content, pos)))
00248         ++pos;
00249     else 
00250         return -1;
00251 
00252     if (is_lf(octstr_get_char(mime_content, pos)))
00253         ++pos;
00254     else 
00255         return -1;
00256 
00257     return pos;
00258 }
00259 
00260 static long parse_transport_padding(Octstr *mime_content, long pos)
00261 {
00262     while (islwspchar(octstr_get_char(mime_content, pos)))
00263         ++pos;
00264 
00265     return pos;
00266 }
00267 
00268 static long parse_close_delimiter(Octstr *close_delimiter, Octstr *mime_content,
00269                                   long pos)
00270 {
00271     if (octstr_ncompare(close_delimiter, mime_content, 
00272                         octstr_len(close_delimiter)) != 0)
00273         return -1;
00274     pos += octstr_len(close_delimiter);
00275 
00276     return pos;
00277 }
00278 
00279 /*
00280  * Splits the first body part away from the multipart message. A body part end with
00281  * either with another body or with a close delimiter. We first split the body and
00282  * then remove the separating stuff  from the remainder. If we have the last body
00283  * part, we must parse all closing stuff. 
00284  * Returns 1, there is still another body part in the multipart message
00285  *         0, if there is none
00286  *         -1, when parsing error.
00287  */
00288 static int parse_body_part (Octstr **multipart, Octstr *boundary, 
00289                             Octstr **body_part)
00290 {
00291     Octstr *part_delimiter,
00292            *close_delimiter;
00293     long boundary_pos,          /* start of the boundary */
00294          close_delimiter_pos,   /* start of the close delimiter */
00295          next_part_pos,         /* start of the next part */
00296          epilogue_pos;          /* start of the epilogue */
00297  
00298     part_delimiter = make_part_delimiter(boundary);
00299     close_delimiter = make_close_delimiter(boundary);
00300 
00301     if ((close_delimiter_pos = octstr_search(*multipart, 
00302             close_delimiter, 0)) < 0) 
00303         goto error;
00304 
00305     boundary_pos = octstr_search(*multipart, part_delimiter, 0);
00306     if (boundary_pos == close_delimiter_pos) {
00307         octstr_split_by_pos(multipart, body_part, close_delimiter_pos);
00308         if ((epilogue_pos = 
00309                 parse_close_delimiter(close_delimiter, *multipart, 0)) < 0)
00310             goto error;
00311         epilogue_pos = parse_transport_padding(*multipart, epilogue_pos);
00312         octstr_delete(*multipart, 0, epilogue_pos);
00313     goto last_part;
00314     }
00315 
00316     octstr_split_by_pos(multipart, body_part, boundary_pos);
00317 
00318     if (parse_tail(multipart, part_delimiter, 0, &next_part_pos) < 0) {
00319         goto error;
00320     }
00321 
00322     octstr_delete(*multipart, 0, next_part_pos);
00323     octstr_destroy(part_delimiter);
00324     octstr_destroy(close_delimiter);
00325 
00326     return 1;
00327 
00328 error:
00329     octstr_destroy(part_delimiter);
00330     octstr_destroy(close_delimiter);
00331     return -1;
00332 
00333 last_part:
00334     octstr_destroy(part_delimiter);
00335     octstr_destroy(close_delimiter);
00336     return 0;
00337 
00338 }
00339 
00340 /*
00341  * PAP, Chapter 8 states that PAP multipart message MUST have at least two 
00342  * parts, control entity (containing the pap control message) and content 
00343  * entity (containing the push message). So we must have at least one body
00344  * part here, and at most two (MIME grammar in rfc 2046, appendix A sets no 
00345  * limitations here).
00346  * Input: mime content, part boundary
00347  * Output: Push content, rdf content if present, content headers. In addi-
00348  * tion, modified mime content (without parsed parts).
00349  * Returns 1, if rdf content was present
00350  *         0, if it was absent
00351  *         -1, when error
00352  */
00353 static int parse_encapsulation(Octstr **mime_content, Octstr *boundary, 
00354                                Octstr **push_data, List **content_headers,
00355                                Octstr **rdf_content)
00356 {
00357     int ret;
00358 
00359     ret = -1;
00360     if ((ret = parse_body_part(mime_content, boundary, push_data)) < 0)
00361         return -1;
00362     if (pass_data_headers(push_data, content_headers) == 0)
00363         return -1;
00364 
00365     if (ret == 0) {
00366         *rdf_content = NULL;
00367         return 0;
00368     }
00369 
00370     if ((ret = parse_body_part(mime_content, boundary, rdf_content)) < 0 || 
00371             ret > 0)
00372         return -1;
00373     else if (ret == 0)
00374         return 1;
00375     
00376     return 1;
00377 }
00378 
00379 /*
00380  * Split os2 from os1, boundary being boundary_pos.
00381  */
00382 static void octstr_split_by_pos(Octstr **os1, Octstr **os2, 
00383                                 long boundary_pos)
00384 {
00385     *os2 = octstr_copy(*os1, 0, boundary_pos);
00386     octstr_delete(*os1, 0, boundary_pos);
00387 }
00388 
00389 static Octstr *make_close_delimiter(Octstr *boundary) 
00390 {
00391     Octstr *close_delimiter;
00392 
00393     close_delimiter = make_part_delimiter(boundary);
00394     octstr_format_append(close_delimiter, "%s", "--");
00395 
00396     return close_delimiter;
00397 }
00398 
00399 static Octstr *make_part_delimiter(Octstr *dash_boundary)
00400 {
00401     Octstr *part_delimiter;
00402 
00403     part_delimiter = octstr_create("\r\n--");
00404     octstr_append(part_delimiter, dash_boundary);
00405     
00406     return part_delimiter;
00407 }
00408 
00409 static Octstr *make_start_delimiter(Octstr *dash_boundary)
00410 {
00411     Octstr *start_delimiter;
00412 
00413     start_delimiter = octstr_create("--");
00414     octstr_append(start_delimiter, dash_boundary);
00415 
00416     return start_delimiter;
00417 }
00418 
00419 /*
00420  * Control entity headers must contain Content-Type: application/xml headers.
00421  * Rfc 2045, Appendix A does not specify the order of entity headers and states
00422  * that all rfc 822 headers having a string "Content" in their field-name must
00423  * be accepted. Rfc 822 grammar is capitulated in appendix D.
00424  * Message starts after the first null line, so only something after it can be
00425  * an extension header (or any header).
00426  */
00427 static int check_control_headers(Octstr **body_part)
00428 {
00429     if (check_control_content_type_header(body_part, octstr_imm("\r\n\r\n")) == 0)
00430         return 0;
00431     if (drop_optional_header(body_part, "Content-Transfer-Encoding:",
00432             octstr_imm("\r\n\r\n")) == 0)
00433         return 0;
00434     if (drop_optional_header(body_part, "Content-ID:", octstr_imm("\r\n\r\n")) == 0)
00435         return 0;
00436     if (drop_optional_header(body_part, "Content-Description:", octstr_imm("\r\n\r\n")) == 0)
00437         return 0;
00438     if (drop_extension_headers(body_part, octstr_imm("\r\n\r\n")) == 0)
00439         return 0;
00440 
00441     return 1;
00442 }
00443 
00444 static int check_control_content_type_header(Octstr **body_part, Octstr *boundary)
00445 {
00446     long content_pos;
00447     long message_start_pos;
00448 
00449     message_start_pos = octstr_search(*body_part, boundary, 0);
00450     if ((content_pos = octstr_case_nsearch(*body_part, octstr_imm("Content-Type:"), 0,
00451             message_start_pos)) < 0 || 
00452             octstr_case_search(*body_part, octstr_imm("application/xml"), 0) < 0) {
00453         return 0;
00454     }
00455 
00456     if (drop_header_true(body_part, content_pos) < 0)
00457         return 0;
00458     
00459     return 1;
00460 }
00461 
00462 /*
00463  * This function actually removes a header (deletes corresponding part from
00464  * the octet string body_part), in addition of all stuff prepending it. So
00465  * deleting start from the octet 0. Content_pos tells where the header starts.
00466  */
00467 static int drop_header_true(Octstr **body_part, long content_pos) 
00468 {
00469     long next_header_pos;
00470 
00471     next_header_pos = -1;
00472     if ((next_header_pos = parse_field_value(*body_part, content_pos)) == 0)
00473         return 0;
00474     if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) == 0)
00475         return 0;
00476     octstr_delete(*body_part, 0, next_header_pos);
00477 
00478     return 1;
00479 }
00480 
00481 static int drop_optional_header(Octstr **body_part, char *name, Octstr *boundary)
00482 {
00483     long content_pos;
00484     long message_start_pos;
00485          
00486     content_pos = -1;
00487     message_start_pos = octstr_search(*body_part, boundary, 0);
00488 
00489     if ((content_pos = octstr_case_nsearch(*body_part, octstr_imm(name), 0, message_start_pos)) < 0)
00490         return 1;
00491     
00492     if (drop_header_true(body_part, content_pos) < 0)
00493         return 0;
00494 
00495     return 1;
00496 }
00497 
00498 /*
00499  * Extension headers are defined in rfc 822, Appendix D, as fields. We must
00500  * parse all rfc 822 headers containing a string "Content". These headers 
00501  * are optional, too. For general definition of message parts see chapter 4.1.
00502  * Specifically: "everything after first null line is message body".
00503  */
00504 static int drop_extension_headers(Octstr **body_part, Octstr *boundary)
00505 {
00506     long content_pos,
00507          next_header_pos;  
00508     long next_content_part_pos;
00509 
00510     next_content_part_pos = octstr_case_search(*body_part, boundary, 0);
00511     do {
00512         if ((content_pos = octstr_case_nsearch(*body_part, octstr_imm("Content"), 0,
00513                 next_content_part_pos)) < 0)
00514             return 1;
00515         if ((next_header_pos = parse_field_name(*body_part, content_pos)) < 0)
00516             return 0;
00517         if ((next_header_pos = parse_field_value(*body_part, 
00518                  next_header_pos)) < 0)
00519         return 0;
00520         if ((next_header_pos = parse_terminator(*body_part, 
00521                  next_header_pos)) == 0)
00522             return 0;
00523     } while (islwspchar(octstr_get_char(*body_part, next_header_pos)));
00524 
00525     octstr_delete(*body_part, content_pos, next_header_pos - content_pos);
00526    
00527     return 1;
00528 }
00529 
00530 static long parse_field_value(Octstr *pap_content, long pos)
00531 {
00532     int c;
00533 
00534     while (!is_cr(c = octstr_get_char(pap_content, pos)) &&
00535          pos < octstr_len(pap_content)) {
00536          ++pos;
00537     }
00538  
00539     if (is_lf(c)) {
00540         if (is_lf(octstr_get_char(pap_content, pos))) {
00541         ++pos;
00542         } else {
00543         return -1;
00544         }
00545     }
00546 
00547     if (pos == octstr_len(pap_content)) {
00548         return -1;
00549     }
00550 
00551     return pos;
00552 }
00553 
00554 static long parse_field_name(Octstr *content, long pos)
00555 {
00556     while (octstr_get_char(content, pos) != ':' && 
00557                pos < octstr_len(content))
00558            ++pos;
00559 
00560     if (pos == octstr_len(content))
00561         return -1;
00562 
00563     return pos;
00564 }
00565 
00566 /*
00567  * Transfer entity headers of a body part (it is, from the content entity) 
00568  * to a header list. Push Message, chapter 6.2.1.10 states that Content-Type
00569  * header is mandatory. 
00570  * Message proper starts after first empty line. We search only to it, and
00571  * remove the line here.
00572  * Return 0 when error, 1 otherwise. In addition, return the modified body
00573  * part and content headers.
00574  */
00575 static int pass_data_headers(Octstr **body_part, List **data_headers)
00576 {
00577     *data_headers = http_create_empty_headers();
00578 
00579     if (check_data_content_type_header(body_part, data_headers, octstr_imm("\r\n\r\n")) == 0) {
00580         warning(0, "MIME: pass_data_headers: Content-Type header missing"); 
00581         return 0;
00582     }
00583         
00584     if (pass_optional_header(body_part, "Content-Transfer-Encoding", data_headers,
00585             octstr_imm("\r\n\r\n")) < 0)
00586         goto operror;
00587     if (pass_optional_header(body_part, "Content-ID", data_headers, octstr_imm("\r\n\r\n")) < 0)
00588         goto operror;
00589     if (pass_optional_header(body_part, "Content-Description", data_headers, 
00590             octstr_imm("\r\n\r\n")) < 0)
00591         goto operror;
00592     if (pass_extension_headers(body_part, data_headers, octstr_imm("\r\n\r\n")) == 0)
00593         goto operror;
00594    
00595     octstr_delete(*body_part, 0, octstr_len(octstr_imm("\r\n")));   
00596 
00597     return 1;
00598 
00599 operror:
00600     warning(0, "MIME: pass_data_headers: an unparsable optional header");
00601     return 0;
00602 }
00603 
00604 /*
00605  * Checks if body_part contains a Content-Type header. Tranfers this header to
00606  * a list content_headers. (Only part before 'boundary').
00607  * Return 1, when Content-Type headers was found, 0 otherwise
00608  */
00609 static int check_data_content_type_header(Octstr **body_part, List **content_headers,
00610                                           Octstr *boundary)
00611 {
00612     long header_pos,
00613          next_header_pos;
00614     Octstr *content_header;
00615     long message_start_pos;
00616 
00617     header_pos = next_header_pos = -1;
00618     content_header = octstr_create("Content-Type");
00619     message_start_pos = octstr_search(*body_part, boundary, 0);
00620     
00621     if ((header_pos = octstr_case_nsearch(*body_part, content_header, 0,
00622              message_start_pos)) < 0) {
00623         goto error;
00624     }
00625     if ((next_header_pos = pass_field_value(body_part, &content_header, 
00626         header_pos + octstr_len(content_header))) < 0) {
00627         goto error;
00628     }
00629     if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) < 0) {
00630         goto error;
00631     }
00632 
00633     octstr_delete(*body_part, header_pos, next_header_pos - header_pos);
00634     gwlist_append(*content_headers, octstr_duplicate(content_header));
00635     octstr_destroy(content_header);
00636 
00637     return 1;
00638 
00639 error:
00640     octstr_destroy(content_header);
00641     return 0;
00642 }
00643 
00644 /*
00645  * We try to find an optional header, so a failure to find one is not an 
00646  * error. Return -1 when error, 0 when header name not found, 1 otherwise.
00647  * Search only until 'boundary'.
00648  */
00649 static int pass_optional_header(Octstr **body_part, char *name, List **content_headers,
00650                                 Octstr *boundary)
00651 {
00652     long content_pos,
00653          next_header_pos;
00654     Octstr *osname,
00655            *osvalue;
00656     long message_start_pos;
00657 
00658     content_pos = next_header_pos = -1;
00659     osname = octstr_create(name);
00660     osvalue = octstr_create("");
00661     message_start_pos = octstr_search(*body_part, boundary, 0);
00662 
00663     if ((content_pos = octstr_case_nsearch(*body_part, osname, 0, message_start_pos)) < 0) 
00664         goto noheader;
00665     if ((next_header_pos = pass_field_value(body_part, &osvalue, 
00666          content_pos + octstr_len(osname))) < 0)
00667         goto error;   
00668     if ((next_header_pos = 
00669          parse_terminator(*body_part, next_header_pos)) == 0)
00670         goto error;
00671 
00672     drop_separator(&osvalue, &next_header_pos);
00673     http_header_add(*content_headers, name, octstr_get_cstr(osvalue));
00674     octstr_delete(*body_part, content_pos, next_header_pos - content_pos);
00675 
00676     octstr_destroy(osname);
00677     octstr_destroy(osvalue);
00678     return 1;
00679 
00680 error:
00681     octstr_destroy(osvalue);
00682     octstr_destroy(osname);
00683     return -1;
00684 
00685 noheader:
00686     octstr_destroy(osvalue);
00687     octstr_destroy(osname);
00688     return 0;
00689 }
00690 
00691 /*
00692  * Remove ':' plus spaces from the header value
00693  */
00694 static void drop_separator(Octstr **header_value, long *pos)
00695 {
00696    long count;
00697 
00698    octstr_delete(*header_value, 0, 1);            /* remove :*/
00699    count = octstr_drop_leading_blanks(header_value);
00700    pos = pos - 1 - count;
00701 } 
00702 
00703 /*
00704  * Return number of spaces dropped.
00705  */
00706 static long octstr_drop_leading_blanks(Octstr **header_value)
00707 {
00708     long count;
00709 
00710     count = 0;
00711     while (octstr_get_char(*header_value, 0) == ' ') {
00712         octstr_delete(*header_value, 0, 1);
00713         ++count;
00714     }
00715 
00716     return count;
00717 }
00718 
00719 /*
00720  * Extension headers are optional, see Push Message, chapter 6.2. Field struc-
00721  * ture is defined in rfc 822, chapter 3.2. Extension headers are defined in 
00722  * rfc 2045, chapter 9, grammar in appendix A. (Only to the next null line).
00723  * Return 0 when error, 1 otherwise.
00724  */
00725 static int pass_extension_headers(Octstr **body_part, List **content_headers, Octstr *boundary)
00726 {
00727     long next_field_part_pos,
00728          count;  
00729     Octstr *header_name,
00730            *header_value; 
00731     long next_content_part_pos;
00732 
00733     header_name = octstr_create("");
00734     header_value = octstr_create("");
00735     count = 0;
00736     next_field_part_pos = 0;
00737     next_content_part_pos = octstr_search(*body_part, boundary, 0);
00738 
00739     do {
00740         if ((octstr_case_nsearch(*body_part, octstr_imm("Content"), 0,
00741                 next_content_part_pos)) < 0)
00742             goto end; 
00743         if ((next_field_part_pos = pass_field_name(body_part, &header_name,
00744                  next_field_part_pos)) < 0)
00745             goto error;
00746         if ((next_field_part_pos = pass_field_value(body_part, &header_value, 
00747                  next_field_part_pos)) < 0)
00748             goto error;
00749         if ((next_field_part_pos = parse_terminator(*body_part, 
00750                  next_field_part_pos)) == 0)
00751             goto error;
00752         drop_separator(&header_value, &next_field_part_pos);
00753         http_header_add(*content_headers, octstr_get_cstr(header_name), 
00754             octstr_get_cstr(header_value));
00755     } while (islwspchar(octstr_get_char(*body_part, next_field_part_pos)));
00756 
00757     octstr_delete(*body_part, 0, next_field_part_pos);
00758 
00759 /*
00760  * An intentional fall-through. We must eventually use a function for memory
00761  * cleaning.
00762  */
00763 end:
00764     octstr_destroy(header_name);
00765     octstr_destroy(header_value);
00766     return 1;
00767 
00768 error:
00769     octstr_destroy(header_name);
00770     octstr_destroy(header_value);
00771     return 0;
00772 }
00773 
00774 static long pass_field_value(Octstr **body_part, Octstr **header, 
00775                              long pos)
00776 {
00777     int c;
00778     long start;
00779     Octstr *field = NULL;
00780 
00781     start = pos;
00782     while (!is_cr(c = octstr_get_char(*body_part, pos)) &&
00783              pos < octstr_len(*body_part)) {
00784         ++pos;
00785     }
00786  
00787     if (pos == octstr_len(*body_part)) {
00788         return -1;
00789     }
00790 
00791     field = octstr_copy(*body_part, start, pos - start);
00792     octstr_append(*header, field);
00793 
00794     octstr_destroy(field);
00795     return pos;
00796 }
00797 
00798 static long pass_field_name(Octstr **body_part, Octstr **field_part, 
00799                             long pos)
00800 {
00801     int c;
00802     long start;
00803     Octstr *name = NULL;
00804 
00805     start = pos;
00806     while (((c = octstr_get_char(*body_part, pos)) != ':') &&
00807             pos < octstr_len(*body_part)) {
00808         ++pos;
00809     }
00810 
00811     if (pos == octstr_len(*body_part)) {
00812         return -1;
00813     }
00814 
00815     name = octstr_copy(*body_part, start, pos - start);
00816     octstr_append(*field_part, name);
00817 
00818     octstr_destroy(name);
00819     return pos;
00820 }
00821 
00822 /* This is actually CRLF epilogue. */
00823 static int parse_epilogue(Octstr **mime_content)
00824 {
00825     long pos;
00826 
00827     if (octstr_len(*mime_content) == 0)
00828         return 0;
00829     
00830     if ((pos = parse_terminator(*mime_content, 0)) < 0)
00831         return -1;
00832 
00833     octstr_delete(*mime_content, 0, octstr_len(*mime_content));
00834     return 0;
00835 }
00836 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.