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 * * * * * * * *
32 #define RFC2231_MAX 64
36 rfc2231_get_param(PARAMETER
*parms
, char *name
,
37 char **charset
, char **lang
)
40 int decode
= 0, name_len
, i
;
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
];
56 memset(pieces
, 0, RFC2231_MAX
* sizeof(char *));
61 n
= (n
* 10) + (*p
- '0');
62 while(isdigit(*++p
) && n
< RFC2231_MAX
);
65 pieces
[n
] = parms
->value
;
70 q_status_message1(SM_ORDER
| SM_DING
, 0, 3,
71 "Invalid attachment parameter segment number: %.25s",
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
))
82 return(NULL
); /* missing segment no.! */
86 for(i
= len
= 0; i
<= count
; i
++)
88 len
+= strlen(pieces
[i
]);
90 q_status_message1(SM_ORDER
| SM_DING
, 0, 3,
91 "Missing attachment parameter sequence: %.25s",
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? */
103 while(*p
&& !(n
&& *p
== '\"' && !*(p
+1)))
110 buf
= cpystr(parms
->value
);
112 /* Do any RFC 2231 decoding? */
114 char *converted
= NULL
, cs
[1000];
119 if((p
= strchr(buf
, '\'')) != NULL
){
122 strncpy(cs
, buf
, sizeof(cs
));
123 cs
[sizeof(cs
)-1] = '\0';
126 *charset
= cpystr(cs
);
128 if((p
= strchr(&buf
[n
], '\'')) != NULL
){
139 /* Suck out the charset & lang while decoding hex */
141 for(i
= 0; (buf
[i
] = *p
) != '\0'; i
++)
142 if(*p
++ == '%' && isxpair(p
)){
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.
155 converted
= convert_to_utf8(buf
, cs
, 0);
157 if(converted
&& converted
!= buf
){
158 fs_give((void **) &buf
);
166 return(cpystr(parms
->value
? parms
->value
: ""));
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
++)
189 if(!(value
&& value
[i
]) || i
> 80){ /* flush! */
190 if((line
++ && !so_puts(so
, ";\015\012 "))
191 || !so_puts(so
, attrib
))
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
, "''"))))
213 if(!(so_writec('%', so
) && so_puts(so
, tmp
)))
216 else if(((*value
== '\\' || *value
== '\"')
217 && !so_writec('\\', so
))
218 || !so_writec(*value
, so
))
224 if(quote
&& !so_writec('\"', so
))
227 if(*value
) /* more? */
228 i
= quote
= 0; /* reset! */
230 return(1); /* done! */
236 if(!quote
&& strchr(specials
, value
[i
]))
243 rfc2231_newparmlist(PARAMETER
*params
)
245 PARMLIST_S
*p
= NULL
;
248 p
= (PARMLIST_S
*) fs_get(sizeof(PARMLIST_S
));
249 memset(p
, 0, sizeof(PARMLIST_S
));
258 rfc2231_free_parmlist(PARMLIST_S
**p
)
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
;
277 fs_give((void **) &plist
->value
);
279 for(pp
= plist
->list
; pp
; pp
= pp
->next
){
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
);
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
);
302 q_status_message1(SM_ORDER
| SM_DING
, 0, 3,
303 "Overly long attachment parameter ignored: %.25s...",