Home | History | Annotate | Download | only in liblcl
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /* Copyright (c) 2000, Sun Microsystems, Inc. All rights reserved. */
     22 
     23 #pragma ident	"@(#)lcl_parse_header.c	1.3	00/01/07 SMI"
     24 
     25 /*
     26  * Determine velues by parsing mime header, then update the
     27  * attribute values. It override the default values in DB.
     28  */
     29 #include <string.h>
     30 #include <stdlib.h>
     31 
     32 #include "lcl.h"
     33 #include "lcl_internal.h"
     34 
     35 #define ENCODE_BEGIN		"=?"
     36 #define CHARSET_DONE		'?'
     37 #define ENCODING_DONE		'?'
     38 #define ENCODE_DONE		"?="
     39 
     40 #define ENCODE_BASE64		"?B?"
     41 #define	ENCODE_QP		"?Q?"
     42 #define ENCODE_NONE		 0
     43 
     44 #define MIME_VERSION		"Mime-Version"
     45 #define CONTENT_TYPE		"Content-Type"
     46 #define TYPE_TEXTPLAIN		"Text/Plain"
     47 #define CHARSET			"charset"
     48 
     49 #define X_SUN_ATTACHEMENT	"X-sun-attachment"
     50 #define X_SUN			"X-Sun"
     51 #define X_SUN_CHARSET		"X-Sun-Charset"
     52 
     53 typedef enum {False=0, True = 1} Bool;
     54 #define Private static;
     55 
     56 /*
     57  * Public functions.
     58  * ----------------
     59  * 1.
     60  * char* _lcl_parse_body(char* h, // unparsed header:in
     61  *		         char* b  // unparsed body:in
     62  *		         LclMailType type // Mail type:in
     63  *        )
     64  * returns the parsed(converted) Body
     65  *
     66  * 2.
     67  * char* _lcl_parse_header(char* h, // unparsed header:in
     68  *			   char* b, // unparsed body:in
     69  *                         LclMailType *type // Mail type:inout
     70  *                         char** charset // charset of parsed header:out
     71  *        )
     72  * returns the parsed(converted) header
     73  *
     74  * 3
     75  * returns Mail type.
     76  * LclMailType _lcl_get_body_charset(char* h, // unparsed header:in
     77  *			   char* b, // unparsed body:in
     78  *			   LclMailType type // Mail type:in
     79  *                         char** charset // charset of parsed header:out
     80  * charset CAN BE NULL if it is UNKNOWN.(or NOT IMPLEMENTED YET ;-)
     81  *
     82  */
     83 
     84 /*/// Need lcld for all functions for MT */
     85 
     86 static Bool
     87 _is_mime_header(char* h){
     88     Bool is_mime = False ;
     89     if(!h) return False ;
     90     if(strcasestr(h, MIME_VERSION) ||
     91        strcasestr(h, CONTENT_TYPE) ||
     92        (strstr(h, ENCODE_BEGIN) && strstr(h, ENCODE_DONE) &&
     93 	(strcasestr(h, ENCODE_BASE64) || strcasestr(h, ENCODE_QP)))
     94       ) {
     95       is_mime = True ;
     96     }
     97     return is_mime ;
     98 }
     99 
    100 static Bool
    101 _is_V3_header(char* h){
    102     /*
    103      * case 1: X-Sun-Attachment is found.
    104      * case 2: Header looks like 822, but other X-Sun- header is found.
    105      * case 3: Header looks like 822, but X-Sun-Charset is found in Body.
    106      * otherwise it should be 822.
    107      */
    108     if(h && strcasestr(h, X_SUN)){
    109 	return True ;
    110     }
    111     /* case 3 is missing */
    112     return False ; /* should be 822 */
    113 }
    114 
    115 static char*
    116 _lcl_V3_header(char* h){
    117     int len = strlen(h);
    118     char* orig = malloc(len +1);
    119     memcpy(orig, h, len+1);
    120     return orig ; /* Waiting for full implementation */
    121 }
    122 
    123 static char*
    124 _lcl_822_header(char* h){
    125     int len = strlen(h);
    126     char* orig = malloc(len +1);
    127     memcpy(orig, h, len+1);
    128     return orig ; /* Waiting for full implementation */
    129 }
    130 
    131 static char *
    132 copy_next_line(char** cur_p, char* copy_p, int *len_p){
    133     char *p = *cur_p ;
    134     char* next_line = strchr(p, '\n') ;
    135     if(next_line){
    136 	int len = next_line - p ;
    137 	strncpy(copy_p, p, len);
    138 	*cur_p = next_line ;
    139 	*len_p = len ;
    140 	return copy_p;
    141     }
    142     return 0 ;
    143 }
    144 
    145 static char *
    146 dup_next_line(char** cur_p, int *len_p){
    147     char *p = *cur_p ;
    148     char* next_line = strchr(p, '\n') ;
    149     if(next_line){
    150 	int len = next_line - p ;
    151 	char *buf = (char*)malloc(len + 1);
    152 	strncpy(buf, p, len);
    153 	buf[len] = (char)0;
    154 	*cur_p = next_line ;
    155 	*len_p = len ;
    156 	return buf;
    157     }
    158     return 0 ;
    159 }
    160 
    161 
    162 static char*
    163 _lcl_mime_header(char* h, char **charset){
    164     int len = strlen(h) ;
    165     char* orig = malloc(len +1);
    166     char* buf = malloc(len*10/8); /* XXX guestimation to be safer side. */
    167     memcpy(orig, h, len+1);
    168     MIME_strHeaderDecode(orig, buf, len, charset);
    169     free(orig);
    170     return buf ;
    171 }
    172 /*
    173  * returns Mail type.
    174  * LclMailType _lcl_get_body_charset(char* t, // unparsed taggedtext:in
    175  * 		                     LclMailType *type // Mail type:out
    176  *                                   char** charset // charset of parsed header:out
    177  *        )
    178  */
    179  LclMailType
    180 _lcl_get_taggedtext_charset(char* t, LclMailType type, char** charset){
    181     if( type == LclV3Type ||
    182        (type == LclUnKnownType && _is_V3_header(t) == True)){
    183 
    184     } else { /* Must be MIME - No 822type for tagged text*/
    185 	/*
    186 	 * Body charset information is in header.
    187 	 */
    188 	char *p = strcasestr(t, "\nContent-Type:");
    189 	if(!p){
    190 	    char *x = strcasestr(t, "Content-Type:");
    191 	    if(x == t)
    192 		p = t ;
    193 	}
    194 	if(p){
    195 	    char* eoline = strchr(p+1, '\n');
    196 	    if(eoline){
    197 		 p = strcasestr(p+14, "charset=") ;
    198 		 if(p && (p < eoline)){
    199 		     int len = eoline - (p+=8) ; /* skip "charset=" */
    200 		     *charset = malloc(len +1);
    201 		     strncpy(*charset, p, len);
    202 		     (*charset)[len] = NULL ;
    203 		 } else *charset = NULL ;
    204 	     } else *charset = NULL ;
    205 	} else *charset = NULL ;
    206 	return LclMIMEType ;
    207     }
    208 }
    209 /*
    210  * returns Mail type.
    211  * LclMailType _lcl_get_body_charset(char* h, // unparsed header:in
    212  *			   char* b, // unparsed body:in
    213  *                         LclMailType *type // Mail type:out
    214  *                         char** charset // charset of parsed header:out
    215  *        )
    216  */
    217  LclMailType
    218 _lcl_get_body_charset(char* h, char* b, LclMailType type, char** charset){
    219     if( type == LclMIMEType ||
    220        (type == LclUnKnownType && _is_mime_header(h) == True)){
    221 	/*
    222 	 * Body charset information is in header.
    223 	 */
    224 	char *p = strcasestr(h, "\nContent-Type:");
    225 	if(!p){
    226 	    char *x = strcasestr(h, "Content-Type:");
    227 	    if(x == h)
    228 		p = h ;
    229 	}
    230 	if(p){
    231 	    char* eoline = strchr(p+1, '\n');
    232 	    if(eoline){
    233 		 p = strcasestr(p+14, "charset=") ;
    234 		 if(p && (p < eoline)){
    235 		     int len = eoline - (p+=8) ; /* skip "charset=" */
    236 		     *charset = malloc(len +1);
    237 		     strncpy(*charset, p, len);
    238 		     (*charset)[len] = NULL ;
    239 		 } else *charset = NULL ;
    240 	     } else *charset = NULL ;
    241 	} else *charset = NULL ;
    242 	return LclMIMEType ;
    243     } else if( type == LclV3Type ||
    244 	      (type == LclUnKnownType && _is_V3_header(h) == True)){
    245 	/*
    246 	 * Body charset information is in header when there is no
    247 	 * attachment.
    248 	 */
    249 	char *p = strcasestr(h, "\nX-Sun-Charset:");
    250 	if(!p) p = strcasestr(b, "\nX-Sun-Charset:");
    251 	if(p){
    252 	    char* eoline = strchr(p+1, '\n');
    253 	    if(eoline){
    254 		p+=15 ; /* skipping "\nX-Sun-Charset:" */
    255 		while(isspace(*++p)); /* skipping space */
    256 		if(p < eoline){
    257 		    int len = eoline - p ; /* skip "charset=" */
    258 		    *charset = malloc(len +1);
    259 		    strncpy(*charset, p, len);
    260 		    (*charset)[len] = NULL ;
    261 		} else *charset = NULL ;
    262 	    } else *charset = NULL ;
    263 	} else *charset = NULL ;
    264 	/*
    265 	 * Body charset information is in body
    266 	 */
    267 	return LclV3Type ;
    268     } else {
    269 	*charset = NULL ; /* Unknown */
    270 	return Lcl822Type ;
    271     }
    272 }
    273 /*
    274  * returns the parsed(converted) header
    275  * char* _lcl_parse_header(char* h, // unparsed header:in
    276  *			   char* b, // unparsed body:in
    277  *                         LclMailType *type // Mail type:out
    278  *                         char** charset // charset of parsed header:out
    279  *        )
    280  */
    281  char*
    282 _lcl_parse_header(char* h, char* b, LclMailType *type ,char** charset){
    283     LclMailType	mail_type = _lcl_get_body_charset(h, b, *type, charset);
    284     if(*charset)
    285 	free(*charset);
    286     *charset = (char *)NULL;
    287 
    288     switch(mail_type){
    289       case LclMIMEType:
    290 	return _lcl_mime_decode_header(h, strlen(h), charset);
    291       case LclV3Type:
    292 	return _lcl_V3_header(h);
    293       case Lcl822Type:
    294 	return _lcl_mime_decode_header(h, strlen(h), charset);
    295       default:
    296 	break ;
    297     }
    298 }
    299 
    300 static Bool
    301 _is_mime_body(char* h){
    302     return strcasestr(h, MIME_VERSION)?True:False ; /* Too easy? */
    303 }
    304 
    305 static Bool
    306 _is_V3_body(char* h){
    307     /*
    308      * case 1: X-Sun-Attachment is found.
    309      * case 2: Header looks like 822, but other X-Sun- header is found.
    310      * case 3: Header looks like 822, but X-Sun-Charset is found in Body.
    311      * otherwise it should be 822.
    312      */
    313     if(strcasestr(h, X_SUN)){
    314 	return True ;
    315     }
    316     /* case 3 is missing */
    317     return False ; /* should be 822 */
    318 }
    319 
    320 static char*
    321 _lcl_mime_body(char* b){
    322     return b ; /* Waiting for full implementation */
    323 }
    324 
    325 
    326 static char*
    327 _lcl_V3_body(char* b){
    328     return b ; /* Waiting for full implementation */
    329 }
    330 
    331 static char*
    332 _lcl_822_body(char* b){
    333     return b ; /* Waiting for full implementation */
    334 }
    335 
    336 /*
    337  * returns the parsed(converted) Body
    338  * char* _lcl_parse_body(char* h, // unparsed header:in
    339  *		         char* b  // unparsed body:in
    340  *        )
    341  */
    342  char*
    343 _lcl_parse_body(char* h, /* unparsed header:in */
    344 		char* b, /* unparsed body:in */
    345 		LclMailType type /* Mail type:in */){
    346     if( type == LclMIMEType ||
    347        (type == LclUnKnownType && h &&_is_mime_header(h) == True)){
    348 	char *p ;
    349 	if(h){
    350 	    p = strcasestr(h, "\nContent-Transfer-Encoding:");
    351 	}
    352 	if(!p){
    353 	    char *x = strcasestr(h, "Content-Transfer-Encoding:");
    354 	    if(x == h)
    355 		p = h ;
    356 	}
    357 	if(p){
    358 	    char* eoline = strchr(p+1, '\n');
    359 	    if(eoline){
    360 		char *save_p=p;
    361 		int b_len = strlen(b) ;
    362 		p = strcasestr(p+27, "quoted-printable");
    363 		if(p && (p < eoline)){
    364 		    char *eb = malloc(b_len + 1);
    365 		    char *db = malloc(b_len + 1);
    366 		    memcpy(eb, b, b_len + 1);
    367 		    str_fromqp(eb, b_len, db, b_len);
    368 		    free(eb);
    369 		    return db ;
    370 		 } else {
    371 		     p = strcasestr(save_p+27, "base64");
    372 		     if(p && (p < eoline)){
    373 			 char *eb = malloc(b_len + 1);
    374 			 char *db = malloc(b_len + 1);
    375 			 memcpy(eb, b, b_len + 1);
    376 			 str_from64(eb, b_len, db, b_len);
    377 			 free(eb);
    378 			 return db ;
    379 		     }
    380 		 }
    381 	    }
    382 	}
    383 	return NULL ;
    384     } else {
    385 	/* No decoding for V3 and 822 */
    386 	return NULL ;
    387     }
    388 }
    389 
    390 char*
    391 _lcl_encode_body(char* b, /* unparsed body:in */
    392 		 LclMailType type, /* Mail type:in */
    393 		 char* charset, /* to charset:in */
    394 		 LclMailEncoding e  /* base64/QP */
    395 		 ){
    396     int b_len = strlen(b);
    397     char* orig = malloc(b_len+1);
    398     char* eb ;
    399     memcpy(orig, b, b_len + 1);
    400     switch(e){
    401       case LclBase64Encoding:
    402 	eb = malloc(b_len*3+1);
    403 	str_to64(orig, b_len, eb, b_len*3, 0);/* no portable newline */
    404 	free(orig);
    405 	break ;
    406       case LclQPEncoding:
    407 	eb = malloc(b_len*2+1);
    408 	str_toqp(orig, b_len, eb, b_len*2, 0);/* no portable newline */
    409 	free(orig);
    410 	break ;
    411       case Lcl822Encoding:
    412       case LclUnKnownEncoding:
    413       default:
    414 	eb = orig ;
    415 	break ;
    416     }
    417     return eb ;
    418 }
    419 
    420 char*
    421 _lcl_encode_header(char* h,            /*  unparsed header:in */
    422 		   LclMailType type,   /* Mail type:in */
    423 		   char* charset,      /* to charset:in */
    424 		   LclMailEncoding he, /* header B/Q:in */
    425 		   LclMailEncoding be, /* body base64/QP:in */
    426 		   boolean_t add_header/* add if true:in */
    427 		   ){
    428     char *eh;
    429     switch(he){
    430       case LclBase64Encoding:
    431 	eh = _lcl_mime_encode_header(h, strlen(h), he, charset);
    432 	if(add_header == B_TRUE){
    433 
    434 	}
    435 	break ;
    436       case LclQPEncoding:
    437 	eh = _lcl_mime_encode_header(h, strlen(h), he, charset);
    438 	if(add_header == B_TRUE){
    439 
    440 	}
    441 	break ;
    442       case Lcl822Encoding:
    443       case LclUnKnownEncoding:
    444       default:
    445     	eh = (char *)NULL;
    446 	break ;
    447     }
    448     return eh ;
    449 }
    450 
    451 char*
    452 _lcl_encode_taggedtext(char* t, /* unparsed taggedtext:in */
    453 		       LclMailType type, /* Mail type:in */
    454 		       char* charset, /* to charset:in */
    455 		       LclMailEncoding e,  /* base64/QP */
    456 		       boolean_t add_header/* add if true:in */
    457 		       ){
    458     char* et = _lcl_encode_body(t, type, charset, e);
    459     if(add_header == B_TRUE){
    460 
    461     }
    462 }
    463 
    464 char*
    465 _lcl_parse_taggedtext(char* t, /* unparsed taggedtext:in */
    466 		      LclMailType *type, /* Mail type:in */
    467 		      char** charset /* charset of parsed text:out */
    468 	){
    469     if(*type == LclUnKnownType){
    470 	if(_is_V3_header(t)){
    471 	    *type = LclV3Type ;
    472 	} else {
    473 	    *type = LclMIMEType ;
    474 	}
    475     }
    476     return _lcl_parse_header(t, t, type , charset);
    477 }
    478 
    479 /*//////////////////////////////////////////////////*/
    480 char*
    481 _lcl_encode_taggedtext_body(char* b, /* unparsed body:in */
    482 			    LclMailType type, /* Mail type:in */
    483 			    char* charset, /* to charset:in */
    484 			    LclMailEncoding e  /* base64/QP */
    485 			    ){
    486     if(type == LclUnKnownType){
    487 	type = LclMIMEType ; /* Brute force */
    488     }
    489     return _lcl_encode_body(b, type, charset, e);
    490 }
    491 
    492 char*
    493 _lcl_encode_taggedtext_header(char* h, /*  unparsed header:in */
    494 			      LclMailType type, /* Mail type:in */
    495 			      char* charset,  /* to charset:in */
    496 			      LclMailEncoding he, /* header B/Q:in */
    497 			      LclMailEncoding be, /* body base64/QP:in */
    498 			      boolean_t add_header /* add if true:in */
    499 			      ){
    500     if(type == LclUnKnownType){
    501 	if(_is_V3_header(h)){
    502 	    type = LclV3Type ;
    503 	} else {
    504 	    type = LclMIMEType ;
    505 	}
    506     }
    507     return _lcl_encode_header(h, type, charset, he, be, add_header);
    508 }
    509 
    510 char*
    511 _lcl_parse_taggedtext_body(char* h, /* unparsed header:in */
    512 			   char* b, /* unparsed body:in */
    513 			   LclMailType type /* Mail type:in */
    514 			   ){
    515     if(type == LclUnKnownType){
    516 	if(_is_V3_header(h)){
    517 	    type = LclV3Type ;
    518 	} else {
    519 	    type = LclMIMEType ;
    520 	}
    521     }
    522     return _lcl_parse_body(h, b, type);
    523 }
    524 
    525 char*
    526 _lcl_parse_taggedtext_header(char* h, /*  unparsed header:in */
    527 			     char* b, /* unparsed body:in */
    528 			     LclMailType *type, /* Mail type:inout */
    529 			     char** charset /* charset of parsed header:out */
    530 			     ){
    531     if(*type == LclUnKnownType){
    532 	if(_is_V3_header(h)){
    533 	    *type = LclV3Type ;
    534 	} else {
    535 	    *type = LclMIMEType ;
    536 	}
    537     }
    538     return _lcl_parse_header(h, b, type , charset);
    539 }
    540