Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[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 #include <strings.h>
78
79 #include "Application.h"
80 #include "DtMail/DtMail.hh"
81 #include "DtMailTypes.h"
82 #include "MailSession.hh"
83 #include "RoamApp.h"
84 #include "str_utils.h"
85
86
87 DmxMsg::DmxMsg (void)
88 {
89         // initialize everything
90         message = NULL;
91         addlInfo = NULL;
92         numBPs = 0;
93         cachedValues = DTM_FALSE;
94         msgHandle = NULL;
95         msgHeader.header_values = 0;
96         msgHeader.number_of_names = 0;
97         bodyParts = NULL;
98         isNew = DTM_FALSE;
99
100         return;
101 }
102
103 void
104 DmxMsg::setHandle (DtMailMessageHandle &h)
105 {
106         msgHandle = h;
107         return;
108 }
109
110 void
111 DmxMsg::setHeader (DtMailHeaderLine &h)
112 {
113         msgHeader = h;
114         return;
115 }
116
117 void
118 DmxMsg::setMessage (DtMail::Message *m)
119 {
120         message = m;
121         return;
122 }
123
124 void
125 DmxMsg::setInfo (char *info)
126 {
127         addlInfo = strdup (info);
128         return;
129 }
130
131 char *
132 DmxMsg::getMessageHeader (DmxHeaders which)
133 {
134         int             i = 0, length = 0;
135         int             buflength = 0;
136         char            *rtn;
137         const char      *str;
138
139         if (which >= DMXNUMHDRS)
140           return (char *) NULL;
141
142         length = msgHeader.header_values[which].length ();
143         if (length == 0)
144             str = errorString(which);
145         else
146             str = *((msgHeader.header_values[which])[0]);
147
148         //need to free this after using it
149         rtn = strdup(str);
150         return (rtn);
151 }
152         
153
154         
155
156 char *
157 DmxMsg::getHeaders (DtMailBoolean abbreviated_only)
158 {
159     DtMailEnv           error;
160     DtMail::Session     *m_session = theRoamApp.session()->session(); 
161     DtMail::MailRc      *mail_rc = m_session->mailRc(error);
162     DtMail::Envelope    *env = message->getEnvelope(error);
163
164     DtMailHeaderHandle  hdr_hnd;
165     char                *name;
166     DtMailValueSeq      value;
167
168     // Code from MsgScrollingList - display_message().
169     // We're trying to reduce heap size by not allocating and 
170     // deleting space in every loop iteration.  So just have a 
171     // fixed size buffer initially.
172     // 
173
174     // Initial line size.  When not enough, allocate more.
175     int                 buffer_size = 2048;   
176     char                *buffer = new char [buffer_size];
177     int                 count = 0;
178     int                 hdr_num = 0;
179     char                *newline = "\n";
180     char                *separator = ": ";
181     int                 val = 0;
182
183     //
184     // Iterate through each header in the message and add it
185     // to the buffer.
186     //
187     for (hdr_hnd = env->getFirstHeader(error, &name, value), *buffer = '\0';
188          hdr_hnd && !error.isSet();
189          hdr_hnd = env->getNextHeader(error, hdr_hnd, &name, value), hdr_num++)
190     {
191         if (abbreviated_only == DTM_TRUE &&
192             (hdr_num != 0 || strcmp(name, "From") != 0))
193         {
194             DtMailEnv ierror;
195             if (mail_rc->ignore(ierror, name))
196             {
197                 free(name);
198                 value.clear();
199                 continue;
200             }
201         }
202             
203         for (val=0;  val<value.length();  val++)
204           count += strlen(name) +
205                    strlen(*(value[val])) +
206                    strlen(separator) +
207                    strlen(newline) + 1;
208
209         if (count > buffer_size)
210         {
211             // Need to increase buffer size.
212             char        *new_buffer;
213             
214             buffer_size *= 2;
215             new_buffer = new char [buffer_size];
216             memset(new_buffer, 0, buffer_size);
217
218             strcpy(new_buffer, buffer);
219             delete [] buffer;
220             buffer = new_buffer;
221         }
222
223         for (val=0;  val<value.length();  val++)
224         {
225             strcat(buffer, name);
226                 
227             if (hdr_num != 0 || strcmp(name, "From") != 0)
228               strcat(buffer, separator);
229             else
230               strcat(buffer, " ");
231                 
232             strcat(buffer, *(value[val]));
233             strcat(buffer, newline);
234         }
235         value.clear();
236         free(name);
237     }
238
239     //
240     // Need to free this after using;
241     //
242     return buffer;
243 }
244         
245
246         
247
248 char *
249 DmxMsg::getPrintedHeaders (DmxPrintHeadersEnum header_format)
250 {
251     char *newline = "\n";
252     char *buffer = NULL;
253
254     switch (header_format)
255     {
256         case DMX_PRINT_HEADERS_NONE:
257             buffer = new char [strlen(newline) + 1];
258             strcpy(buffer, (const char *) newline);
259             break;
260         case DMX_PRINT_HEADERS_STANDARD:
261             buffer = getStandardHeaders(msgHeader);
262             break;
263         case DMX_PRINT_HEADERS_ABBREV:
264             buffer = getHeaders(DTM_TRUE);
265             break;
266         case DMX_PRINT_HEADERS_ALL:
267             buffer = getHeaders(DTM_FALSE);
268             break;
269         default:
270             fprintf (stderr, "error in DmxMsg::display\n");
271             break;
272     }
273
274     //
275     // Need to free this after using;
276     //
277     return buffer;
278 }
279
280
281 void
282 DmxMsg::display (
283                 DmxPrintHeadersEnum header_format,
284                 DmxPrintOutputProc print_proc,
285                 XtPointer stream)
286 {
287     DtMailEnv           env;
288     DtMailBoolean       FirstIsText = DTM_FALSE;
289     DtMail::BodyPart    *firstPart = NULL, *nextpart = NULL;
290     char                *buf = NULL,
291                         *description = NULL,
292                         *name = NULL,
293                         *newline = NULL,
294                         *sunDataDescription = NULL,
295                         *type = NULL;
296
297     void                *contents = NULL;
298     unsigned long       length = 0;
299     int                 mode = 0;
300
301     // For CHARSET
302     char                v3_cs[64],
303                         *mime_cs = NULL,
304                         *from_cs = NULL,
305                         *to_cs = NULL;
306
307         
308     // read in body part info
309     if (cachedValues != DTM_TRUE)
310       parse ();
311
312     firstPart = bodyParts [0];
313
314     firstPart->getContents(env,
315                 (const void **) &contents, 
316                 &length,
317                 NULL,   //type
318                 NULL,   //name
319                 NULL,   //mode
320                 NULL);  //description
321
322     if (handleError(env, "getContents") == DTM_TRUE)
323       exit (1);
324
325     // For CHARSET
326     DtMailValueSeq      value;
327     DtMailBoolean       err = DTM_FALSE;
328
329     // Get the bodypart's charset - Try MIME first then V3
330     firstPart->getHeader(env, DtMailMessageContentType, DTM_TRUE, value);
331     if (env.isNotSet()) {
332         mime_cs = firstPart->csFromContentType(value);
333     } else {
334         env.clear();
335         value.clear();
336         firstPart->getHeader(env, DtMailMessageV3charset, DTM_TRUE, value);
337         if (env.isNotSet()) {
338             strcpy(v3_cs, *(value[0]));
339         } else {
340              err = DTM_TRUE;
341              env.clear();
342              value.clear();
343         }
344     }
345
346     // If cannot obtain bodypart's charset header, then maybe this message
347     // has only one bodypart, then in this case the charset header maybe
348     // among the message's envelope (main message headers).
349     // Get the envelope of the message (in order to access the headers)
350     DtMail::Envelope    *envelope = NULL;
351     if (err == DTM_TRUE) {
352         envelope = message->getEnvelope(env);
353         err = DTM_FALSE;
354 #ifdef DEBUG
355         env.logError(
356                 DTM_FALSE,
357                 "DEBUG dtmailpr: Looking at main message header\n");
358 #endif
359     }
360
361     //   Check for MIME charset header and then for V3 charset header
362     if (envelope != NULL) {
363         envelope->getHeader(env, DtMailMessageContentType, DTM_TRUE, value);
364         if (env.isNotSet()) {
365             mime_cs = firstPart->csFromContentType(value);
366         } else {
367             err = DTM_TRUE;
368             env.clear();
369         }
370         if (mime_cs == NULL || err == DTM_TRUE) {
371             value.clear();
372             envelope->getHeader(env, DtMailMessageV3charset, DTM_TRUE, value);
373             if (env.isNotSet()) {
374                 strcpy(v3_cs, *(value[0]));
375             } else {
376                 err = DTM_TRUE;
377                 env.clear();
378             }
379         }
380     } else {
381 #ifdef DEBUG
382         env.logError(DTM_FALSE, "DEBUG dtmailpr: envelope is null\n");
383 #endif
384         env.clear();
385     }
386
387     // Default codeset in case mime_cs and v3_cs are both null.
388     if ((mime_cs == NULL) && (strlen(v3_cs) == 0)) {
389         char *ret = NULL;
390         firstPart->DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
391                                         setlocale(LC_CTYPE, NULL),
392                                         NULL,
393                                         NULL,
394                                         &ret);
395         strcpy(v3_cs, "DEFAULT");
396         strcat(v3_cs, ".");
397         strcat(v3_cs, 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