⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 msg_mime.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@ingroup msg_mime * @CFILE msg_mime.c * * MIME-related headers and MIME multipart bodies for SIP/HTTP/RTSP. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Tue Jun 13 02:57:51 2000 ppessi * * */#include "config.h"#define _GNU_SOURCE 1#include <stddef.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <errno.h>#include <assert.h>#include <sofia-sip/su_alloc.h>#include "msg_internal.h"#include "sofia-sip/msg.h"#include "sofia-sip/msg_mime.h"#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/su_errno.h>#if !HAVE_MEMMEMvoid *memmem(const void *haystack, size_t haystacklen,	     const void *needle, size_t needlelen);#endifsize_t memspn(const void *mem, size_t memlen,	      const void *accept, size_t acceptlen);size_t memcspn(const void *mem, size_t memlen,	       const void *reject, size_t rejectlen);/** Protocol version of MIME */char const msg_mime_version_1_0[] = "MIME/1.0";#include <sofia-sip/msg_parser.h>#include <sofia-sip/msg_mime_protos.h>/** Define a header class for headers without any extra data to copy */#define MSG_HEADER_CLASS_G(c, l, s, kind) \  MSG_HEADER_CLASS(msg_, c, l, s, g_common, kind, msg_generic, msg_generic)#define msg_generic_update NULL/** Define a header class for a msg_list_t kind of header */#define MSG_HEADER_CLASS_LIST(c, l, s, kind) \  MSG_HEADER_CLASS(msg_, c, l, s, k_items, kind, msg_list, msg_list)#define msg_list_update NULL/* ====================================================================== *//** Calculate length of line ending (0, 1 or 2). @internal */#define CRLF_TEST(b) ((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n')/**@ingroup msg_mime * @defgroup msg_multipart MIME Multipart Body * * Representing MIME multipart bodies and their manipulation. * * The #msg_multipart_t is an object for storing MIME multipart message * bodies. It includes message components used for framing and identifying * message parts. Its syntax is defined in  @RFC2046 as follows: * * @code * *   multipart-body := [preamble CRLF] *                     dash-boundary transport-padding CRLF *                     body-part *encapsulation *                     close-delimiter transport-padding *                     [CRLF epilogue] * *   preamble := discard-text * *   discard-text := *(*text CRLF) *                   ; May be ignored or discarded. * *   dash-boundary := "--" boundary *                    ; boundary taken from the value of boundary parameter *                    ; of the Content-Type field. * *   boundary := 0*69<bchars> bcharsnospace * *   bchars := bcharsnospace / " " * *   bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / *                    "+" / "_" / "," / "-" / "." / *                    "/" / ":" / "=" / "?" * *   transport-padding := *LWSP-char *                        ; Composers MUST NOT generate non-zero length *                        ; transport padding, but receivers MUST be able to *                        ; handle padding added by message transports. * *   body-part := <"message" as defined in @RFC822, with all header fields *                 optional, not starting with the specified dash-boundary, *                 and with the delimiter not occurring anywhere in the body *                 part. Note that the semantics of a part differ from the *                 semantics of a message, as described in the text.> * *   encapsulation := delimiter transport-padding CRLF  *                    body-part * *   close-delimiter := delimiter "--" * *   delimiter := CRLF dash-boundary * *   epilogue := discard-text * * @endcode * * @par Parsing a Multipart Message *  * When a message body contains a multipart entity (in other words, it has a * MIME media type of "multipart"), the application can split the multipart * entity into body parts * * The parsing is relatively simple, the application just gives a memory * home object, a Content-Type header object and message body object as an  * argument to msg_multipart_parse() function: * @code *    if (sip->sip_content_type &&  *        strncasecmp(sip->sip_content_type, "multipart/", 10) == 0) { *      msg_multipart_t *mp; * *      if (sip->sip_multipart) *        mp = sip->sip_multipart; *      else *        mp = msg_multipart_parse(msg_home(msg),  *                                 sip->sip_content_type, *                                 (sip_payload_t *)sip->sip_payload); *  *      if (mp) *        ... processing multipart ... *      else *        ... error handling ... *    } * @endcode * * The resulting list of msg_multipart_t structures contain the parts of the * multipart entity, each part represented by a separate #msg_multipart_t * structure. Please note that in order to make error recovery possible, the * parsing is not recursive - if multipart contains another multipart, the * application is responsible for scanning for it and parsing it. * * @par Constructing a Multipart Message * * Constructing a multipart body is a bit more hairy. The application needs * a message object (#msg_t), which is used to buffer the encoding of * multipart components. * * As an example, let us create a "multipart/mixed" multipart entity with a * HTML and GIF contents, and convert it into a #sip_payload_t structure: * @code *   msg_t *msg = msg_create(sip_default_mclass, 0); *   su_home_t *home = msg_home(msg); *   sip_t *sip = sip_object(msg); *   sip_content_type_t *c; *   msg_multipart_t *mp = NULL; *   msg_header_t *h = NULL; *   char *b; *   size_t len, offset; *  *   mp = msg_multipart_create(home, "text/html;level=3", html, strlen(html)); *   mp->mp_next = msg_multipart_create(home, "image/gif", gif, giflen); * *   c = sip_content_type_make(home, "multipart/mixed"); *  *   // Add delimiters to multipart, and boundary parameter to content-type *   if (msg_multipart_complete(home, c, mp) < 0) *     return -1;		// Error * *   // Combine multipart components into the chain *   h = NULL; *   if (msg_multipart_serialize(&h, mp) < 0) *     return -1;		// Error * *   // Encode all multipart components  *   len = msg_multipart_prepare(msg, mp, 0); *   if (len < 0) *     return -1;		// Error * *   pl = sip_payload_create(home, NULL, len); * *   // Copy each element from multipart to pl_data  *   b = pl->pl_data; *   for (offset = 0, h = mp; offset < len; h = h->sh_succ) { *     memcpy(b + offset, h->sh_data, h->sh_len); *     offset += h->sh_len; *   } * @endcode * *//**Create a part for MIME multipart entity. * * The function msg_multipart_create() allocates a new #msg_multipart_t * object from memory home @a home. If @a content_type is non-NULL, it makes * a #msg_content_type_t header object and adds the header to the * #msg_multipart_t object. If @a dlen is nonzero, it allocates a * msg_payload_t structure of @a dlen bytes for the payload of the newly * created #msg_multipart_t object. If @a data is non-NULL, it copies the @a * dlen bytes of of data to the payload of the newly created * #msg_multipart_t object. * * @return A pointer to the newly created #msg_multipart_t object, or NULL * upon an error. */msg_multipart_t *msg_multipart_create(su_home_t *home,				      char const *content_type,				      void const *data,				      isize_t dlen){  msg_multipart_t *mp;  mp = (msg_multipart_t *)msg_header_alloc(home, msg_multipart_class, 0);  if (mp) {    if (content_type)      mp->mp_content_type = msg_content_type_make(home, content_type);    if (dlen)      mp->mp_payload = msg_payload_create(home, data, dlen);    if ((!mp->mp_content_type && content_type) ||	(!mp->mp_payload && dlen)) {      su_free(home, mp->mp_content_type);      su_free(home, mp->mp_payload);      su_free(home, mp);      mp = NULL;    }  }  return mp;}/** Convert boundary parameter to a search string. */static char *msg_multipart_boundary(su_home_t *home, char const *b){  char *boundary;  if (!b || !(boundary = su_alloc(home, 2 + 2 + strlen(b) + 2 + 1)))    return NULL;  strcpy(boundary, CR LF "--");  if (b[0] == '"') /* " See http://bugzilla.gnome.org/show_bug.cgi?id=134216 */    msg_unquote(boundary + 4, b);  else    strcpy(boundary + 4, b);  strcat(boundary + 4, CR LF);  return boundary;}/** Boundary chars. */static char const bchars[] = "'()+_,-./:=?""0123456789""ABCDEFGHIJKLMNOPQRSTUVWXYZ""abcdefghijklmnopqrstuvwxyz"" ";#define bchars_len (sizeof(bchars) - 1)/** Search for a suitable boundary from MIME. */static char *msg_multipart_search_boundary(su_home_t *home, char const *p, size_t len){  size_t m;  unsigned crlf;  char const *end = p + len;  char *boundary;  if (len < 2)    return NULL;  /* Boundary looks like LF -- string SP* [CR] LF */  if (memcmp("--", p, 2) == 0) {    /* We can be at boundary beginning, there is no CR LF */    m = 2 + memspn(p + 2, len - 2, bchars, bchars_len);    if (m + 2 >= len)      return NULL;    crlf = p[m] == '\r' ? 1 + (p[m + 1] == '\n') : (p[m] == '\n');    while (p[m - 1] == ' ' || p[m - 1] == '\t')      m--;    if (m > 2 && crlf) {      boundary = su_alloc(home, 2 + m + 2 + 1);      if (boundary) {	memcpy(boundary, CR LF, 2);	memcpy(boundary + 2, p, m);	strcpy(boundary + m + 2, CR LF);      }      return boundary;    }  }   /* Look for LF -- */  for (;(p = memmem(p, end - p, LF "--", 3)); p += 3) {    len = end - p;    m = 3 + memspn(p + 3, len - 3, bchars, bchars_len);    if (m + 2 >= len)      return NULL;    crlf = p[m] == '\r' ? 1 + (p[m + 1] == '\n') : (p[m] == '\n');    while (p[m - 1] == ' ' || p[m - 1] == '\t')      m--;    m--;    if (m > 2 && crlf) {      boundary = su_alloc(home, 2 + m + 2 + 1);      if (boundary) {	memcpy(boundary, CR LF, 2);	memcpy(boundary + 2, p + 1, m);	strcpy(boundary + 2 + m, CR LF);      }      return boundary;    }  }  return NULL;}/** Parse a MIME multipart. * * The function msg_multipart_parse() parses a MIME multipart message. The * common syntax of multiparts is described in @RFC2046 (section 7). * * @param[in,out] home home for allocating structures  * @param[in]     c    content-type header for multipart  * @param[in]     pl   payload structure for multipart  * * After parsing, the @a pl will contain the plain-text preamble (if any). * * @note If no @b Content-Type header is given, the msg_multipart_parse() * tries to look for a suitable boundary. Currently, it takes first * boundary-looking string and uses that, so it can be fooled with, for * instance, signature @c "--Pekka". */msg_multipart_t *msg_multipart_parse(su_home_t *home,				     msg_content_type_t const *c,				     msg_payload_t *pl){  msg_multipart_t *mp = NULL, *all = NULL, **mmp = &all;  /* Dummy msg object */  msg_t msg[1] = {{{ SU_HOME_INIT(msg) }}};  size_t len, m, blen;  char *boundary, *p, *next, save;  char const *b, *end;  msg_param_t param;  p = pl->pl_data; len = pl->pl_len; end = p + len;  su_home_init(msg_home(msg));  msg->m_class = msg_multipart_mclass;  msg->m_tail = &msg->m_chain;  /* Get boundary from Content-Type */  if (c && (param = msg_header_find_param(c->c_common, "boundary=")))    boundary = msg_multipart_boundary(msg_home(msg), param);  else    boundary = msg_multipart_search_boundary(msg_home(msg), p, len);  if (!boundary)    return NULL;  m = strlen(boundary) - 2, blen = m - 1;  /* Find first delimiter */  if (memcmp(boundary + 2, p, m - 2) == 0)    b = p, p = p + m - 2, len -= m - 2;  else if ((p = memmem(p, len, boundary + 1, m - 1))) {    if (p != pl->pl_data && p[-1] == '\r')      b = --p, p = p + m, len -= m;    else      b = p, p = p + m - 1, len -= m - 1;  }  else {    su_home_deinit(msg_home(msg));    return NULL;  }  /* Split multipart into parts */  for (;;) {    while (p[0] == ' ')       p++;    p += p[0] == '\r' ? 1 + (p[1] == '\n') : (p[0] == '\n');    len = end - p;    if (len < blen)      break;    next = memmem(p, len, boundary + 1, m = blen);    if (!next)      break;			/* error */    if (next != p && next[-1] == '\r')      next--, m++;    mp = (msg_multipart_t *)msg_header_alloc(msg_home(msg), msg_multipart_class, 0);    if (mp == NULL)      break;			/* error */    *mmp = mp; mmp = &mp->mp_next;    /* Put delimiter transport-padding CRLF here */    mp->mp_common->h_data = b;    mp->mp_common->h_len = p - b;    /* .. and body-part here */    mp->mp_data = p;    mp->mp_len = next - p;    if (next[m] == '-' && next[m + 1] == '-') {      /* We found close-delimiter */      assert(mp);      if (!mp)	break;			/* error */      mp->mp_close_delim = (msg_payload_t *)	msg_header_alloc(msg_home(msg), msg_payload_class, 0);      if (!mp->mp_close_delim)	break;			/* error */      /* Include also transport-padding and epilogue in the close-delimiter */      mp->mp_close_delim->pl_data = next;      mp->mp_close_delim->pl_len = p + len - next;      break;    }    b = next; p = next + m;   }  if (!mp || !mp->mp_close_delim) {    su_home_deinit(msg_home(msg));    /* Delimiter error */    return NULL;  }  /* Parse each part */  for (mp = all; mp; mp = mp->mp_next) {    msg->m_object = (msg_pub_t *)mp; p = mp->mp_data; next = p + mp->mp_len;    if (msg->m_tail)      mp->mp_common->h_prev = msg->m_tail,	*msg->m_tail = (msg_header_t *)mp;    msg->m_chain = (msg_header_t *)mp;    msg->m_tail = &mp->mp_common->h_succ;    save = *next; *next = '\0';	/* NUL-terminate this part */    for (len = next - p; len > 0; len -= m, p += m) {      if (IS_CRLF(p[0])) {	m = msg_extract_separator(msg, (msg_pub_t*)mp, p, len, 1);	assert(m > 0);	p += m; len -= m;	if (len > 0) {	  m = msg_extract_payload(msg, (msg_pub_t*)mp, NULL, len, p, len, 1);	  assert(m > 0);	  assert(len == m);	}	break;      }      m = msg_extract_header(msg, (msg_pub_t*)mp, p, len, 1);      if (m <= 0) {	assert(m > 0);	/* Xyzzy */      }    }    *next = save; /* XXX - Should we leave the payload NUL-terminated? */  }  /* Postprocess */  blen = strlen(boundary);  for (mp = all; mp; mp = mp->mp_next) {    mp->mp_data = boundary;     mp->mp_len = blen;    assert(mp->mp_payload || mp->mp_separator);    if (mp->mp_close_delim) {      msg_header_t **tail;      if (mp->mp_payload)	tail = &mp->mp_payload->pl_common->h_succ;      else	tail = &mp->mp_separator->sep_common->h_succ;      assert(msg->m_chain == (msg_header_t *)mp);      assert(*tail == NULL);      mp->mp_close_delim->pl_common->h_prev = tail;      *tail = (msg_header_t *)mp->mp_close_delim;    }  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -