Index: pjproject/trunk/pjsip/include/pjsip/sip_msg.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_msg.h	(revision 3240)
+++ pjproject/trunk/pjsip/include/pjsip/sip_msg.h	(revision 3241)
@@ -516,7 +516,41 @@
     pj_str_t type;	    /**< Media type. */
     pj_str_t subtype;	    /**< Media subtype. */
-    pj_str_t param;	    /**< Media type parameters (concatenated). */
+    pjsip_param param;	    /**< Media type parameters */
 } pjsip_media_type;
 
+
+/**
+ * Initialize the media type with the specified type and subtype string.
+ *
+ * @param mt		The media type.
+ * @param type		Optionally specify the media type.
+ * @param subtype	Optionally specify the media subtype.
+ */
+PJ_DECL(void) pjsip_media_type_init(pjsip_media_type *mt,
+				    pj_str_t *type,
+				    pj_str_t *subtype);
+
+/**
+ * Initialize the media type with the specified type and subtype string.
+ *
+ * @param mt		The media type.
+ * @param type		Optionally specify the media type.
+ * @param subtype	Optionally specify the media subtype.
+ */
+PJ_DECL(void) pjsip_media_type_init2(pjsip_media_type *mt,
+				     char *type,
+				     char *subtype);
+
+/**
+ * Compare two media types.
+ *
+ * @param mt1		The first media type.
+ * @param mt2		The second media type.
+ *
+ * @return		Zero if both media types are equal, -1 if mt1 < mt2,
+ * 			1 if mt1 > mt2.
+ */
+PJ_DECL(int) pjsip_media_type_cmp(const pjsip_media_type *mt1,
+				  const pjsip_media_type *mt2);
 
 /**
@@ -530,4 +564,17 @@
 				  pjsip_media_type *dst,
 				  const pjsip_media_type *src);
+
+/**
+ * Print media type to the specified buffer.
+ *
+ * @param buf		Destination buffer.
+ * @param len		Length of the buffer.
+ * @param mt		The media type to be printed.
+ *
+ * @return		The number of characters printed to the buffer, or -1
+ * 			if there's not enough space in the buffer.
+ */
+PJ_DECL(int) pjsip_media_type_print(char *buf, unsigned len,
+				    const pjsip_media_type *mt);
 
 /**
Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_xfer.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-ua/sip_xfer.c	(revision 3240)
+++ pjproject/trunk/pjsip/src/pjsip-ua/sip_xfer.c	(revision 3241)
@@ -375,4 +375,5 @@
     pjsip_tx_data *tdata;
     pjsip_xfer *xfer;
+    pjsip_param *param;
     const pj_str_t reason = { "noresource", 10 };
     char *body;
@@ -423,11 +424,15 @@
     /* Create SIP message body. */
     msg_body = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_msg_body);
-    msg_body->content_type.type = STR_MESSAGE;
-    msg_body->content_type.subtype = STR_SIPFRAG;
-    msg_body->content_type.param = STR_SIPFRAG_VERSION;
+    pjsip_media_type_init(&msg_body->content_type, (pj_str_t*)&STR_MESSAGE,
+			  (pj_str_t*)&STR_SIPFRAG);
     msg_body->data = body;
     msg_body->len = bodylen;
     msg_body->print_body = &pjsip_print_text_body;
     msg_body->clone_data = &pjsip_clone_text_data;
+
+    param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
+    param->name = pj_str("version");
+    param->value = pj_str("2.0");
+    pj_list_push_back(&msg_body->content_type.param, param);
 
     /* Attach sipfrag body. */
Index: pjproject/trunk/pjsip/src/pjsip/sip_msg.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_msg.c	(revision 3240)
+++ pjproject/trunk/pjsip/src/pjsip/sip_msg.c	(revision 3241)
@@ -23,4 +23,5 @@
 #include <pjsip/sip_errno.h>
 #include <pj/ctype.h>
+#include <pj/guid.h>
 #include <pj/string.h>
 #include <pj/pool.h>
@@ -146,5 +147,6 @@
 
 static pj_str_t status_phrase[710];
-static int print_media_type(char *buf, const pjsip_media_type *media);
+static int print_media_type(char *buf, unsigned len,
+			    const pjsip_media_type *media);
 
 static int init_status_phrase()
@@ -490,12 +492,10 @@
 
 	    /* Add Content-Type header. */
