Changed all of the proprietary strucmp() and struncmp() calls to the more
[citadel.git] / citadel / citmail.c
1 /*
2  * citmail.c v4.0
3  *
4  * This program may be used as a local mail delivery agent, which will allow
5  * all Citadel users to receive Internet e-mail.  To enable this functionality,
6  * you must tell sendmail, smail, or whatever mailer you are using, that this
7  * program is your local mail delivery agent.  This program is a direct
8  * replacement for lmail, deliver, or whatever.
9  *
10  * Usage:
11  *
12  * citmail <recipient>       - Deliver a message
13  * citmail -t <recipient>    - Address test mode (will not deliver)
14  * citmail -i                - Run as an SMTP daemon (typically from inetd)
15  *
16  */
17
18 #include "sysdep.h"
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <ctype.h>
24 #include <string.h>
25 #include <time.h>
26 #include <pwd.h>
27 #include <errno.h>
28 #include <syslog.h>
29 #include "citadel.h"
30
31 #define LOCAL 0
32 #define REMOTE 1
33 #define UUCP 2
34 #define CCITADEL 3
35
36 #undef tolower
37 #define tolower(x) isupper(x) ? (x+'a'-'A') : x
38
39 char *monthdesc[] = {   "Jan","Feb","Mar","Apr","May","Jun",
40                         "Jul","Aug","Sep","Oct","Nov","Dec" };
41
42
43
44 void LoadInternetConfig();
45 void get_config();
46 int IsHostLocal();
47 struct config config;
48
49 char ALIASES[128];
50 char CIT86NET[128];
51 char SENDMAIL[128];
52 char FALLBACK[128];
53 char GW_DOMAIN[128];
54 char TABLEFILE[128];
55 char OUTGOING_FQDN[128];
56 int RUN_NETPROC = 1;
57
58 long conv_date(sdbuf)
59 char sdbuf[]; {
60         int a,b,cpos,tend,tval;
61         long now;
62         struct tm *tmbuf;
63         char dbuf[128];
64
65         strcpy(dbuf,sdbuf);
66         time(&now);
67         tmbuf = (struct tm *)localtime(&now);
68
69         /* get rid of + or - timezone mods */
70         for (a=0; a<strlen(dbuf); ++a) 
71                 if ((dbuf[a]=='+')||(dbuf[a]=='-'))
72                         do {
73                                 strcpy(&dbuf[a],&dbuf[a+1]);
74                                 } while ((dbuf[a]!=32)&&(dbuf[a]!=0));
75
76         /* try and extract the time by looking for colons */
77         cpos = (-1);
78         for (a=strlen(dbuf); a>=0; --a)
79                 if ((dbuf[a]==':')&&(atoi(&dbuf[a-1])!=0)) cpos=a;
80         if (cpos>=0) {
81                 cpos = cpos - 2;
82                 tend = strlen(dbuf);
83                 for (a=tend; a>=cpos; --a) if (dbuf[a]==' ') tend=a;
84
85                 tmbuf->tm_hour = atoi(&dbuf[cpos]);
86                 tmbuf->tm_min = atoi(&dbuf[cpos+3]);
87                 tmbuf->tm_sec = atoi(&dbuf[cpos+6]);
88
89                 do {
90                         strcpy(&dbuf[cpos],&dbuf[cpos+1]);
91                         } while ((dbuf[cpos]!=32)&&(dbuf[cpos]!=0));
92                 }
93
94         /* next try to extract a month */
95         
96         tval = (-1);
97         for (a=0; a<strlen(dbuf); ++a)
98                 for (b=0; b<12; ++b)
99                         if (!strncmp(&dbuf[a],monthdesc[b],3)) {
100                                 tval = b;
101                                 cpos = a;
102                                 }
103         if (tval >= 0) {
104                 tmbuf->tm_mon = tval;
105                 strcpy(&dbuf[cpos],&dbuf[cpos+3]);
106                 }
107
108         /* now the year */
109
110         for (a=0; a<strlen(dbuf); ++a)
111                 if ((atoi(&dbuf[a])>=1900) && (dbuf[a]!=32)) {
112                         tmbuf->tm_year = atoi(&dbuf[a]) - 1900;
113                         strcpy(&dbuf[a],&dbuf[a+4]);
114                         }
115
116         /* whatever's left is the mday (hopefully) */
117
118         for (a=0; a<strlen(dbuf); ++a)
119                 if ((dbuf[a]!=32)&&(atoi(&dbuf[a])>=1)&&(atoi(&dbuf[a])<=31)
120                    && ( (a==0)||(dbuf[a-1]==' ') ) ) {
121                         tmbuf->tm_mday = atoi(&dbuf[a]);
122                         strcpy(&dbuf[a],&dbuf[a+2]);
123                         }
124
125         return((long)mktime(tmbuf));
126         }
127
128
129 #ifdef NO_STRERROR
130 /*
131  * replacement strerror() for systems that don't have it
132  */
133 char *strerror(e)
134 int e; {
135         static char buf[32];
136
137         sprintf(buf,"errno = %d",e);
138         return(buf);
139         }
140 #endif
141
142 int haschar(st,ch)
143 char st[];
144 int ch; {
145         int a,b;
146         b=0;
147         for (a=0; a<strlen(st); ++a) if (st[a]==ch) ++b;
148         return(b);
149         }
150
151 void strip_trailing_whitespace(buf)
152 char buf[]; {
153         while(isspace(buf[strlen(buf)-1]))
154                 buf[strlen(buf)-1]=0;
155         }
156
157 /* strip leading and trailing spaces */
158 void striplt(buf)
159 char buf[]; {
160         while ( (strlen(buf)>0) && (buf[0]==32) ) strcpy(buf,&buf[1]);
161         while (buf[strlen(buf)-1] == 32) buf[strlen(buf)-1] = 0;
162         }
163
164
165 /*
166  * Check to see if a given FQDN really maps to a Citadel network node
167  */
168 void host_alias(char host[]) {
169
170         int a;
171
172         /* What name is the local host known by? */
173         /* if (!strcasecmp(host, config.c_fqdn)) { */
174         if (IsHostLocal(host)) {
175                 strcpy(host, config.c_nodename);
176                 return;
177                 }
178
179         /* Other hosts in the gateway domain? */
180         for (a=0; a<strlen(host); ++a) {
181                 if ((host[a]=='.') && (!strcasecmp(&host[a+1], GW_DOMAIN))) {
182                         host[a] = 0;
183                         for (a=0; a<strlen(host); ++a) {
184                                 if (host[a]=='.') host[a] = 0;
185                                 }
186                         return;
187                         }
188                 }
189
190         /* Otherwise, do nothing... */
191         }
192
193
194
195 /*
196  * Split an RFC822-style address into userid, host, and full name
197  */
198 void process_rfc822_addr(rfc822,user,node,name)
199 char rfc822[];
200 char user[];
201 char node[];
202 char name[];  {
203         int a;
204
205         /* extract full name - first, it's From minus <userid> */
206         strcpy(name,rfc822);
207         for (a=0; a<strlen(name); ++a) if (name[a]=='<') {
208                 do {
209                         strcpy(&name[a],&name[a+1]);
210                         } while ( (strlen(name) > 0) && (name[a]!='>') );
211                 strcpy(&name[a],&name[a+1]);
212                 }
213
214         /* strip anything to the left of a bang */
215         while ( (strlen(name)>0) && (haschar(name,'!')>0) ) 
216                 strcpy(name,&name[1]);
217
218         /* and anything to the right of a @ or % */
219         for (a=0; a<strlen(name); ++a) {
220                 if (name[a]=='@') name[a]=0;
221                 if (name[a]=='%') name[a]=0;
222                 }
223
224         /* but if there are parentheses, that changes the rules... */
225         if ( (haschar(rfc822,'(') == 1) && (haschar(rfc822,')') == 1) ) {
226                 strcpy(name,rfc822);
227                 while ( (strlen(name) > 0) && (name[0]!='(') ) {
228                         strcpy(&name[0],&name[1]);
229                         }
230                 strcpy(&name[0],&name[1]);
231                 for (a=0; a<strlen(name); ++a)
232                          if (name[a]==')') name[a]=0;
233                 }
234
235         /* but if there are a set of quotes, that supersedes everything */
236         if (haschar(rfc822,34)==2) {
237                 strcpy(name,rfc822);
238                 while ( (strlen(name) > 0) && (name[0]!=34) ) {
239                         strcpy(&name[0],&name[1]);
240                         }
241                 strcpy(&name[0],&name[1]);
242                 for (a=0; a<strlen(name); ++a)
243                         if (name[a]==34) name[a]=0;
244                 }
245
246         /* extract user id */
247         strcpy(user,rfc822);
248
249         /* first get rid of anything in parens */
250         for (a=0; a<strlen(user); ++a) if (user[a]=='(') {
251                 do {
252                         strcpy(&user[a],&user[a+1]);
253                         } while ( (strlen(user) > 0) && (user[a]!=')') );
254                 strcpy(&user[a],&user[a+1]);
255                 }
256
257         /* if there's a set of angle brackets, strip it down to that */
258         if ( (haschar(user,'<') == 1) && (haschar(user,'>') == 1) ) {
259                 while ( (strlen(user) > 0) && (user[0]!='<') ) {
260                         strcpy(&user[0],&user[1]);
261                         }
262                 strcpy(&user[0],&user[1]);
263                 for (a=0; a<strlen(user); ++a)
264                          if (user[a]=='>') user[a]=0;
265                 }
266
267         /* strip anything to the left of a bang */
268         while ( (strlen(user)>0) && (haschar(user,'!')>0) ) 
269                 strcpy(user,&user[1]);
270
271         /* and anything to the right of a @ or % */
272         for (a=0; a<strlen(user); ++a) {
273                 if (user[a]=='@') user[a]=0;
274                 if (user[a]=='%') user[a]=0;
275                 }
276
277
278         
279         /* extract node name */
280         strcpy(node, rfc822);
281
282         /* first get rid of anything in parens */
283         for (a=0; a<strlen(node); ++a) if (node[a]=='(') {
284                 do {
285                         strcpy(&node[a],&node[a+1]);
286                         } while ( (strlen(node) > 0) && (node[a]!=')') );
287                 strcpy(&node[a],&node[a+1]);
288                 }
289
290         /* if there's a set of angle brackets, strip it down to that */
291         if ( (haschar(node,'<') == 1) && (haschar(node,'>') == 1) ) {
292                 while ( (strlen(node) > 0) && (node[0]!='<') ) {
293                         strcpy(&node[0],&node[1]);
294                         }
295                 strcpy(&node[0],&node[1]);
296                 for (a=0; a<strlen(node); ++a)
297                          if (node[a]=='>') node[a]=0;
298                 }
299
300         /* strip anything to the left of a @ */
301         while ( (strlen(node)>0) && (haschar(node,'@')>0) ) 
302                 strcpy(node,&node[1]);
303
304         /* strip anything to the left of a % */
305         while ( (strlen(node)>0) && (haschar(node,'%')>0) ) 
306                 strcpy(node,&node[1]);
307
308         /* reduce multiple system bang paths to node!user */
309         while ( (strlen(node)>0) && (haschar(node,'!')>1) ) 
310                 strcpy(node,&node[1]);
311
312         /* now get rid of the user portion of a node!user string */
313         for (a=0; a<strlen(node); ++a) if (node[a]=='!') node[a]=0;
314
315
316
317         /* strip leading and trailing spaces in all strings */
318         striplt(user);
319         striplt(node);
320         striplt(name);
321         }
322
323 /*
324  * Copy line by line, ending at EOF or a "." 
325  */
326 void loopcopy(FILE *to, FILE *from) {
327         char buf[1024];
328         char *r;
329         
330         while (1) {
331                 r = fgets(buf, sizeof(buf), from);
332                 if (r == NULL) return;
333                 strip_trailing_whitespace(buf);
334                 if (!strcmp(buf, ".")) return;
335                 fprintf(to, "%s\n", buf);
336                 }
337         }
338
339
340 /*
341  * pipe message through netproc
342  */
343 void do_citmail(char recp[], int dtype) {
344
345         long now;
346         FILE *temp;
347         int a;
348         char buf[128];
349         char from[512];
350         char userbuf[256];
351         char frombuf[256];
352         char nodebuf[256];
353         char destsys[256];
354         char subject[256];
355
356
357         if (dtype==REMOTE) {
358
359                 /* get the Citadel node name out of the path */
360                 strncpy(destsys, recp, sizeof(destsys) );
361                 for (a=0; a<strlen(destsys); ++a) {
362                         if ((destsys[a]=='!')||(destsys[a]=='.')) {
363                                 destsys[a]=0;
364                                 }
365                         }
366
367                 /* chop the system name out, so we're left with a user */
368                 while (haschar(recp,'!')) strcpy(recp,&recp[1]);
369
370                 /* now convert underscores to spaces */
371                 for (a=0; a<strlen(recp); ++a) if (recp[a]=='_') recp[a]=' ';
372
373                 }
374
375         time(&now);
376         sprintf(from, "postmaster@%s", config.c_nodename);
377
378         sprintf(buf, "./network/spoolin/citmail.%d", getpid());
379         temp = fopen(buf,"w");
380
381         putc(255,temp); putc(MES_NORMAL,temp); putc(1,temp);
382         strcpy(subject,"");
383         strcpy(nodebuf, config.c_nodename);
384         do {
385                 if (fgets(buf,128,stdin) == NULL) strcpy(buf, ".");
386                 strip_trailing_whitespace(buf);
387
388                 if (!strncmp(buf,"Subject: ",9)) strcpy(subject,&buf[9]);
389                 if (!strncmp(buf,"Date: ",6)) now = conv_date(&buf[6]);
390                 if (!strncmp(buf,"From: ",6)) strcpy(from, &buf[6]);
391                 } while ( (strcmp(buf, ".")) && (strcmp(buf, "")) );
392
393         process_rfc822_addr(from, userbuf, nodebuf, frombuf);
394
395         /* now convert it to Citadel format */
396         fprintf(temp,"P%s@%s%c", userbuf, nodebuf, 0);
397         fprintf(temp,"E%s%c", userbuf, 0);
398         fprintf(temp,"T%ld%c", now, 0);
399         fprintf(temp,"A%s%c", frombuf, 0);
400         fprintf(temp,"OMail%c", 0);
401         fprintf(temp,"N%s%c", nodebuf, 0);
402         if (dtype==REMOTE) {
403                 fprintf(temp,"D%s%c", destsys, 0);
404                 }
405         fprintf(temp,"R%s%c", recp, 0);
406         if (strlen(subject)>0) {
407                 fprintf(temp,"U%s%c", subject, 0);
408                 }
409         putc('M',temp);
410         if (strcmp(buf, ".")) loopcopy(temp, stdin);
411         putc(0,temp);
412         fclose(temp);
413         }
414
415 void do_roommail(recp)  /* pipe public message through netproc */
416 char recp[]; {
417         long now;
418         FILE *temp;
419         int a;
420         char buf[128],userbuf[128],frombuf[128],nodebuf[128];
421         char subject[128], from[256];
422
423         strcpy(subject,"");
424         sprintf(from, "postmaster@%s", config.c_nodename);
425         strcpy(recp,&recp[5]);
426         for (a=0; a<strlen(recp); ++a) if (recp[a]=='_') recp[a]=32;
427         time(&now);
428
429
430         sprintf(buf,"./network/spoolin/citmail.%d",getpid());
431         temp = fopen(buf,"w");
432
433         putc(255,temp); putc(MES_NORMAL,temp); putc(1,temp);
434         strcpy(frombuf,"Internet Mail Gateway");
435         strcpy(nodebuf, config.c_nodename);
436         do {
437                 if (fgets(buf,128,stdin) == NULL) strcpy(buf, ".");
438                 strip_trailing_whitespace(buf);
439
440                 if (!strncmp(buf,"Subject: ",9)) strcpy(subject,&buf[9]);
441                 if (!strncmp(buf,"Date: ",6)) now = conv_date(&buf[6]);
442                 if (!strncmp(buf,"From: ",6)) strcpy(from, &buf[6]);
443                 } while ( (strcmp(buf, ".")) && (strcmp(buf, "")) );
444
445         process_rfc822_addr(from, userbuf, nodebuf, frombuf);
446
447         fprintf(temp,"P%s@%s",userbuf,nodebuf); putc(0,temp);
448         fprintf(temp,"T%ld",now); putc(0,temp);
449         fprintf(temp,"A%s",frombuf); putc(0,temp);
450         fprintf(temp,"O%s",recp); putc(0,temp);
451         fprintf(temp,"N%s",nodebuf); putc(0,temp);
452         if (strlen(subject)>0) {
453                 fprintf(temp,"U%s",subject); putc(0,temp);
454                 }
455         putc('M',temp);
456         if (strcmp(buf, ".")) loopcopy(temp, stdin);
457         putc(0,temp);
458         fclose(temp);
459         }
460
461 void do_uudecode(target)
462 char *target;  {
463         static char buf[1024];
464         FILE *fp;
465         
466         sprintf(buf,"cd %s; uudecode",target);
467
468         fp=popen(buf,"w");
469         if (fp==NULL) return;
470         while (fgets(buf,1024,stdin)!=NULL) {
471                 fprintf(fp,"%s",buf);
472                 }
473         pclose(fp);
474
475         }
476
477 void do_fallback(recp)
478 char recp[]; {
479         static char buf[1024];
480         FILE *fp;
481         
482         sprintf(buf, FALLBACK, recp);
483         fp=popen(buf,"w");
484         if (fp==NULL) fp = popen("cat >/dev/null", "w");
485         loopcopy(fp, stdin);
486         pclose(fp);
487         }
488
489 int alias(name)
490 char *name; {
491         FILE *fp;
492         int a;
493         char abuf[256];
494         
495         fp=fopen(ALIASES,"r");
496         if (fp==NULL) {
497                 syslog(LOG_ERR,"cannot open %s: %s",ALIASES,strerror(errno));
498                 return(2);
499                 }
500
501         while (fgets(abuf,256,fp)!=NULL) {
502                 strip_trailing_whitespace(abuf);
503                 for (a=0; a<strlen(abuf); ++a) {
504                         if (abuf[a]==',') {
505                                 abuf[a]=0;
506                                 if (!strcasecmp(name,abuf)) {
507                                         strcpy(name,&abuf[a+1]);
508                                         }
509                                 }
510                         }
511                 }
512         fclose(fp);
513         return(0);
514         }
515
516
517 void deliver(char recp[], int is_test, int deliver_to_ignet) {
518
519         /* various ways we can deliver mail... */
520
521         if (deliver_to_ignet) {
522                 syslog(LOG_NOTICE,"to Citadel network user %s",recp);
523                 if (is_test == 0) do_citmail(recp, REMOTE);
524                 }
525
526         else if (!strcmp(recp,"uudecode")) {
527                 syslog(LOG_NOTICE,"uudecoding to bit bucket directory");
528                 if (is_test == 0) do_uudecode(config.c_bucket_dir);
529                 }
530
531         else if (!strcmp(recp,"cit86net")) {
532                 syslog(LOG_NOTICE,"uudecoding to Cit86net spool");
533                 if (is_test == 0) {
534                         do_uudecode(CIT86NET);
535                         system("exec ./BatchTranslate86");
536                         }
537                 }
538
539         else if (!strcmp(recp,"null")) {
540                 syslog(LOG_NOTICE,"zapping nulled message");
541                 }
542
543         else if (!strncasecmp(recp,"room_",5)) {
544                 syslog(LOG_NOTICE,"to room %s",recp);
545                 if (is_test == 0) do_roommail(recp);
546                 }
547
548         else {
549                 /* Otherwise, we treat the recipient as the name of a local
550                  * Citadel user.  If the username doesn't exist, we still
551                  * deliver it to Citadel -- netproc will handle the bounce.
552                  */
553                 syslog(LOG_NOTICE,"to Citadel user %s",recp);
554                 if (is_test == 0) do_citmail(recp, LOCAL);
555                 }
556
557         }
558
559
560
561 void main(argc,argv)
562 int argc;
563 char *argv[]; {
564         int is_test = 0;
565         int deliver_to_ignet = 0;
566         int smtp = 0;
567         static char recp[1024], buf[1024];
568         static char user[1024], node[1024], name[1024];
569         int a;
570
571         openlog("citmail", LOG_PID, LOG_USER);
572         get_config();
573         LoadInternetConfig();
574
575         if (!strcmp(argv[1],"-t")) {
576                 is_test = 1;
577                 syslog(LOG_NOTICE,"test mode - will not deliver");
578                 }
579         if (!strcmp(argv[1], "-i")) {
580                 smtp = 1;
581                 syslog(LOG_NOTICE,"started as an SMTP daemon");
582                 }
583
584
585         if (smtp) {
586                 strcpy(recp, "");
587                 }
588         else if (is_test == 0) {
589                 strcpy(recp,argv[1]);
590                 }
591         else {
592                 strcpy(recp,argv[2]);
593                 }
594
595
596         if (smtp) {
597                 /*** SMTP delivery mode ***/
598
599                 printf("200 Citadel/UX SMTP gateway ready.\n");
600         
601                 do {
602                         fflush(stdout);
603                         fflush(stderr);
604                         fgets(buf, 1024, stdin);
605                         while ( (strlen(buf)>0) && (buf[strlen(buf)-1]>0) && (buf[strlen(buf)-1]<32) ) {
606                                 buf[strlen(buf)-1] = 0;
607                                 }
608
609                         /* null-pad to allow some lazy compares */
610                         buf[strlen(buf)+1] = 0;
611                         buf[strlen(buf)+2] = 0;
612                         buf[strlen(buf)+3] = 0;
613         
614                         if (!strncasecmp(buf, "QUIT", 4)) {
615                                 printf("221 Later, dude.\n");
616                                 }
617                         else if (!strncasecmp(buf, "HELP", 4)) {
618                                 printf("214 You think _you_ need help?\n");
619                                 }
620                         else if (!strncasecmp(buf, "HELO", 4)) {
621                                 printf("250 Howdy ho, Mr. Hankey!\n");
622                                 }
623                         else if (!strncasecmp(buf, "MAIL", 4)) {
624                                 printf("250 Sure, whatever...\n");
625                                 }
626
627
628                         else if (!strncasecmp(buf, "RCPT To: ", 9)) {
629                                 if (strlen(recp) > 0) {
630                                         printf("571 Multiple recipients not supported.\n");
631                                         }
632                                 else {
633                                         strcpy(recp, &buf[9]);
634                                         if (haschar(recp, ',')) {
635                                                 printf("571 Multiple recipients not supported.\n");
636                                                 strcpy(recp, "");
637                                                 }
638                                         else {
639                                                 syslog(LOG_NOTICE,"recp: %s",recp);
640                                                 for (a=0; a<2; ++a) {
641                                                         alias(recp);
642                                                         }
643
644                                                 /* did we alias it back to a remote address? */
645                                                 if (    (haschar(recp,'%'))
646                                                 ||      (haschar(recp,'@'))
647                                                 ||      (haschar(recp,'!')) ) {
648         
649                                                         process_rfc822_addr(recp, user, node, name);
650                                                         host_alias(node);
651                 
652                                                         /* If there are dots, it's an Internet host, so feed it
653                                                         * back to an external mail transport agent such as sendmail.
654                                                         */
655                                                         if (haschar(node, '.')) {
656                                                                 printf("571 Away with thee, spammer!\n");
657                                                                 strcpy(recp, "");
658                                                                 }
659                 
660                                                         /* Otherwise, we're dealing with Citadel mail. */
661                                                         else {
662                                                                 sprintf(recp, "%s!%s", node, user);
663                                                                 deliver_to_ignet = 1;
664                                                                 printf("250 IGnet recipient.\n");
665                                                                 }
666                                                         }
667                                                 else {
668                                                         printf("250 Local recipient.\n");
669                                                         }
670         
671                                                 }
672         
673                                         }
674                                 }
675
676
677
678                         else if (!strncasecmp(buf, "RCPT", 4)) {
679                                 printf("501 Only 'To:' commands are supported.\n");
680                                 }
681                         else if (!strncasecmp(buf, "DATA", 4)) {
682                                 if (strlen(recp) > 0) {
683                                         printf("354 Sock it to me, baby...\n");
684                                         fflush(stdout);
685                                         deliver(recp, is_test, deliver_to_ignet);
686                                         printf("250 Cool beans!\n");
687                                         }
688                                 else {
689                                         printf("503 No recipient has been specified.\n");
690                                         }
691                                 }
692                         else {
693                                 printf("500 Huh?\n");
694                                 }
695         
696                         } while (strncasecmp(buf,"QUIT",4));
697                 }
698
699         else {
700                 /*** Non-SMTP delivery mode ***/
701                 syslog(LOG_NOTICE,"recp: %s",recp);
702                 for (a=0; a<2; ++a) {
703                         alias(recp);
704                         }
705         
706                 /* did we alias it back to a remote address? */
707                 if (    (haschar(recp,'%'))
708                 ||      (haschar(recp,'@'))
709                 ||      (haschar(recp,'!')) ) {
710         
711                         process_rfc822_addr(recp, user, node, name);
712                         host_alias(node);
713                 
714                         /* If there are dots, it's an Internet host, so feed it
715                         * back to an external mail transport agent such as sendmail.
716                         */
717                         if (haschar(node, '.')) {
718                                 sprintf(buf, SENDMAIL, recp);
719                                 system(buf);
720                                 exit(0);
721                                 }
722         
723                         /* Otherwise, we're dealing with Citadel mail. */
724                         else {
725                                 sprintf(recp, "%s!%s", node, user);
726                                 deliver_to_ignet = 1;
727                                 }
728         
729                         }
730         
731                 deliver(recp, is_test, deliver_to_ignet);
732                 }
733         
734         closelog();
735         if (RUN_NETPROC) execlp("./netproc","netproc",NULL);
736         exit(0);
737         }
738