dtcm/reminders.c: NULL is not 0
[oweals/cde.git] / cde / programs / dtcm / dtcm / submit.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*******************************************************************************
24 **
25 **  submit.c
26 **
27 **  $XConsortium: submit.c /main/5 1996/10/03 10:58:04 drk $
28 **
29 **  RESTRICTED CONFIDENTIAL INFORMATION:
30 **
31 **  The information in this document is subject to special
32 **  restrictions in a confidential disclosure agreement between
33 **  HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34 **  document outside HP, IBM, Sun, USL, SCO, or Univel without
35 **  Sun's specific written approval.  This document and all copies
36 **  and derivative works thereof must be returned or destroyed at
37 **  Sun's request.
38 **
39 **  Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
40 **
41 *******************************************************************************/
42
43 /*                                                                      *
44  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
45  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
46  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
47  * (c) Copyright 1993, 1994 Novell, Inc.                                *
48  */
49
50 #ifndef lint
51 #endif
52
53 #include <stdio.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <stdlib.h>
57 #include <sys/wait.h>
58 #include <LocaleXlate.h>
59 #include <RFCMIME.h>
60 #include "rerule.h"                     /* FALSE */
61
62
63 static char **
64 arpaPhrase(const char * name)
65 {
66     register char c;
67     register const char *cp;
68     char * cp2;
69     int gotlt, lastsp, didq;
70     int nesting;
71     const char * last_comma = name;
72     int biggest = 0;
73     int n_addrs = 0;
74     int cur_addr;
75     int distance;
76     char ** addrs;
77     const char * comma;
78     const char * start;
79     
80     if (name == (char *) 0) {
81         return(NULL);
82     }
83
84     /* We need to figure out what is the biggest possible address.
85        This will be the maximum distance between commas.
86        */
87     for (comma = name; *comma; comma++) {
88         if (*comma == ',') {
89             n_addrs += 1;
90             distance = comma - last_comma;
91             biggest = biggest < distance ? distance : biggest;
92             last_comma = comma;
93         }
94     }
95     distance = comma - last_comma;
96     biggest = biggest < distance ? distance : biggest;
97     biggest += 2; /* Just in case. */
98
99     cur_addr = 0;
100     addrs = (char **)malloc((n_addrs + 1) * sizeof(char *));
101
102     cp2 = (char *)malloc(biggest);
103     addrs[cur_addr++] = cp2;
104
105     gotlt = 0;
106     lastsp = 0;
107     start = name;
108     for (cp = name; (c = *cp++) != 0;) {
109         switch (c) {
110           case '(':
111             /*
112               Start of a comment, ignore it.
113               */
114             nesting = 1;
115             while ((c = *cp) != 0) {
116                 cp++;
117                 switch(c) {
118                   case '\\':
119                     if (*cp == 0) goto outcm;
120                     cp++;
121                     break;
122                   case '(':
123                     nesting++;
124                     break;
125                   case ')':
126                     --nesting;
127                     break;
128                 }
129                 if (nesting <= 0) break;
130             }
131           outcm:
132             lastsp = 0;
133             break;
134             
135           case '"':
136             /*
137               Start a quoted string.
138               Copy it in its entirety.
139               */
140             didq = 0;
141             while ((c = *cp) != 0) {
142                 cp++;
143                 switch (c) {
144                   case '\\':
145                     if ((c = *cp) == 0) goto outqs;
146                     cp++;
147                     break;
148                   case '"':
149                     goto outqs;
150                 }
151                 if (gotlt == 0 || gotlt == '<') {
152                     if (lastsp) {
153                         lastsp = 0;
154                         *cp2++ = ' ';
155                     }
156                     if (!didq) {
157                         *cp2++ = '"';
158                         didq++;
159                     }
160                     *cp2++ = c;
161                 }
162             }
163           outqs:
164             if (didq)
165                 *cp2++ = '"';
166             lastsp = 0;
167             break;
168             
169           case ' ':
170           case '\t':
171           case '\n':
172               done:
173             *cp2 = 0;
174
175             cp2 = (char *)malloc(biggest);
176             addrs[cur_addr++] = cp2;
177
178             lastsp = 1;
179             break;
180             
181           case ',':
182             *cp2++ = c;
183             if (gotlt != '<') {
184                 gotlt = 0;
185                 goto done;
186             }
187             break;
188             
189           case '<':
190             cp2 = addrs[cur_addr - 1];
191             gotlt = c;
192             lastsp = 0;
193             break;
194             
195           case '>':
196             if (gotlt == '<') {
197                 gotlt = c;
198                 break;
199             }
200             
201             /* FALLTHROUGH . . . */
202             
203           default:
204             if (gotlt == 0 || gotlt == '<') {
205                 if (lastsp) {
206                     lastsp = 0;
207                     *cp2++ = ' ';
208                 }
209                 *cp2++ = c;
210             }
211             break;
212         }
213     }
214     *cp2 = 0;
215     addrs[cur_addr] = NULL;
216     return(addrs);
217 }
218
219 static char *
220 formatMessage(char ** addrs, const char * subject, const char * body)
221 {
222     char *      msg;
223     int         size = 0;
224     int         line;
225     char **     to;
226     int isAllASCII;
227     char hdr_buf[1024];
228     _DtXlateDb db = NULL;
229     char plat[_DtPLATFORM_MAX_LEN];
230     int execver;
231     int compver;
232     int body_len;
233     char digest[16];
234     char mime_type[64];
235     char tmpbuf[20];
236     char *ret_locale = NULL;
237     char *ret_lang = NULL;
238     char *ret_codeset = NULL;
239     char default_charset[64];
240     char *NewBuf = NULL;
241     unsigned long _len = 0;
242     Encoding enc;
243
244     /* Figure out how big we need the buffer to be. */
245     for (to = addrs; *to; to++) {
246         size += strlen(*to);
247         size += 2; /* Leave room for the , */
248     }
249
250     size += strlen(subject);
251     size += strlen(body);
252
253     /* We will need space for the header names, a blank line, and
254        other general formatting things. We could be exact, but
255        1024 is more than enough and give us some spare.
256        */
257     size += 1024;
258
259     msg = (char *)malloc(size);
260
261     strcpy(msg, "To: ");
262     line = 4;
263
264     for (to = addrs; *to; to++) {
265         strcat(msg, *to);
266         if (*(to + 1) != NULL) {
267             strcat(msg, ", ");
268             line += strlen(*to);
269             if (line > 72) {
270                 strcat(msg, "\n    ");
271                 line = 0;
272             }
273         }
274     }
275     strcat(msg, "\nSubject: ");
276
277     /* Encode the body of the message */
278     
279     /* 1) Open Lcx data bases */
280
281     if ((_DtLcxOpenAllDbs(&db) == 0) &&
282         (_DtXlateGetXlateEnv(db,plat,&execver,&compver) != 0))
283         {
284                 _DtLcxCloseDb(&db);
285                 strcat(msg, subject);
286                 if (msg[strlen(msg) - 1] == '\n') {
287                         msg[strlen(msg) - 1] = 0;
288                 }
289
290                 strcat(msg, "\nMime-Version: 1.0\n");
291                 strcat(msg, "Content-Type: text/plain;charset=us-ascii\n\n");
292                 strcat(msg, body);
293         }
294     else
295         {
296
297                 body_len = strlen(body);
298
299                 hdr_buf[0]='\0';
300                 
301                 strcpy(mime_type,"text/plain");
302                 rfc1522cpy(hdr_buf,subject);    
303                 strcat(hdr_buf,"Mime-Version: 1.0\n");
304                 isAllASCII= CvtStr((char *)NULL,(void *)body,(unsigned long)body_len,(void**)&NewBuf, &_len, CURRENT_TO_INTERNET);
305
306                 enc = getEncodingType(body,body_len,FALSE);
307        /*
308          * Here is an ugly adjustment again. If mime_type is text/plain and if
309          * ret_codeset is ISO-2022-JP/KR/TW/CN, we have to always use
310          * enc = MIME_7BIT
311          * This means if the user inputs UDC/VDC into the e-mail body,
312          * fold7 may convert it to the string with MSB-on character and
313          * dtmail passes it to sendmail as if I had all 7bit chars.
314          */
315                 getCharSet(default_charset);
316                 DtXlateOpToStdLocale(DtLCX_OPER_MIME, default_charset,
317                                         &ret_locale, &ret_lang, &ret_codeset);
318                 if ( !strncasecmp( mime_type, "text/plain", 10 ) &&
319                  ( !strncasecmp( ret_codeset, "ISO-2022-JP", 11 ) ||
320                    !strncasecmp( ret_codeset, "ISO-2022-KR", 11 ) ||
321                    !strncasecmp( ret_codeset, "ISO-2022-TW", 11 ) ||
322                    !strncasecmp( ret_codeset, "ISO-2022-CN", 11 )   ) ) 
323                         enc = MIME_7BIT;
324
325                 memset(digest,0,sizeof(digest));
326                 md5PlainText(body,body_len,digest);
327                 writeContentHeaders(hdr_buf,mime_type,enc,(char *)digest,isAllASCII);
328                 strcat(hdr_buf,"\n");
329                 strcat(hdr_buf,"Content-Length: ");
330                 if (( NewBuf != NULL) && ( _len != 0))
331                 {
332                         sprintf(tmpbuf,"%ld",_len);
333                         strcat(hdr_buf,tmpbuf);
334                         strcat(hdr_buf,"\n");
335                         strcat(msg,hdr_buf);
336                         strncat(msg,NewBuf,_len);
337                         strcat(hdr_buf,"\n");
338                 }
339                 else
340                 {
341                         sprintf(tmpbuf,"%d",body_len);
342                         strcat(hdr_buf,tmpbuf);
343                         strcat(hdr_buf,"\n");
344                         strcat(msg,hdr_buf);
345                         strcat(msg,body);
346                 }
347         }
348
349
350     return(msg);
351 }
352
353 static int
354 deliver(char ** addrs, char * msg)
355 {
356     char **     argv;
357     int         fd[2];
358     int         c_pid;
359     int         status;
360     int         n_addrs;
361     int         cp;
362
363     for (n_addrs = 0; addrs[n_addrs]; n_addrs++) {
364         continue;
365     }
366
367     argv = (char **)malloc((n_addrs + 2) * sizeof(char *));
368     argv[0] = "/usr/lib/sendmail";
369
370     for (cp = 0; addrs[cp]; cp++) {
371         argv[cp + 1] = addrs[cp];
372     }
373     argv[cp + 1] = NULL;
374
375     pipe(fd);
376
377     c_pid = fork();
378     if (c_pid < 0) {
379         return(c_pid);
380     }
381
382     if (c_pid == 0) { /* The child. */
383         dup2(fd[0], STDIN_FILENO);
384
385         execvp("/usr/lib/sendmail", (char *const *)argv);
386         _exit(1); /* This had better never happen! */
387     }
388     else { /* The parent. */
389         write(fd[1], msg, strlen(msg));
390         close(fd[0]);
391         close(fd[1]);
392
393         waitpid(c_pid, &status, 0);
394     }
395
396     return(status);
397 }
398
399 int
400 submit_mail(const char * to,
401             const char * subject,
402             const char * body)
403 {
404     char **     addrs;
405     char **     ad;
406     char *      msg;
407     int         status;
408
409     /* 
410       Parse the address list so we can form a reasonable one
411       for the user to see in the message.
412       */
413     addrs = arpaPhrase(to);
414
415     msg = formatMessage(addrs, subject, body);
416
417     status = deliver(addrs, msg);
418
419     for (ad = addrs; *ad; ad++) {
420         free(*ad);
421     }
422     free(addrs);
423
424     free(msg);
425
426     return(status);
427 }