Last of the spelling fixed
[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 libraries 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         msgHandle = NULL;
99         msgHeader.header_values = 0;
100         msgHeader.number_of_names = 0;
101         bodyParts = NULL;
102         isNew = DTM_FALSE;
103
104         return;
105 }
106
107 void
108 DmxMsg::setHandle (DtMailMessageHandle &h)
109 {
110         msgHandle = h;
111         return;
112 }
113
114 void
115 DmxMsg::setHeader (DtMailHeaderLine &h)
116 {
117         msgHeader = h;
118         return;
119 }
120
121 void
122 DmxMsg::setMessage (DtMail::Message *m)
123 {
124         message = m;
125         return;
126 }
127
128 void
129 DmxMsg::setInfo (char *info)
130 {
131         addlInfo = strdup (info);
132         return;
133 }
134
135 char *
136 DmxMsg::getMessageHeader (DmxHeaders which)
137 {
138         int             i = 0, length = 0;
139         int             buflength = 0;
140         char            *rtn;
141         const char      *str;
142
143         if (which >= DMXNUMHDRS)
144           return (char *) NULL;
145
146         length = msgHeader.header_values[which].length ();
147         if (length == 0)
148             str = errorString(which);
149         else
150             str = *((msgHeader.header_values[which])[0]);
151
152         //need to free this after using it
153         rtn = strdup(str);
154         return (rtn);
155 }
156         
157
158         
159
160 char *
161 DmxMsg::getHeaders (DtMailBoolean abbreviated_only)
162 {
163     DtMailEnv           error;
164     DtMail::Session     *m_session = theRoamApp.session()->session(); 
165     DtMail::MailRc      *mail_rc = m_session->mailRc(error);
166     DtMail::Envelope    *env = message->getEnvelope(error);
167
168     DtMailHeaderHandle  hdr_hnd;
169     char                *name;
170     DtMailValueSeq      value;
171
172     // Code from MsgScrollingList - display_message().
173     // We're trying to reduce heap size by not allocating and 
174     // deleting space in every loop iteration.  So just have a 
175     // fixed size buffer initially.
176     // 
177
178     // Initial line size.  When not enough, allocate more.
179     int                 buffer_size = 2048;   
180     char                *buffer = new char [buffer_size];
181     int                 count = 0;
182     int                 hdr_num = 0;
183     char                *newline = "\n";
184     char                *separator = ": ";
185     int                 val = 0;
186
187     //
188     // Iterate through each header in the message and add it
189     // to the buffer.
190     //
191     for (hdr_hnd = env->getFirstHeader(error, &name, value), *buffer = '\0';
192          hdr_hnd && !error.isSet();
193          hdr_hnd = env->getNextHeader(error, hdr_hnd, &name, value), hdr_num++)
194     {
195         if (abbreviated_only == DTM_TRUE &&
196             (hdr_num != 0 || strcmp(name, "From") != 0))
197         {
198             DtMailEnv ierror;
199             if (mail_rc->ignore(ierror, name))
200             {
201                 free(name);
202                 value.clear();
203                 continue;
204             }
205         }
206             
207         for (val=0;  val<value.length();  val++)
208           count += strlen(name) +
209                    strlen(*(value[val])) +
210                    strlen(separator) +
211                    strlen(newline) + 1;
212
213         if (count > buffer_size)
214         {
215             // Need to increase buffer size.
216             char        *new_buffer;
217             
218             buffer_size *= 2;
219             new_buffer = new char [buffer_size];
220             memset(new_buffer, 0, buffer_size);
221
222             strcpy(new_buffer, buffer);
223             delete [] buffer;
224             buffer = new_buffer;
225         }
226
227         for (val=0;  val<value.length();  val++)
228         {
229             strcat(buffer, name);
230                 
231             if (hdr_num != 0 || strcmp(name, "From") != 0)
232               strcat(buffer, separator);
233             else
234               strcat(buffer, " ");
235                 
236             strcat(buffer, *(value[val]));
237             strcat(buffer, newline);
238         }
239         value.clear();
240         free(name);
241     }
242
243     //
244     // Need to free this after using;
245     //
246     return buffer;
247 }
248         
249
250         
251
252 char *
253 DmxMsg::getPrintedHeaders (DmxPrintHeadersEnum header_format)
254 {
255     char *newline = "\n";
256     char *buffer = NULL;
257
258     switch (header_format)
259     {
260         case DMX_PRINT_HEADERS_NONE:
261             buffer = new char [strlen(newline) + 1];
262             strcpy(buffer, (const char *) newline);
263             break;
264         case DMX_PRINT_HEADERS_STANDARD:
265             buffer = getStandardHeaders(msgHeader);
266             break;
267         case DMX_PRINT_HEADERS_ABBREV:
268             buffer = getHeaders(DTM_TRUE);
269             break;
270         case DMX_PRINT_HEADERS_ALL:
271             buffer = getHeaders(DTM_FALSE);
272             break;
273         default:
274             fprintf (stderr, "error in DmxMsg::display\n");
275             break;
276     }
277
278     //
279     // Need to free this after using;
280     //
281     return buffer;
282 }
283
284
285 void
286 DmxMsg::display (
287                 DmxPrintHeadersEnum header_format,
288                 DmxPrintOutputProc print_proc,
289                 XtPointer stream)
290 {
291     DtMailEnv           env;
292     DtMailBoolean       FirstIsText = DTM_FALSE;
293     DtMail::BodyPart    *firstPart = NULL, *nextpart = NULL;
294     char                *buf = NULL,
295                         *description = NULL,
296                         *name = NULL,
297                         *newline = NULL,
298                         *sunDataDescription = NULL,
299                         *type = NULL;
300
301     void                *contents = NULL;
302     unsigned long       length = 0;
303     int                 mode = 0;
304
305     // For CHARSET
306     char                v3_cs[64],
307                         *mime_cs = NULL,
308                         *from_cs = NULL,
309                         *to_cs = NULL;
310
311         
312     // read in body part info
313     if (cachedValues != DTM_TRUE)
314       parse ();
315
316     firstPart = bodyParts [0];
317
318     firstPart->getContents(env,
319                 (const void **) &contents, 
320                 &length,
321                 NULL,   //type
322                 NULL,   //name
323                 NULL,   //mode
324                 NULL);  //description
325
326     if (handleError(env, "getContents") == DTM_TRUE)
327       exit (1);
328
329     // For CHARSET
330     DtMailValueSeq      value;
331     DtMailBoolean       err = DTM_FALSE;
332
333     // Get the bodypart's charset - Try MIME first then V3
334     firstPart->getHeader(env, DtMailMessageContentType, DTM_TRUE, value);
335     if (env.isNotSet()) {
336         mime_cs = firstPart->csFromContentType(value);
337     } else {
338         env.clear();
339         value.clear();
340         firstPart->getHeader(env, DtMailMessageV3charset, DTM_TRUE, value);
341         if (env.isNotSet()) {
342             strcpy(v3_cs, *(value[0]));
343         } else {
344              err = DTM_TRUE;
345              env.clear();
346              value.clear();
347         }
348     }
349
350     // If cannot obtain bodypart's charset header, then maybe this message
351     // has only one bodypart, then in this case the charset header maybe
352     // among the message's envelope (main message headers).
353     // Get the envelope of the message (in order to access the headers)
354     DtMail::Envelope    *envelope = NULL;
355     if (err == DTM_TRUE) {
356         envelope = message->getEnvelope(env);
357         err = DTM_FALSE;
358 #ifdef DEBUG
359         env.logError(
360                 DTM_FALSE,
361                 "DEBUG dtmailpr: Looking at main message header\n");
362 #endif
363     }
364
365     //   Check for MIME charset header and then for V3 charset header
366     if (envelope != NULL) {
367         envelope->getHeader(env, DtMailMessageContentType, DTM_TRUE, value);
368         if (env.isNotSet()) {
369             mime_cs = firstPart->csFromContentType(value);
370         } else {
371             err = DTM_TRUE;
372             env.clear();
373         }
374         if (mime_cs == NULL || err == DTM_TRUE) {
375             value.clear();
376             envelope->getHeader(env, DtMailMessageV3charset, DTM_TRUE, value);
377             if (env.isNotSet()) {
378                 strcpy(v3_cs, *(value[0]));
379             } else {
380                 err = DTM_TRUE;
381                 env.clear();
382             }
383         }
384     } else {
385 #ifdef DEBUG
386         env.logError(DTM_FALSE, "DEBUG dtmailpr: envelope is null\n");
387 #endif
388         env.clear();
389     }
390
391     // Default codeset in case mime_cs and v3_cs are both null.
392     if ((mime_cs == NULL) && (strlen(v3_cs) == 0)) {
393         char *ret = NULL;
394         firstPart->DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
395                                         setlocale(LC_CTYPE, NULL),
396                                         NULL,
397                                         NULL,
398                                         &ret);
399         strcpy(v3_cs, "DEFAULT");
400         strcat(v3_cs, ".");
401         strcat(v3_cs, ret);
402         free(ret);
403     }
404
405     // Get iconv from and to codeset and do conversion.
406     int converted = 0;
407     if (mime_cs) {
408         from_cs = firstPart->csToConvName(mime_cs);
409 #ifdef DEBUG
410         env.logError(DTM_FALSE, "DEBUG dtmailpr: mime_cs = %s\n", mime_cs);
411 #endif
412     } else {
413        from_cs = firstPart->csToConvName(v3_cs);
414 #ifdef DEBUG
415        env.logError(DTM_FALSE, "DEBUG dtmailpr: v3_cs = %s\n", v3_cs);
416 #endif
417     }
418     to_cs = firstPart->locToConvName();
419
420 #ifdef DEBUG
421     if ( from_cs == NULL )
422       env.logError(DTM_FALSE, "DEBUG dtmailpr: from_cs is NULL\n");
423     else
424       env.logError(DTM_FALSE, "DEBUG dtmailpr: from_cs = %s\n", from_cs);
425
426     if ( to_cs == NULL )
427       env.logError(DTM_FALSE, "DEBUG dtmailpr: to_cs is NULL\n");
428     else
429       env.logError(DTM_FALSE, "DEBUG dtmailpr: to_cs = %s\n", to_cs);
430 #endif
431
432     if ( from_cs && to_cs ) {
433         if ( strcasecmp(from_cs, to_cs) != 0 ) {
434             converted = firstPart->csConvert(
435                                         (char **)&contents,
436                                         length,
437                                         0,
438                                         from_cs,
439                                         to_cs);
440 #ifdef DEBUG
441             env.logError(DTM_FALSE,
442                          "DEBUG dtmailpr: converted = %d\n", converted);
443 #endif
444         }
445     }
446     if ( mime_cs )
447       free ( mime_cs );
448     if ( from_cs )
449       free( from_cs );
450     if ( to_cs )
451       free ( to_cs );
452  
453     // End of For CHARSET
454
455     newline = new char [2];
456     newline[0] = '\n';
457     newline[1] = '\0';
458
459     //
460     // Print out the message headers.
461     //
462     buf = getPrintedHeaders(header_format);
463     print_proc(stream, buf);
464     print_proc(stream, newline);
465     delete buf;
466
467     //
468     // Print out the message body.
469     //
470     buf = new char [length + 1];
471     memset (buf, 0, (unsigned int) length + 1);
472     memmove (buf, contents, (unsigned int) length);
473     buf [length] = '\0';        // null-terminate that puppy
474     print_proc(stream, buf);
475     print_proc(stream, newline);
476     delete [] buf;
477
478     // For CHARSET
479     if (converted && contents)
480       free(contents);
481
482     // No attachments?  We're done.
483     if (numBPs < 2)
484         return;
485
486     int         i = 0, attbuflen = 0;
487     char        *attbuf = NULL;
488     char        *sunbuf = NULL;
489
490     print_proc(stream, newline);
491     for (i = 1; i < numBPs ; i++)
492     {
493         nextpart = bodyParts [i];
494
495         if (nextpart == NULL)
496           fprintf (stderr, "Error getting part!\n");
497
498         length = 0;
499         type = "";
500         sunDataDescription = "";
501         description = "";
502         name = "";
503         mode = -1;
504                 
505         nextpart->getContents(env,
506                         NULL,
507                         &length,
508                         &type,
509                         &name,
510                         &mode,
511                         &sunDataDescription);
512         if (handleError (env, "getContents") == DTM_TRUE)
513           exit (1);
514
515         if (type == NULL)
516           type = "(type unknown)";
517
518         if (name == NULL)
519           name = "(name unknown)";
520
521         if (sunDataDescription == NULL)
522         {
523             description = "";
524         } else {
525             // should add bracket or something
526             sunbuf = new char [strlen (sunDataDescription) + 10];
527             sprintf(sunbuf, " (%s)", sunDataDescription);
528             description = sunbuf;
529         }
530
531         attbuflen = strlen(name) + strlen(type) + strlen(description);
532         attbuf = new char [attbuflen + 64];
533         sprintf(attbuf,
534                 "[%d] \"%s\"%s, %s, %ld bytes",
535                 i,
536                 name,
537                 description,
538                 type,
539                 length);
540         print_proc(stream, attbuf);
541         print_proc(stream, newline);
542         delete [] attbuf;
543
544         if (sunbuf != NULL)
545           delete [] sunbuf;
546     }
547
548     return;
549 }
550
551 void
552 DmxMsg::parse (void)
553 {
554         // store the body parts for later reference
555
556         DtMailEnv                       env;
557         DtMailBoolean           FirstIsText = DTM_FALSE;
558         DtMail::BodyPart        *part = NULL, *nextpart = NULL;
559         char                    *type = NULL, *attr = NULL;
560
561         int     bc = message->getBodyCount (env);
562         if (handleError (env, "getBodyCount") == DTM_TRUE)
563                 exit (1);
564
565         part = message->getFirstBodyPart (env);
566         if (handleError (env, "getFirstBodyPart") == DTM_TRUE)
567                 exit (1);
568
569         part->getContents (env, NULL, NULL, &type, NULL, NULL, NULL);
570         if (handleError (env, "getContents") == DTM_TRUE)
571                 exit (1);
572
573         bodyParts = new (DtMail::BodyPart *[bc]);
574         cachedValues = DTM_TRUE;
575         
576         // cache values
577         bodyParts [0] = part;
578         numBPs++;
579
580
581         if (type != NULL)
582         {
583                 attr = DtDtsDataTypeToAttributeValue (type,
584                                                 DtDTS_DA_IS_TEXT,
585                                                 NULL);
586                 if (attr != NULL)
587                 {
588                         FirstIsText = DTM_TRUE;
589                 }
590                 //free (type);  // it's allocating some data for us
591         } else {
592                 FirstIsText = DTM_FALSE;
593         }
594
595         // No attachments?  We're done.
596         if (bc < 2)
597                 return;
598
599         int     i;
600
601         for (i = 1; i < bc; i++)
602         {
603                 nextpart = NULL;
604                 nextpart = message->getNextBodyPart (env,
605                                                 part);
606                 if (handleError (env, "getNextBodyPart") == DTM_TRUE)
607                         exit (1);
608
609                 if (nextpart == NULL)
610                         fprintf (stderr, "Error getting part!\n");
611
612
613                 bodyParts [i] = nextpart;
614                 numBPs++;
615
616                 part = nextpart;
617         }
618 }
619