]> git.sur5r.net Git - openldap/blob - clients/rcpt500/main.c
s/<stdlib.h>/<ac/stdlib.h>/
[openldap] / clients / rcpt500 / main.c
1 /*
2  * main.c: for rcpt500 (X.500 email query responder)
3  *
4  * 16 June 1992 by Mark C Smith
5  * Copyright (c) 1992 The Regents of The University of Michigan
6  * All Rights Reserved
7  */
8
9 #include "portable.h"
10
11 #include <stdio.h>
12
13 #include <ac/stdlib.h>
14
15 #include <ac/ctype.h>
16 #include <ac/signal.h>
17 #include <ac/string.h>
18 #include <ac/syslog.h>
19 #include <ac/unistd.h>
20
21 #include "ldapconfig.h"
22 #include "rcpt500.h"
23
24 int dosyslog = 0;
25 #ifdef LDAP_CONNECTIONLESS
26 int do_cldap = 0;
27 #endif /* LDAP_CONNECTIONLESS */
28
29 int derefaliases = 1;
30 int sizelimit = RCPT500_SIZELIMIT;
31 int rdncount = RCPT500_RDNCOUNT;
32 int ldapport = 0;
33 char *ldaphost = NULL;
34 char *searchbase = NULL;
35 char *dapuser = NULL;
36 char *filterfile = FILTERFILE;
37 char *templatefile = TEMPLATEFILE;
38 static char reply[ MAXSIZE * RCPT500_LISTLIMIT ];
39
40
41 /*
42  * functions
43  */
44 static int  read_msg(FILE *fp, struct msginfo *msgp);
45 static char *read_hdr(FILE *fp, int off, char *buf, int MAXSIZEe, char **ln_p);
46 static int  send_reply(struct msginfo *msgp, char *body);
47 static int  find_command(char *text, char **argp);
48
49 /*
50  * main is invoked by sendmail via the alias file
51  * the entire incoming message gets piped to our standard input
52  */
53 int
54 main( int argc, char **argv )
55 {
56     char                *prog, *usage = "%s [-l] [-U] [-h ldaphost] [-p ldapport] [-b searchbase] [-a] [-z sizelimit] [-u dapuser] [-f filterfile] [-t templatefile] [-c rdncount]\n";
57     struct msginfo      msg;
58     int                 c, errflg;
59
60     *reply = '\0';
61
62     if (( prog = strrchr( argv[ 0 ], '/' )) == NULL ) {
63         prog = strdup( argv[ 0 ] );
64     } else {
65         prog = strdup( prog + 1 );
66     }
67
68     errflg = 0;
69     while (( c = getopt( argc, argv, "alUh:b:s:z:f:t:p:c:" )) != EOF ) {
70         switch( c ) {
71         case 'a':
72             derefaliases = 0;
73             break;
74         case 'l':
75             dosyslog = 1;
76             break;
77         case 'U':
78 #ifdef LDAP_CONNECTIONLESS
79             do_cldap = 1;
80 #else /* LDAP_CONNECTIONLESS */
81             fprintf( stderr,
82                         "Compile with -DLDAP_CONNECTIONLESS for -U support\n" );
83 #endif /* LDAP_CONNECTIONLESS */
84             break;      
85         case 'b':
86             searchbase = optarg;
87             break;
88         case 'h':
89             ldaphost = optarg;
90             break;
91         case 'p':
92             ldapport = atoi( optarg );
93             break;
94         case 'z':
95             sizelimit = atoi( optarg );
96             break;
97         case 'u':
98             dapuser = optarg;
99             break;
100         case 'f':
101             filterfile = optarg;
102             break;
103         case 't':
104             templatefile = optarg;
105             break;
106         case 'c':
107             rdncount = atoi( optarg );
108             break;
109         default:
110             ++errflg;
111         }
112     }
113     if ( errflg || optind < argc ) {
114         fprintf( stderr, usage, prog );
115         exit( 1 );
116     }
117
118 #ifdef SIGPIPE
119         (void) SIGNAL( SIGPIPE, SIG_IGN );
120 #endif
121
122     if ( dosyslog ) {
123         /*
124          * if syslogging requested, initialize
125          */
126 #ifdef LOG_DAEMON
127         openlog( prog, OPENLOG_OPTIONS, LOG_DAEMON );
128 #else
129         openlog( prog, OPENLOG_OPTIONS );
130 #endif
131     }
132
133     if ( read_msg( stdin, &msg ) < 0 ) {
134         if ( dosyslog ) {
135             syslog( LOG_INFO, "unparseable message ignored" );
136         }
137         exit( 0 );      /* so as not to give sendmail an error */
138     }
139
140     if ( dosyslog ) {
141         syslog( LOG_INFO, "processing command \"%s %s\" from %s",
142                 ( msg.msg_command < 0 ) ? "Unknown" :
143                 cmds[ msg.msg_command ].cmd_text,
144                 ( msg.msg_arg == NULL ) ? "" : msg.msg_arg, msg.msg_replyto );
145     }
146
147     if ( msg.msg_command < 0 ) {
148         msg.msg_command = 0;    /* unknown command == help command */
149     }
150
151 /*
152     sprintf( reply, "Your request was interpreted as: %s %s\n\n",
153             cmds[ msg.msg_command ].cmd_text, msg.msg_arg );
154 */
155
156     (*cmds[ msg.msg_command ].cmd_handler)( &msg, reply );
157
158     if ( send_reply( &msg, reply ) < 0 ) {
159         if ( dosyslog ) {
160             syslog( LOG_INFO, "reply failed: %m" );
161         }
162         exit( 0 );      /* so as not to give sendmail an error */
163     }
164
165     if ( dosyslog ) {
166         syslog( LOG_INFO, "reply OK" );
167     }
168
169     exit( 0 );
170 }
171
172
173 static int
174 read_msg( FILE *fp, struct msginfo *msgp )
175 {
176     char        buf[ MAXSIZE ], *line;
177     int         command = -1;
178
179     msgp->msg_replyto = msgp->msg_date = msgp->msg_subject = NULL;
180
181     line = NULL;
182     while( 1 ) {
183         if ( line == NULL ) {
184             if (( line = fgets( buf, MAXSIZE, fp )) == NULL ) {
185                 break;
186             }
187             buf[ strlen( buf ) - 1 ] = '\0';    /* remove trailing newline */
188         }
189
190         if ( *buf == '\0' ) {   /* start of message body */
191             break;
192         }
193         if ( strncasecmp( buf, "Reply-To:", 9 ) == 0 ) {
194             if ( msgp->msg_replyto != NULL ) {
195                 free( msgp->msg_replyto );
196             }
197              msgp->msg_replyto = read_hdr( fp, 9, buf, MAXSIZE, &line );
198         } else if ( strncasecmp( buf, "From:", 5 ) == 0 &&
199                     msgp->msg_replyto == NULL ) {
200              msgp->msg_replyto = read_hdr( fp, 5, buf, MAXSIZE, &line );
201         } else if ( strncasecmp( buf, "Date:", 5 ) == 0 ) {
202              msgp->msg_date = read_hdr( fp, 5, buf, MAXSIZE, &line );
203         } else if ( strncasecmp( buf, "Message-ID:", 5 ) == 0 ) {
204              msgp->msg_messageid = read_hdr( fp, 11, buf, MAXSIZE, &line );
205         } else if ( strncasecmp( buf, "Subject:", 8 ) == 0 ) {
206              if (( msgp->msg_subject =
207                     read_hdr( fp, 8, buf, MAXSIZE, &line )) != NULL ) {
208                 command = find_command( msgp->msg_subject, &msgp->msg_arg );
209             }
210         } else {
211             line = NULL;        /* discard current line */
212         }
213     }
214
215     while ( command < 0 && line != NULL ) {
216         /*
217          * read the body of the message, looking for commands
218          */
219         if (( line = fgets( buf, MAXSIZE, fp )) != NULL ) {
220             buf[ strlen( buf ) - 1 ] = '\0';    /* remove trailing newline */
221             command = find_command( buf, &msgp->msg_arg );
222         }
223     }
224
225     if ( msgp->msg_replyto == NULL ) {
226         return( -1 );
227     }
228
229     msgp->msg_command = command;
230     return( 0 );
231 }
232
233
234 static char *
235 read_hdr( FILE *fp, int offset, char *buf, int MAXSIZEe, char **linep )
236 {
237     char        *hdr;
238
239     for ( hdr = buf + offset; isspace( (unsigned char) *hdr ); ++hdr ) {
240         ;
241     }
242     if (( hdr = strdup( hdr )) == NULL ) {
243         if ( dosyslog ) {
244             syslog( LOG_ERR, "strdup: %m" );
245         }
246         exit( 1 );
247     }
248
249     while ( 1 ) {
250         *linep = fgets( buf, MAXSIZE, fp );
251         buf[ strlen( buf ) - 1 ] = '\0';        /* remove trailing newline */
252         if ( *linep == NULL || !isspace( (unsigned char) **linep )) {
253             break;
254         }
255         if (( hdr = realloc( hdr, strlen( hdr ) +
256                     strlen( *linep ) + 3 )) == NULL) {
257             if ( dosyslog ) {
258                 syslog( LOG_ERR, "realloc: %m" );
259             }
260             exit( 1 );
261         }
262         strcat( hdr, "\n" );
263         strcat( hdr, *linep );
264     }
265
266     return( hdr );
267 }
268
269
270 static int
271 send_reply( struct msginfo *msgp, char *body )
272 {
273     char        buf[ MAXSIZE ];
274     FILE        *cmdpipe;
275     int         rc;
276     
277     if (( cmdpipe = popen( RCPT500_PIPEMAILCMD, "w" )) == NULL ) {
278         if ( dosyslog ) {
279             syslog( LOG_ERR, "popen pipemailcmd failed: %m" );
280         }
281         return( -1 );
282     }
283
284     /*
285      * send the headers
286      */
287
288     sprintf( buf, "From: %s\n", RCPT500_FROM );
289     rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
290
291     if ( rc == 1 ) {
292         if ( msgp->msg_subject != NULL ) {
293             sprintf( buf, "Subject: Re: %s\n", msgp->msg_subject );
294         } else {
295             sprintf( buf, "Subject: query response\n" );
296         }
297         rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
298     }
299
300     if ( rc == 1 && msgp->msg_date != NULL ) {
301         /*
302          * add "In-reply-to:" header
303          */
304         if ( msgp->msg_messageid == NULL ) {
305             sprintf( buf, "In-reply-to: Your message of \"%s\"\n",
306                     msgp->msg_date );
307         } else {
308             sprintf( buf,
309                     "In-reply-to: Your message of \"%s\"\n             %s\n",
310                     msgp->msg_date, msgp->msg_messageid );
311         }
312         rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
313     }
314
315     if ( rc == 1 ) {
316         sprintf( buf, "To: %s\n", msgp->msg_replyto );
317         rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
318     }
319
320     /*
321      * send the header/body separator (blank line)
322      */
323     if ( rc == 1 ) {
324         rc = fwrite( "\n", 1, 1, cmdpipe );
325     }
326
327     /*
328      * send the body
329      */
330     if ( rc == 1 ) {
331         rc = fwrite( body, strlen( body ), 1, cmdpipe );
332     }
333
334     if ( rc != 1 && dosyslog ) {
335         syslog( LOG_ERR, "write to binmail failed: %m" );
336     }
337
338     if ( pclose( cmdpipe ) < 0 ) {
339         if ( dosyslog ) {
340             syslog( LOG_ERR, "pclose binmail failed: %m" );
341         }
342         return( -1 );
343     }
344
345     return( rc == 1 ? 0 : -1 );
346 }
347
348
349 static int
350 find_command( char *text, char **argp )
351 {
352     int         i;
353     char        *s, *p;
354     static char argbuf[ MAXSIZE ];
355
356     p = text;
357     for ( s = argbuf; *p != '\0'; ++p ) {
358         *s++ = TOLOWER( (unsigned char) *p );
359     }
360     *s = '\0';
361
362     for ( i = 0; cmds[ i ].cmd_text != NULL; ++i ) {
363         if (( s = strstr( argbuf, cmds[ i ].cmd_text )) != NULL
364             && isspace( (unsigned char) s[ strlen( cmds[ i ].cmd_text ) ] )) {
365             strcpy( argbuf, text + (s - argbuf) + strlen( cmds[ i ].cmd_text ));
366             *argp = argbuf;
367             while ( isspace( (unsigned char) **argp )) {
368                 ++(*argp);
369             }
370             return( i );
371         }
372     }
373
374     return( -1 );
375 }