summaryrefslogtreecommitdiffstats
path: root/rfc2045/rfc2231.c
diff options
context:
space:
mode:
authorSam Varshavchik2013-08-19 16:39:41 -0400
committerSam Varshavchik2013-08-25 14:43:51 -0400
commit9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch)
tree7a81a04cb51efb078ee350859a64be2ebc6b8813 /rfc2045/rfc2231.c
parenta9520698b770168d1f33d6301463bb70a19655ec (diff)
downloadcourier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2
Initial checkin
Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'rfc2045/rfc2231.c')
-rw-r--r--rfc2045/rfc2231.c375
1 files changed, 375 insertions, 0 deletions
diff --git a/rfc2045/rfc2231.c b/rfc2045/rfc2231.c
new file mode 100644
index 0000000..f0908e8
--- /dev/null
+++ b/rfc2045/rfc2231.c
@@ -0,0 +1,375 @@
+/*
+** Copyright 2002-2011 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+/*
+*/
+
+#if HAVE_CONFIG_H
+#include "rfc2045_config.h"
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "rfc2045.h"
+#include "rfc822/rfc822.h"
+#include "unicode/unicode.h"
+
+/*
+** Deallocate a link list of rfc2231param structures.
+*/
+
+void rfc2231_paramDestroy(struct rfc2231param *p)
+{
+ while (p)
+ {
+ struct rfc2231param *q=p->next;
+
+ free(p);
+ p=q;
+ }
+}
+
+int rfc2231_buildAttrList(struct rfc2231param **paramList,
+ const char *name,
+
+ const char *attrName,
+ const char *attrValue)
+{
+ int nameLen=strlen(name);
+
+ if (strncmp(attrName, name, nameLen) == 0 &&
+ (attrName[nameLen] == 0 ||
+ attrName[nameLen] == '*'))
+ {
+ struct rfc2231param *n
+ =malloc(sizeof(struct rfc2231param)), **o;
+
+ const char *p=attrName + nameLen;
+
+ if (!n)
+ {
+ rfc2231_paramDestroy(*paramList);
+ return -1;
+ }
+
+ /*
+ ** A non-rfc 2231 parameter has paramnum set to 0, an
+ ** rfc 2231 parameter has paramnum set to its number, plus 1.
+ */
+
+ if (*p == 0)
+ {
+ n->paramnum=0;
+ }
+ else
+ {
+ p++;
+
+ n->paramnum=atoi(p)+1;
+
+ if (n->paramnum <= 0)
+ n->paramnum=1;
+ }
+
+ p=strrchr(attrName, '*');
+
+ n->encoded=p && p[1] == 0;
+ n->value=attrValue;
+
+ for (o=paramList; *o; o= &(*o)->next)
+ if ( (*o)->paramnum > n->paramnum)
+ break;
+
+ n->next= *o;
+ *o=n;
+ }
+ return 0;
+}
+
+
+/*
+** Create a link list of rfc2231param structures for a specific attribute
+**
+** Returns: 0 - ok, < 0 - out of memory.
+*/
+
+static int rfc2231_paramCreate(struct rfc2045attr *attr,
+ const char *name,
+ struct rfc2231param **paramList)
+{
+ *paramList=NULL;
+
+ while (attr)
+ {
+ if (rfc2231_buildAttrList(paramList, name, attr->name,
+ attr->value) < 0)
+ return (-1);
+ attr=attr->next;
+ }
+
+ return (0);
+}
+
+static const char rfc2231_xdigit[]="0123456789ABCDEFabcdef";
+
+static int nyb(char c)
+{
+ const char *p=strchr(rfc2231_xdigit, c);
+ int n;
+
+ if (!p)
+ return 0;
+
+ n=p-rfc2231_xdigit;
+
+ if (n >= 16)
+ n -= 6;
+
+ return n;
+}
+
+/*
+** Decode an rfc2231param link list.
+**
+** charset, language, text, are decoded, if the corresponding args below are
+** not null. Their corresponding lengths (including the null bytes) are
+** always saved in the corresponding int args. rfc2231_decode() is called
+** twice to get the lengths, then once again after the buffers are allocated.
+*/
+
+void rfc2231_paramDecode(struct rfc2231param *paramList,
+ char *charsetPtr,
+ char *langPtr,
+ char *textPtr,
+ int *charsetLen,
+ int *langLen,
+ int *textLen)
+{
+ int first=1;
+
+ *charsetLen=*langLen=*textLen=1; /* null byte */
+
+ if (paramList && paramList->paramnum == 0 &&
+ paramList->next)
+ paramList=paramList->next;
+ /*
+ ** Both a non-rfc2231 and an rfc2231 parameter was specified, so
+ ** take the better one.
+ */
+
+ while (paramList)
+ {
+ const char *p=paramList->value;
+
+ if (first && paramList->encoded)
+ {
+ const char *q=strchr(p, '\'');
+
+ if (q && strchr(q+1, '\''))
+ {
+ while (*p != '\'')
+ {
+ if (charsetPtr)
+ *charsetPtr++ = *p;
+ p++;
+ (*charsetLen)++;
+ }
+ p++;
+ while (*p != '\'')
+ {
+ if (langPtr)
+ *langPtr++ = *p;
+ p++;
+ (*langLen)++;
+ }
+ p++;
+ }
+ }
+
+ first=0;
+
+ while (*p)
+ {
+ if (*p == '%' && p[1] && p[2] && paramList->encoded)
+ {
+ if (textPtr)
+ *textPtr++ = nyb(p[1]) * 16 +
+ nyb(p[2]);
+ p += 3;
+ }
+ else
+ {
+ if (textPtr)
+ *textPtr++ = *p;
+
+ p++;
+ }
+
+ (*textLen)++;
+ }
+
+ paramList=paramList->next;
+ }
+
+ if (charsetPtr)
+ *charsetPtr=0;
+ if (langPtr)
+ *langPtr=0;
+ if (textPtr)
+ *textPtr=0;
+}
+
+/*
+** Retrieve RFC 2231 information from a specific rfc2045attr list
+**
+** Returns 0 success, -1 for failure
+*/
+
+static int rfc2231_decode(struct rfc2045attr *attrList,
+ const char *name,
+
+ char **chsetPtr,
+ char **langPtr,
+ char **textPtr)
+{
+ int chsetLen;
+ int langLen;
+ int textLen;
+
+ struct rfc2231param *paramList;
+
+ if (rfc2231_paramCreate(attrList, name, &paramList) < 0)
+ return -1;
+
+ rfc2231_paramDecode(paramList, NULL, NULL, NULL,
+ &chsetLen,
+ &langLen,
+ &textLen);
+
+ if (chsetPtr)
+ *chsetPtr=NULL;
+
+ if (langPtr)
+ *langPtr=NULL;
+
+ if (textPtr)
+ *textPtr=NULL;
+
+
+ if ((chsetPtr && (*chsetPtr=malloc(chsetLen)) == NULL)
+ || (langPtr && (*langPtr=malloc(langLen)) == NULL)
+ || (textPtr && (*textPtr=malloc(textLen)) == NULL))
+ {
+ rfc2231_paramDestroy(paramList);
+
+ if (*chsetPtr)
+ free(*chsetPtr);
+
+ if (*langPtr)
+ free(*langPtr);
+
+ if (*textPtr)
+ free(*textPtr);
+ return (-1);
+ }
+
+ rfc2231_paramDecode(paramList,
+ chsetPtr ? *chsetPtr:NULL,
+ langPtr ? *langPtr:NULL,
+ textPtr ? *textPtr:NULL,
+ &chsetLen,
+ &langLen,
+ &textLen);
+ return 0;
+}
+
+int rfc2231_decodeType(struct rfc2045 *rfc, const char *name,
+ char **chsetPtr,
+ char **langPtr,
+ char **textPtr)
+{
+ return rfc2231_decode(rfc->content_type_attr, name,
+ chsetPtr, langPtr, textPtr);
+}
+
+int rfc2231_decodeDisposition(struct rfc2045 *rfc, const char *name,
+ char **chsetPtr,
+ char **langPtr,
+ char **textPtr)
+{
+ return rfc2231_decode(rfc->content_disposition_attr, name,
+ chsetPtr, langPtr, textPtr);
+}
+
+static int conv_unicode(char **text, const char *fromChset,
+ const char *toChset)
+{
+ int err;
+ char *p;
+
+ if (!toChset)
+ toChset=unicode_default_chset();
+
+ if (!fromChset || !*fromChset)
+ return 0;
+
+ p=libmail_u_convert_tobuf(*text, fromChset, toChset, &err);
+
+ if (p && err)
+ {
+ free(p);
+ p=NULL;
+ }
+
+ if (!p)
+ return (-1);
+
+ free(*text);
+ *text=p;
+ return (0);
+}
+
+int rfc2231_udecodeType(struct rfc2045 *rfc, const char *name,
+ const char *myCharset,
+ char **textPtr)
+{
+ char *text, *chset;
+
+ if (rfc2231_decodeType(rfc, name, &chset, NULL, &text) < 0)
+ return (-1);
+
+ if (conv_unicode(&text, chset, myCharset) < 0)
+ {
+ free(text);
+ free(chset);
+ return (-1);
+ }
+
+ *textPtr=text;
+ free(chset);
+ return (0);
+}
+
+int rfc2231_udecodeDisposition(struct rfc2045 *rfc, const char *name,
+ const char *myCharset,
+ char **textPtr)
+{
+ char *text, *chset;
+
+ if (rfc2231_decodeDisposition(rfc, name, &chset, NULL, &text) < 0)
+ return (-1);
+
+ if (conv_unicode(&text, chset, myCharset) < 0)
+ {
+ free(text);
+ free(chset);
+ return (-1);
+ }
+
+ *textPtr=text;
+ free(chset);
+ return (0);
+}