* NTLM authentication support with the ntlm library, in Unix systems.
[alpine.git] / pith / rfc2231.c
blobb2d286094f831b155d3619ea5b0e7451b6cd04f3
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: rfc2231.c 1012 2008-03-26 00:44:22Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2017 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "../pith/headers.h"
20 #include "../pith/rfc2231.h"
21 #include "../pith/mimedesc.h"
22 #include "../pith/state.h"
23 #include "../pith/conf.h"
24 #include "../pith/store.h"
25 #include "../pith/status.h"
26 #include "../pith/send.h"
27 #include "../pith/string.h"
31 * * * * * * * * * RFC 2231 support routines * * * * * * * *
35 /* Useful def's */
36 #define RFC2231_MAX 64
39 char *
40 rfc2231_get_param(PARAMETER *parms, char *name,
41 char **charset, char **lang)
43 char *buf, *p;
44 int decode = 0, name_len, i;
45 unsigned n;
47 name_len = strlen(name);
48 for(; parms ; parms = parms->next)
49 if(!struncmp(name, parms->attribute, name_len)){
50 if(parms->attribute[name_len] == '*'){
51 for(p = &parms->attribute[name_len + 1], n = 0; *(p+n); n++)
54 decode = *(p + n - 1) == '*';
56 if(isdigit((unsigned char) *p)){
57 char *pieces[RFC2231_MAX];
58 int count = 0, len;
60 memset(pieces, 0, RFC2231_MAX * sizeof(char *));
62 while(parms){
63 n = 0;
65 n = (n * 10) + (*p - '0');
66 while(isdigit(*++p) && n < RFC2231_MAX);
68 if(n < RFC2231_MAX){
69 pieces[n] = parms->value;
70 if(n > count)
71 count = n;
73 else{
74 q_status_message1(SM_ORDER | SM_DING, 0, 3,
75 "Invalid attachment parameter segment number: %.25s",
76 name);
77 return(NULL); /* Too many segments! */
80 while((parms = parms->next) != NULL)
81 if(!struncmp(name, parms->attribute, name_len)){
82 if(*(p = &parms->attribute[name_len]) == '*'
83 && isdigit((unsigned char) *++p))
84 break;
85 else
86 return(NULL); /* missing segment no.! */
90 for(i = len = 0; i <= count; i++)
91 if(pieces[i])
92 len += strlen(pieces[i]);
93 else{
94 q_status_message1(SM_ORDER | SM_DING, 0, 3,
95 "Missing attachment parameter sequence: %.25s",
96 name);
98 return(NULL); /* hole! */
101 buf = (char *) fs_get((len + 1) * sizeof(char));
103 for(i = len = 0; i <= count; i++){
104 if((n = *(p = pieces[i]) == '\"') != 0) /* quoted? */
105 p++;
107 while(*p && !(n && *p == '\"' && !*(p+1)))
108 buf[len++] = *p++;
111 buf[len] = '\0';
113 else
114 buf = cpystr(parms->value);
116 /* Do any RFC 2231 decoding? */
117 if(decode){
118 char *converted = NULL, cs[1000];
120 cs[0] = '\0';
121 n = 0;
123 if((p = strchr(buf, '\'')) != NULL){
124 n = (p - buf) + 1;
125 *p = '\0';
126 strncpy(cs, buf, sizeof(cs));
127 cs[sizeof(cs)-1] = '\0';
128 *p = '\'';
129 if(charset)
130 *charset = cpystr(cs);
132 if((p = strchr(&buf[n], '\'')) != NULL){
133 n = (p - buf) + 1;
134 if(lang){
135 *p = '\0';
136 *lang = cpystr(p);
137 *p = '\'';
142 if(n){
143 /* Suck out the charset & lang while decoding hex */
144 p = &buf[n];
145 for(i = 0; (buf[i] = *p) != '\0'; i++)
146 if(*p++ == '%' && isxpair(p)){
147 buf[i] = X2C(p);
148 p += 2;
151 else
152 fs_give((void **) &buf); /* problems!?! */
155 * Callers will expect the returned value to be UTF-8
156 * text, so we may need to translate here.
158 if(buf)
159 converted = convert_to_utf8(buf, cs, 0);
161 if(converted && converted != buf){
162 fs_give((void **) &buf);
163 buf = converted;
167 return(buf);
169 else
170 return(cpystr(parms->value ? parms->value : ""));
173 return(NULL);
178 rfc2231_output(STORE_S *so, char *attrib, char *value, char *specials, char *charset)
180 int i, line = 0, encode = 0, quote = 0;
183 * scan for hibit first since encoding clue has to
184 * come on first line if any parms are broken up...
186 for(i = 0; value && value[i]; i++)
187 if(value[i] & 0x80){
188 encode++;
189 break;
192 for(i = 0; ; i++){
193 if(!(value && value[i]) || i > 80){ /* flush! */
194 if((line++ && !so_puts(so, ";\015\012 "))
195 || !so_puts(so, attrib))
196 return(0);
198 if(value){
199 if(((value[i] || line > 1) /* more lines or already lines */
200 && !(so_writec('*', so)
201 && so_puts(so, int2string(line - 1))))
202 || (encode && !so_writec('*', so))
203 || !so_writec('=', so)
204 || (quote && !so_writec('\"', so))
205 || ((line == 1 && encode)
206 && !(so_puts(so, charset ? charset : UNKNOWN_CHARSET)
207 && so_puts(so, "''"))))
208 return(0);
210 while(i--){
211 if(*value & 0x80){
212 char tmp[3], *p;
214 p = tmp;
215 C2XPAIR(*value, p);
216 *p = '\0';
217 if(!(so_writec('%', so) && so_puts(so, tmp)))
218 return(0);
220 else if(((*value == '\\' || *value == '\"')
221 && !so_writec('\\', so))
222 || !so_writec(*value, so))
223 return(0);
225 value++;
228 if(quote && !so_writec('\"', so))
229 return(0);
231 if(*value) /* more? */
232 i = quote = 0; /* reset! */
233 else
234 return(1); /* done! */
236 else
237 return(1);
240 if(!quote && strchr(specials, value[i]))
241 quote++;
246 PARMLIST_S *
247 rfc2231_newparmlist(PARAMETER *params)
249 PARMLIST_S *p = NULL;
251 if(params){
252 p = (PARMLIST_S *) fs_get(sizeof(PARMLIST_S));
253 memset(p, 0, sizeof(PARMLIST_S));
254 p->list = params;
257 return(p);
261 void
262 rfc2231_free_parmlist(PARMLIST_S **p)
264 if(*p){
265 if((*p)->value)
266 fs_give((void **) &(*p)->value);
268 mail_free_body_parameter(&(*p)->seen);
269 fs_give((void **) p);
275 rfc2231_list_params(PARMLIST_S *plist)
277 PARAMETER *pp, **ppp;
278 int i;
280 if(plist->value)
281 fs_give((void **) &plist->value);
283 for(pp = plist->list; pp; pp = pp->next){
284 /* get a name */
285 for(i = 0; i < 32; i++)
286 if(!(plist->attrib[i] = pp->attribute[i]) || pp->attribute[i] == '*'){
287 plist->attrib[i] = '\0';
289 for(ppp = &plist->seen;
290 *ppp && strucmp((*ppp)->attribute, plist->attrib);
291 ppp = &(*ppp)->next)
294 if(!*ppp){
295 plist->list = pp->next;
296 *ppp = mail_newbody_parameter(); /* add to seen list */
297 (*ppp)->attribute = cpystr(plist->attrib);
298 plist->value = parameter_val(pp,plist->attrib);
299 return(TRUE);
302 break;
305 if(i >= 32)
306 q_status_message1(SM_ORDER | SM_DING, 0, 3,
307 "Overly long attachment parameter ignored: %.25s...",
308 pp->attribute);
312 return(FALSE);