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