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