-	    if ( (end-p) < 24 + media->type.slen + media->subtype.slen + 
-			   media->param.slen) 
-	    {
+	    if ( (end-p) < 24 + media->type.slen + media->subtype.slen) {
 		return -1;
 	    }
 	    pj_memcpy(p, ctype_hdr.ptr, ctype_hdr.slen);
 	    p += ctype_hdr.slen;
-	    p += print_media_type(p, media);
+	    p += print_media_type(p, end-p, media);
 	    *p++ = '\r';
 	    *p++ = '\n';
@@ -603,4 +603,63 @@
  * Media type
  */
+/*
+ * Init media type.
+ */
+PJ_DEF(void) pjsip_media_type_init( pjsip_media_type *mt,
+				    pj_str_t *type,
+				    pj_str_t *subtype)
+{
+    pj_bzero(mt, sizeof(*mt));
+    pj_list_init(&mt->param);
+    if (type)
+	mt->type = *type;
+    if (subtype)
+	mt->subtype = *subtype;
+}
+
+PJ_DEF(void) pjsip_media_type_init2( pjsip_media_type *mt,
+				     char *type,
+				     char *subtype)
+{
+    pj_str_t s_type, s_subtype;
+
+    if (type) {
+	s_type = pj_str(type);
+    } else {
+	s_type.ptr = NULL;
+	s_type.slen = 0;
+    }
+
+    if (subtype) {
+	s_subtype = pj_str(subtype);
+    } else {
+	s_subtype.ptr = NULL;
+	s_subtype.slen = 0;
+    }
+
+    pjsip_media_type_init(mt, &s_type, &s_subtype);
+}
+
+/*
+ * Compare two media types.
+ */
+PJ_DEF(int) pjsip_media_type_cmp( const pjsip_media_type *mt1,
+				  const pjsip_media_type *mt2)
+{
+    int rc;
+
+    PJ_ASSERT_RETURN(mt1 && mt2, 1);
+
+    rc = pj_stricmp(&mt1->type, &mt2->type);
+    if (rc) return rc;
+
+    rc = pj_stricmp(&mt1->subtype, &mt2->subtype);
+    if (rc) return rc;
+
+    rc = pjsip_param_cmp(&mt1->param, &mt2->param, 0);
+
+    return rc;
+}
+
 PJ_DEF(void) pjsip_media_type_cp( pj_pool_t *pool,
 				  pjsip_media_type *dst,
@@ -610,5 +669,5 @@
     pj_strdup(pool, &dst->type,    &src->type);
     pj_strdup(pool, &dst->subtype, &src->subtype);
-    pj_strdup(pool, &dst->param,   &src->param);
+    pjsip_param_clone(pool, &dst->param, &src->param);
 }
 
@@ -1264,4 +1323,5 @@
     pj_bzero(mem, sizeof(pjsip_ctype_hdr));
     init_hdr(hdr, PJSIP_H_CONTENT_TYPE, &ctype_hdr_vptr);
+    pj_list_init(&hdr->media.param);
     return hdr;
 
@@ -1274,7 +1334,10 @@
 }
 
-static int print_media_type(char *buf, const pjsip_media_type *media)
+static int print_media_type(char *buf, unsigned len,
+			    const pjsip_media_type *media)
 {
     char *p = buf;
+    pj_ssize_t printed;
+    const pjsip_parser_const_t *pc;
 
     pj_memcpy(p, media->type.ptr, media->type.slen);
@@ -1284,10 +1347,21 @@
     p += media->subtype.slen;
 
-    if (media->param.slen) {
-	pj_memcpy(p, media->param.ptr, media->param.slen);
-	p += media->param.slen;
-    }
+    pc = pjsip_parser_const();
+    printed = pjsip_param_print_on(&media->param, p, buf+len-p,
+				   &pc->pjsip_TOKEN_SPEC,
+				   &pc->pjsip_TOKEN_SPEC, ';');
+    if (printed < 0)
+	return -1;
+
+    p += printed;
 
     return p-buf;
+}
+
+
+PJ_DEF(int) pjsip_media_type_print(char *buf, unsigned len,
+				   const pjsip_media_type *media)
+{
+    return print_media_type(buf, len, media);
 }
 
