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