wap_push_pap_mime.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:22k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * Implementation of a gateway oriented mime parser for pap module. This 
  3.  * parser follows proxy rules stated in Push Message, chapter 7.
  4.  *
  5.  * By Aarno Syv鋘en for Wiral Ltd
  6.  */
  7. #include "wap_push_pap_mime.h"
  8. /*****************************************************************************
  9.  *
  10.  * Prototypes for internal functions
  11.  */
  12. static int is_cr(int c);
  13. static int is_lf(int c);
  14. static int islwspchar(int c);
  15. static long octstr_drop_leading_blanks(Octstr **header_value);
  16. static void drop_separator(Octstr **header_value, long *pos);
  17. static int parse_preamble(Octstr **mime_content, Octstr *boundary);
  18. static long parse_transport_padding(Octstr *mime_content, long pos);
  19. static long parse_terminator(Octstr *mime_content, long pos);
  20. static int parse_body_part(Octstr **multipart, Octstr *boundary, 
  21.                             Octstr **body_part);
  22. static int parse_encapsulation(Octstr **mime_content, Octstr *boundary, 
  23.                                Octstr **push_data, List **content_headers,
  24.        Octstr **rdf_content);
  25. static int check_control_headers(Octstr **body_part);
  26. static int check_control_content_type_header(Octstr **body_part);
  27. static int drop_optional_header(Octstr **body_part, char *name);
  28. static int drop_header_true(Octstr **body_part, long content_pos);
  29. static int drop_extension_headers(Octstr **mime_content);
  30. static long parse_field_value(Octstr *pap_content, long pos);
  31. static long parse_field_name(Octstr *pap_content, long pos);
  32. static void octstr_split_by_pos(Octstr **mime_content, Octstr **pap_content, 
  33.                                 long boundary_pos);
  34. static Octstr *make_close_delimiter(Octstr *boundary);
  35. static Octstr *make_part_delimiter(Octstr *boundary);
  36. static Octstr *make_start_delimiter(Octstr *dash_boundary);
  37. static int pass_data_headers(Octstr **body_part, List **data_headers);
  38. static int check_data_content_type_header(Octstr **body_part, 
  39.                                           List **data_headers);
  40. static int pass_optional_header(Octstr **body_part, char *name, 
  41.                                 List **content_headers);
  42. static int pass_extension_headers(Octstr **body_part, List **data_headers);
  43. static long pass_field_name(Octstr **body_part, Octstr **content_header, 
  44.     long pos);
  45. static long pass_field_value(Octstr **body_part, Octstr **content_header, 
  46.                              long pos);
  47. static void parse_epilogue(Octstr **mime_content);
  48. static int parse_tail(Octstr **multipart, Octstr *part_delimiter, 
  49.                       long boundary_pos, long *next_part_pos);
  50. /*****************************************************************************
  51.  *
  52.  * Implementation of the external function, PAP uses MIME type multipart/
  53.  * related to communicate a push message and related control information from 
  54.  * pi to ppg. Mime_parse separates parts of message and in addition returns
  55.  * MIME-part-headers of the content entity. Preamble and epilogue of are dis-
  56.  * carded from control messages, but not from a multipart content entity. 
  57.  * Already parsed parts of mime content are removed. 
  58.  * Multipart/related content type is defined in rfc 2046, chapters 5.1, 5.1.1, 
  59.  * and 5.1.7. Grammar is capitulated in rfc 2046 appendix A and in rfc 822, 
  60.  * appendix D. PAP, chapter 8 defines how MIME multipart message is used by PAP
  61.  * protocol. Functions called by mime_parse remove parsed parts from the mime
  62.  * content. 
  63.  * Input: pointer to mime boundary and mime content
  64.  * Output: Pointer to pap control document and push data, if parsable, NULL
  65.  * otherwise. If there is a capabilities document, pointer to this is return-
  66.  * ed, too. If there is none, pointer to NULL instead. Neither prologue nor 
  67.  * epilogue is returned. 
  68.  * In addition, return 1 if parsing was succesfull, 0 otherwise.
  69.  */
  70. int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content, 
  71.                Octstr **push_data, List **content_headers, 
  72.                Octstr **rdf_content)
  73. {
  74.     int ret;
  75.     *pap_content = NULL;
  76.     *push_data = NULL;
  77.     *content_headers = NULL;
  78.     *rdf_content = NULL;
  79.     if (parse_preamble(&mime_content, boundary) < 0) {
  80.         warning(0, "erroneous preamble");
  81.         return 0;
  82.     }
  83.     if (parse_body_part(&mime_content, boundary, pap_content) <= 0) {
  84.         warning(0, "erroneous control entity");
  85.         return 0;
  86.     }
  87.     if (check_control_headers(pap_content) == 0) {
  88.         warning(0, "erroneous control headers");
  89.         return 0;
  90.     }
  91.     ret = -1;
  92.     if ((ret = parse_encapsulation(&mime_content, boundary, push_data, 
  93.                                    content_headers, rdf_content)) < 0) {
  94.         warning(0, "erroneous content entity (push message)");
  95.         return 0;
  96.     } else if (ret == 0) {
  97.         gw_assert(*rdf_content == NULL);
  98.         parse_epilogue(&mime_content);
  99.         gw_assert(octstr_len(mime_content) == 0);
  100.         return 1;
  101.     }
  102.     if (check_control_headers(rdf_content) == 0) {
  103.         warning(0, "erroneous capacity (rdf) headers");
  104.         return 0;
  105.     }
  106.     parse_epilogue(&mime_content);
  107.     gw_assert(octstr_len(mime_content) == 0);
  108.     
  109.     return 1;
  110. }
  111. /*****************************************************************************
  112.  *
  113.  * Implementation of internal functions
  114.  */
  115. static int is_cr(int c)
  116. {
  117.     return c == 'r';
  118. }
  119. static int is_lf(int c)
  120. {
  121.     return c == 'n';
  122. }
  123. /*
  124.  * Lwspchar is defined in rfc 822, appendix D.
  125.  */
  126. static int islwspchar(int c)
  127. {
  128.     return c == 't' || c == ' ';
  129. }
  130. static int parse_tail(Octstr **multipart, Octstr *delimiter, 
  131.                       long boundary_pos, long *next_part_pos)
  132. {
  133.     *next_part_pos = parse_transport_padding(*multipart, 
  134.          boundary_pos + octstr_len(delimiter));
  135.     if ((*next_part_pos = parse_terminator(*multipart, *next_part_pos)) < 0)
  136.         return -1;
  137.     
  138.     return 0;
  139. }
  140. /*
  141.  * Boundary misses crlf here. This is intentional: Kannel header parsing pro-
  142.  * cess drops this terminator.
  143.  */
  144. static int parse_preamble(Octstr **mime_content, Octstr *boundary)
  145. {
  146.     long boundary_pos,
  147.          next_part_pos;
  148.     Octstr *dash_boundary;
  149.     boundary_pos = next_part_pos = -1;
  150.     dash_boundary = make_start_delimiter(boundary);
  151.     
  152.     if ((boundary_pos = octstr_search(*mime_content, dash_boundary, 0)) < 0)
  153.         goto error;
  154.     if (parse_tail(mime_content, dash_boundary, boundary_pos, 
  155.             &next_part_pos) < 0) 
  156.         goto error;
  157.     octstr_delete(*mime_content, 0, next_part_pos);
  158.     octstr_destroy(dash_boundary);
  159.     return 0;
  160. error:
  161.     octstr_destroy(dash_boundary);
  162.     return -1;
  163. }
  164.     
  165. static long parse_terminator(Octstr *mime_content, long pos)
  166. {
  167.     if (is_cr(octstr_get_char(mime_content, pos)))
  168.         ++pos;
  169.     else 
  170.         return -1;
  171.     if (is_lf(octstr_get_char(mime_content, pos)))
  172.         ++pos;
  173.     else 
  174.         return -1;
  175.     return pos;
  176. }
  177. static long parse_transport_padding(Octstr *mime_content, long pos)
  178. {
  179.     while (islwspchar(octstr_get_char(mime_content, 0)))
  180.         ++pos;
  181.     return pos;
  182. }
  183. /*
  184.  * Splits the first body part away from the multipart message, if there is 
  185.  * more than one left. A body part end with either with another body or with 
  186.  * a close delimiter. If there is more than one body part left, we first split
  187.  * the first one and then remove the stuff separating bodies from the remaind-
  188.  * er. If there is none just remove the ending stuff.
  189.  * Returns 1, there is still another body part in the multipart message
  190.  *         0, if there is none
  191.  *         -1, when parsing error.
  192.  */
  193. static int parse_body_part (Octstr **multipart, Octstr *boundary, 
  194.                             Octstr **body_part)
  195. {
  196.     Octstr *part_delimiter,
  197.            *close_delimiter;
  198.     long boundary_pos,          /* start of the boundary */
  199.          close_delimiter_pos,   /* start of the close delimiter */
  200.          end_pos,               /* end of the message */
  201.          next_part_pos;         /* start of the next part */
  202.  
  203.     part_delimiter = make_part_delimiter(boundary);
  204.     close_delimiter = make_close_delimiter(boundary);
  205.     if ((close_delimiter_pos = octstr_search(*multipart, 
  206.             close_delimiter, 0)) < 0) 
  207.         goto error;
  208.     boundary_pos = octstr_search(*multipart, part_delimiter, 0);
  209.     if (boundary_pos == close_delimiter_pos) {
  210.         if (parse_tail(multipart, close_delimiter, close_delimiter_pos,
  211.                        &end_pos) < 0) {
  212.             goto error;
  213.         } else {
  214.             octstr_delete(*multipart, close_delimiter_pos, 
  215.                           end_pos - close_delimiter_pos);
  216.             *body_part = octstr_duplicate(*multipart);
  217.             octstr_delete(*multipart, 0, end_pos);
  218.         goto last_part;
  219.         }
  220.     }
  221.     *body_part = octstr_create("");
  222.     octstr_split_by_pos(multipart, body_part, boundary_pos);
  223.     if (parse_tail(multipart, part_delimiter, 0, &next_part_pos) < 0) {
  224.         goto error;
  225.     }
  226.     octstr_delete(*multipart, 0, next_part_pos);
  227.     octstr_destroy(part_delimiter);
  228.     octstr_destroy(close_delimiter);
  229.     return 1;
  230. error:
  231.     octstr_destroy(part_delimiter);
  232.     octstr_destroy(close_delimiter);
  233.     return -1;
  234. last_part:
  235.     octstr_destroy(part_delimiter);
  236.     octstr_destroy(close_delimiter);
  237.     return 0;
  238. }
  239. /*
  240.  * PAP, Chapter 8 states that PAP multipart message MUST have at least two 
  241.  * parts, control entity (containing the pap control message) and content 
  242.  * entity (containing the push message). So we must have at least one body
  243.  * part here, and at most two (MIME grammar in rfc 2046, appendix A sets no 
  244.  * limitations here).
  245.  * Returns 1, if rdf content was present
  246.  *         0, if it was absent
  247.  *         -1, when error
  248.  */
  249. static int parse_encapsulation(Octstr **mime_content, Octstr *boundary, 
  250.                                Octstr **push_data, List **content_headers,
  251.                                Octstr **rdf_content)
  252. {
  253.     int ret;
  254.     ret = -1;
  255.     if ((ret = parse_body_part(mime_content, boundary, push_data)) < 0)
  256.         return -1;
  257.     if (pass_data_headers(push_data, content_headers) == 0)
  258.         return -1;
  259.     if (ret == 0) {
  260.         *rdf_content = NULL;
  261.         return 0;
  262.     }
  263.     if ((ret = parse_body_part(mime_content, boundary, rdf_content)) < 0 || 
  264.             ret > 0)
  265.         return -1;
  266.     else if (ret == 0)
  267.         return 1;
  268.     
  269.     return 1;
  270. }
  271. /*
  272.  * Split os2 from os1, boundary being boundary_pos.
  273.  */
  274. static void octstr_split_by_pos(Octstr **os1, Octstr **os2, 
  275.                                 long boundary_pos)
  276. {
  277.     long i;
  278.     
  279.     for (i = 0; i < boundary_pos; i++) {
  280.         octstr_format_append(*os2, "%c", octstr_get_char(*os1, i));   
  281.     }         
  282.     for (i = 0; i < boundary_pos; i++) {
  283.         octstr_delete(*os1, 0, 1);
  284.     }
  285. }
  286. static Octstr *make_close_delimiter(Octstr *boundary) 
  287. {
  288.     Octstr *close_delimiter;
  289.     close_delimiter = make_part_delimiter(boundary);
  290.     octstr_format_append(close_delimiter, "%s", "--");
  291.     return close_delimiter;
  292. }
  293. static Octstr *make_part_delimiter(Octstr *dash_boundary)
  294. {
  295.     Octstr *part_delimiter;
  296.     part_delimiter = octstr_create("");
  297.     octstr_format_append(part_delimiter, "%c", 'r');
  298.     octstr_format_append(part_delimiter, "%c", 'n');
  299.     octstr_format_append(part_delimiter, "%s", "--");
  300.     octstr_append(part_delimiter, dash_boundary);
  301.     
  302.     return part_delimiter;
  303. }
  304. static Octstr *make_start_delimiter(Octstr *dash_boundary)
  305. {
  306.     Octstr *start_delimiter;
  307.     start_delimiter = octstr_create("");
  308.     octstr_format_append(start_delimiter, "%s", "--");
  309.     octstr_append(start_delimiter, dash_boundary);
  310.     return start_delimiter;
  311. }
  312. /*
  313.  * Control entity headers must contain Content-Type: application/xml headers.
  314.  * Rfc 2045, Appendix A does not specify the order of entity headers and states
  315.  * that all rfc 822 headers having a string "Content" in their field-name must
  316.  * be accepted. Rfc 822 grammar is capitulated in appendix D.
  317.  */
  318. static int check_control_headers(Octstr **body_part)
  319. {
  320.     if (check_control_content_type_header(body_part) == 0)
  321.         return 0;
  322.     if (drop_optional_header(body_part, "Content-Transfer-Encoding:") == 0)
  323.         return 0;
  324.     if (drop_optional_header(body_part, "Content-ID:") == 0)
  325.         return 0;
  326.     if (drop_optional_header(body_part, "Content-Description:") == 0)
  327.         return 0;
  328.     if (drop_extension_headers(body_part) == 0)
  329.         return 0;
  330.     return 1;
  331. }
  332. static int check_control_content_type_header(Octstr **body_part)
  333. {
  334.     long content_pos;
  335.     if ((content_pos = octstr_case_search(*body_part, 
  336.             octstr_imm("Content-Type:"), 0)) < 0 || 
  337.             octstr_case_search(*body_part, 
  338.                 octstr_imm("application/xml"), 0) < 0) {
  339.         return 0;
  340.     }
  341.     if (drop_header_true(body_part, content_pos) < 0)
  342.         return 0;
  343.     
  344.     return 1;
  345. }
  346. /*
  347.  * This function actually removes a header (deletes corresponding part from
  348.  * the octet string body_part), in addition of all stuff prepending it. So
  349.  * deleting start from the octet 0. Content_pos tells where the header starts.
  350.  */
  351. static int drop_header_true(Octstr **body_part, long content_pos) 
  352. {
  353.     long next_header_pos;
  354.     next_header_pos = -1;
  355.     if ((next_header_pos = parse_field_value(*body_part, content_pos)) == 0)
  356.         return 0;
  357.     if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) == 0)
  358.         return 0;
  359.     octstr_delete(*body_part, 0, next_header_pos);
  360.     return 1;
  361. }
  362. static int drop_optional_header(Octstr **body_part, char *name)
  363. {
  364.     long content_pos;
  365.          
  366.     content_pos = -1;
  367.     if ((content_pos = octstr_case_search(*body_part, 
  368.              octstr_imm(name), 0)) < 0)
  369.         return 1;
  370.     
  371.     if (drop_header_true(body_part, content_pos) < 0)
  372.         return 0;
  373.     return 1;
  374. }
  375. /*
  376.  * Extension headers are defined in rfc 822, Appendix D, as fields. We must
  377.  * parse all rfc 822 headers containing a string "Content". These headers 
  378.  * are optional, too.
  379.  */
  380. static int drop_extension_headers(Octstr **body_part)
  381. {
  382.     long content_pos,
  383.          next_header_pos;  
  384.     do {
  385.         if ((content_pos = octstr_case_search(*body_part, 
  386.                  octstr_imm("Content"), 0)) < 0)
  387.             return 1;
  388.         if ((next_header_pos = parse_field_name(*body_part, content_pos)) < 0)
  389.             return 0;
  390.         if ((next_header_pos = parse_field_value(*body_part, 
  391.                  next_header_pos)) < 0)
  392.     return 0;
  393.         if ((next_header_pos = parse_terminator(*body_part, 
  394.                  next_header_pos)) == 0)
  395.             return 0;
  396.     } while (islwspchar(octstr_get_char(*body_part, next_header_pos)));
  397.     octstr_delete(*body_part, content_pos, next_header_pos - content_pos);
  398.    
  399.     return 1;
  400. }
  401. static long parse_field_value(Octstr *pap_content, long pos)
  402. {
  403.     int c;
  404.     while (!is_cr(c = octstr_get_char(pap_content, pos)) &&
  405.      pos < octstr_len(pap_content)) {
  406.          ++pos;
  407.     }
  408.  
  409.     if (is_lf(c)) {
  410.         if (is_lf(octstr_get_char(pap_content, pos))) {
  411.     ++pos;
  412.         } else {
  413.     return -1;
  414.         }
  415.     }
  416.     if (pos == octstr_len(pap_content)) {
  417.         return -1;
  418.     }
  419.     return pos;
  420. }
  421. static long parse_field_name(Octstr *content, long pos)
  422. {
  423.     while (octstr_get_char(content, pos) != ':' && 
  424.                pos < octstr_len(content))
  425.            ++pos;
  426.     if (pos == octstr_len(content))
  427.         return -1;
  428.     return pos;
  429. }
  430. /*
  431.  * Transfer entity headers of a body part (it is, from the content entity) 
  432.  * to a header list. Push Message, chapter 6.2.1.10 states that Content-Type
  433.  * header is mandatory. 
  434.  * Return 0 when error, 1 otherwise. In addition, return the modified body
  435.  * part and content headers.
  436.  */
  437. static int pass_data_headers(Octstr **body_part, List **data_headers)
  438. {
  439.     *data_headers = http_create_empty_headers();
  440.     if (check_data_content_type_header(body_part, data_headers) == 0) {
  441.         warning(0, "MIME: pass_data_headers: Content-Type header missing"); 
  442.         return 0;
  443.     }
  444.         
  445.     if (pass_optional_header(body_part, "Content-Transfer-Encoding", 
  446.                              data_headers) < 0)
  447.         goto operror;
  448.     if (pass_optional_header(body_part, "Content-ID", data_headers) < 0)
  449.         goto operror;
  450.     if (pass_optional_header(body_part, "Content-Description", 
  451.                          data_headers) < 0)
  452.         goto operror;
  453.     if (pass_extension_headers(body_part, data_headers) == 0)
  454.         goto operror;
  455.    
  456.     return 1;
  457. operror:
  458.     warning(0, "MIME: pass_data_headers: an unparsable optional header");
  459.     return 0;
  460. }
  461. /*
  462.  * Checks if body_part contains a Content-Type header. Tranfers this header to
  463.  * a list content_headers.
  464.  * Return 1, when Content-Type headers was found, 0 otherwise
  465.  */
  466. static int check_data_content_type_header(Octstr **body_part, 
  467.                                           List **content_headers)
  468. {
  469.     long header_pos,
  470.          next_header_pos;
  471.     Octstr *content_header;
  472.     header_pos = next_header_pos = -1;
  473.     content_header = octstr_create("Content-Type");
  474.     
  475.     if ((header_pos = octstr_case_search(*body_part, content_header, 0)) < 0) {
  476.         goto error;
  477.     }
  478.     if ((next_header_pos = pass_field_value(body_part, &content_header, 
  479.     header_pos + octstr_len(content_header))) < 0) {
  480.         goto error;
  481.     }
  482.     if ((next_header_pos = 
  483.      parse_terminator(*body_part, next_header_pos)) < 0) {
  484.         goto error;
  485.     }
  486.     octstr_delete(*body_part, header_pos, next_header_pos - header_pos);
  487.     list_append(*content_headers, octstr_duplicate(content_header));
  488.     octstr_destroy(content_header);
  489.     return 1;
  490. error:
  491.     octstr_destroy(content_header);
  492.     return 0;
  493. }
  494. /*
  495.  * We try to find an optional header, so a failure to find one is not an 
  496.  * error. Return -1 when error, 0 when header name not found, 1 otherwise.
  497.  */
  498. static int pass_optional_header(Octstr **body_part, char *name, 
  499.                                 List **content_headers)
  500. {
  501.     long content_pos,
  502.          next_header_pos;
  503.     Octstr *osname,
  504.            *osvalue;
  505.     content_pos = next_header_pos = -1;
  506.     osname = octstr_create(name);
  507.     osvalue = octstr_create("");
  508.     if ((content_pos = octstr_case_search(*body_part, osname, 0)) < 0) 
  509.         goto noheader;
  510.     if ((next_header_pos = pass_field_value(body_part, &osvalue, 
  511.      content_pos + octstr_len(osname))) < 0)
  512.         goto error;   
  513.     if ((next_header_pos = 
  514.      parse_terminator(*body_part, next_header_pos)) == 0)
  515.         goto error;
  516.     drop_separator(&osvalue, &next_header_pos);
  517.     http_header_add(*content_headers, name, octstr_get_cstr(osvalue));
  518.     octstr_delete(*body_part, content_pos, next_header_pos - content_pos);
  519.     octstr_destroy(osname);
  520.     octstr_destroy(osvalue);
  521.     return 1;
  522. error:
  523.     octstr_destroy(osvalue);
  524.     octstr_destroy(osname);
  525.     return -1;
  526. noheader:
  527.     octstr_destroy(osvalue);
  528.     octstr_destroy(osname);
  529.     return 0;
  530. }
  531. /*
  532.  * Remove ':' plus spaces from the header value
  533.  */
  534. static void drop_separator(Octstr **header_value, long *pos)
  535. {
  536.    long count;
  537.    octstr_delete(*header_value, 0, 1);            /* remove :*/
  538.    count = octstr_drop_leading_blanks(header_value);
  539.    pos = pos - 1 - count;
  540. /*
  541.  * Return number of spaces dropped.
  542.  */
  543. static long octstr_drop_leading_blanks(Octstr **header_value)
  544. {
  545.     long count;
  546.     count = 0;
  547.     while (octstr_get_char(*header_value, 0) == ' ') {
  548.         octstr_delete(*header_value, 0, 1);
  549.         ++count;
  550.     }
  551.     return count;
  552. }
  553. /*
  554.  * Extension headers are optional, see Push Message, chapter 6.2. Field struc-
  555.  * ture is defined in rfc 822, chapter 3.2. Extension headers are defined in 
  556.  * rfc 2045, chapter 9, grammar in appendix A.
  557.  * Return 0 when error, 1 otherwise.
  558.  */
  559. static int pass_extension_headers(Octstr **body_part, List **content_headers)
  560. {
  561.     long next_field_part_pos,
  562.          count;  
  563.     Octstr *header_name,
  564.            *header_value; 
  565.     header_name = octstr_create("");
  566.     header_value = octstr_create("");
  567.     count = 0;
  568.     next_field_part_pos = 0;
  569.     do {
  570.         if ((octstr_case_search(*body_part, octstr_imm("Content"), 0)) < 0)
  571.             goto end; 
  572.         if ((next_field_part_pos = pass_field_name(body_part, &header_name,
  573.                  next_field_part_pos)) < 0)
  574.             goto error;
  575.         if ((next_field_part_pos = pass_field_value(body_part, &header_value, 
  576.                  next_field_part_pos)) < 0)
  577.             goto error;
  578.         if ((next_field_part_pos = parse_terminator(*body_part, 
  579.                  next_field_part_pos)) == 0)
  580.             goto error;
  581.         drop_separator(&header_value, &next_field_part_pos);
  582.         http_header_add(*content_headers, octstr_get_cstr(header_name), 
  583.             octstr_get_cstr(header_value));
  584.     } while (islwspchar(octstr_get_char(*body_part, next_field_part_pos)));
  585.     octstr_delete(*body_part, 0, next_field_part_pos);
  586. /*
  587.  * An intentional fall-through. We must eventually use a function for memory
  588.  * cleaning.
  589.  */
  590. end:
  591.     octstr_destroy(header_name);
  592.     octstr_destroy(header_value);
  593.     return 1;
  594. error:
  595.     octstr_destroy(header_name);
  596.     octstr_destroy(header_value);
  597.     return 0;
  598. }
  599. static long pass_field_value(Octstr **body_part, Octstr **header, 
  600.                              long pos)
  601. {
  602.     int c;
  603.     while (!is_cr(c = octstr_get_char(*body_part, pos)) &&
  604.              pos < octstr_len(*body_part)) {
  605.         octstr_format_append(*header, "%c", c);
  606.         ++pos;
  607.     }
  608.  
  609.     if (pos == octstr_len(*body_part))
  610.         return -1;
  611.     return pos;
  612. }
  613. static long pass_field_name(Octstr **body_part, Octstr **field_part, 
  614.                             long pos)
  615. {
  616.     int c;
  617.     while (((c = octstr_get_char(*body_part, pos)) != ':') &&
  618.             pos < octstr_len(*body_part)) {
  619.         octstr_format_append(*field_part, "%c", c);
  620.         ++pos;
  621.     }
  622.     if (pos == octstr_len(*body_part))
  623.         return -1;
  624.     return pos;
  625. }
  626. static void parse_epilogue(Octstr **mime_content)
  627. {
  628.     if (octstr_len(*mime_content) == 0)
  629.         return;
  630.     debug("wap.push.pap.mime", 0, "our epilogue was");
  631.     octstr_dump(*mime_content, 0);
  632.     octstr_delete(*mime_content, 0, octstr_len(*mime_content));
  633. }