-fpermissive to allow GCC to compile old C++
[oweals/cde.git] / cde / programs / dtmail / dtmail / DmxMessage.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 /* $TOG: DmxMessage.C /main/6 1998/07/24 16:18:17 mgreess $ */
24
25 /*
26  *+SNOTICE
27  *
28  *      $:$
29  *
30  *      RESTRICTED CONFIDENTIAL INFORMATION:
31  *      
32  *      The information in this document is subject to special
33  *      restrictions in a confidential disclosure agreement between
34  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
35  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
36  *      Sun's specific written approval.  This document and all copies
37  *      and derivative works thereof must be returned or destroyed at
38  *      Sun's request.
39  *
40  *      Copyright 1994 Sun Microsystems, Inc.  All rights reserved.
41  *
42  *+ENOTICE
43  */
44 /*
45  *                   Common Desktop Environment
46  *
47  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
48  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
49  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
50  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
51  *   (c) Copyright 1995 Digital Equipment Corp.
52  *   (c) Copyright 1995 Fujitsu Limited
53  *   (c) Copyright 1995 Hitachi, Ltd.
54  *                                                                   
55  *
56  *                     RESTRICTED RIGHTS LEGEND                              
57  *
58  *Use, duplication, or disclosure by the U.S. Government is subject to
59  *restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
60  *Technical Data and Computer Software clause in DFARS 252.227-7013.  Rights
61  *for non-DOD U.S. Government Departments and Agencies are as set forth in
62  *FAR 52.227-19(c)(1,2).
63
64  *Hewlett-Packard Company, 3000 Hanover Street, Palo Alto, CA 94304 U.S.A.
65  *International Business Machines Corp., Route 100, Somers, NY 10589 U.S.A. 
66  *Sun Microsystems, Inc., 2550 Garcia Avenue, Mountain View, CA 94043 U.S.A.
67  *Novell, Inc., 190 River Road, Summit, NJ 07901 U.S.A.
68  *Digital Equipment Corp., 111 Powdermill Road, Maynard, MA 01754, U.S.A.
69  *Fujitsu Limited, 1015, Kamikodanaka Nakahara-Ku, Kawasaki 211, Japan
70  *Hitachi, Ltd., 6, Kanda Surugadai 4-Chome, Chiyoda-ku, Tokyo 101, Japan
71  */
72
73 #include "Dmx.h"
74 // For CHARSET
75 #include <LocaleXlate.h>
76 #include <locale.h>
77 #if !defined(USL) && !defined(__uxp__)
78 #include <strings.h>
79 #else 
80 #include <EUSCompat.h>
81 #endif 
82
83 #include "Application.h"
84 #include "DtMail/DtMail.hh"
85 #include "DtMailTypes.h"
86 #include "MailSession.hh"
87 #include "RoamApp.h"
88 #include "str_utils.h"
89
90
91 DmxMsg::DmxMsg (void)
92 {
93         // initialize everything
94         message = NULL;
95         addlInfo = NULL;
96         numBPs = 0;
97         cachedValues = DTM_FALSE;
98
99         return;
100 }
101
102 void
103 DmxMsg::setHandle (DtMailMessageHandle &h)
104 {
105         msgHandle = h;
106         return;
107 }
108
109 void
110 DmxMsg::setHeader (DtMailHeaderLine &h)
111 {
112         msgHeader = h;
113         return;
114 }
115
116 void
117 DmxMsg::setMessage (DtMail::Message *m)
118 {
119         message = m;
120         return;
121 }
122
123 void
124 DmxMsg::setInfo (char *info)
125 {
126         addlInfo = strdup (info);
127         return;
128 }
129
130 char *
131 DmxMsg::getMessageHeader (DmxHeaders which)
132 {
133         int             i = 0, length = 0;
134         int             buflength = 0;
135         char            *rtn;
136         const char      *str;
137
138         if (which >= DMXNUMHDRS)
139           return (char *) NULL;
140
141         length = msgHeader.header_values[which].length ();
142         if (length == 0)
143             str = errorString(which);
144         else
145             str = *((msgHeader.header_values[which])[0]);
146
147         //need to free this after using it
148         rtn = strdup(str);
149         return (rtn);
150 }
151         
152
153         
154
155 char *
156 DmxMsg::getHeaders (DtMailBoolean abbreviated_only)
157 {
158     DtMailEnv           error;
159     DtMail::Session     *m_session = theRoamApp.session()->session(); 
160     DtMail::MailRc      *mail_rc = m_session->mailRc(error);
161     DtMail::Envelope    *env = message->getEnvelope(error);
162
163     DtMailHeaderHandle  hdr_hnd;
164     char                *name;
165     DtMailValueSeq      value;
166
167     // Code from MsgScrollingList - display_message().
168     // We're trying to reduce heap size by not allocating and 
169     // deleting space in every loop iteration.  So just have a 
170     // fixed size buffer initially.
171     // 
172
173     // Initial line size.  When not enough, allocate more.
174     int                 buffer_size = 2048;   
175     char                *buffer = new char [buffer_size];
176     int                 count = 0;
177     int                 hdr_num = 0;
178     char                *newline = "\n";
179     char                *separator = ": ";
180     int                 val = 0;
181
182     //
183     // Iterate through each header in the message and add it
184     // to the buffer.
185     //
186     for (hdr_hnd = env->getFirstHeader(error, &name, value), *buffer = '\0';
187          hdr_hnd && !error.isSet();
188          hdr_hnd = env->getNextHeader(error, hdr_hnd, &name, value), hdr_num++)
189     {
190         if (abbreviated_only == DTM_TRUE &&
191             (hdr_num != 0 || strcmp(name, "From") != 0))
192         {
193             DtMailEnv ierror;
194             if (mail_rc->ignore(ierror, name))
195             {
196                 free(name);
197                 value.clear();
198                 continue;
199             }
200         }
201             
202         for (val=0;  val<value.length();  val++)
203           count += strlen(name) +
204                    strlen(*(value[val])) +
205                    strlen(separator) +
206                    strlen(newline) + 1;
207
208         if (count > buffer_size)
209         {
210             // Need to increase buffer size.
211             char        *new_buffer;
212             
213             buffer_size *= 2;
214             new_buffer = new char [buffer_size];
215             memset(new_buffer, 0, buffer_size);
216
217             strcpy(new_buffer, buffer);
218             delete [] buffer;
219             buffer = new_buffer;
220         }
221
222         for (val=0;  val<value.length();  val++)
223         {
224             strcat(buffer, name);
225                 
226             if (hdr_num != 0 || strcmp(name, "From") != 0)
227               strcat(buffer, separator);
228             else
229               strcat(buffer, " ");
230                 
231             strcat(buffer, *(value[val]));
232             strcat(buffer, newline);
233         }
234         value.clear();
235         free(name);
236     }
237
238     //
239     // Need to free this after using;
240     //
241     return buffer;
242 }
243         
244
245         
246
247 char *
248 DmxMsg::getPrintedHeaders (DmxPrintHeadersEnum header_format)
249 {
250     char *newline = "\n";
251     char *buffer = NULL;
252
253     switch (header_format)
254     {
255         case DMX_PRINT_HEADERS_NONE:
256             buffer = new char [strlen(newline) + 1];
257             strcpy(buffer, (const char *) newline);
258             break;
259         case DMX_PRINT_HEADERS_STANDARD:
260             buffer = getStandardHeaders(msgHeader);
261             break;
262         case DMX_PRINT_HEADERS_ABBREV:
263             buffer = getHeaders(DTM_TRUE);
264             break;
265         case DMX_PRINT_HEADERS_ALL:
266             buffer = getHeaders(DTM_FALSE);
267             break;
268         default:
269             fprintf (stderr, "error in DmxMsg::display\n");
270             break;
271     }
272
273     //
274     // Need to free this after using;
275     //
276     return buffer;
277 }
278
279
280 void
281 DmxMsg::display (
282                 DmxPrintHeadersEnum header_format,
283                 DmxPrintOutputProc print_proc,
284                 XtPointer stream)
285 {
286     DtMailEnv           env;
287     DtMailBoolean       FirstIsText = DTM_FALSE;
288     DtMail::BodyPart    *firstPart = NULL, *nextpart = NULL;
289     char                *buf = NULL,
290                         *description = NULL,
291                         *name = NULL,
292                         *newline = NULL,
293                         *sunDataDescription = NULL,
294                         *type = NULL;
295
296     void                *contents = NULL;
297     unsigned long       length = 0;
298     int                 mode = 0;
299
300     // For CHARSET
301     char                v3_cs[64],
302                         *mime_cs = NULL,
303                         *from_cs = NULL,
304                         *to_cs = NULL;
305
306         
307     // read in body part info
308     if (cachedValues != DTM_TRUE)
309       parse ();
310
311     firstPart = bodyParts [0];
312
313     firstPart->getContents(env,
314                 (const void **) &contents, 
315                 &length,
316                 NULL,   //type
317                 NULL,   //name
318                 NULL,   //mode
319                 NULL);  //description
320
321     if (handleError(env, "getContents") == DTM_TRUE)
322       exit (1);
323
324     // For CHARSET
325     DtMailValueSeq      value;
326     DtMailBoolean       err = DTM_FALSE;
327
328     // Get the bodypart's charset - Try MIME first then V3
329     firstPart->getHeader(env, DtMailMessageContentType, DTM_TRUE, value);
330     if (env.isNotSet()) {
331         mime_cs = firstPart->csFromContentType(value);
332     } else {
333         env.clear();
334         value.clear();
335         firstPart->getHeader(env, DtMailMessageV3charset, DTM_TRUE, value);
336         if (env.isNotSet()) {
337             strcpy(v3_cs, *(value[0]));
338         } else {
339              err = DTM_TRUE;
340              env.clear();
341              value.clear();
342         }
343     }
344
345     // If cannot obtain bodypart's charset header, then maybe this message
346     // has only one bodypart, then in this case the charset header maybe
347     // among the message's envelope (main message headers).
348     // Get the envelope of the message (in order to access the headers)
349     DtMail::Envelope    *envelope = NULL;
350     if (err == DTM_TRUE) {
351         envelope = message->getEnvelope(env);
352         err = DTM_FALSE;
353 #ifdef DEBUG
354         env.logError(
355                 DTM_FALSE,
356                 "DEBUG dtmailpr: Looking at main message header\n");
357 #endif
358     }
359
360     //   Check for MIME charset header and then for V3 charset header
361     if (envelope != NULL) {
362         envelope->getHeader(env, DtMailMessageContentType, DTM_TRUE, value);
363         if (env.isNotSet()) {
364             mime_cs = firstPart->csFromContentType(value);
365         } else {
366             err = DTM_TRUE;
367             env.clear();
368         }
369         if (mime_cs == NULL || err == DTM_TRUE) {
370             value.clear();
371             envelope->getHeader(env, DtMailMessageV3charset, DTM_TRUE, value);
372             if (env.isNotSet()) {
373                 strcpy(v3_cs, *(value[0]));
374             } else {
375                 err = DTM_TRUE;
376                 env.clear();
377             }
378         }
379     } else {
380 #ifdef DEBUG
381         env.logError(DTM_FALSE, "DEBUG dtmailpr: envelope is null\n");
382 #endif
383         env.clear();
384     }
385
386     // Default codeset in case mime_cs and v3_cs are both null.
387     if ((mime_cs == NULL) && (strlen(v3_cs) == 0)) {
388         char *ret = NULL;
389         firstPart->DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
390                                         setlocale(LC_CTYPE, NULL),
391                                         NULL,
392                                         NULL,
393                                         &ret);
394         strcpy(v3_cs, "DEFAULT");
395         strcat(v3_cs, ".");
396         strcat(v3_cs, ret);
397         if (ret)
398           free(ret);
399     }
400
401     // Get iconv from and to codeset and do conversion.
402     int converted = 0;
403     if (mime_cs) {
404         from_cs = firstPart->csToConvName(mime_cs);
405 #ifdef DEBUG
406         env.logError(DTM_FALSE, "DEBUG dtmailpr: mime_cs = %s\n", mime_cs);
407 #endif
408     } else {
409        from_cs = firstPart->csToConvName(v3_cs);
410 #ifdef DEBUG
411        env.logError(DTM_FALSE, "DEBUG dtmailpr: v3_cs = %s\n", v3_cs);
412 #endif
413     }
414     to_cs = firstPart->locToConvName();
415
416 #ifdef DEBUG
417     if ( from_cs == NULL )
418       env.logError(DTM_FALSE, "DEBUG dtmailpr: from_cs is NULL\n");
419     else
420       env.logError(DTM_FALSE, "DEBUG dtmailpr: from_cs = %s\n", from_cs);
421
422     if ( to_cs == NULL )
423       env.logError(DTM_FALSE, "DEBUG dtmailpr: to_cs is NULL\n");
424     else
425       env.logError(DTM_FALSE, "DEBUG dtmailpr: to_cs = %s\n", to_cs);
426 #endif
427
428     if ( from_cs && to_cs ) {
429         if ( strcasecmp(from_cs, to_cs) != 0 ) {
430             converted = firstPart->csConvert(
431                                         (char **)&contents,
432                                         length,
433                                         0,
434                                         from_cs,
435                                         to_cs);
436 #ifdef DEBUG
437             env.logError(DTM_FALSE,
438                          "DEBUG dtmailpr: converted = %d\n", converted);
439 #endif
440         }
441     }
442     if ( mime_cs )
443       free ( mime_cs );
444     if ( from_cs )
445       free( from_cs );
446     if ( to_cs )
447       free ( to_cs );
448  
449     // End of For CHARSET
450
451     newline = new char [2];
452     newline[0] = '\n';
453     newline[1] = '\0';
454
455     //
456     // Print out the message headers.
457     //
458     buf = getPrintedHeaders(header_format);
459     print_proc(stream, buf);
460     print_proc(stream, newline);
461     delete buf;
462
463     //
464     // Print out the message body.
465     //
466     buf = new char [length + 1];
467     memset (buf, 0, (unsigned int) length + 1);
468     memmove (buf, contents, (unsigned int) length);
469     buf [length] = '\0';        // null-terminate that puppy
470     print_proc(stream, buf);
471     print_proc(stream, newline);
472     delete [] buf;
473
474     // For CHARSET
475     if (converted && contents)
476       free(contents);
477
478     // No attachments?  We're done.
479     if (numBPs < 2)
480         return;
481
482     int         i = 0, attbuflen = 0;
483     char        *attbuf = NULL;
484     char        *sunbuf = NULL;
485
486     print_proc(stream, newline);
487     for (i = 1; i < numBPs ; i++)
488     {
489         nextpart = bodyParts [i];
490
491         if (nextpart == NULL)
492           fprintf (stderr, "Error getting part!\n");
493
494         length = 0;
495         type = "";
496         sunDataDescription = "";
497         description = "";
498         name = "";
499         mode = -1;
500                 
501         nextpart->getContents(env,
502                         NULL,
503                         &length,
504                         &type,
505                         &name,
506                         &mode,
507                         &sunDataDescription);
508         if (handleError (env, "getContents") == DTM_TRUE)
509           exit (1);
510
511         if (type == NULL)
512           type = "(type unknown)";
513
514         if (name == NULL)
515           name = "(name unknown)";
516
517         if (sunDataDescription == NULL)
518         {
519             description = "";
520         } else {
521             // should add bracket or something
522             sunbuf = new char [strlen (sunDataDescription) + 10];
523             sprintf(sunbuf, " (%s)", sunDataDescription);
524             description = sunbuf;
525         }
526
527         attbuflen = strlen(name) + strlen(type) + strlen(description);
528         attbuf = new char [attbuflen + 64];
529         sprintf(attbuf,
530                 "[%d] \"%s\"%s, %s, %ld bytes",
531                 i,
532                 name,
533                 description,
534                 type,
535                 length);
536         print_proc(stream, attbuf);
537         print_proc(stream, newline);
538         delete [] attbuf;
539
540         if (sunbuf != NULL)
541           delete [] sunbuf;
542     }
543
544     return;
545 }
546
547 void
548 DmxMsg::parse (void)
549 {
550         // store the body parts for later reference
551
552         DtMailEnv                       env;
553         DtMailBoolean           FirstIsText = DTM_FALSE;
554         DtMail::BodyPart        *part = NULL, *nextpart = NULL;
555         char                    *type = NULL, *attr = NULL;
556
557         int     bc = message->getBodyCount (env);
558         if (handleError (env, "getBodyCount") == DTM_TRUE)
559                 exit (1);
560
561         part = message->getFirstBodyPart (env);
562         if (handleError (env, "getFirstBodyPart") == DTM_TRUE)
563                 exit (1);
564
565         part->getContents (env, NULL, NULL, &type, NULL, NULL, NULL);
566         if (handleError (env, "getContents") == DTM_TRUE)
567                 exit (1);
568
569         bodyParts = new (DtMail::BodyPart *[bc]);
570         cachedValues = DTM_TRUE;
571         
572         // cache values
573         bodyParts [0] = part;
574         numBPs++;
575
576
577         if (type != NULL)
578         {
579                 attr = DtDtsDataTypeToAttributeValue (type,
580                                                 DtDTS_DA_IS_TEXT,
581                                                 NULL);
582                 if (attr != NULL)
583                 {
584                         FirstIsText = DTM_TRUE;
585                 }
586                 //free (type);  // it's allocating some data for us
587         } else {
588                 FirstIsText = DTM_FALSE;
589         }
590
591         // No attachments?  We're done.
592         if (bc < 2)
593                 return;
594
595         int     i;
596
597         for (i = 1; i < bc; i++)
598         {
599                 nextpart = NULL;
600                 nextpart = message->getNextBodyPart (env,
601                                                 part);
602                 if (handleError (env, "getNextBodyPart") == DTM_TRUE)
603                         exit (1);
604
605                 if (nextpart == NULL)
606                         fprintf (stderr, "Error getting part!\n");
607
608
609                 bodyParts [i] = nextpart;
610                 numBPs++;
611
612                 part = nextpart;
613         }
614 }
615