Index: gwlib/conn.c
===================================================================
RCS file: /home/cvs/gateway/gwlib/conn.c,v
retrieving revision 1.78
diff -u -r1.78 conn.c
--- gwlib/conn.c	29 Dec 2005 19:29:37 -0000	1.78
+++ gwlib/conn.c	17 Feb 2006 05:49:06 -0000
@@ -1348,6 +1348,28 @@
     return preverify_ok;
 }
 
+void use_global_trusted_ca_file(Octstr *ssl_trusted_ca_file)
+{
+    if (ssl_trusted_ca_file != NULL) {
+	if (!SSL_CTX_load_verify_locations(global_ssl_context,
+					   octstr_get_cstr(ssl_trusted_ca_file),
+					   NULL)) {
+	    panic(0, "Failed to load SSL CA file: %s", octstr_get_cstr(ssl_trusted_ca_file));
+	} else {
+	    info(0, "Using CA root certificates from file %s",
+		 octstr_get_cstr(ssl_trusted_ca_file));
+	    SSL_CTX_set_verify(global_ssl_context,
+			       SSL_VERIFY_PEER,
+			       verify_callback);
+	}
+	
+    } else {
+	SSL_CTX_set_verify(global_ssl_context,
+			   SSL_VERIFY_NONE,
+			   NULL);
+    }
+}
+
 void conn_config_ssl (CfgGroup *grp)
 {
     Octstr *ssl_client_certkey_file = NULL;
@@ -1374,25 +1396,8 @@
 
     ssl_trusted_ca_file = cfg_get(grp, octstr_imm("ssl-trusted-ca-file"));
     
-    if (ssl_trusted_ca_file != NULL) {
-	if (!SSL_CTX_load_verify_locations(global_ssl_context,
-					   octstr_get_cstr(ssl_trusted_ca_file),
-					   NULL)) {
-	    panic(0, "Failed to load SSL CA file: %s", octstr_get_cstr(ssl_trusted_ca_file));
-	} else {
-	    info(0, "Using CA root certificates from file %s",
-		 octstr_get_cstr(ssl_trusted_ca_file));
-	    SSL_CTX_set_verify(global_ssl_context,
-			       SSL_VERIFY_PEER,
-			       verify_callback);
-	}
-	
-    } else {
-	SSL_CTX_set_verify(global_ssl_context,
-			   SSL_VERIFY_NONE,
-			   NULL);
-    }
-    
+    use_global_trusted_ca_file(ssl_trusted_ca_file);
+
     octstr_destroy(ssl_client_certkey_file);
     octstr_destroy(ssl_server_cert_file);
     octstr_destroy(ssl_server_key_file);
Index: gwlib/conn.h
===================================================================
RCS file: /home/cvs/gateway/gwlib/conn.h,v
retrieving revision 1.31
diff -u -r1.31 conn.h
--- gwlib/conn.h	11 Feb 2005 15:35:48 -0000	1.31
+++ gwlib/conn.h	17 Feb 2006 05:49:20 -0000
@@ -319,6 +319,11 @@
  */
 void use_global_server_certkey_file(Octstr *certfile, Octstr *keyfile); 
 
+/* Specifies files containing certificates Kannel is willing to trusted when
+ * actins as https clients
+ */
+void use_global_trusted_ca_file(Octstr *ssl_trusted_ca_file);
+
 /* Configures all global variables for client and server SSL mode 
  * from the values specified within the configuration file.
  */
Index: gwlib/mime.c
===================================================================
RCS file: /home/cvs/gateway/gwlib/mime.c,v
retrieving revision 1.12
diff -u -r1.12 mime.c
--- gwlib/mime.c	9 Dec 2005 02:41:14 -0000	1.12
+++ gwlib/mime.c	17 Feb 2006 05:49:30 -0000
@@ -73,6 +73,12 @@
 #include "gwlib/gwlib.h"
 #include "gwlib/mime.h"
 
+struct MIMEEntity {
+    List *headers;
+    List *multiparts;
+    Octstr *body;
+    struct MIMEEntity *start;   /* in case multipart/related */
+};
 
 /********************************************************************
  * Creation and destruction routines.
@@ -111,6 +117,7 @@
 }    
 
 
+
 /********************************************************************
  * Helper routines. Some are derived from gwlib/http.[ch]
  */
@@ -149,6 +156,40 @@
     return 0;
 }
 