@@ -1300,6 +1374,5 @@
 
     if ((pj_ssize_t)size < hname->slen + 
-			   hdr->media.type.slen + hdr->media.subtype.slen + 
-			   hdr->media.param.slen + 8)
+			   hdr->media.type.slen + hdr->media.subtype.slen + 8)
     {
 	return -1;
@@ -1311,5 +1384,5 @@
     *p++ = ' ';
 
-    len = print_media_type(p, &hdr->media);
+    len = print_media_type(p, buf+size-p, &hdr->media);
     p += len;
 
@@ -1324,5 +1397,5 @@
     pj_strdup(pool, &hdr->media.type, &rhs->media.type);
     pj_strdup(pool, &hdr->media.subtype, &rhs->media.subtype);
-    pj_strdup(pool, &hdr->media.param, &rhs->media.param);
+    pjsip_param_clone(pool, &hdr->media.param, &rhs->media.param);
     return hdr;
 }
@@ -2079,10 +2152,6 @@
 
     /* Duplicate content-type */
-    pj_strdup(pool, &dst_body->content_type.type, 
-		    &src_body->content_type.type);
-    pj_strdup(pool, &dst_body->content_type.subtype, 
-		    &src_body->content_type.subtype);
-    pj_strdup(pool, &dst_body->content_type.param,
-		    &src_body->content_type.param);
+    pjsip_media_type_cp(pool, &dst_body->content_type,
+		        &src_body->content_type);
 
     /* Duplicate data. */
@@ -2130,5 +2199,5 @@
     pj_strdup(pool, &body->content_type.type, type);
     pj_strdup(pool, &body->content_type.subtype, subtype);
-    body->content_type.param.slen = 0;
+    pj_list_init(&body->content_type.param);
 
     body->data = pj_pool_alloc(pool, text->slen);
Index: pjproject/trunk/pjsip/src/test/msg_test.c
===================================================================
--- pjproject/trunk/pjsip/src/test/msg_test.c	(revision 3240)
+++ pjproject/trunk/pjsip/src/test/msg_test.c	(revision 3241)
@@ -482,4 +482,5 @@
     pjsip_via_hdr *via;
     pjsip_generic_string_hdr *generic;
+    pjsip_param *prm;
     pj_str_t str;
 
@@ -570,5 +571,8 @@
     pj_strdup2(pool, &ctype->media.type, "text");
     pj_strdup2(pool, &ctype->media.subtype, "html");
-    pj_strdup2(pool, &ctype->media.param, ";charset=ISO-8859-4");
+    prm = PJ_POOL_ALLOC_T(pool, pjsip_param);
+    prm->name = pj_str("charset");
+    prm->value = pj_str("ISO-8859-4");
+    pj_list_push_back(&ctype->media.param, prm);
 
     /* "Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n" */
@@ -1591,4 +1595,5 @@
 {
     pjsip_ctype_hdr *hdr = (pjsip_ctype_hdr*)h;
+    const pjsip_param *prm;
 
     if (h->type != PJSIP_H_CONTENT_TYPE)
@@ -1604,8 +1609,23 @@
      * pjsip will print the parameter unescaped.
      */
-    PJ_TODO(FIX_PARAMETER_IN_MEDIA_TYPE);
-
-    if (pj_strcmp2(&hdr->media.param, ";" GENERIC_PARAM_PARSED))
-	return -1940;
+    prm = hdr->media.param.next;
+    if (prm == &hdr->media.param) return -1940;
+    if (pj_strcmp2(&prm->name, "p0")) return -1941;
+    if (pj_strcmp2(&prm->value, "a")) return -1942;
+
+    prm = prm->next;
+    if (prm == &hdr->media.param) return -1950;
+    if (pj_strcmp2(&prm->name, "p1")) { PJ_LOG(3,("", "%.*s", (int)prm->name.slen, prm->name.ptr)); return -1951; }
+    if (pj_strcmp2(&prm->value, "\"ab:;cd\"")) { PJ_LOG(3,("", "%.*s", (int)prm->value.slen, prm->value.ptr)); return -1952; }
+
+    prm = prm->next;
+    if (prm == &hdr->media.param) return -1960;
+    if (pj_strcmp2(&prm->name, "p2")) return -1961;
+    if (pj_strcmp2(&prm->value, "ab:cd")) return -1962;
+
+    prm = prm->next;
+    if (prm == &hdr->media.param) return -1970;
+    if (pj_strcmp2(&prm->name, "p3")) return -1971;
+    if (pj_strcmp2(&prm->value, "")) return -1972;
 
     return 0;
