dtcm: Resolve CID 87562
[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 <errno.h>
58 #include <sys/wait.h>
59 #include <LocaleXlate.h>
60 #include <RFCMIME.h>
61 #include "rerule.h"                     /* FALSE */
62
63
64 static char **
65 arpaPhrase(const char * name)
66 {
67     register char c;
68     register const char *cp;
69     char * cp2;
70     int gotlt, lastsp, didq;
71     int nesting;
72     const char * last_comma = name;
73     int biggest = 0;
74     int n_addrs = 0;
75     int cur_addr;
76     int distance;
77     char ** addrs;
78     const char * comma;
79     const char * start;
80     
81     if (name == (char *) 0) {
82         return(NULL);
83     }
84
85     /* We need to figure out what is the biggest possible address.
86        This will be the maximum distance between commas.
87        */
88     for (comma = name; *comma; comma++) {
89         if (*comma == ',') {
90             n_addrs += 1;
91             distance = comma - last_comma;
92             biggest = biggest < distance ? distance : biggest;
93             last_comma = comma;
94         }
95     }
96     distance = comma - last_comma;
97     biggest = biggest < distance ? distance : biggest;
98     biggest += 2; /* Just in case. */
99
100     cur_addr = 0;
101     addrs = (char **)malloc((n_addrs + 1) * sizeof(char *));
102
103     cp2 = (char *)malloc(biggest);
104     addrs[cur_addr++] = cp2;
105
106     gotlt = 0;
107     lastsp = 0;
108     start = name;
109     for (cp = name; (c = *cp++) != 0;) {
110         switch (c) {
111           case '(':
112             /*
113               Start of a comment, ignore it.
114               */
115             nesting = 1;
116             while ((c = *cp) != 0) {
117                 cp++;
118                 switch(c) {
119                   case '\\':
120                     if (*cp == 0) goto outcm;
121                     cp++;
122                     break;
123                   case '(':
124                     nesting++;
125                     break;
126                   case ')':
127                     --nesting;
128                     break;
129                 }
130                 if (nesting <= 0) break;
131             }
132           outcm:
133             lastsp = 0;
134             break;
135             
136           case '"':
137             /*
138               Start a quoted string.
139               Copy it in its entirety.
140               */
141             didq = 0;
142             while ((c = *cp) != 0) {
143                 cp++;
144                 switch (c) {
145                   case '\\':
146                     if ((c = *cp) == 0) goto outqs;
147                     cp++;
148                     break;
149                   case '"':
150                     goto outqs;
151                 }
152                 if (gotlt == 0 || gotlt == '<') {
153                     if (lastsp) {
154                         lastsp = 0;
155                         *cp2++ = ' ';
156                     }
157                     if (!didq) {
158                         *cp2++ = '"';
159                         didq++;
160                     }
161                     *cp2++ = c;
162                 }
163             }
164           outqs:
165             if (didq)
166                 *cp2++ = '"';
167             lastsp = 0;
168             break;
169             
170           case ' ':
171           case '\t':
172           case '\n':
173               done:
174             *cp2 = 0;
175
176             cp2 = (char *)malloc(biggest);
177             addrs[cur_addr++] = cp2;
178
179             lastsp = 1;
180             break;
181             
182           case ',':
183             *cp2++ = c;
184             if (gotlt != '<') {
185                 gotlt = 0;
186                 goto done;
187             }
188             break;
189             
190           case '<':
191             cp2 = addrs[cur_addr - 1];
192             gotlt = c;
193             lastsp = 0;
194             break;
195             
196           case '>':
197             if (gotlt == '<') {
198                 gotlt = c;
199                 break;
200             }
201             
202             /* FALLTHROUGH . . . */
203             
204           default:
205             if (gotlt == 0 || gotlt == '<') {
206                 if (lastsp) {
207                     lastsp = 0;
208                     *cp2++ = ' ';
209                 }
210                 *cp2++ = c;
211             }
212             break;
213         }
214     }
215     *cp2 = 0;
216     addrs[cur_addr] = NULL;
217     return(addrs);
218 }
219
220 static char *
221 formatMessage(char ** addrs, const char * subject, const char * body)
222 {
223     char *      msg;
224     int         size = 0;
225     int         line;
226     char **     to;
227     int isAllASCII;
228     char hdr_buf[1024];
229     _DtXlateDb db = NULL;
230     char plat[_DtPLATFORM_MAX_LEN];
231     int execver;
232     int compver;
233     int body_len;
234     char digest[16];
235     char mime_type[64];
236     char tmpbuf[20];
237     char *ret_locale = NULL;
238     char *ret_lang = NULL;
239     char *ret_codeset = NULL;
240     char default_charset[64];
241     char *NewBuf = NULL;
242     unsigned long _len = 0;
243     Encoding enc;
244
245     /* Figure out how big we need the buffer to be. */
246     for (to = addrs; *to; to++) {
247         size += strlen(*to);
248         size += 2; /* Leave room for the , */
249     }
250
251     size += strlen(subject);
252     size += strlen(body);
253
254     /* We will need space for the header names, a blank line, and
255        other general formatting things. We could be exact, but
256        1024 is more than enough and give us some spare.
257        */
258     size += 1024;
259
260     msg = (char *)malloc(size);
261
262     strcpy(msg, "To: ");
263     line = 4;
264
265     for (to = addrs; *to; to++) {
266         strcat(msg, *to);
267         if (*(to + 1) != NULL) {
268             strcat(msg, ", ");
269             line += strlen(*to);
270             if (line > 72) {
271                 strcat(msg, "\n    ");
272                 line = 0;
273             }
274         }
275     }
276     strcat(msg, "\nSubject: ");
277
278     /* Encode the body of the message */
279     
280     /* 1) Open Lcx data bases */
281
282     if ((_DtLcxOpenAllDbs(&db) == 0) &&
283         (_DtXlateGetXlateEnv(db,plat,&execver,&compver) != 0))
284         {
285                 _DtLcxCloseDb(&db);
286                 strcat(msg, subject);
287                 if (msg[strlen(msg) - 1] == '\n') {
288                         msg[strlen(msg) - 1] = 0;
289                 }
290
291                 strcat(msg, "\nMime-Version: 1.0\n");
292                 strcat(msg, "Content-Type: text/plain;charset=us-ascii\n\n");
293                 strcat(msg, body);
294         }
295     else
296         {
297
298                 body_len = strlen(body);
299
300                 hdr_buf[0]='\0';
301                 
302                 strcpy(mime_type,"text/plain");
303                 rfc1522cpy(hdr_buf,subject);    
304                 strcat(hdr_buf,"Mime-Version: 1.0\n");
305                 isAllASCII= CvtStr((char *)NULL,(void *)body,(unsigned long)body_len,(void**)&NewBuf, &_len, CURRENT_TO_INTERNET);
306
307                 enc = getEncodingType(body,body_len,FALSE);
308        /*
309          * Here is an ugly adjustment again. If mime_type is text/plain and if
310          * ret_codeset is ISO-2022-JP/KR/TW/CN, we have to always use
311          * enc = MIME_7BIT
312          * This means if the user inputs UDC/VDC into the e-mail body,
313          * fold7 may convert it to the string with MSB-on character and
314          * dtmail passes it to sendmail as if I had all 7bit chars.
315          */
316                 getCharSet(default_charset);
317                 DtXlateOpToStdLocale(DtLCX_OPER_MIME, default_charset,
318                                         &ret_locale, &ret_lang, &ret_codeset);
319                 if ( !strncasecmp( mime_type, "text/plain", 10 ) &&
320                  ( !strncasecmp( ret_codeset, "ISO-2022-JP", 11 ) ||
321                    !strncasecmp( ret_codeset, "ISO-2022-KR", 11 ) ||
322                    !strncasecmp( ret_codeset, "ISO-2022-TW", 11 ) ||
323                    !strncasecmp( ret_codeset, "ISO-2022-CN", 11 )   ) ) 
324                         enc = MIME_7BIT;
325
326                 memset(digest,0,sizeof(digest));
327                 md5PlainText(body,body_len,digest);
328                 writeContentHeaders(hdr_buf,mime_type,enc,(char *)digest,isAllASCII);
329                 strcat(hdr_buf,"\n");
330                 strcat(hdr_buf,"Content-Length: ");
331                 if (( NewBuf != NULL) && ( _len != 0))
332                 {
333                         sprintf(tmpbuf,"%ld",_len);
334                         strcat(hdr_buf,tmpbuf);
335                         strcat(hdr_buf,"\n");
336                         strcat(msg,hdr_buf);
337                         strncat(msg,NewBuf,_len);
338                         strcat(hdr_buf,"\n");
339                 }
340                 else
341                 {
342                         sprintf(tmpbuf,"%d",body_len);
343                         strcat(hdr_buf,tmpbuf);
344                         strcat(hdr_buf,"\n");
345                         strcat(msg,hdr_buf);
346                         strcat(msg,body);
347                 }
348         }
349
350
351     return(msg);
352 }
353
354 static int
355 deliver(char ** addrs, char * msg)
356 {
357     char **     argv;
358     int         fd[2];
359     int         c_pid;
360     int         status;
361     int         n_addrs;
362     int         cp;
363
364     for (n_addrs = 0; addrs[n_addrs]; n_addrs++) {
365         continue;
366     }
367
368     argv = (char **)malloc((n_addrs + 2) * sizeof(char *));
369     argv[0] = "/usr/lib/sendmail";
370
371     for (cp = 0; addrs[cp]; cp++) {
372         argv[cp + 1] = addrs[cp];
373     }
374     argv[cp + 1] = NULL;
375
376     if(-1 == pipe(fd)) {
377         fprintf(stderr, "pipe() failed %d '%s'\n", errno, strerror(errno));
378         exit(EXIT_FAILURE);    
379     }
380
381     c_pid = fork();
382     if (c_pid < 0) {
383         return(c_pid);
384     }
385
386     if (c_pid == 0) { /* The child. */
387         dup2(fd[0], STDIN_FILENO);
388
389         execvp("/usr/lib/sendmail", (char *const *)argv);
390         _exit(1); /* This had better never happen! */
391     }
392     else { /* The parent. */
393         if(-1 == write(fd[1], msg, strlen(msg))) {
394             fprintf(stderr, "write() failed %d '%s'\n", errno, strerror(errno));
395             exit(EXIT_FAILURE);    
396         }
397         close(fd[0]);
398         close(fd[1]);
399
400         waitpid(c_pid, &status, 0);
401     }
402
403     return(status);
404 }
405
406 int
407 submit_mail(const char * to,
408             const char * subject,
409             const char * body)
410 {
411     char **     addrs;
412     char **     ad;
413     char *      msg;
414     int         status;
415
416     /* 
417       Parse the address list so we can form a reasonable one
418       for the user to see in the message.
419       */
420     addrs = arpaPhrase(to);
421
422     msg = formatMessage(addrs, subject, body);
423
424     status = deliver(addrs, msg);
425
426     for (ad = addrs; *ad; ad++) {
427         free(*ad);
428     }
429     free(addrs);
430
431     free(msg);
432
433     return(status);
434 }