1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #ifndef PL_sv_undef
6 #ifdef sv_undef
7 # define PL_sv_undef sv_undef
8 #endif
9 #endif
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <glib.h>
18 #include <gmime/gmime.h>
19 #include "gmime-version.h"
20
21 #define XSINTERFACE_FUNC_MIMEFAST_MESSAGE_SET(cv,f) \
22 CvXSUBANY(cv).any_dptr = (void (*) (pTHX_ void*))(CAT2( g_mime_message_,f ))
23 #define XSINTERFACE_FUNC_MIMEFAST_PART_SET(cv,f) \
24 CvXSUBANY(cv).any_dptr = (void (*) (pTHX_ void*))(CAT2( g_mime_part_,f ))
25 #define XSINTERFACE_FUNC_MIMEFAST_MULTIPART_SET(cv,f) \
26 CvXSUBANY(cv).any_dptr = (void (*) (pTHX_ void*))(CAT2( g_mime_multipart_,f ))
27 #define XSINTERFACE_FUNC_MIMEFAST_IA_SET(cv,f) \
28 CvXSUBANY(cv).any_dptr = (void (*) (pTHX_ void*))(CAT2( internet_address_,f ))
29
30 /* debug output from MIME::Fast module */
31 static gboolean gmime_debug = 0;
32
33 struct raw_header {
34 struct raw_header *next;
35 char *name;
36 char *value;
37 };
38
39 typedef struct _GMimeHeader {
40 GHashTable *hash;
41 GHashTable *writers;
42 struct raw_header *headers;
43 } local_GMimeHeader;
44
45 static int
not_here(char * s)46 not_here(char *s)
47 {
48 croak("%s not implemented on this architecture", s);
49 return -1;
50 }
51
52 #define GMIME_LENGTH_ENCODED 1
53 #define GMIME_LENGTH_CUMULATIVE 2
54
55 #include "gmime-stream-perlio.h"
56
57 #include "gmime-newfunc.c"
58 #include "gmime-newfuncheader.c"
59 #include "perl-constants.c"
60
61 void
warn_type(SV * svmixed,char * text)62 warn_type(SV *svmixed, char *text)
63 {
64 SV *svval;
65 svtype svvaltype;
66 char *svtext;
67 STRLEN vallen;
68
69 svval = svmixed;
70 if (SvROK(svmixed)) {
71 svval = SvRV(svmixed);
72 }
73 svvaltype = SvTYPE(svval);
74
75 svtext =
76 (svvaltype == SVt_NULL) ?
77 "SVt_NULL" : /* 0 */
78 (svvaltype == SVt_IV) ?
79 "SVt_IV" : /* 1 */
80 (svvaltype == SVt_NV) ?
81 "SVt_NV" : /* 2 */
82 (svvaltype == SVt_RV) ?
83 "SVt_RV" : /* 3 */
84 (svvaltype == SVt_PV) ?
85 "SVt_PV" : /* 4 */
86 (svvaltype == SVt_PVIV) ?
87 "SVt_PVIV" : /* 5 */
88 (svvaltype == SVt_PVNV) ?
89 "SVt_PVNV" : /* 6 */
90 (svvaltype == SVt_PVMG) ?
91 "SVt_PVMG" : /* 7 */
92 (svvaltype == SVt_PVBM) ?
93 "SVt_PVBM" : /* 8 */
94 (svvaltype == SVt_PVLV) ?
95 "SVt_PVLV" : /* 9 */
96 (svvaltype == SVt_PVAV) ?
97 "SVt_PVAV" : /* 10 */
98 (svvaltype == SVt_PVHV) ?
99 "SVt_PVHV" : /* 11 */
100 (svvaltype == SVt_PVCV) ?
101 "SVt_PVCV" : /* 12 */
102 (svvaltype == SVt_PVGV) ?
103 "SVt_PVGV" : /* 13 */
104 (svvaltype == SVt_PVFM) ?
105 "SVt_PVFM" : /* 14 */
106 (svvaltype == SVt_PVIO) ?
107 "SVt_PVIO" : /* 15 */
108 "Unknown";
109
110 warn("warn_type '%s': %s%d / %s, value='%s'", text,
111 (SvROK(svmixed)) ? "ref " : "",
112 (int)svvaltype,
113 svtext,
114 SvOK(svval) ? SvPV(svval, vallen) : "undef");
115
116 }
117
118 /* enums */
119 typedef GMimePartEncodingType MIME__Fast__PartEncodingType;
120 typedef InternetAddressType MIME__Fast__InternetAddressType;
121 typedef GMimeBestEncoding MIME__Fast__BestEncoding;
122 typedef GMimeFilterFromMode MIME__Fast__FilterFromMode;
123 typedef GMimeFilterYencDirection Mime__Fast__FilterYencDirection;
124 typedef GMimeSeekWhence MIME__Fast__SeekWhence;
125
126 /* C types */
127 typedef GMimeObject * MIME__Fast__Object;
128 typedef GMimeParam * MIME__Fast__Param;
129 typedef GMimePart * MIME__Fast__Part;
130 typedef GMimeParser * MIME__Fast__Parser;
131 typedef GMimeMultipart * MIME__Fast__MultiPart;
132 typedef GMimeMessage * MIME__Fast__Message;
133 typedef GMimeMessagePart * MIME__Fast__MessagePart;
134 typedef GMimeMessagePartial * MIME__Fast__MessagePartial;
135 #if GMIME_CHECK_VERSION_UNSUPPORTED
136 typedef GMimeMessageDelivery * MIME__Fast__MessageDelivery;
137 typedef GMimeMessageMDN * MIME__Fast__MessageMDN;
138 typedef GMimeMessageMDNDisposition * MIME__Fast__MessageMDNDisposition;
139 typedef GMimeFilterFunc * MIME__Fast__Filter__Func;
140 #endif
141 typedef GMimeFilterEnriched * MIME__Fast__Filter__Enriched;
142 #if GMIME_CHECK_VERSION_2_1_0
143 typedef GMimeFilterWindows * MIME__Fast__Filter__Windows;
144 #endif
145 typedef InternetAddress * MIME__Fast__InternetAddress;
146 typedef GMimeDisposition * MIME__Fast__Disposition;
147 typedef GMimeContentType * MIME__Fast__ContentType;
148 typedef GMimeStream * MIME__Fast__Stream;
149 typedef GMimeStreamFilter * MIME__Fast__StreamFilter;
150 typedef GMimeDataWrapper * MIME__Fast__DataWrapper;
151 typedef GMimeFilter * MIME__Fast__Filter;
152 typedef GMimeFilterBasic * MIME__Fast__Filter__Basic;
153 typedef GMimeFilterBest * MIME__Fast__Filter__Best;
154 typedef GMimeFilterCharset * MIME__Fast__Filter__Charset;
155 typedef GMimeFilterCRLF * MIME__Fast__Filter__CRLF;
156 typedef GMimeFilterFrom * MIME__Fast__Filter__From;
157 typedef GMimeFilterHTML * MIME__Fast__Filter__HTML;
158 typedef GMimeFilterMd5 * MIME__Fast__Filter__Md5;
159 typedef GMimeFilterStrip * MIME__Fast__Filter__Strip;
160 typedef GMimeFilterYenc * MIME__Fast__Filter__Yenc;
161 typedef GMimeCharset * MIME__Fast__Charset;
162
163 /*
164 * Declarations for message header hash array
165 */
166
167 static gboolean
recipients_destroy(gpointer key,gpointer value,gpointer user_data)168 recipients_destroy (gpointer key, gpointer value, gpointer user_data)
169 {
170 InternetAddressList *recipients = value;
171
172 internet_address_list_destroy (recipients);
173
174 return TRUE;
175 }
176
177 typedef struct {
178 int keyindex; /* key index for firstkey */
179 char *fetchvalue; /* value for each() method fetched with FETCH */
180 MIME__Fast__Message objptr; /* any object pointer */
181 } hash_header;
182
183 typedef hash_header * MIME__Fast__Hash__Header;
184
185 /*
186 * Double linked list of perl allocated pointers (for DESTROY xsubs)
187 */
188 static GList *plist = NULL;
189
190 /*
191 * Calling callback function for each mime part
192 */
193 struct _user_data_sv {
194 SV * svfunc;
195 SV * svuser_data;
196 SV * svfunc_complete;
197 SV * svfunc_sizeout;
198 };
199
200 static void
call_sub_foreach(GMimeObject * mime_object,gpointer data)201 call_sub_foreach(GMimeObject *mime_object, gpointer data)
202 {
203 SV * svpart;
204 SV * rvpart;
205
206 dSP ;
207 struct _user_data_sv *svdata;
208
209 svdata = (struct _user_data_sv *) data;
210 svpart = sv_newmortal();
211
212 if (GMIME_IS_MESSAGE_PARTIAL(mime_object))
213 rvpart = sv_setref_pv(svpart, "MIME::Fast::MessagePartial", (MIME__Fast__MessagePartial)mime_object);
214 #if GMIME_CHECK_VERSION_UNSUPPORTED
215 else if (GMIME_IS_MESSAGE_MDN(mime_object))
216 rvpart = sv_setref_pv(svpart, "MIME::Fast::MessageMDN", (MIME__Fast__MessageMDN)mime_object);
217 else if (GMIME_IS_MESSAGE_DELIVERY(mime_object))
218 rvpart = sv_setref_pv(svpart, "MIME::Fast::MessageDelivery", (MIME__Fast__MessageDelivery)mime_object);
219 #endif
220 else if (GMIME_IS_MESSAGE_PART(mime_object))
221 rvpart = sv_setref_pv(svpart, "MIME::Fast::MessagePart", (MIME__Fast__MessagePart)mime_object);
222 else if (GMIME_IS_MULTIPART(mime_object))
223 rvpart = sv_setref_pv(svpart, "MIME::Fast::MultiPart", (MIME__Fast__MultiPart)mime_object);
224 else if (GMIME_IS_PART(mime_object))
225 rvpart = sv_setref_pv(svpart, "MIME::Fast::Part", (MIME__Fast__Part)mime_object);
226 else
227 rvpart = sv_setref_pv(svpart, "MIME::Fast::Object", mime_object);
228
229 if (gmime_debug)
230 warn("function call_sub_foreach: setref (not in plist) MIME::Fast object 0x%x", mime_object);
231 PUSHMARK(sp);
232 XPUSHs(rvpart);
233 XPUSHs(sv_mortalcopy(svdata->svuser_data));
234 PUTBACK ;
235 if (svdata->svfunc)
236 perl_call_sv(svdata->svfunc, G_DISCARD);
237 }
238
239 /* filter sizeout func */
240 size_t
call_filter_sizeout_func(size_t len,gpointer data)241 call_filter_sizeout_func (size_t len, gpointer data)
242 {
243 dSP ;
244 int count = 0;
245 size_t outlen = 0;
246 struct _user_data_sv *svdata;
247
248 ENTER ;
249 SAVETMPS;
250
251 svdata = (struct _user_data_sv *) data;
252
253 PUSHMARK(sp);
254 XPUSHs(sv_2mortal(newSViv(len)));
255 if (svdata->svuser_data)
256 XPUSHs(svdata->svuser_data);
257 PUTBACK ;
258
259 if (svdata->svfunc_sizeout)
260 count = perl_call_sv(svdata->svfunc_sizeout, G_SCALAR);
261
262 SPAGAIN ;
263
264 switch (count) {
265 case 1:
266 outlen = POPi;
267 break;
268 }
269 PUTBACK ;
270 FREETMPS ;
271 LEAVE ;
272 return outlen;
273 }
274
275
276 /* filter complete func */
277 size_t
call_filter_complete_func(unsigned char * in,size_t len,unsigned char * out,int * state,guint32 * save,gpointer data)278 call_filter_complete_func (unsigned char *in, size_t len, unsigned char *out, int *state, guint32 *save, gpointer data)
279 {
280 dSP ;
281 int count = 0;
282 size_t outlen = 0;
283 struct _user_data_sv *svdata;
284 char *outptr;
285 SV * svin;
286
287 ENTER ;
288 SAVETMPS;
289
290 svdata = (struct _user_data_sv *) data;
291
292 svin = sv_newmortal();
293 SvUPGRADE (svin, SVt_PV);
294 SvREADONLY_on (svin);
295 SvPVX (svin) = (char *)in;
296 SvCUR_set (svin, len);
297 SvLEN_set (svin, 0);
298 SvPOK_only (svin);
299
300 PUSHMARK(sp);
301 XPUSHs(svin);
302 XPUSHs(sv_2mortal(newSViv(*state)));
303 XPUSHs(sv_2mortal(newSViv(*save)));
304 if (svdata->svuser_data)
305 XPUSHs(svdata->svuser_data);
306 PUTBACK ;
307
308 if (svdata->svfunc_complete)
309 count = perl_call_sv(svdata->svfunc_complete, G_ARRAY);
310
311 SPAGAIN ;
312
313 switch (count) {
314 case 3:
315 *save = POPi;
316 case 2:
317 *state = POPi;
318 case 1:
319 {
320 STRLEN n_a;
321 outptr = POPpx;
322 outlen = n_a;
323 if (out && outptr && outlen > 0) {
324 memcpy (out, outptr, outlen);
325 }
326 }
327 break;
328 }
329 PUTBACK ;
330 FREETMPS ;
331 LEAVE ;
332 g_free (svdata);
333
334 return outlen;
335 }
336
337
338
339 /* filter step func */
340 size_t
call_filter_step_func(unsigned char * in,size_t len,unsigned char * out,int * state,guint32 * save,gpointer data)341 call_filter_step_func (unsigned char *in, size_t len, unsigned char *out, int *state, guint32 *save, gpointer data)
342 {
343 dSP ;
344 int count = 0;
345 size_t outlen = 0;
346 struct _user_data_sv *svdata;
347 char *outptr;
348 SV * svin;
349
350 ENTER ;
351 SAVETMPS;
352
353 svdata = (struct _user_data_sv *) data;
354
355 svin = sv_newmortal();
356 SvUPGRADE (svin, SVt_PV);
357 SvREADONLY_on (svin);
358 SvPVX (svin) = (char *)in;
359 SvCUR_set (svin, len);
360 SvLEN_set (svin, 0);
361 SvPOK_only (svin);
362
363 PUSHMARK(sp);
364 XPUSHs(svin);
365 XPUSHs(sv_2mortal(newSViv(*state)));
366 XPUSHs(sv_2mortal(newSViv(*save)));
367 if (svdata->svuser_data)
368 XPUSHs(svdata->svuser_data);
369 PUTBACK ;
370
371 if (svdata->svfunc)
372 count = perl_call_sv(svdata->svfunc, G_ARRAY);
373
374 SPAGAIN ;
375
376 switch (count) {
377 case 3:
378 *save = POPi;
379 case 2:
380 *state = POPi;
381 case 1:
382 {
383 STRLEN n_a;
384 outptr = POPpx;
385 outlen = n_a;
386 if (out && outptr && outlen > 0) {
387 memcpy (out, outptr, outlen);
388 }
389 }
390 break;
391 }
392 PUTBACK ;
393 FREETMPS ;
394 LEAVE ;
395
396 return outlen;
397 }
398
399 void
call_sub_header_regex(GMimeParser * parser,const char * header,const char * value,off_t offset,gpointer user_data)400 call_sub_header_regex (GMimeParser *parser, const char *header,
401 const char *value, off_t offset,
402 gpointer user_data)
403 {
404 SV *svfunc = NULL;
405 SV *svuser_data = NULL;
406 SV **sv;
407 HV *hvarray;
408
409 dSP ;
410
411 if (!user_data)
412 return;
413
414 if (!user_data || !SvROK((SV *)user_data))
415 return;
416
417 hvarray = (HV *)(SvRV((SV *)user_data));
418
419 sv = hv_fetch(hvarray, "func", 4, FALSE);
420 if (sv == (SV**)NULL)
421 croak("call_sub_header_regex: Internal error getting func ...\n") ;
422 svfunc = *sv;
423
424 sv = hv_fetch(hvarray, "user_data", 9, FALSE);
425 if (sv == (SV**)NULL)
426 croak("call_sub_header_regex: Internal error getting user data...\n") ;
427 svuser_data = *sv;
428
429 PUSHMARK(sp);
430 XPUSHs(sv_2mortal(newSVpv(header, 0)));
431 XPUSHs(sv_2mortal(newSVpv(value, 0)));
432 XPUSHs(sv_2mortal(newSViv(offset)));
433 XPUSHs(sv_mortalcopy(svuser_data));
434 PUTBACK ;
435 if (svfunc)
436 perl_call_sv(svfunc, G_DISCARD);
437 }
438
439 MODULE = MIME::Fast PACKAGE = MIME::Fast
440
441 SV *
442 get_object_type(svmixed)
443 SV * svmixed
444 PREINIT:
445 void * data = NULL;
446 SV* svval;
447 svtype svvaltype;
448 CODE:
449 svval = svmixed;
450 svvaltype = SvTYPE(svval);
451 if (!sv_isobject(svmixed))
452 XSRETURN_UNDEF;
453 if (SvROK(svmixed)) {
454 IV tmp;
455 svval = SvRV(svmixed);
456 tmp = SvIV(svval);
457 data = (void *)tmp;
458 } else {
459 XSRETURN_UNDEF;
460 }
461 if (data == NULL) {
462 XSRETURN_UNDEF;
463 #if GMIME_CHECK_VERSION_UNSUPPORTED
464 } else if (GMIME_IS_MESSAGE_MDN((GMimeMessageMDN *)data)) {
465 RETVAL = newSVpvn("MIME::Fast::MessageMDN", 22);
466 } else if (GMIME_IS_MESSAGE_DELIVERY((GMimeMessageDelivery *)data)) {
467 RETVAL = newSVpvn("MIME::Fast::MessageDelivery", 27);
468 #endif
469 } else if (GMIME_IS_MESSAGE_PARTIAL((GMimeMessagePartial *)data)) {
470 RETVAL = newSVpvn("MIME::Fast::MessagePartial", 26);
471 } else if (GMIME_IS_PART((GMimePart *)data)) {
472 RETVAL = newSVpvn("MIME::Fast::Part", 16);
473 } else if (GMIME_IS_MULTIPART((GMimeMultipart *)data)) {
474 RETVAL = newSVpvn("MIME::Fast::MultiPart", 21);
475 } else if (GMIME_IS_MESSAGE((GMimeMessage *)data)) {
476 RETVAL = newSVpvn("MIME::Fast::Message", 19);
477 } else if (GMIME_IS_MESSAGE_PART((GMimeMessagePart *)data)) {
478 RETVAL = newSVpvn("MIME::Fast::MessagePart", 23);
479 } else if (GMIME_IS_OBJECT((GMimeObject *)data)) {
480 RETVAL = newSVpvn("MIME::Fast::Object", 18);
481 } else if (sv_isobject(svmixed)) {
482 RETVAL = newSVpv( HvNAME( SvSTASH(SvRV(svmixed)) ), 0);
483 } else {
484 XSRETURN_UNDEF;
485 }
486 OUTPUT:
487 RETVAL
488
489
490 BOOT:
491 g_mime_init(0);
492
493 double
494 constant(sv,arg)
495 PREINIT:
496 STRLEN len;
497 INPUT:
498 SV * sv
499 char * s = SvPV(sv, len);
500 int arg
501 CODE:
502 RETVAL = constant(s,len,arg);
503 OUTPUT:
504 RETVAL
505
506 const char *
507 constant_string(sv,arg)
508 PREINIT:
509 STRLEN len;
510 INPUT:
511 SV * sv
512 char * s = SvPV(sv, len);
513 int arg
514 CODE:
515 RETVAL = constant_string(s,len,arg);
516 OUTPUT:
517 RETVAL
518
519
520 INCLUDE: Fast/Object.xs
521 INCLUDE: Fast/Param.xs
522 INCLUDE: Fast/ContentType.xs
523 INCLUDE: Fast/MultiPart.xs
524 INCLUDE: Fast/Part.xs
525 INCLUDE: Fast/Message.xs
526 INCLUDE: Fast/MessagePart.xs
527 INCLUDE: Fast/MessagePartial.xs
528
529 #if GMIME_CHECK_VERSION_UNSUPPORTED
530
531 INCLUDE: Fast/MessageDelivery.xs
532 INCLUDE: Fast/MessageMDN.xs
533 INCLUDE: Fast/MessageMDNDisposition.xs
534
535 #endif
536
537 INCLUDE: Fast/InternetAddress.xs
538 INCLUDE: Fast/Charset.xs
539 INCLUDE: Fast/DataWrapper.xs
540 INCLUDE: Fast/Stream.xs
541 INCLUDE: Fast/StreamFilter.xs
542 INCLUDE: Fast/Filter.xs
543 INCLUDE: Fast/Filter/Basic.xs
544 INCLUDE: Fast/Filter/Best.xs
545 INCLUDE: Fast/Filter/Charset.xs
546 INCLUDE: Fast/Filter/CRLF.xs
547 INCLUDE: Fast/Filter/Enriched.xs
548 INCLUDE: Fast/Filter/From.xs
549
550 #if GMIME_CHECK_VERSION_UNSUPPORTED
551
552 INCLUDE: Fast/Filter/Func.xs
553
554 #endif
555
556 INCLUDE: Fast/Filter/HTML.xs
557 INCLUDE: Fast/Filter/Md5.xs
558 INCLUDE: Fast/Filter/Strip.xs
559
560 #if GMIME_CHECK_VERSION_2_1_0
561
562 INCLUDE: Fast/Filter/Windows.xs
563
564 #endif
565
566 INCLUDE: Fast/Filter/Yenc.xs
567 INCLUDE: Fast/Parser.xs
568 INCLUDE: Fast/Disposition.xs
569 INCLUDE: Fast/Utils.xs
570 INCLUDE: Fast/Hash.xs
571
572