+/* This function checks that there is a boundary parameter in the headers
+ * for a multipart MIME object. If not, it is inserted and passed back to caller
+ * in the variable boundary_elem.
+ */
+static void fix_boundary_element(List *headers, Octstr **boundary_elem)
+{
+     /* 
+      * Check if we have an boundary parameter already in the 
+      * Content-Type header. If no, add one, otherwise parse which one 
+      * we should use.
+      * XXX this can be abstracted as function in gwlib/http.[ch].
+      */
+     Octstr *value = http_header_value(headers, octstr_imm("Content-Type"));
+     Octstr *boundary = value ? http_get_header_parameter(value, octstr_imm("boundary")) :
+	  NULL;
+     if (boundary == NULL) {
+	  boundary = octstr_format("_boundary_%d_%ld_%c_%c_bd%d", 
+				   random(), (long)time(NULL), 'A' + (random()%26), 
+				   'a'+(random() % 26), random());
+	  octstr_format_append(value, "; boundary=%S", boundary);
+	  
+	  http_header_remove_all(headers, "Content-Type");
+	  http_header_add(headers, "Content-Type", octstr_get_cstr(value));
+	  http_header_add(headers, "MIME-Version", "1.0");
+     }
+     if (value)
+	  octstr_destroy(value);
+     if (boundary_elem)
+	  *boundary_elem = boundary;
+     else if (boundary)
+	  octstr_destroy(boundary);
+}
+
+
 
 /********************************************************************
  * Mapping function from other data types, mainly Octstr and HTTP.
@@ -156,7 +197,7 @@
 
 static Octstr *mime_entity_to_octstr_real(MIMEEntity *m, unsigned int level)
 {
-    Octstr *mime, *value, *boundary;
+    Octstr *mime, *boundary = NULL;
     List *headers;
     long i;
 
@@ -181,26 +222,9 @@
         goto finished;
     }
 
-    /* 
-     * Check if we have an boundary parameter already in the 
-     * Content-Type header. If no, add one, otherwise parse which one 
-     * we should use.
-     * XXX this can be abstracted as function in gwlib/http.[ch].
-     */
+    /* This call ensures boundary exists, and returns it */
+    fix_boundary_element(m->headers, &boundary);
     headers = http_header_duplicate(m->headers);
-    value = http_header_value(headers, octstr_imm("Content-Type"));
-    boundary = http_get_header_parameter(value, octstr_imm("boundary"));
-    if (boundary == NULL) {
-        boundary = octstr_format("_boundary_%d_%ld_%c_%c_bd%d", 
-            random(), (long)time(NULL), 'A' + (random()%26), 
-            'a'+(random() % 26), random());
-        octstr_format_append(value, "; boundary=%S", boundary);
-
-        http_header_remove_all(headers, "Content-Type");
-        http_header_add(headers, "Content-Type", octstr_get_cstr(value));
-        http_header_add(headers, "MIME-Version", "1.0");
-    }
-    octstr_destroy(value);
 
     /* headers */
     for (i = 0; i < gwlist_len(headers); i++) {
@@ -253,7 +277,6 @@
     return mime;
 }
 
-
 /*
  * This routine is used for mime_[http|octstr]_to_entity() in order to
  * reduce code duplication. Basically the only difference is how the headers
@@ -409,6 +432,9 @@
 
     gw_assert(m != NULL && m->headers != NULL);
 
+    /* Need a fixup before hand over. */
+    fix_boundary_element(m->headers,NULL);
+
     headers = http_header_duplicate(m->headers);
 
     return headers;
@@ -423,6 +449,10 @@
 
     gw_assert(m != NULL && m->headers != NULL);
 
+    /* For non-multipart, return body directly. */
+    if (mime_entity_num_parts(m) == 0)
+	 return octstr_duplicate(m->body);
+
     os = mime_entity_to_octstr(m);
     context = parse_context_create(os);
     e = mime_entity_create();
@@ -446,6 +476,115 @@
     return body;
 }
 
