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