Add support for tab-completion when selecting by rule
[alpine.git] / pith / rfc2231.c
blobaf62acd9e6bd55184b65e5439a1f7902fa1fed15
1 /*
2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #include "../pith/headers.h"
16 #include "../pith/rfc2231.h"
17 #include "../pith/mimedesc.h"
18 #include "../pith/state.h"
19 #include "../pith/conf.h"
20 #include "../pith/store.h"
21 #include "../pith/status.h"
22 #include "../pith/send.h"
23 #include "../pith/string.h"
27 * * * * * * * * * RFC 2231 support routines * * * * * * * *
31 /* Useful def's */
32 #define RFC2231_MAX 64
35 char *
36 rfc2231_get_param(PARAMETER *parms, char *name,
37 char **charset, char **lang)
39 char *buf, *p;
40 int decode = 0, name_len, i;
41 unsigned n;
43 name_len = strlen(name);
44 for(; parms ; parms = parms->next)
45 if(!struncmp(name, parms->attribute, name_len)){
46 if(parms->attribute[name_len] == '*'){
47 for(p = &parms->attribute[name_len + 1], n = 0; *(p+n); n++)
50 decode = *(p + n - 1) == '*';
52 if(isdigit((unsigned char) *p)){
53 char *pieces[RFC2231_MAX];
54 int count = 0, len;
56 memset(pieces, 0, RFC2231_MAX * sizeof(char *));
58 while(parms){
59 n = 0;
61 n = (n * 10) + (*p - '0');
62 while(isdigit(*++p) && n < RFC2231_MAX);
64 if(n < RFC2231_MAX){
65 pieces[n] = parms->value;
66 if(n > count)
67 count = n;
69 else{
70 q_status_message1(SM_ORDER | SM_DING, 0, 3,
71 "Invalid attachment parameter segment number: %.25s",
72 name);
73 return(NULL); /* Too many segments! */
76 while((parms = parms->next) != NULL)
77 if(!struncmp(name, parms->attribute, name_len)){
78 if(*(p = &parms->attribute[name_len]) == '*'
79 && isdigit((unsigned char) *++p))
80 break;
81 else
82 return(NULL); /* missing segment no.! */
86 for(i = len = 0; i <= count; i++)
87 if(pieces[i])
88 len += strlen(pieces[i]);
89 else{
90 q_status_message1(SM_ORDER | SM_DING, 0, 3,
91 "Missing attachment parameter sequence: %.25s",
92 name);
94 return(NULL); /* hole! */
97 buf = (char *) fs_get((len + 1) * sizeof(char));
99 for(i = len = 0; i <= count; i++){
100 if((n = *(p = pieces[i]) == '\"') != 0) /* quoted? */
101 p++;
103 while(*p && !(n && *p == '\"' && !*(p+1)))
104 buf[len++] = *p++;
107 buf[len] = '\0';
109 else
110 buf = cpystr(parms->value);
112 /* Do any RFC 2231 decoding? */
113 if(decode){
114 char *converted = NULL, cs[1000];
116 cs[0] = '\0';
117 n = 0;
119 if((p = strchr(buf, '\'')) != NULL){
120 n = (p - buf) + 1;
121 *p = '\0';
122 strncpy(cs, buf, sizeof(cs));
123 cs[sizeof(cs)-1] = '\0';
124 *p = '\'';
125 if(charset)
126 *charset = cpystr(cs);
128 if((p = strchr(&buf[n], '\'')) != NULL){
129 n = (p - buf) + 1;
130 if(lang){
131 *p = '\0';
132 *lang = cpystr(p);
133 *p = '\'';
138 if(n){
139 /* Suck out the charset & lang while decoding hex */
140 p = &buf[n];
141 for(i = 0; (buf[i] = *p) != '\0'; i++)
142 if(*p++ == '%' && isxpair(p)){
143 buf[i] = X2C(p);
144 p += 2;
147 else
148 fs_give((void **) &buf); /* problems!?! */
151 * Callers will expect the returned value to be UTF-8
152 * text, so we may need to translate here.
154 if(buf)
155 converted = convert_to_utf8(buf, cs, 0);
157 if(converted && converted != buf){
158 fs_give((void **) &buf);
159 buf = converted;
163 return(buf);
165 else
166 return(cpystr(parms->value ? parms->value : ""));
169 return(NULL);
174 rfc2231_output(STORE_S *so, char *attrib, char *value, char *specials, char *charset)
176 int i, line = 0, encode = 0, quote = 0;
179 * scan for hibit first since encoding clue has to
180 * come on first line if any parms are broken up...
182 for(i = 0; value && value[i]; i++)
183 if(value[i] & 0x80){
184 encode++;
185 break;
188 for(i = 0; ; i++){
189 if(!(value && value[i]) || i > 80){ /* flush! */
190 if((line++ && !so_puts(so, ";\015\012 "))
191 || !so_puts(so, attrib))
192 return(0);
194 if(value){
195 if(((value[i] || line > 1) /* more lines or already lines */
196 && !(so_writec('*', so)
197 && so_puts(so, int2string(line - 1))))
198 || (encode && !so_writec('*', so))
199 || !so_writec('=', so)
200 || (quote && !so_writec('\"', so))
201 || ((line == 1 && encode)
202 && !(so_puts(so, charset ? charset : UNKNOWN_CHARSET)
203 && so_puts(so, "''"))))
204 return(0);
206 while(i--){
207 if(*value & 0x80){
208 char tmp[3], *p;
210 p = tmp;
211 C2XPAIR(*value, p);
212 *p = '\0';
213 if(!(so_writec('%', so) && so_puts(so, tmp)))
214 return(0);
216 else if(((*value == '\\' || *value == '\"')
217 && !so_writec('\\', so))
218 || !so_writec(*value, so))
219 return(0);
221 value++;
224 if(quote && !so_writec('\"', so))
225 return(0);
227 if(*value) /* more? */
228 i = quote = 0; /* reset! */
229 else
230 return(1); /* done! */
232 else
233 return(1);
236 if(!quote && strchr(specials, value[i]))
237 quote++;
242 PARMLIST_S *
243 rfc2231_newparmlist(PARAMETER *params)
245 PARMLIST_S *p = NULL;
247 if(params){
248 p = (PARMLIST_S *) fs_get(sizeof(PARMLIST_S));
249 memset(p, 0, sizeof(PARMLIST_S));
250 p->list = params;
253 return(p);
257 void
258 rfc2231_free_parmlist(PARMLIST_S **p)
260 if(*p){
261 if((*p)->value)
262 fs_give((void **) &(*p)->value);
264 mail_free_body_parameter(&(*p)->seen);
265 fs_give((void **) p);
271 rfc2231_list_params(PARMLIST_S *plist)
273 PARAMETER *pp, **ppp;
274 int i;
276 if(plist->value)
277 fs_give((void **) &plist->value);
279 for(pp = plist->list; pp; pp = pp->next){
280 /* get a name */
281 for(i = 0; i < 32; i++)
282 if(!(plist->attrib[i] = pp->attribute[i]) || pp->attribute[i] == '*'){
283 plist->attrib[i] = '\0';
285 for(ppp = &plist->seen;
286 *ppp && strucmp((*ppp)->attribute, plist->attrib);
287 ppp = &(*ppp)->next)
290 if(!*ppp){
291 plist->list = pp->next;
292 *ppp = mail_newbody_parameter(); /* add to seen list */
293 (*ppp)->attribute = cpystr(plist->attrib);
294 plist->value = parameter_val(pp,plist->attrib);
295 return(TRUE);
298 break;
301 if(i >= 32)
302 q_status_message1(SM_ORDER | SM_DING, 0, 3,
303 "Overly long attachment parameter ignored: %.25s...",
304 pp->attribute);
308 return(FALSE);