+/* Make a copy of a mime object. recursively. */
+MIMEEntity *mime_entity_duplicate(MIMEEntity *e)
+{
+     MIMEEntity *copy = mime_entity_create();
+     int i, n;
+     
+     mime_replace_headers(copy, e->headers);
+     copy->body = e->body ? octstr_duplicate(e->body) : NULL;
+     
+     for (i = 0, n = gwlist_len(e->multiparts); i < n; i++)
+	  gwlist_append(copy->multiparts, 
+			mime_entity_duplicate(gwlist_get(e->multiparts, i)));
+     return copy;
+}
+
+
+/* Replace top-level MIME headers: Old ones removed completetly */
+void mime_replace_headers(MIMEEntity *e, List *headers)
+{
+     gw_assert(e != NULL);
+     gw_assert(headers != NULL);
+
+     http_destroy_headers(e->headers);
+     e->headers = http_header_duplicate(headers);
+}
+
+
+/* Get number of body parts. Returns 0 if this is not
+ * a multipart object.
+ */
+int mime_entity_num_parts(MIMEEntity *e)
+{
+     gw_assert(e != NULL);
+     return e->multiparts ? gwlist_len(e->multiparts) : 0;
+}
+
+
+/* Append  a new part to list of body parts. Copy is made
+ * Note that if it was not multipart, this action makes it so!
+ */ 
+void mime_entity_add_part(MIMEEntity *e, MIMEEntity *part)
+{
+     gw_assert(e != NULL);
+     gw_assert(part != NULL);
+     
+     gwlist_append(e->multiparts, mime_entity_duplicate(part));
+}
+
+
+/* Get part i in list of body parts. Copy is made*/ 
+MIMEEntity *mime_entity_get_part(MIMEEntity *e, int i)
+{
+     MIMEEntity *m;
+     gw_assert(e != NULL);
+     gw_assert(i >= 0);
+     gw_assert(i < gwlist_len(e->multiparts));
+
+     m = gwlist_get(e->multiparts, i);
+     gw_assert(m);
+     return mime_entity_duplicate(m);
+}
+
+
+/* Remove part i in list of body parts. */ 
+void mime_entity_remove_part(MIMEEntity *e, int i)
+{
+     MIMEEntity *m;
+
+     gw_assert(e != NULL);
+     gw_assert(i >= 0);
+     gw_assert(i < gwlist_len(e->multiparts));
+     
+     
+     m = gwlist_get(e->multiparts, i);
+     gwlist_delete(e->multiparts, i, 1);
+     
+     mime_entity_destroy(m);
+}
+
+/* Replace part i in list of body parts.  Old one will be deleted */ 
+void mime_entity_replace_part(MIMEEntity *e, int i, MIMEEntity *newpart)
+{
+
+     MIMEEntity *m;
+     
+     gw_assert(e != NULL);
+     gw_assert(i >= 0);
+     gw_assert(i < gwlist_len(e->multiparts));
+     
+     m = gwlist_get(e->multiparts, i);
+     gwlist_delete(e->multiparts, i, 1);
+     gwlist_insert(e->multiparts, i, mime_entity_duplicate(newpart));
+
+     mime_entity_destroy(m);
+}
+
+/* Change body element of non-multipart entity.
+ * We don't check that object is multi part. Result is just that 
+ * body will be ignored.
+ */
+void mime_entity_set_body(MIMEEntity *e, Octstr *body)
+{
+     gw_assert(e != NULL);
+     gw_assert(body != NULL);
+
+     if (e->body)
+	  octstr_destroy(e->body);
+     e->body = octstr_duplicate(body);
+}
 
 /********************************************************************
  * Routines for debugging purposes.
Index: gwlib/mime.h
===================================================================
RCS file: /home/cvs/gateway/gwlib/mime.h,v
retrieving revision 1.8
diff -u -r1.8 mime.h
--- gwlib/mime.h	11 Feb 2005 15:35:48 -0000	1.8
+++ gwlib/mime.h	17 Feb 2006 05:49:32 -0000
@@ -93,18 +93,42 @@
 
 /* Define an generic MIME entity structure to be 
  * used for MIME multipart parsing. */
-typedef struct MIMEEntity {
-    List *headers;
-    List *multiparts;
-    Octstr *body;
-    struct MIMEEntity *start;   /* in case multipart/related */
-} MIMEEntity;
+typedef struct MIMEEntity MIMEEntity;
 
 
 /* create and destroy MIME multipart entity */
 MIMEEntity *mime_entity_create(void);
 void mime_entity_destroy(MIMEEntity *e);
 
+/* make a copy of a MIME object. */
+MIMEEntity *mime_entity_duplicate(MIMEEntity *e);
+
+
+/* Replace top-level MIME headers: Old ones removed completetly */
+void mime_replace_headers(MIMEEntity *e, List *headers);
+
+
+/* Get number of body parts. Returns 0 if this is not
+ * a multipart object.
+ */
+int mime_entity_num_parts(MIMEEntity *e);
+
+/* Append  a new part to list of body parts. Copy is made*/ 
+void mime_entity_add_part(MIMEEntity *e, MIMEEntity *part);
+
+/* Get part i in list of body parts. Copy is made*/ 
+MIMEEntity *mime_entity_get_part(MIMEEntity *e, int i);
+
+/* Replace part i in list of body parts.  Old one will be deleted */ 
+void mime_entity_replace_part(MIMEEntity *e, int i, MIMEEntity *newpart);
+
+/* Remove part i in list of body parts. */ 
+void mime_entity_remove_part(MIMEEntity *e, int i);
+
+/* Change body element of non-multipart entity. */
+void mime_entity_set_body(MIMEEntity *e, Octstr *body);
+
+
 /*
  * Parse the given Octstr that contains a normative text representation
  * of the MIME multipart document into our representation strucuture.
