1 #   include	"appUtilConfig.h"
2 
3 #   include	"sioSmtp.h"
4 #   include	"sioMemory.h"
5 #   include	"sioBase64.h"
6 #   include	"utilMemoryBuffer.h"
7 
8 #   include	<stdlib.h>
9 #   include	<stdarg.h>
10 #   include	<stdio.h>
11 #   include	<time.h>
12 #   include	<sys/types.h>
13 #   include	<sys/socket.h>
14 #   include	<pwd.h>
15 #   include	<unistd.h>
16 #   include	<errno.h>
17 #   include	<string.h>
18 #   include	<sys/utsname.h>
19 #   include	<netdb.h>
20 
21 #   include	<appDebugon.h>
22 
23 #   ifdef	NeXT
24 #	include	<libc.h>
25 
26 #	if HAVE_UNAME
27 #	else
28 #	    define USE_GETHOSTNAME
29 #	endif
30 #   endif
31 
32 #   ifdef __VMS
33 #	define	HAVE_PW_GECOS	0
34 #   else
35 #	define	HAVE_PW_GECOS	1
36 #   endif
37 
38 /************************************************************************/
39 /*									*/
40 /*  Forward declarations						*/
41 /*									*/
42 /************************************************************************/
43 
44 static int sioSmtpSayRecipients(	int			fd,
45 					const char *		recipients,
46 					void *			through,
47 					APP_COMPLAIN		complain );
48 
49 static int mmWriteHeader(	int			fd,
50 				const char *		name,
51 				const char *		value,
52 				void *			through,
53 				APP_COMPLAIN		complain );
54 
55 static int mmWrite(		int			fd,
56 				const char *		buf,
57 				unsigned int		len,
58 				void *			through,
59 				APP_COMPLAIN		complain );
60 
61 static int mmWriteCRLF(		int			fd,
62 				const char *		buf,
63 				void *			through,
64 				APP_COMPLAIN		complain );
65 
66 static int sioOutSmtpWriteBytes( void *			voidmc,
67 				const unsigned char *	buf,
68 				int			len );
69 
70 static int sioOutSmtpClose(	void *			voidmc );
71 
72 static int mmReadCRLF(	int			fd,
73 			char *			buf,
74 			void *			through,
75 			APP_COMPLAIN		complain );
76 
77 typedef struct MailContext
78     {
79     int			mcFd;
80     int			mcAtBeginOfLine;
81     void *		mcThrough;
82     APP_COMPLAIN	mcComplain;
83     } MailContext;
84 
85 static char MMscratch[1024];
86 
87 /************************************************************************/
88 /*									*/
89 /*  Abort an Smtp connection.						*/
90 /*									*/
91 /************************************************************************/
92 
sioOutSmtpAbortMessage(MailContext * mc,void * through,APP_COMPLAIN complain)93 static void sioOutSmtpAbortMessage(	MailContext *		mc,
94 					void *			through,
95 					APP_COMPLAIN		complain )
96     {
97     if  ( mmWriteCRLF( mc->mcFd, "RSET", through, complain ) )
98 	{ LDEB(1); return;	}
99 
100     if  ( mmReadCRLF( mc->mcFd, MMscratch, through, complain ) )
101 	{ LDEB(1); return;	}
102 
103     if  ( mmWriteCRLF( mc->mcFd, "QUIT", through, complain ) )
104 	{ LDEB(1); return;	}
105 
106     if  ( mmReadCRLF( mc->mcFd, MMscratch, through, complain ) )
107 	{ LDEB(1); return;	}
108 
109     return;
110     }
111 
112 
113 /************************************************************************/
114 /*									*/
115 /*  respond to a challenge from the mail server.			*/
116 /*									*/
117 /************************************************************************/
118 
sioOutSmtpChallengeResponse(MailContext * mc,const char * response,int responseLen,void * through,APP_COMPLAIN complain)119 static int sioOutSmtpChallengeResponse(	MailContext *		mc,
120 					const char *		response,
121 					int			responseLen,
122 					void *			through,
123 					APP_COMPLAIN		complain )
124     {
125     int				rval= 0;
126 
127     SimpleOutputStream *	sosmb= (SimpleOutputStream *)0;
128     SimpleOutputStream *	sosb64= (SimpleOutputStream *)0;
129     MemoryBuffer		mb64;
130 
131     utilInitMemoryBuffer( &mb64 );
132 
133     sosmb= sioOutMemoryOpen( &mb64 );
134     if  ( ! sosmb )
135 	{ XDEB(sosmb); rval= -1; goto ready; }
136     sosb64= sioOutBase64Open( sosmb );
137     if  ( ! sosb64 )
138 	{ XDEB(sosb64); rval= -1; goto ready; }
139 
140     sioOutWriteBytes( sosb64, (const unsigned char *)response, responseLen );
141 
142     sioOutClose( sosb64 ); sosb64= (SimpleOutputStream *)0;
143     sioOutClose( sosmb ); sosmb= (SimpleOutputStream *)0;
144 
145     if  ( mmWriteCRLF( mc->mcFd, (char *)mb64.mbBytes, through, complain ) )
146 	{ LDEB(1); rval= -1;	}
147 
148   ready:
149     if  ( sosb64 )
150 	{ sioOutClose( sosb64 );	}
151     if  ( sosmb )
152 	{ sioOutClose( sosmb );		}
153 
154     utilCleanMemoryBuffer( &mb64 );
155 
156     return rval;
157     }
158 
159 /************************************************************************/
160 /*									*/
161 /*  Open a connection to an SMTP server and send the mail headers	*/
162 /*									*/
163 /************************************************************************/
164 
sioOutSmtpOpen(const char * mailHost,const char * mailPort,const char * user,const char * pass,const char * from,const char * to,const char * cc,const char * bcc,const char * subject,const char * typeSlashSubtype,const char * mimeBoundary,void * through,APP_COMPLAIN complain)165 SimpleOutputStream * sioOutSmtpOpen(	const char *	mailHost,
166 					const char *	mailPort,
167 					const char *	user,
168 					const char *	pass,
169 					const char *	from,
170 					const char *	to,
171 					const char *	cc,
172 					const char *	bcc,
173 					const char *	subject,
174 					const char *	typeSlashSubtype,
175 					const char *	mimeBoundary,
176 					void *		through,
177 					APP_COMPLAIN	complain )
178     {
179     MailContext *		mc= (MailContext *)0;
180     const char *		past;
181     const char *		start;
182     const char *		nodename= (const char *)0;
183 
184     int				haveEsmtp= 1;
185     int				haveAuthLogin= 0;
186     /*
187     int				haveAuth= 0;
188     int				haveAuthPlain= 0;
189     */
190 
191     SimpleOutputStream *	sos;
192 
193 #   if HAVE_UNAME
194     struct utsname		un;
195 #   endif
196 
197 #   ifdef USE_GETHOSTNAME
198     char			node_scratch[256+1];
199 #   endif
200 
201     if  ( ! from || ! from[0] )
202 	{
203 	XDEB(from);
204 	(*complain)( through, APP_SYSTEMeFROM, (char *)0 );
205 	goto mmError;
206 	}
207 
208     if  ( ! to || ! to[0] )
209 	{
210 	XDEB(to);
211 	(*complain)( through, APP_SYSTEMeRCPT, (char *)0 );
212 	goto mmError;
213 	}
214 
215     if  ( ! (mc= (MailContext *)malloc( sizeof( MailContext ) )) )
216 	{
217 	XDEB(mc);
218 	(*complain)( through, APP_SYSTEMeNOMEM, (char *)0 );
219 	goto mmError;
220 	}
221 
222     mc->mcFd= -1;
223     mc->mcAtBeginOfLine= 1;
224     mc->mcThrough= through;
225     mc->mcComplain= complain;
226 
227     /********************************************************************/
228     /*  Open connection							*/
229     /********************************************************************/
230 
231     if  ( ! mailHost || ! mailHost[0] )
232 	{ mailHost= "mailhost";	}
233     if  ( ! mailPort || ! mailPort[0] )
234 	{ mailPort= "smtp";	}
235 
236     mc->mcFd= appOpenSocket( mailHost, mailPort, through, complain );
237     if  ( mc->mcFd < 0 )
238 	{ LDEB(mc->mcFd); goto mmError;	}
239 
240     do  {
241 	if  ( mmReadCRLF( mc->mcFd, MMscratch, through, complain ) )
242 	    { LDEB(1); goto mmError;				}
243 
244 	if  ( strncmp( MMscratch, "220", 3 ) )
245 	    {
246 	    SDEB(MMscratch);
247 	    (void) (*complain)( through, APP_SYSTEMeSMTP, MMscratch );
248 	    goto mmError;
249 	    }
250 	} while( MMscratch[3] != ' ' );
251 
252     /********************************************************************/
253     /*  Say hello							*/
254     /********************************************************************/
255 #   if HAVE_UNAME
256     if  ( uname( &un ) < 0 )
257 	{ LDEB(1); goto mmError;				}
258     nodename= un.nodename;
259 #   endif
260 
261 #   ifdef USE_GETHOSTNAME
262     if  ( gethostname( node_scratch, sizeof(node_scratch)- 1 ) )
263 	{ LDEB(1); goto mmError;				}
264 
265     node_scratch[sizeof(node_scratch)-1]= '\0';
266     nodename= node_scratch;
267 #   endif
268 
269     if  ( ! nodename )
270 	{ XDEB(nodename); goto mmError;	}
271 
272     sprintf( MMscratch, "EHLO %s", nodename );
273     if  ( mmWriteCRLF( mc->mcFd, MMscratch, through, complain ) )
274 	{ LDEB(1); goto mmError;				}
275 
276     do  {
277 	char *	head;
278 	char *	tail;
279 
280 	if  ( mmReadCRLF( mc->mcFd, MMscratch, through, complain ) )
281 	    { LDEB(1); goto mmError;				}
282 
283 	if  ( strncmp( MMscratch, "250", 3 ) )
284 	    {
285 	    if  ( strncmp( MMscratch, "500", 3 )	&&
286 		  strncmp( MMscratch, "502", 3 )	&&
287 		  strncmp( MMscratch, "554", 3 )	)
288 		{
289 		SDEB(MMscratch);
290 		(void) (*complain)( through, APP_SYSTEMeSMTP, MMscratch );
291 		goto mmError;
292 		}
293 	    else{ haveEsmtp= 0;	}
294 	    }
295 
296 	head= tail= MMscratch+ 4;
297 	while( *tail && ! isspace( *tail ) )
298 	    {
299 	    if  ( islower( *tail ) )
300 		{ *tail= toupper( *tail );	}
301 	    tail++;
302 	    }
303 
304 	if  ( tail- head == 4 && ! strncmp( head, "AUTH", 4 ) )
305 	    {
306 	    /* haveAuth= 1; */
307 
308 	    while( *tail && isspace( *tail ) )
309 		{ tail++;	}
310 	    head= tail;
311 	    while( *head )
312 		{
313 		while( *tail && ! isspace( *tail ) )
314 		    {
315 		    if  ( islower( *tail ) )
316 			{ *tail= toupper( *tail );	}
317 		    tail++;
318 		    }
319 
320 		if  ( tail- head == 5 && ! strncmp( head, "LOGIN", 5 ) )
321 		    { haveAuthLogin= 1;	}
322 		/*
323 		if  ( tail- head == 5 && ! strncmp( head, "PLAIN", 5 ) )
324 		    { haveAuthPlain= 1;	}
325 		*/
326 
327 		while( *tail && isspace( *tail ) )
328 		    { tail++;	}
329 		head= tail;
330 		}
331 	    }
332 
333 	} while( MMscratch[3] != ' ' );
334 
335     if  ( ! haveEsmtp )
336 	{
337 	sprintf( MMscratch, "HELO %s", nodename );
338 	if  ( mmWriteCRLF( mc->mcFd, MMscratch, through, complain ) )
339 	    { LDEB(1); goto mmError;				}
340 
341 	do  {
342 	    if  ( mmReadCRLF( mc->mcFd, MMscratch, through, complain ) )
343 		{ LDEB(1); goto mmError;				}
344 
345 	    if  ( strncmp( MMscratch, "250", 3 ) )
346 		{
347 		SDEB(MMscratch);
348 		(void) (*complain)( through, APP_SYSTEMeSMTP, MMscratch );
349 		goto mmError;
350 		}
351 	    } while( MMscratch[3] != ' ' );
352 	}
353 
354     /********************************************************************/
355     /*  Login into the server.						*/
356     /********************************************************************/
357     if  ( user && pass && haveAuthLogin )
358 	{
359 	sprintf( MMscratch, "AUTH LOGIN" );
360 	if  ( mmWriteCRLF( mc->mcFd, MMscratch, through, complain ) )
361 	    { LDEB(1); goto mmError;				}
362 
363 	for (;;)
364 	    {
365 	    if  ( mmReadCRLF( mc->mcFd, MMscratch, through, complain ) )
366 		{ LDEB(1); goto mmError;				}
367 
368 	    if  ( ! strncmp( MMscratch, "235", 3 ) )
369 		{ break;	}
370 
371 	    if  ( strncmp( MMscratch, "334", 3 ) )
372 		{
373 		SDEB(MMscratch);
374 		(void) (*complain)( through, APP_SYSTEMeSMTP, MMscratch );
375 		goto mmAbort;
376 		}
377 
378 	    /*  Username: */
379 	    if  ( ! strcmp( MMscratch+ 4, "VXNlcm5hbWU6" ) )
380 		{
381 		if  ( sioOutSmtpChallengeResponse( mc,
382 						user, strlen( user ),
383 						through, complain ) )
384 		    { LDEB(1);  goto mmAbort;	}
385 
386 		continue;
387 		}
388 
389 	    /*  Password: */
390 	    if  ( ! strcmp( MMscratch+ 4, "UGFzc3dvcmQ6" ) )
391 		{
392 		if  ( sioOutSmtpChallengeResponse( mc,
393 						pass, strlen( pass ),
394 						through, complain ) )
395 		    { LDEB(1);  goto mmAbort;	}
396 
397 		continue;
398 		}
399 
400 	    SDEB(MMscratch); goto mmAbort;
401 	    }
402 	}
403 
404     /********************************************************************/
405     /*  Say sender							*/
406     /********************************************************************/
407     if  ( (start= strchr( from, '<' )) && ( past= strchr( start, '>' ) ) )
408 	{ start++;						}
409     else{ start= from; past= from+ strlen( from );		}
410 
411     sprintf( MMscratch, "MAIL FROM:<%.*s>", (int)( past- start ), start );
412     if  ( mmWriteCRLF( mc->mcFd, MMscratch, through, complain ) )
413 	{ LDEB(1); goto mmAbort;				}
414 
415     do  {
416 	if  ( mmReadCRLF( mc->mcFd, MMscratch, through, complain ) )
417 	    { LDEB(1); goto mmAbort;				}
418 
419 	if  ( strncmp( MMscratch, "250", 3 ) )
420 	    {
421 	    SDEB(MMscratch);
422 	    (void) (*complain)( through, APP_SYSTEMeSMTP, MMscratch );
423 	    goto mmAbort;
424 	    }
425 	} while( MMscratch[3] != ' ' );
426 
427     /********************************************************************/
428     /*  Say recipient(s)						*/
429     /********************************************************************/
430 
431     if  ( sioSmtpSayRecipients( mc->mcFd, to, through, complain ) )
432 	{ LDEB(1); goto mmAbort;	}
433 
434     if  ( cc								&&
435 	  cc[0]								&&
436 	  sioSmtpSayRecipients( mc->mcFd, cc, through, complain )	)
437 	{ LDEB(1); goto mmAbort;	}
438 
439     if  ( bcc								&&
440 	  bcc[0]							&&
441 	  sioSmtpSayRecipients( mc->mcFd, bcc, through, complain )	)
442 	{ LDEB(1); goto mmAbort;	}
443 
444     /********************************************************************/
445     /*  Say DATA							*/
446     /********************************************************************/
447     if  ( mmWriteCRLF( mc->mcFd, "DATA", through, complain ) )
448 	{ LDEB(1); goto mmAbort;				}
449 
450     do  {
451 	if  ( mmReadCRLF( mc->mcFd, MMscratch, through, complain ) )
452 	    { LDEB(1); goto mmAbort;				}
453 
454 	if  ( strncmp( MMscratch, "354", 3 ) )
455 	    {
456 	    SDEB(MMscratch);
457 	    (void) (*complain)( through, APP_SYSTEMeSMTP, MMscratch );
458 	    goto mmAbort;
459 	    }
460 	} while( MMscratch[3] != ' ' );
461 
462     /********************************************************************/
463     /*  Write headers							*/
464     /********************************************************************/
465     if  ( mmWriteHeader( mc->mcFd, "From", from, through, complain )	||
466 	  mmWriteHeader( mc->mcFd, "To", to, through, complain )	||
467 	  mmWriteHeader( mc->mcFd, "Cc", cc, through, complain )	||
468 	  mmWriteHeader( mc->mcFd, "Subject", subject,
469 					    through, complain )		)
470 	{ LDEB(1); goto mmAbort;	}
471 
472     if  ( mimeBoundary )
473 	{
474 	const char *	mimeVersion= "MIME-Version";
475 
476 	const char *	name= "Content-Type";
477 	int		len= strlen( name );
478 	const char *	name2= " boundary=\"";
479 
480 	if  ( mmWriteHeader( mc->mcFd, mimeVersion, "1.0",
481 						through, complain )	||
482 	      mmWrite( mc->mcFd, name, len, through, complain )		||
483 	      mmWrite( mc->mcFd, ": ", 2, through, complain )		||
484 	      mmWrite( mc->mcFd, typeSlashSubtype,
485 					strlen( typeSlashSubtype ),
486 					through, complain )		||
487 	      mmWriteCRLF( mc->mcFd, ";", through, complain )		)
488 	    { LDEB(1); goto mmAbort;	}
489 
490 	len= strlen( name2 );
491 	if  ( mmWrite( mc->mcFd, name2, len, through, complain )	||
492 	      mmWrite( mc->mcFd, mimeBoundary,
493 				strlen( mimeBoundary ),
494 				through, complain )			||
495 	      mmWriteCRLF( mc->mcFd, "\"",  through, complain )		)
496 	    { LDEB(1); goto mmAbort;	}
497 	}
498     else{
499 	if  ( mmWriteHeader( mc->mcFd, "Content-Type", typeSlashSubtype,
500 						    through, complain )	)
501 	    { LDEB(1); goto mmAbort;	}
502 	}
503 
504     if  ( mmWriteCRLF( mc->mcFd, "\n", through, complain )		)
505 	{ LDEB(1); goto mmAbort;	}
506 
507     sos= sioOutOpen( (void *)mc, sioOutSmtpWriteBytes, sioOutSmtpClose );
508 
509     if  ( ! sos )
510 	{ XDEB(sos); goto mmAbort;	}
511 
512     return sos;
513 
514   mmAbort:
515     sioOutSmtpAbortMessage( mc, through, complain );
516 
517   mmError:
518 
519     if  ( mc )
520 	{
521 	if  ( mc->mcFd != -1 )
522 	    { close( mc->mcFd );				}
523 	free( (char *)mc );
524 	}
525 
526     return (SimpleOutputStream *)0;
527     }
528 
529 /************************************************************************/
530 /*									*/
531 /*  Send the next part of the mail body					*/
532 /*									*/
533 /************************************************************************/
534 
sioOutSmtpWriteBytes(void * voidmc,const unsigned char * buf,int len)535 static int sioOutSmtpWriteBytes(	void *			voidmc,
536 					const unsigned char *	buf,
537 					int			len )
538     {
539     static char			crlf[]	= "\015\012";
540     MailContext *		mc	= (MailContext *)voidmc;
541     const unsigned char *	start	= buf;
542     const unsigned char *	past;
543     unsigned int		todo	= len;
544 
545     while( todo > 0 )
546 	{
547 	past= (const unsigned char *)memchr( start, '\n', todo );
548 	if  ( past )
549 	    { todo -= past- start;				}
550 	else{ past= start+ todo; todo= 0;			}
551 
552 	if  ( past > start )
553 	    {
554 	    if  ( mmWrite( mc->mcFd, (const char *)start, past - start,
555 					mc->mcThrough, mc->mcComplain ) )
556 		{ LDEB(1); return -1;				}
557 	    }
558 
559 	if  ( todo > 0 )
560 	    {
561 	    if  ( mmWrite( mc->mcFd, crlf, 2,
562 					mc->mcThrough, mc->mcComplain ) )
563 		{ LDEB(1); return -1;				}
564 	    todo--; past++;
565 	    mc->mcAtBeginOfLine= 1;
566 	    }
567 	else{
568 	    mc->mcAtBeginOfLine= 0;
569 	    }
570 
571 	start= past;
572 	}
573 
574     return (int)len;
575     }
576 
577 /************************************************************************/
578 /*									*/
579 /*  Finish sending the mail body and close the connection		*/
580 /*									*/
581 /************************************************************************/
582 
sioOutSmtpClose(void * voidmc)583 static int sioOutSmtpClose(	void *		voidmc )
584     {
585     int			rval= 0;
586     MailContext *	mc= (MailContext *)voidmc;
587 
588     if  ( ! mc->mcAtBeginOfLine						&&
589 	  mmWriteCRLF( mc->mcFd, "\n", mc->mcThrough, mc->mcComplain )	)
590 	{ LDEB(1); rval= -1;	}
591 
592     if  ( ! rval							&&
593 	  mmWriteCRLF( mc->mcFd, ".\nQUIT\n", mc->mcThrough, mc->mcComplain ) )
594 	{ LDEB(1); rval= -1;	}
595 
596     close( mc->mcFd );
597     free( (char *)mc );
598 
599     return rval;
600     }
601 
602 /************************************************************************/
603 /*									*/
604 /*  Write a list of recipients to the SMTP connection			*/
605 /*									*/
606 /*  1)  Look for the end of this recipient.				*/
607 /*  2)  Distinguish between <name> and name.				*/
608 /*  3)  Tell the SMTP server about the recipient.			*/
609 /*  4)  Get its answer.							*/
610 /*									*/
611 /************************************************************************/
612 
sioSmtpSayRecipients(int fd,const char * recipients,void * through,APP_COMPLAIN complain)613 static int sioSmtpSayRecipients(	int			fd,
614 					const char *		recipients,
615 					void *			through,
616 					APP_COMPLAIN		complain )
617     {
618     int	ok= 0;
619 
620     while( recipients[0] == ' ' )
621 	{ recipients++;	}
622 
623     while( recipients[0] )
624 	{
625 	const char *		comma;
626 	const char *		start;
627 	const char *		past;
628 
629 	/*  1  */
630 	comma= strchr( recipients, ',' );
631 	if  ( ! comma )
632 	    { comma= recipients+ strlen( recipients );	} /*lie*/
633 
634 	/*  2  */
635 	start= recipients;
636 	while( *start && start < comma && *start != '<' )
637 	    { start++; }
638 
639 	if  ( *start == '<' )
640 	    {
641 	    start++; past= start;
642 	    while( *past && past < comma && *past != '>' )
643 		{ past++; }
644 	    }
645 	else{ start= recipients; past= comma;	}
646 
647 	/*  3  */
648 	sprintf( MMscratch, "RCPT TO:<%.*s>", (int)(past- start), start );
649 	if  ( mmWriteCRLF( fd, MMscratch, through, complain ) )
650 	    { LDEB(1); return -1;				}
651 
652 	/*  4  */
653 	do  {
654 	    if  ( mmReadCRLF( fd, MMscratch, through, complain ) )
655 		{ LDEB(1); return -1;				}
656 
657 	    if  ( ! strncmp( MMscratch, "250", 3 ) )
658 		{ ok++;						}
659 	    else{ (void) (*complain)( through, APP_SYSTEMeSMTP, MMscratch ); }
660 	    } while( MMscratch[3] != ' ' );
661 
662 	if  ( *comma == ',' )
663 	    { comma++;	}
664 
665 	recipients= comma;
666 	while( recipients[0] == ' ' )
667 	    { recipients++;	}
668 	}
669 
670     return (ok > 0)?0:-1;
671     }
672 
673 /************************************************************************/
674 /*									*/
675 /*  SMTP connection read and write utilities				*/
676 /*									*/
677 /************************************************************************/
678 
mmReadCRLF(int fd,char * buf,void * through,APP_COMPLAIN complain)679 static int mmReadCRLF(	int			fd,
680 			char *			buf,
681 			void *			through,
682 			APP_COMPLAIN		complain )
683     {
684     static char smallbuf[2];
685     int		nbytes= 0;
686 
687     for (;;)
688 	{
689 	int	done= read( fd, smallbuf, 1 );
690 
691 	if  ( done != 1 )
692 	    {
693 	    LSDEB(done,strerror(errno));
694 	    (*complain)( through, APP_SYSTEMeREAD, (char *)0 );
695 	    return -1;
696 	    }
697 
698 	nbytes += done;
699 
700 	*buf= *smallbuf;
701 
702 	if  ( nbytes >= 2 && *buf == 10 && *(buf-1) == 13 )
703 	    { *(buf-1)= 0; return 0;	}
704 
705 	buf++;
706 	}
707     }
708 
mmWriteCRLF(int fd,const char * buf,void * through,APP_COMPLAIN complain)709 static int mmWriteCRLF(	int			fd,
710 			const char *		buf,
711 			void *			through,
712 			APP_COMPLAIN		complain )
713     {
714     static char		crlf[]	= "\015\012";
715 
716     const char *	start	= buf;
717     const char *	past;
718 
719     while( *start )
720 	{
721 	past= strchr( start, '\n' );
722 	if  ( ! past )
723 	    { past= start + strlen( start );			}
724 
725 	if  ( past > start )
726 	    {
727 	    if  ( mmWrite( fd, start, past - start, through, complain ) )
728 		{ LDEB(1); return -1;				}
729 	    }
730 	if  ( mmWrite( fd, crlf, 2, through, complain ) )
731 	    { LDEB(1); return -1;				}
732 
733 	start= (*past) ? past + 1 : past;
734 	}
735 
736     return 0;
737     }
738 
mmWriteHeader(int fd,const char * name,const char * value,void * through,APP_COMPLAIN complain)739 static int mmWriteHeader(	int			fd,
740 				const char *		name,
741 				const char *		value,
742 				void *			through,
743 				APP_COMPLAIN		complain )
744     {
745     unsigned int	len;
746 
747     if  ( ! value || ! value[0] )
748 	{ return 0;						}
749 
750     len= strlen( name );
751     if  ( mmWrite( fd, name, len, through, complain )	||
752 	  mmWrite( fd, ": ", 2, through, complain )	||
753 	  mmWriteCRLF( fd, value, through, complain )	)
754 	{ LDEB(1); return -1;					}
755 
756     return 0;
757     }
758 
mmWrite(int fd,const char * buf,unsigned int len,void * through,APP_COMPLAIN complain)759 static int mmWrite(	int			fd,
760 			const char *		buf,
761 			unsigned int		len,
762 			void *			through,
763 			APP_COMPLAIN		complain )
764     {
765     int		done= write( fd, buf, len );
766 
767     if  ( done != (int)len )
768 	{
769 	LLDEB(len,done); SDEB(strerror(errno));
770 	(*complain)( through, APP_SYSTEMeWRITE, (char *)0 );
771 	return -1;
772 	}
773 
774     return 0;
775     }
776 
777 /************************************************************************/
778 /*									*/
779 /*  Return a qualified guess about the callers mail address.		*/
780 /*									*/
781 /************************************************************************/
782 
sioSmtpGuessMailAddress(void)783 char *	sioSmtpGuessMailAddress( void )
784     {
785     static char *	rval;
786     char *		to;
787 
788     const char *	domainname= (const char *)0;
789     const char *	fullhost= (const char *)0;
790     const char *	nodename= (const char *)0;
791     int			l;
792 
793     int			didFullName= 0;
794 
795     struct passwd *	pwd;
796 
797 #   if HAVE_UNAME
798     struct utsname	un;
799 #   endif
800 
801 #   ifdef USE_GETHOSTNAME
802     char			node_scratch[256+1];
803 #   endif
804 
805     if  ( rval )
806 	{ return rval;	}
807 
808 #   if HAVE_UNAME
809     if  ( uname( &un ) < 0 )
810 	{ LDEB(1); return (char *)0;	}
811     nodename= un.nodename;
812 #   endif
813 
814 #   ifdef USE_GETHOSTNAME
815     if  ( gethostname( node_scratch, sizeof(node_scratch)- 1 ) )
816 	{ LDEB(1); return (char *)0;		}
817 
818     node_scratch[sizeof(node_scratch)-1]= '\0';
819     nodename= node_scratch;
820 #   endif
821 
822     if  ( ! nodename )
823 	{ XDEB(nodename); return (char *)0;	}
824 
825 #   if defined(UTSNAME_DOMAIN) && ! defined(__cplusplus)
826     if  ( un.UTSNAME_DOMAIN[0] && strcmp( un.UTSNAME_DOMAIN, "(none)" ) )
827 	{ domainname= un.UTSNAME_DOMAIN;	}
828 #   endif
829 
830     if  ( ! domainname )
831 	{
832 	if  ( strchr( nodename, '.' ) )
833 	    { fullhost= nodename; }
834 	else{
835 	    struct hostent *	host= gethostbyname( nodename );
836 
837 	    l= strlen( nodename );
838 	    if  ( host )
839 		{
840 		char **		a= host->h_aliases;
841 
842 		if  ( ! strncmp( nodename, host->h_name, l )	&&
843 		      host->h_name[l] == '.'			)
844 		    { fullhost= host->h_name;	}
845 		else{
846 		    if  ( a ) while( *a )
847 			{
848 			if  ( ! strncmp( nodename, *a, l )	&&
849 			      (*a)[l] == '.'			)
850 			    { fullhost= *a; break;	}
851 
852 			a++;
853 			}
854 		    }
855 
856 		if  ( ! fullhost )
857 		    {
858 		    a= host->h_aliases;
859 
860 		    if  ( strchr( host->h_name, '.' ) )
861 			{ fullhost= host->h_name;	}
862 		    else{
863 			if  ( a ) while( *a )
864 			    {
865 			    if  ( strchr( *a, '.' ) )
866 				{ fullhost= *a; break;	}
867 
868 			    a++;
869 			    }
870 			}
871 		    }
872 		}
873 
874 	    if  ( ! fullhost )
875 		{ fullhost= nodename;	}
876 	    }
877 	}
878 
879     if  ( ! domainname && ! fullhost )
880 	{ XXDEB(domainname,fullhost); return (char *)0;	}
881 
882     pwd= getpwuid( getuid() );
883     if  ( ! pwd )
884 	{ LXDEB(getuid(),pwd); return (char *)0; }
885 
886     l= 0;
887     l += strlen( pwd->pw_name );
888 #   if HAVE_PW_GECOS
889     if  ( pwd->pw_gecos && *pwd->pw_gecos )
890 	{ l += strlen( pwd->pw_gecos )+ 3;	}
891 #   endif
892 
893     if  ( domainname )
894 	{
895 	l += strlen( nodename );
896 	l += 1;
897 	l += strlen( domainname );
898 	}
899     else{ l += strlen( fullhost ); }
900 
901     rval= (char *)malloc( l+ 2 );
902     if  ( ! rval )
903 	{ XDEB(rval); return (char *)0;	}
904 
905     to= rval; *to= '\0';
906 #   if HAVE_PW_GECOS
907     if  ( pwd->pw_gecos && *pwd->pw_gecos )
908 	{
909 	char *	s;
910 	char *	firstAlnum;
911 	char *	pastAlnum;
912 
913 	firstAlnum= pwd->pw_gecos;
914 	while( *firstAlnum && ! isalnum( *firstAlnum ) )
915 	    { firstAlnum++;	}
916 	s= pastAlnum= firstAlnum;
917 	while( *s )
918 	    {
919 	    if  ( isalnum( *s ) )
920 		{ pastAlnum= s+ 1;	}
921 	    s++;
922 	    }
923 
924 	if  ( pastAlnum > firstAlnum )
925 	    {
926 	    memcpy( to, firstAlnum, pastAlnum- firstAlnum );
927 	    to +=  pastAlnum- firstAlnum;
928 	    strcpy( to, " <" ); to += 2;
929 
930 	    didFullName= 1;
931 	    }
932 
933 	}
934 #   endif
935     strcpy( to, pwd->pw_name ); to += strlen( to );
936     strcpy( to, "@" ); to += strlen( to );
937     if  ( domainname )
938 	{
939 	strcpy( to, nodename ); to += strlen( to );
940 	strcpy( to, "." ); to += strlen( to );
941 	strcpy( to, domainname ); to += strlen( to );
942 	}
943     else{ strcpy( to, fullhost ); to += strlen( to );	}
944 
945     if  ( didFullName )
946 	{ strcpy( to, ">" ); to += strlen( to ); }
947 
948     return rval;
949     }
950