2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
27 * $TOG: Session.C /main/16 1998/07/24 16:08:39 mgreess $
29 * RESTRICTED CONFIDENTIAL INFORMATION:
31 * The information in this document is subject to special
32 * restrictions in a confidential disclosure agreement bertween
33 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
34 * document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
35 * Sun's specific written approval. This documment and all copies
36 * and derivative works thereof must be returned or destroyed at
39 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
46 // Workaround for CDExc19308
48 // This ifdef was added as a workaround for the
49 // bug in the OSF1 V3.2 148 /usr/include/sys/localedef.h
50 // header file, and should be removed as soon as the bug is
56 #include <DtHelp/LocaleXlate.h>
65 #include <sys/socket.h>
68 #include <DtMail/DtMail.hh>
69 #include <EUSDebug.hh>
70 #include "DynamicLib.hh"
71 #include <DtMail/Threads.hh>
72 #include <DtMail/ImplDriver.hh>
73 #include "ImplConfigTable.hh"
74 #include "SigChldImpl.hh"
75 #include <DtMail/IO.hh>
76 #include <DtMail/Common.h>
89 #if defined(USL) && (OSMAJORVERSION == 2)
92 #if defined(USL) && (OSMAJORVERSION == 2)
97 #include <sys/socket.h>
100 #include <DtMail/DtMail.hh>
102 #include <EUSDebug.hh>
103 #include "DynamicLib.hh"
104 #include <DtMail/Threads.hh>
105 #include <DtMail/ImplDriver.hh>
106 #include "ImplConfigTable.hh"
107 #include "SigChldImpl.hh"
108 #include <DtMail/IO.hh>
109 #include <DtMail/Common.h>
112 //-------------------------------------
114 // Any code change within "For CHARSET" should be changed in
115 // RFCBodyPart and Session because the same methods are duplicated
116 // in both of these classes.
117 // See RFCImpl.hh or DtMail/DtMail.hh for more explanation.
118 //-------------------------------------
121 #include <DtHelp/LocaleXlate.h>
134 #if defined(SunOS) && (SunOS < 55)
141 // Iconv not defined for linux. Use the EUSCompat stubs instead.
142 # include <EUSCompat.h>
145 #if defined(SunOS) && (SunOS < 55)
149 // End of For CHARSET
150 #endif // ! defined(__osf__)
152 DtVirtArray<SigChldInfo *> *DtMailSigChldList;
155 static const int SessionSignature = 0xef9421cc;
156 static const int MaxImpls = 16;
158 static const int MAXIMUM_PATH_LENGTH = 2048;
160 DtMail::Session::Session(DtMailEnv & error, const char * app_name)
161 : _events(16), _valid_keys(2048)
163 _DtMutex = MutexInit();
167 _object_signature = 0;
170 // Create the ToolTalk session for managing file locking,
171 // if one doesn't exist.
172 _tt_channel = tt_default_procid();
173 if (tt_pointer_error(_tt_channel) != TT_OK) {
174 _tt_channel = ttdt_open(&_tt_fd, app_name, "SunSoft", "%I", 0);
175 if (tt_pointer_error(_tt_channel) != TT_OK) {
176 error.setError(DTME_TTFailure);
178 "DtMail::createSession - ttdt_open returns %s\n",
179 tt_status_message(tt_pointer_error(_tt_channel)));
187 // The event_fd is how we allow async behavior to occur in a
188 // compatible way. We use a Unix domain socket as the file descriptor.
189 // The client will watch for activity on this file descriptor, and
190 // call our event routine when there is activity (either from XtMainLoop,
191 // or through some other method).
195 _app_name = strdup(app_name);
199 _mail_rc = new MailRc(error, this);
201 buildImplTable(error);
206 _obj_mutex = MutexInit();
208 // The default implementation is specified via the DEFAULT_BACKEND
209 // variable. If this is not set in the .mailrc, then choose entry
213 _mail_rc->getValue(b_error, "DEFAULT_BACKEND", &value);
214 if (b_error.isNotSet()) {
215 _default_impl = lookupImpl(value);
216 if (_default_impl < 0) {
225 DtMailSigChldList = new DtVirtArray<SigChldInfo *>(8);
228 _busy_cb_data = NULL;
229 _canAutoSave = DTM_TRUE;
231 _object_signature = SessionSignature;
236 DtMail::Session::~Session(void)
238 if (_object_signature != SessionSignature) { // Been here, did that!
243 MutexLock lock_scope(_obj_mutex);
245 _object_signature = 0;
247 ttdt_close(_tt_channel, NULL, 1);
251 // Close off the dynamic libraries and free the impl table.
252 for (int tbl = 0; tbl < _num_impls; tbl++) {
253 free(_impls[tbl].impl_name);
254 DynamicLib * dl = (DynamicLib *)_impls[tbl].impl_lib;
260 lock_scope.unlock_and_destroy();
270 DtMail::Session::enumerateImpls(DtMailEnv & error)
277 DtMail::Session::setDefaultImpl(DtMailEnv & error, const char * impl)
279 int slot = lookupImpl(impl);
282 error.setError(DTME_NoSuchImplementation);
286 MutexLock lock_scope(_obj_mutex);
288 _default_impl = slot;
293 DtMail::Session::getDefaultImpl(DtMailEnv & error)
295 if (_num_impls == 0) {
296 error.setError(DTME_NoImplementations);
302 return(_impl_names[_default_impl]);
306 DtMail::Session::queryImpl(DtMailEnv & error,
308 const char * capability,
313 va_start(args, capability);
314 queryImplV(error, impl, capability, args);
321 DtMail::Session::queryImplV(DtMailEnv & error,
323 const char * capability,
326 int slot = lookupImpl(impl);
329 error.setError(DTME_NoSuchImplementation);
335 // We need to retrieve the QueryImpl entry point for the implementation.
339 qie = (QueryImplEntry)_impls[slot].impl_meta_factory(QueryImplEntryOp);
341 error.setError(DTME_ImplFailure);
345 qie(*this, error, capability, args);
351 DtMail::Session::mailBoxConstruct(DtMailEnv & error,
352 DtMailObjectSpace space,
354 DtMailCallback open_callback,
356 const char * impl_name)
358 // If the client specified an implementation of choice, then that
359 // is the only thing we use.
361 int primary_impl = _default_impl;
364 int sl = lookupImpl(impl_name);
366 error.setError(DTME_NoSuchImplementation);
373 // First thing we will do is see if the default implementation
374 // can open this file. If so, then we will create a mail box object
375 // based on the default implementation.
380 qoe = (QueryOpenEntry)
381 _impls[primary_impl].impl_meta_factory(QueryOpenEntryOp);
383 error.setError(DTME_ImplFailure);
387 if (qoe(*this, error, space, arg) == DTM_FALSE) {
388 // Don't go on if the client specified an implementation.
391 error.setError(DTME_ImplFailure);
395 // Oh well, let's walk through the list of impls and see if any of
396 // them will take ownership of this file.
398 MutexLock lock_scope(_obj_mutex);
401 for(int slot = 0; slot < _num_impls; slot++) {
402 qoe = (QueryOpenEntry)
403 _impls[slot].impl_meta_factory(QueryOpenEntryOp);
405 // Just skip this implementation.
408 if (qoe(*this, error, space, arg) == DTM_TRUE) {
414 // If we didn't find an impl, then we have to give up.
416 if (const_impl < 0) {
417 error.setError(DTME_NotMailBox);
422 const_impl = primary_impl;
425 // At this point we have an implementation that is willing to work
426 // with the path. Get its mail box constructor and build a mailbox
429 MailBoxConstructEntry mbce;
431 mbce = (MailBoxConstructEntry)
432 _impls[const_impl].impl_meta_factory(MailBoxConstructEntryOp);
434 error.setError(DTME_ImplFailure);
438 return(mbce(*this, error, space, arg, open_callback, client_data));
442 DtMail::Session::messageConstruct(DtMailEnv & error,
443 DtMailObjectSpace space,
445 DtMailCallback open_callback,
447 const char * impl_name)
449 // If the client specified an implementation of choice, then that
450 // is the only thing we use.
452 int primary_impl = _default_impl;
455 int sl = lookupImpl(impl_name);
457 error.setError(DTME_NoSuchImplementation);
465 QueryMessageEntry qoe;
467 qoe = (QueryMessageEntry)
468 _impls[primary_impl].impl_meta_factory(QueryMessageEntryOp);
470 error.setError(DTME_ImplFailure);
474 if (qoe(*this, error, space, arg) == DTM_FALSE) {
475 // Don't go on if the client specified an implementation.
478 error.setError(DTME_ImplFailure);
482 // Oh well, let's walk through the list of impls and see if any of
483 // them will take ownership of this file.
485 MutexLock lock_scope(_obj_mutex);
488 for(int slot = 0; slot < _num_impls; slot++) {
489 qoe = (QueryMessageEntry)
490 _impls[slot].impl_meta_factory(QueryMessageEntryOp);
492 // Just skip this implementation.
495 if (qoe(*this, error, space, arg) == DTM_TRUE) {
501 // If we didn't find an impl, then we have to give up.
503 if (const_impl < 0) {
504 error.setError(DTME_ImplFailure);
509 const_impl = primary_impl;
512 // At this point we have an implementation that is willing to work
513 // with the path. Get its mail box constructor and build a mailbox
516 MessageConstructEntry mbce;
518 mbce = (MessageConstructEntry)
519 _impls[const_impl].impl_meta_factory(MessageConstructEntryOp);
521 error.setError(DTME_ImplFailure);
525 return(mbce(*this, error, space, arg, open_callback, client_data));
529 DtMail::Session::transportConstruct(DtMailEnv & error,
531 DtMailStatusCallback call_back,
534 // We need to find the implementation for starters.
536 int slot = lookupImpl(impl);
538 error.setError(DTME_NoSuchImplementation);
542 TransportConstructEntry tce;
543 tce = (TransportConstructEntry)
544 _impls[slot].impl_meta_factory(TransportConstructEntryOp);
547 error.setError(DTME_NotSupported);
551 return(tce(*this, error, call_back, client_data));
555 DtMail::Session::mailRc(DtMailEnv & error)
563 // NEEDS TO BE DELETED .. SHOULD NO LONGER BE USED...
566 DtMail::Session::setError(DtMailEnv & error, const DTMailError_t minor_code)
568 error.setError(minor_code);
569 //DtMail::setError(*this, error, minor_code);
573 DtMail::Session::pollRequired(DtMailEnv & error)
577 #if defined(POSIX_THREADS)
586 DtMail::Session::eventFileDesc(DtMailEnv & error)
590 return(_event_fd[0]);
594 DtMail::Session::poll(DtMailEnv & error)
598 #if defined(POSIX_THREADS)
599 return; // A thread does this job.
602 // We will grab the time and determine what needs to run.
603 // Any events that have expired since the last time we were
604 // called are automatically ran. If the event returns DTM_TRUE,
605 // then reset last_ran to the current time to cause the event
606 // to not run for the full wait interval; otherwise, refrain
607 // and let the event happen again at the next poll interval
609 time_t now = time(NULL);
611 for (int ev = 0; ev < _events.length(); ev++) {
612 EventRoutine * event = _events[ev];
613 if ((now - event->last_ran) > event->interval) {
614 if (event->routine(event->client_data) == DTM_TRUE)
615 event->last_ran = now;
625 DtMail::Session::expandPath(DtMailEnv & error, const char * path)
627 const char * fold_path;
630 error.setError(DTME_BadArg);
636 char * exp_name = (char *)malloc(MAXIMUM_PATH_LENGTH);
637 if (exp_name == NULL) {
638 error.setError(DTME_NoMemory);
641 if (strchr(path, '$') != NULL) {
642 sprintf (exp_name, "echo %s", path);
644 if ((fp = popen(exp_name, "r")) != NULL) {
646 if (fgets(exp_name, MAXIMUM_PATH_LENGTH, fp) != NULL &&
648 // get rid of \n at end of string
649 exp_name[strlen(exp_name)-1] = '\0';
651 strcpy(exp_name, path);
655 strcpy(exp_name, path);
658 strcpy(exp_name, path);
660 char * exp_name2 = (char *)malloc(MAXIMUM_PATH_LENGTH);
663 switch (exp_name[0]) {
665 // This is relative to the folder path. Figure out what that is.
667 _mail_rc->getValue(error, "folder", &fold_path);
668 if (error.isNotSet()) {
669 if (*fold_path != '/' && *fold_path != '.' &&
670 *fold_path != '~' && *fold_path != '$')
671 strcpy(exp_name2, "~/");
673 strcat(exp_name2, fold_path);
674 strcat(exp_name2, "/");
676 else // Use the default folder
677 strcpy(exp_name2, "~/");
679 strcat(exp_name2, &exp_name[1]);
681 // We need to call ourselves again to deal with
682 // relative paths in the folder directory.
684 char * old_exp = exp_name2;
685 exp_name2 = expandPath(error, old_exp);
691 // This is relative to the user's home directory.
696 if (exp_name[1] == '/' || exp_name[1] == '\0') {
697 GetPasswordEntry(pw);
698 start = &exp_name[1];
703 char * slash = strchr(&exp_name[1], '/');
706 error.setError(DTME_NoSuchFile);
710 int len = slash - &exp_name[1];
711 char * name = new char[len + 1];
712 strncpy(name, &exp_name[1], len);
714 pw_p = getpwnam(name);
718 error.setError(DTME_NoSuchFile);
728 strcpy(exp_name2, pw.pw_dir);
729 strcat(exp_name2, start);
733 // We have a directory or no specials. Just copy the path and
738 strcpy(exp_name2, exp_name);
746 // This routine takes a path and checks to see if the path can be
747 // expressed relative to the "folder" path. If it can, it returns
748 // the relative path; otherwise, it returns the original path.
750 DtMail::Session::getRelativePath(DtMailEnv & error, const char * path)
752 const char * fold_path;
755 error.setError(DTME_BadArg);
761 char * exp_name = (char *)malloc(MAXIMUM_PATH_LENGTH);
763 error.setError(DTME_NoMemory);
766 exp_name[0] = '\0'; // Just for errors.
770 // This is an absolute path, so there is a chance that
771 // we can trim it down to a relative path if it goes down
772 // the same way as the folder path.
774 _mail_rc->getValue(error, "folder", &fold_path);
775 if (error.isNotSet()) {
776 strcpy(exp_name, fold_path);
778 // We need to call ourselves again to deal with
779 // relative paths in the folder directory.
781 char * old_exp = exp_name;
782 exp_name = expandPath(error, old_exp);
785 // Check to see if the path starts with the folder path.
786 char * matched_path = const_cast<char *>(strstr(path, exp_name));
787 if (matched_path == path) {
788 // Yes it does, make it a relative path to the folder dir.
789 int folder_path_length = strlen(exp_name);
790 while (path[folder_path_length] == '/')
791 folder_path_length++;
792 strcpy(exp_name, &path[folder_path_length]);
795 strcpy(exp_name, path);
800 // There is no folder variable so just fall through to the
806 // This is relative to the folder path. Leave it alone.
807 // The only time we are likely to see a leading '+' is
808 // when the path was carried over from mailtool in the .mailrc.
810 // This is relative to the user's home directory. Leave it alone.
811 // The only time we are likely to see a leading '~' is
812 // when the path was carried over from mailtool in the .mailrc.
814 // This is relative to the current directory where dtmail is
815 // running. Leave it alone. The only time we are likely to see
816 // a leading '.' is when the path was carried over from mailtool
820 strcpy(exp_name, path);
830 DtMail::Session::addEventRoutine(DtMailEnv & error,
831 DtMailEventFunc routine,
837 EventRoutine * er = new EventRoutine;
839 er->routine = routine;
840 er->client_data = client_data;
841 er->interval = interval;
842 er->last_ran = 0; // This will case this routine to run immediately.
848 DtMail::Session::removeEventRoutine(DtMailEnv & error,
849 DtMailEventFunc routine,
854 for (int slot = 0; slot < _events.length(); slot++) {
855 EventRoutine * event = _events[slot];
856 if (event->routine == routine &&
857 event->client_data == client_data) {
859 _events.remove(slot);
865 DtMail::Session::writeEventData(DtMailEnv&,
867 const unsigned long size)
869 int status = SafeWrite(_event_fd[1], buf, (int)size);
873 DtMail::Session::validObjectKey(DtMailObjectKey key)
875 return(_valid_keys.indexof(key) < 0 ? DTM_FALSE : DTM_TRUE);
879 DtMail::Session::newObjectKey(void)
881 MutexLock lock_scope(_obj_mutex);
884 _valid_keys.append(_cur_key);
890 DtMail::Session::removeObjectKey(DtMailObjectKey key)
892 MutexLock lock_scope(_obj_mutex);
894 int slot = _valid_keys.indexof(key);
896 _valid_keys.remove(slot);
901 DtMail::Session::registerDisableGroupPrivilegesCallback(
902 DisableGroupPrivilegesCallback cb,
905 _disableGroupPrivileges_cb = cb;
906 _disableGroupPrivileges_cb_data = cb_data;
911 DtMail::Session::unregisterDisableGroupPrivilegesCallback(void)
913 _disableGroupPrivileges_cb = NULL;
914 _disableGroupPrivileges_cb_data = NULL;
916 #endif /* DEAD_WOOD */
919 DtMail::Session::disableGroupPrivileges(void)
921 if (_disableGroupPrivileges_cb) {
922 _disableGroupPrivileges_cb(_disableGroupPrivileges_cb_data);
927 DtMail::Session::registerEnableGroupPrivilegesCallback(
928 EnableGroupPrivilegesCallback cb,
931 _enableGroupPrivileges_cb = cb;
932 _enableGroupPrivileges_cb_data = cb_data;
937 DtMail::Session::unregisterEnableGroupPrivilegesCallback(void)
939 _enableGroupPrivileges_cb = NULL;
940 _enableGroupPrivileges_cb_data = NULL;
942 #endif /* DEAD_WOOD */
945 DtMail::Session::enableGroupPrivileges(void)
947 if (_enableGroupPrivileges_cb) {
948 _enableGroupPrivileges_cb(_enableGroupPrivileges_cb_data);
953 DtMail::Session::registerBusyCallback(DtMailEnv&,
954 BusyApplicationCallback cb,
958 _busy_cb_data = cb_data;
963 DtMail::Session::unregisterBusyCallback(DtMailEnv & error)
966 _busy_cb_data = NULL;
968 #endif /* DEAD_WOOD */
971 DtMail::Session::setBusyState(DtMailEnv &error, DtMailBusyState busy_state)
974 _busy_cb(error, busy_state, _busy_cb_data);
980 DtMail::Session::registerLastInteractiveEventTimeCallback(
981 LastInteractiveEventTimeCallback cb,
984 _interactive_time_cb = cb;
985 _interactive_time_cb_data = cb_data;
989 DtMail::Session::lastInteractiveEventTime(void)
991 if (_interactive_time_cb) {
992 return(_interactive_time_cb(_interactive_time_cb_data));
999 DtMail::Session::buildImplTable(DtMailEnv & error)
1003 // Let's pick a ridiculous number of implementations.
1004 _impls = (Impls *)malloc(sizeof(Impls) * MaxImpls);
1005 _impl_names = (const char **)malloc(sizeof(char *) * (MaxImpls + 1));
1007 // We will simply walk through the default implementations
1008 // to start, adding them to the impl table.
1010 for (tbl = 0, _num_impls = 0; initial_impls[tbl].meta_entry_point; tbl++) {
1011 // Get the library handle.
1012 DynamicLib * dl = CreatePlatformDl(initial_impls[tbl].lib_name);
1014 if (dl) { // We are only interested in libraries we can load.
1015 _impls[_num_impls].impl_lib = dl;
1016 _impls[_num_impls].impl_meta_factory =
1017 (MetaImplFactory)dl->getSym(initial_impls[tbl].meta_entry_point);
1018 if (_impls[_num_impls].impl_meta_factory == NULL) {
1022 _impls[_num_impls].impl_name = strdup(initial_impls[tbl].impl_name);
1023 _impl_names[_num_impls] = _impls[_num_impls].impl_name;
1028 _impl_names[_num_impls] = NULL;
1030 if (_num_impls == 0) {
1031 error.setError(DTME_NoImplementations);
1036 DtMail::Session::lookupImpl(const char * impl)
1038 MutexLock lock_scope(_obj_mutex);
1039 for(int i = 0; i < _num_impls; i++) {
1040 if (strcmp(_impls[i].impl_name, impl) == 0) {
1049 DtMail::Session::setAutoSaveFlag(
1053 _canAutoSave = flag;
1057 DtMail::Session::getAutoSaveFlag()
1059 return(_canAutoSave);
1063 ChildExitNotify(const int pid, const int status)
1065 // We need to lookup the child, and set the status of the
1066 // correct condition variable. We will remove the slot, but
1067 // the thread will destroy the buffer in the slot.
1069 for (int slot = 0; slot < DtMailSigChldList->length(); slot++) {
1070 if ((*DtMailSigChldList)[slot]->pid == pid) {
1071 (*DtMailSigChldList)[slot]->cond = status;
1072 DtMailSigChldList->remove(slot);
1077 // Not finding the pid is not a problem. Just means it wasn't
1086 * Wrapper functions taken from libHelp/CEUtil.c
1088 * We took these functions and renamed them because
1089 * 1. Originally these are called _DtHelpCeXlate* and thus they are private
1090 * to libHelp and not exported to outside of libHelp.
1091 * 2. When these functions are moved to another library, then users of these
1092 * functions would only need to link with a different library. The caller
1093 * doesn't have to modify code.
1096 static const char *DfltStdCharset = "us-ascii";
1097 static const char *DfltStdLang = "C";
1099 static char MyPlatform[_DtPLATFORM_MAX_LEN+1];
1100 static _DtXlateDb MyDb = NULL;
1101 static char MyProcess = False;
1102 static char MyFirst = True;
1107 /******************************************************************************
1108 * Function: static int OpenLcxDb ()
1112 * Return Value: 0: ok
1117 * Purpose: Opens the Ce-private Lcx database
1119 *****************************************************************************/
1121 DtMail::Session::OpenLcxDb (void)
1126 while (MyProcess == True)
1128 /* if time out, return */
1129 if (time(&time2) == (time_t)-1)
1134 else if (time2 - time1 >= (time_t)30)
1138 if (MyFirst == True)
1141 if (_DtLcxOpenAllDbs(&MyDb) == 0 &&
1142 _DtXlateGetXlateEnv(MyDb,MyPlatform,&ExecVer,&CompVer) != 0)
1144 _DtLcxCloseDb(&MyDb);
1151 return (MyDb == NULL ? -1 : 0 );
1154 /******************************************************************************
1155 * Function: int DtXlateOpToStdLocale(char *operation, char *opLocale,
1156 * char **ret_stdLocale,
1157 * char **ret_stdLang,
1158 * char **ret_stdSet)
1161 * operation Operation associated with the locale value
1162 * opLocale An operation-specific locale string
1163 * ret_locale Returns the std locale
1164 * Caller must free this string.
1165 * ret_stdLang Returns the std language & territory string.
1166 * Caller must free this string.
1167 * ret_stdSet Returns the std code set string.
1168 * Caller must free this string.
1172 * Purpose: Gets the standard locale given an operation and its locale
1174 *****************************************************************************/
1176 DtMail::Session::DtXlateOpToStdLocale (
1179 char **ret_stdLocale,
1183 int result = OpenLcxDb();
1186 (void) _DtLcxXlateOpToStd(
1187 MyDb, MyPlatform, CompVer,
1188 operation, opLocale,
1189 ret_stdLocale, ret_stdLang, ret_stdSet, NULL);
1192 /* if failed, give default values */
1193 if (ret_stdLocale != NULL && (result != 0 || *ret_stdLocale == NULL))
1196 (char *)malloc(strlen(DfltStdLang)+strlen(DfltStdCharset)+3);
1197 sprintf(*ret_stdLocale,"%s.%s",DfltStdLang,DfltStdCharset);
1200 if (ret_stdLang != NULL && (result != 0 || *ret_stdLang == NULL))
1201 *ret_stdLang = (char *)strdup(DfltStdLang);
1202 if (ret_stdSet != NULL && (result != 0 || *ret_stdSet == NULL))
1203 *ret_stdSet = (char *)strdup(DfltStdCharset);
1206 /******************************************************************************
1207 * Function: int DtXlateStdToOpLocale(char *operation,
1209 * char *dflt_opLocale,
1210 * char **ret_opLocale)
1213 * operation operation whose locale value will be retrieved
1214 * stdLocale standard locale value
1215 * dflt_opLocale operation-specific locale-value
1216 * This is the default value used in error case
1217 * ret_opLocale operation-specific locale-value placed here
1218 * Caller must free this string.
1222 * Purpose: Gets an operation-specific locale string given the standard string
1224 *****************************************************************************/
1226 DtMail::Session::DtXlateStdToOpLocale (
1229 char *dflt_opLocale,
1230 char **ret_opLocale)
1232 int result = this->OpenLcxDb();
1235 *ret_opLocale = NULL;
1238 (void) _DtLcxXlateStdToOp(
1239 MyDb, MyPlatform, CompVer,
1240 operation, stdLocale,
1245 /* if translation fails, use a default value */
1246 if (ret_opLocale && (result != 0 || *ret_opLocale == NULL))
1248 if (dflt_opLocale) *ret_opLocale = (char *)strdup(dflt_opLocale);
1249 else if (stdLocale) *ret_opLocale = (char *)strdup(stdLocale);
1254 /******************************************************************************
1255 * Function: int DtXlateStdToOpCodeset (
1258 * char *dflt_opCodeset,
1259 * char **ret_opCodeset)
1262 * operation operation whose codeset value will be retrieved
1263 * stdCodeset standard codeset value
1264 * dflt_opCodeset operation-specific codeset-value
1265 * This is the default value used in error case
1266 * ret_opCodeset operation-specific codeset-value placed here
1267 * Caller must free this string.
1271 * Purpose: Gets an operation-specific locale string given the standard string
1273 *****************************************************************************/
1275 DtMail::Session::DtXlateStdToOpCodeset (
1278 char *dflt_opCodeset,
1279 char **ret_opCodeset)
1281 int result = this->OpenLcxDb();
1284 *ret_opCodeset = NULL;
1288 (void) _DtLcxXlateStdToOp(
1289 MyDb, MyPlatform, CompVer,
1291 NULL, NULL, stdCodeset, NULL,
1295 /* if translation fails, use a default value */
1296 if (ret_opCodeset && (result != 0 || *ret_opCodeset == NULL))
1298 if (dflt_opCodeset) *ret_opCodeset = (char *)strdup(dflt_opCodeset);
1299 else if (stdCodeset) *ret_opCodeset = (char *)strdup(stdCodeset);
1304 DtMail::Session::DtXlateMimeToIconv(
1306 const char *defaultCommonCS,
1307 const char *defaultIconvCS,
1308 char **ret_commonCS,
1309 char **ret_platformIconv)
1315 exists = _DtLcxXlateOpToStd(
1316 MyDb, MyPlatform, CompVer,
1317 DtLCX_OPER_MIME, mimeId,
1318 NULL, NULL, ret_commonCS, NULL);
1322 exists = _DtLcxXlateOpToStd(
1324 DtLCX_OPER_MIME, mimeId,
1325 NULL, NULL, ret_commonCS, NULL);
1327 *ret_commonCS = (char *)strdup(defaultCommonCS);
1330 exists = _DtLcxXlateStdToOp(
1331 MyDb, MyPlatform, CompVer,
1333 NULL, NULL, *ret_commonCS, NULL,
1336 *ret_platformIconv = (char *)strdup(defaultIconvCS);
1340 DtMail::Session::DtXlateLocaleToMime(
1341 const char * locale,
1342 const char * defaultCommonCS,
1343 const char * defaultMimeCS,
1346 char * commonCS = NULL;
1350 /* look for platform-specific locale to CDE translation */
1352 MyDb, MyPlatform, CompVer,
1353 DtLCX_OPER_SETLOCALE, locale,
1354 NULL, NULL, &commonCS, NULL);
1356 commonCS = (char *)strdup(defaultCommonCS);
1358 /* look for platform-specific MIME types; by default, there is none */
1360 MyDb, MyPlatform, CompVer,
1362 NULL, NULL, commonCS, NULL,
1369 NULL, NULL, commonCS, NULL,
1372 *ret_mimeCS = (char *)strdup(defaultMimeCS);
1379 // Return iconv name of the given codeset.
1380 // If iconv name does not exist, return NULL.
1382 DtMail::Session::csToConvName(char *cs)
1385 char *commonCS = NULL;
1386 char *convName = NULL;
1387 char *ret_target = NULL;
1391 // Convert charset to upper case first because charset table is
1395 int len_cs = strlen(cs);
1396 for ( int num_cs = 0; num_cs < len_cs; num_cs++ )
1397 *(cs+num_cs) = toupper(*(cs+num_cs));
1399 exists = _DtLcxXlateOpToStd(
1400 MyDb, MyPlatform, CompVer,
1401 DtLCX_OPER_MIME, cs,
1402 NULL, NULL, &commonCS, NULL);
1404 exists = _DtLcxXlateOpToStd(
1406 DtLCX_OPER_MIME, cs,
1407 NULL, NULL, &commonCS, NULL);
1412 DtXlateStdToOpCodeset(DtLCX_OPER_INTERCHANGE_CODESET,
1416 DtXlateStdToOpCodeset(DtLCX_OPER_ICONV3,
1426 // Workaround for libDtHelp
1427 // Case of no iconv name for a particular locale, eg. C,
1428 // check for empty string.
1429 if ( convName != NULL )
1431 if ( strlen(convName) > 0 )
1439 // Return current locale's iconv name.
1441 DtMail::Session::locToConvName()
1443 char *ret_locale = NULL;
1444 char *ret_lang = NULL;
1445 char *ret_codeset = NULL;
1447 DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
1448 setlocale(LC_CTYPE, NULL),
1463 DtXlateStdToOpLocale(DtLCX_OPER_ICONV3,
1471 // Workaround for libDtHelp
1472 // Case of no iconv name for a particular locale, eg. C,
1473 // check for empty string.
1474 if ( ret_codeset != NULL )
1476 if ( strlen(ret_codeset) > 0 )
1484 // Return target codeset's iconv name.
1486 DtMail::Session::targetConvName()
1488 char *ret_locale = NULL;
1489 char *ret_lang = NULL;
1490 char *ret_codeset = NULL;
1491 char *ret_target = NULL;
1492 char *ret_convName = NULL;
1494 DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
1495 setlocale(LC_CTYPE, NULL),
1499 DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
1503 // Or do I call csToConvName() here??
1504 DtXlateStdToOpCodeset(DtLCX_OPER_ICONV3,
1518 // Workaround for libDtHelp
1519 // Case of no iconv name for a particular locale, eg. C,
1520 // check for empty string.
1521 if ( ret_convName != NULL )
1523 if ( strlen(ret_convName) > 0 )
1524 return ret_convName;
1531 // Return target codeset's MIME (tag) name.
1533 DtMail::Session::targetTagName()
1535 char *ret_locale = NULL;
1536 char *ret_lang = NULL;
1537 char *ret_codeset = NULL;
1538 char *ret_target = NULL;
1540 DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
1541 setlocale(LC_CTYPE, NULL),
1545 DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
1549 DtXlateStdToOpCodeset(DtLCX_OPER_MIME,
1564 // Given an extension to the interchange codeset name.
1565 // Return target codeset's MIME (tag) name.
1566 // The extension is for Sun V3 backward compatibility so that
1567 // reverse mapping of out-going charset tag is the same as
1568 // OpenWindows Mailtool.
1570 DtMail::Session::targetTagName(char *special)
1572 char *ret_locale = NULL;
1573 char *ret_lang = NULL;
1574 char *ret_codeset = NULL;
1575 char *ret_target = NULL;
1577 DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
1578 setlocale(LC_CTYPE, NULL),
1583 // Allocate two more bytes for "." and null terminator.
1584 char *special_locale;
1586 special_locale = (char *)calloc(
1587 strlen(ret_locale) + strlen(special) + 2,
1589 sprintf(special_locale, "%s%s%s", ret_locale, ".", special);
1591 DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
1595 DtXlateStdToOpCodeset(DtLCX_OPER_MIME,
1609 // Given a message text and codesets
1610 // Convert message text from one codeset to another
1611 // Return 1 if conversion is successful else return 0.
1614 DtMail::Session::csConvert(char **bp, unsigned long &bp_len, int free_bp,
1615 char *from_cs, char *to_cs)
1619 size_t ileft = (size_t) bp_len, oleft = (size_t) bp_len, ret = 0;
1620 #if defined(_AIX) || defined(sun) || defined(CSRG_BASED)
1621 const char *ip = (const char *) *bp;
1626 char *op_start = NULL;
1630 if ( *bp == NULL || **bp == '\0' || bp_len <= 0 )
1632 if ( to_cs == NULL || from_cs == NULL )
1634 if ( (cd = iconv_open(to_cs, from_cs)) == (iconv_t) -1 ) {
1637 error.logError(DTM_FALSE,
1638 "DtMail: Conversion from %s to %s is not supported.\n",
1641 } // end of switch statement
1644 // Caller will set _must_free_body to DTM_TRUE if this routine
1645 // succeeds. Then this space will be freed appropriately.
1646 // Add 1 to buffer size for null terminator.
1647 op_start = op = (char *)calloc((unsigned int) bp_len + 1, sizeof(char));
1649 // When ileft finally reaches 0, the conversion still might not be
1650 // complete. Here's why we also need to check for E2BIG: Let's
1651 // say we're converting from eucJP to ISO-2022-JP, and there's just
1652 // enough room in the output buffer for the last input character,
1653 // but not enough room for the trailing "ESC ( B" (for switching
1654 // back to ASCII). In that case, iconv() will convert the last
1655 // input character, decrement ileft to zero, and then set errno to
1656 // E2BIG to tell us that it still needs more room for the "ESC ( B".
1658 while ( ileft > 0 || errno == E2BIG ) {
1660 if ((ret = iconv(cd, &ip, &ileft, &op, &oleft)) == (size_t) -1) {
1662 case E2BIG: // increase output buffer size
1663 delta = ileft ? ileft : 3;
1665 op_start = (char *)realloc(
1667 (unsigned int) bp_len + 1);
1668 op = op_start + bp_len - delta - oleft;
1670 // realloc does not clear out unused space.
1671 // Therefore, garbage shows up in output buffer.
1672 memset(op, 0, oleft + 1);
1674 case EILSEQ: // input byte does not belong to input codeset
1675 case EINVAL: // invalid input
1676 mb_ret = mblen(ip, MB_LEN_MAX);
1677 if ( (mb_ret > 0) && (oleft >= mb_ret) ) {
1678 strncat(op_start, ip, mb_ret);
1685 // mb_ret is either 0 or -1 at this point,
1686 // then skip one byte
1687 // and try conversion again.
1692 case EBADF: // bad conversion descriptor
1694 } // end of switch statement
1696 } // end of while loop
1699 // Is this necessary?? Is _body_decode_len == strlen(_body)??
1700 // Or can _body_decode_len contain spaces??
1702 // Check to see if a body had been allocated by prior decoding.
1707 bp_len = strlen(*bp);
1712 // End of For CHARSET