Session.C 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657
  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. /*
  24. *+SNOTICE
  25. *
  26. *
  27. * $TOG: Session.C /main/16 1998/07/24 16:08:39 mgreess $
  28. *
  29. * RESTRICTED CONFIDENTIAL INFORMATION:
  30. *
  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
  37. * Sun's request.
  38. *
  39. * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
  40. *
  41. *+ENOTICE
  42. */
  43. #include <stdlib.h>
  44. #include <unistd.h>
  45. #include <string.h>
  46. #include <pwd.h>
  47. #include <sys/socket.h>
  48. #include <ctype.h>
  49. #include <DtMail/DtMail.hh>
  50. #include <EUSDebug.hh>
  51. #include "DynamicLib.hh"
  52. #include <DtMail/Threads.hh>
  53. #include <DtMail/ImplDriver.hh>
  54. #include "ImplConfigTable.hh"
  55. #include "SigChldImpl.hh"
  56. #include <DtMail/IO.hh>
  57. #include <DtMail/Common.h>
  58. // For CHARSET
  59. //-------------------------------------
  60. // HACK ALERT
  61. // Any code change within "For CHARSET" should be changed in
  62. // RFCBodyPart and Session because the same methods are duplicated
  63. // in both of these classes.
  64. // See RFCImpl.hh or DtMail/DtMail.hh for more explanation.
  65. //-------------------------------------
  66. #include <locale.h>
  67. #include <time.h>
  68. #include <DtHelp/LocaleXlate.h>
  69. #include <errno.h>
  70. #include <stdlib.h>
  71. #include <limits.h>
  72. #include <ctype.h>
  73. #ifndef True
  74. #define True 1
  75. #endif
  76. #ifndef False
  77. #define False 0
  78. #endif
  79. #if defined(SunOS) && (SunOS < 55)
  80. extern "C" {
  81. #endif
  82. #include <iconv.h>
  83. #if defined(SunOS) && (SunOS < 55)
  84. }
  85. #endif
  86. //End of CHARSET
  87. DtVirtArray<SigChldInfo *> *DtMailSigChldList;
  88. void * _DtMutex;
  89. static const int SessionSignature = 0xef9421cc;
  90. static const int MaxImpls = 16;
  91. static const int MAXIMUM_PATH_LENGTH = 2048;
  92. DtMail::Session::Session(DtMailEnv & error, const char * app_name)
  93. : _events(16), _valid_keys(2048)
  94. {
  95. _DtMutex = MutexInit();
  96. error.clear();
  97. _object_signature = 0;
  98. _cur_key = 0;
  99. // Create the ToolTalk session for managing file locking,
  100. // if one doesn't exist.
  101. _tt_channel = tt_default_procid();
  102. if (tt_pointer_error(_tt_channel) != TT_OK) {
  103. _tt_channel = ttdt_open(&_tt_fd, app_name, "SunSoft", "%I", 0);
  104. if (tt_pointer_error(_tt_channel) != TT_OK) {
  105. error.setError(DTME_TTFailure);
  106. DebugPrintf(1,
  107. "DtMail::createSession - ttdt_open returns %s\n",
  108. tt_status_message(tt_pointer_error(_tt_channel)));
  109. return;
  110. }
  111. }
  112. else {
  113. _tt_fd = tt_fd();
  114. }
  115. // The event_fd is how we allow async behavior to occur in a
  116. // compatible way. We use a Unix domain socket as the file descriptor.
  117. // The client will watch for activity on this file descriptor, and
  118. // call our event routine when there is activity (either from XtMainLoop,
  119. // or through some other method).
  120. //
  121. pipe(_event_fd);
  122. _app_name = strdup(app_name);
  123. DtMailEnv b_error;
  124. _mail_rc = new MailRc(error, this);
  125. buildImplTable(error);
  126. if (error.isSet()) {
  127. return;
  128. }
  129. _obj_mutex = MutexInit();
  130. // The default implementation is specified via the DEFAULT_BACKEND
  131. // variable. If this is not set in the .mailrc, then choose entry
  132. // zero.
  133. //
  134. const char * value;
  135. _mail_rc->getValue(b_error, "DEFAULT_BACKEND", &value);
  136. if (b_error.isNotSet()) {
  137. _default_impl = lookupImpl(value);
  138. if (_default_impl < 0) {
  139. _default_impl = 0;
  140. }
  141. }
  142. else {
  143. b_error.clear();
  144. _default_impl = 0;
  145. }
  146. DtMailSigChldList = new DtVirtArray<SigChldInfo *>(8);
  147. _busy_cb = NULL;
  148. _busy_cb_data = NULL;
  149. _canAutoSave = DTM_TRUE;
  150. _object_signature = SessionSignature;
  151. return;
  152. }
  153. DtMail::Session::~Session(void)
  154. {
  155. if (_object_signature != SessionSignature) { // Been here, did that!
  156. return;
  157. }
  158. {
  159. MutexLock lock_scope(_obj_mutex);
  160. _object_signature = 0;
  161. ttdt_close(_tt_channel, NULL, 1);
  162. DtMailEnv b_error;
  163. // Close off the dynamic libraries and free the impl table.
  164. for (int tbl = 0; tbl < _num_impls; tbl++) {
  165. free(_impls[tbl].impl_name);
  166. DynamicLib * dl = (DynamicLib *)_impls[tbl].impl_lib;
  167. delete dl;
  168. }
  169. free(_impls);
  170. lock_scope.unlock_and_destroy();
  171. delete _mail_rc;
  172. close(_event_fd[0]);
  173. close(_event_fd[1]);
  174. }
  175. }
  176. const char **
  177. DtMail::Session::enumerateImpls(DtMailEnv & error)
  178. {
  179. error.clear();
  180. return(_impl_names);
  181. }
  182. void
  183. DtMail::Session::setDefaultImpl(DtMailEnv & error, const char * impl)
  184. {
  185. int slot = lookupImpl(impl);
  186. if (slot < 0) {
  187. error.setError(DTME_NoSuchImplementation);
  188. return;
  189. }
  190. MutexLock lock_scope(_obj_mutex);
  191. _default_impl = slot;
  192. error.clear();
  193. }
  194. const char *
  195. DtMail::Session::getDefaultImpl(DtMailEnv & error)
  196. {
  197. if (_num_impls == 0) {
  198. error.setError(DTME_NoImplementations);
  199. return(NULL);
  200. }
  201. error.clear();
  202. return(_impl_names[_default_impl]);
  203. }
  204. void
  205. DtMail::Session::queryImpl(DtMailEnv & error,
  206. const char * impl,
  207. const char * capability,
  208. ...)
  209. {
  210. va_list args;
  211. va_start(args, capability);
  212. queryImplV(error, impl, capability, args);
  213. va_end(args);
  214. return;
  215. }
  216. void
  217. DtMail::Session::queryImplV(DtMailEnv & error,
  218. const char * impl,
  219. const char * capability,
  220. va_list args)
  221. {
  222. int slot = lookupImpl(impl);
  223. if (slot < 0) {
  224. error.setError(DTME_NoSuchImplementation);
  225. return;
  226. }
  227. error.clear();
  228. // We need to retrieve the QueryImpl entry point for the implementation.
  229. //
  230. QueryImplEntry qie;
  231. qie = (QueryImplEntry)_impls[slot].impl_meta_factory(QueryImplEntryOp);
  232. if (!qie) {
  233. error.setError(DTME_ImplFailure);
  234. return;
  235. }
  236. qie(*this, error, capability, args);
  237. return;
  238. }
  239. DtMail::MailBox *
  240. DtMail::Session::mailBoxConstruct(DtMailEnv & error,
  241. DtMailObjectSpace space,
  242. void * arg,
  243. DtMailCallback open_callback,
  244. void * client_data,
  245. const char * impl_name)
  246. {
  247. // If the client specified an implementation of choice, then that
  248. // is the only thing we use.
  249. //
  250. int primary_impl = _default_impl;
  251. if (impl_name) {
  252. int sl = lookupImpl(impl_name);
  253. if (sl < 0) {
  254. error.setError(DTME_NoSuchImplementation);
  255. return(NULL);
  256. }
  257. primary_impl = sl;
  258. }
  259. // First thing we will do is see if the default implementation
  260. // can open this file. If so, then we will create a mail box object
  261. // based on the default implementation.
  262. //
  263. int const_impl;
  264. QueryOpenEntry qoe;
  265. qoe = (QueryOpenEntry)
  266. _impls[primary_impl].impl_meta_factory(QueryOpenEntryOp);
  267. if (!qoe) {
  268. error.setError(DTME_ImplFailure);
  269. return(NULL);
  270. }
  271. if (qoe(*this, error, space, arg) == DTM_FALSE) {
  272. // Don't go on if the client specified an implementation.
  273. //
  274. if (impl_name) {
  275. error.setError(DTME_ImplFailure);
  276. return(NULL);
  277. }
  278. // Oh well, let's walk through the list of impls and see if any of
  279. // them will take ownership of this file.
  280. //
  281. MutexLock lock_scope(_obj_mutex);
  282. const_impl = -1;
  283. for(int slot = 0; slot < _num_impls; slot++) {
  284. qoe = (QueryOpenEntry)
  285. _impls[slot].impl_meta_factory(QueryOpenEntryOp);
  286. if (!qoe) {
  287. // Just skip this implementation.
  288. continue;
  289. }
  290. if (qoe(*this, error, space, arg) == DTM_TRUE) {
  291. const_impl = slot;
  292. break;
  293. }
  294. }
  295. // If we didn't find an impl, then we have to give up.
  296. //
  297. if (const_impl < 0) {
  298. error.setError(DTME_NotMailBox);
  299. return(NULL);
  300. }
  301. }
  302. else {
  303. const_impl = primary_impl;
  304. }
  305. // At this point we have an implementation that is willing to work
  306. // with the path. Get its mail box constructor and build a mailbox
  307. // from it.
  308. //
  309. MailBoxConstructEntry mbce;
  310. mbce = (MailBoxConstructEntry)
  311. _impls[const_impl].impl_meta_factory(MailBoxConstructEntryOp);
  312. if (!mbce) {
  313. error.setError(DTME_ImplFailure);
  314. return(NULL);
  315. }
  316. return(mbce(*this, error, space, arg, open_callback, client_data));
  317. }
  318. DtMail::Message *
  319. DtMail::Session::messageConstruct(DtMailEnv & error,
  320. DtMailObjectSpace space,
  321. void * arg,
  322. DtMailCallback open_callback,
  323. void * client_data,
  324. const char * impl_name)
  325. {
  326. // If the client specified an implementation of choice, then that
  327. // is the only thing we use.
  328. //
  329. int primary_impl = _default_impl;
  330. if (impl_name) {
  331. int sl = lookupImpl(impl_name);
  332. if (sl < 0) {
  333. error.setError(DTME_NoSuchImplementation);
  334. return(NULL);
  335. }
  336. primary_impl = sl;
  337. }
  338. int const_impl;
  339. QueryMessageEntry qoe;
  340. qoe = (QueryMessageEntry)
  341. _impls[primary_impl].impl_meta_factory(QueryMessageEntryOp);
  342. if (!qoe) {
  343. error.setError(DTME_ImplFailure);
  344. return(NULL);
  345. }
  346. if (qoe(*this, error, space, arg) == DTM_FALSE) {
  347. // Don't go on if the client specified an implementation.
  348. //
  349. if (impl_name) {
  350. error.setError(DTME_ImplFailure);
  351. return(NULL);
  352. }
  353. // Oh well, let's walk through the list of impls and see if any of
  354. // them will take ownership of this file.
  355. //
  356. MutexLock lock_scope(_obj_mutex);
  357. const_impl = -1;
  358. for(int slot = 0; slot < _num_impls; slot++) {
  359. qoe = (QueryMessageEntry)
  360. _impls[slot].impl_meta_factory(QueryMessageEntryOp);
  361. if (!qoe) {
  362. // Just skip this implementation.
  363. continue;
  364. }
  365. if (qoe(*this, error, space, arg) == DTM_TRUE) {
  366. const_impl = slot;
  367. break;
  368. }
  369. }
  370. // If we didn't find an impl, then we have to give up.
  371. //
  372. if (const_impl < 0) {
  373. error.setError(DTME_ImplFailure);
  374. return(NULL);
  375. }
  376. }
  377. else {
  378. const_impl = primary_impl;
  379. }
  380. // At this point we have an implementation that is willing to work
  381. // with the path. Get its mail box constructor and build a mailbox
  382. // from it.
  383. //
  384. MessageConstructEntry mbce;
  385. mbce = (MessageConstructEntry)
  386. _impls[const_impl].impl_meta_factory(MessageConstructEntryOp);
  387. if (!mbce) {
  388. error.setError(DTME_ImplFailure);
  389. return(NULL);
  390. }
  391. return(mbce(*this, error, space, arg, open_callback, client_data));
  392. }
  393. DtMail::Transport *
  394. DtMail::Session::transportConstruct(DtMailEnv & error,
  395. const char * impl,
  396. DtMailStatusCallback call_back,
  397. void * client_data)
  398. {
  399. // We need to find the implementation for starters.
  400. //
  401. int slot = lookupImpl(impl);
  402. if (slot < 0) {
  403. error.setError(DTME_NoSuchImplementation);
  404. return(NULL);
  405. }
  406. TransportConstructEntry tce;
  407. tce = (TransportConstructEntry)
  408. _impls[slot].impl_meta_factory(TransportConstructEntryOp);
  409. if (!tce) {
  410. error.setError(DTME_NotSupported);
  411. return(NULL);
  412. }
  413. return(tce(*this, error, call_back, client_data));
  414. }
  415. DtMail::MailRc *
  416. DtMail::Session::mailRc(DtMailEnv & error)
  417. {
  418. error.clear();
  419. return(_mail_rc);
  420. }
  421. //
  422. // NEEDS TO BE DELETED .. SHOULD NO LONGER BE USED...
  423. //
  424. void
  425. DtMail::Session::setError(DtMailEnv & error, const DTMailError_t minor_code)
  426. {
  427. error.setError(minor_code);
  428. //DtMail::setError(*this, error, minor_code);
  429. }
  430. DtMailBoolean
  431. DtMail::Session::pollRequired(DtMailEnv & error)
  432. {
  433. error.clear();
  434. #if defined(POSIX_THREADS)
  435. return(DTM_FALSE);
  436. #else
  437. return(DTM_TRUE);
  438. #endif
  439. }
  440. int
  441. DtMail::Session::eventFileDesc(DtMailEnv & error)
  442. {
  443. error.clear();
  444. return(_event_fd[0]);
  445. }
  446. void
  447. DtMail::Session::poll(DtMailEnv & error)
  448. {
  449. error.clear();
  450. #if defined(POSIX_THREADS)
  451. return; // A thread does this job.
  452. #else
  453. // We will grab the time and determine what needs to run.
  454. // Any events that have expired since the last time we were
  455. // called are automatically ran. If the event returns DTM_TRUE,
  456. // then reset last_ran to the current time to cause the event
  457. // to not run for the full wait interval; otherwise, refrain
  458. // and let the event happen again at the next poll interval
  459. //
  460. time_t now = time(NULL);
  461. for (int ev = 0; ev < _events.length(); ev++) {
  462. EventRoutine * event = _events[ev];
  463. if ((now - event->last_ran) > event->interval) {
  464. if (event->routine(event->client_data) == DTM_TRUE)
  465. event->last_ran = now;
  466. }
  467. }
  468. return;
  469. #endif
  470. }
  471. char *
  472. DtMail::Session::expandPath(DtMailEnv & error, const char * path)
  473. {
  474. const char * fold_path;
  475. if (path == NULL) {
  476. error.setError(DTME_BadArg);
  477. return(NULL);
  478. }
  479. error.clear();
  480. char * exp_name = (char *)malloc(MAXIMUM_PATH_LENGTH);
  481. if (exp_name == NULL) {
  482. error.setError(DTME_NoMemory);
  483. return(NULL);
  484. }
  485. if (strchr(path, '$') != NULL) {
  486. sprintf (exp_name, "echo %s", path);
  487. FILE *fp;
  488. if ((fp = popen(exp_name, "r")) != NULL) {
  489. exp_name[0] = '\0';
  490. if (fgets(exp_name, MAXIMUM_PATH_LENGTH, fp) != NULL &&
  491. exp_name[0] != '\0')
  492. // get rid of \n at end of string
  493. exp_name[strlen(exp_name)-1] = '\0';
  494. else
  495. strcpy(exp_name, path);
  496. pclose(fp);
  497. }
  498. else
  499. strcpy(exp_name, path);
  500. }
  501. else
  502. strcpy(exp_name, path);
  503. char * exp_name2 = (char *)malloc(MAXIMUM_PATH_LENGTH);
  504. exp_name2[0] = '\0';
  505. switch (exp_name[0]) {
  506. case '+':
  507. // This is relative to the folder path. Figure out what that is.
  508. {
  509. _mail_rc->getValue(error, "folder", &fold_path);
  510. if (error.isNotSet()) {
  511. if (*fold_path != '/' && *fold_path != '.' &&
  512. *fold_path != '~' && *fold_path != '$')
  513. strcpy(exp_name2, "~/");
  514. strcat(exp_name2, fold_path);
  515. strcat(exp_name2, "/");
  516. }
  517. else // Use the default folder
  518. strcpy(exp_name2, "~/");
  519. strcat(exp_name2, &exp_name[1]);
  520. // We need to call ourselves again to deal with
  521. // relative paths in the folder directory.
  522. //
  523. char * old_exp = exp_name2;
  524. exp_name2 = expandPath(error, old_exp);
  525. free(old_exp);
  526. break;
  527. }
  528. case '~':
  529. // This is relative to the user's home directory.
  530. {
  531. passwd pw;
  532. const char * start;
  533. if (exp_name[1] == '/' || exp_name[1] == '\0') {
  534. GetPasswordEntry(pw);
  535. start = &exp_name[1];
  536. }
  537. else {
  538. passwd * pw_p;
  539. char * slash = strchr(&exp_name[1], '/');
  540. if (slash == NULL) {
  541. error.clear();
  542. error.setError(DTME_NoSuchFile);
  543. break;
  544. }
  545. int len = slash - &exp_name[1];
  546. char * name = new char[len + 1];
  547. strncpy(name, &exp_name[1], len);
  548. name[len] = 0;
  549. pw_p = getpwnam(name);
  550. if (!pw_p) {
  551. error.clear();
  552. error.setError(DTME_NoSuchFile);
  553. break;
  554. }
  555. pw = *pw_p;
  556. delete [] name;
  557. start = slash;
  558. }
  559. strcpy(exp_name2, pw.pw_dir);
  560. strcat(exp_name2, start);
  561. break;
  562. }
  563. // We have a directory or no specials. Just copy the path and
  564. // return.
  565. case '.':
  566. case '/':
  567. default:
  568. strcpy(exp_name2, exp_name);
  569. break;
  570. }
  571. free(exp_name);
  572. return(exp_name2);
  573. }
  574. // This routine takes a path and checks to see if the path can be
  575. // expressed relative to the "folder" path. If it can, it returns
  576. // the relative path; otherwise, it returns the original path.
  577. char *
  578. DtMail::Session::getRelativePath(DtMailEnv & error, const char * path)
  579. {
  580. const char * fold_path;
  581. if (path == NULL) {
  582. error.setError(DTME_BadArg);
  583. return(NULL);
  584. }
  585. error.clear();
  586. char * exp_name = (char *)malloc(MAXIMUM_PATH_LENGTH);
  587. if (!exp_name) {
  588. error.setError(DTME_NoMemory);
  589. return(NULL);
  590. }
  591. exp_name[0] = '\0'; // Just for errors.
  592. switch (path[0]) {
  593. case '/':
  594. // This is an absolute path, so there is a chance that
  595. // we can trim it down to a relative path if it goes down
  596. // the same way as the folder path.
  597. {
  598. _mail_rc->getValue(error, "folder", &fold_path);
  599. if (error.isNotSet()) {
  600. strcpy(exp_name, fold_path);
  601. // We need to call ourselves again to deal with
  602. // relative paths in the folder directory.
  603. //
  604. char * old_exp = exp_name;
  605. exp_name = expandPath(error, old_exp);
  606. free(old_exp);
  607. // Check to see if the path starts with the folder path.
  608. char * matched_path = const_cast<char *>(strstr(path, exp_name));
  609. if (matched_path == path) {
  610. // Yes it does, make it a relative path to the folder dir.
  611. int folder_path_length = strlen(exp_name);
  612. while (path[folder_path_length] == '/')
  613. folder_path_length++;
  614. strcpy(exp_name, &path[folder_path_length]);
  615. break;
  616. } else {
  617. strcpy(exp_name, path);
  618. break;
  619. }
  620. }
  621. else {
  622. // There is no folder variable so just fall through to the
  623. // default.
  624. error.clear();
  625. }
  626. }
  627. case '+':
  628. // This is relative to the folder path. Leave it alone.
  629. // The only time we are likely to see a leading '+' is
  630. // when the path was carried over from mailtool in the .mailrc.
  631. case '~':
  632. // This is relative to the user's home directory. Leave it alone.
  633. // The only time we are likely to see a leading '~' is
  634. // when the path was carried over from mailtool in the .mailrc.
  635. case '.':
  636. // This is relative to the current directory where dtmail is
  637. // running. Leave it alone. The only time we are likely to see
  638. // a leading '.' is when the path was carried over from mailtool
  639. // in the .mailrc.
  640. default:
  641. {
  642. strcpy(exp_name, path);
  643. break;
  644. }
  645. }
  646. return(exp_name);
  647. }
  648. void
  649. DtMail::Session::addEventRoutine(DtMailEnv & error,
  650. DtMailEventFunc routine,
  651. void * client_data,
  652. time_t interval)
  653. {
  654. error.clear();
  655. EventRoutine * er = new EventRoutine;
  656. er->routine = routine;
  657. er->client_data = client_data;
  658. er->interval = interval;
  659. er->last_ran = 0; // This will case this routine to run immediately.
  660. _events.append(er);
  661. }
  662. void
  663. DtMail::Session::removeEventRoutine(DtMailEnv & error,
  664. DtMailEventFunc routine,
  665. void * client_data)
  666. {
  667. error.clear();
  668. for (int slot = 0; slot < _events.length(); slot++) {
  669. EventRoutine * event = _events[slot];
  670. if (event->routine == routine &&
  671. event->client_data == client_data) {
  672. delete event;
  673. _events.remove(slot);
  674. }
  675. }
  676. }
  677. void
  678. DtMail::Session::writeEventData(DtMailEnv&,
  679. const void * buf,
  680. const unsigned long size)
  681. {
  682. int status = SafeWrite(_event_fd[1], buf, (int)size);
  683. }
  684. DtMailBoolean
  685. DtMail::Session::validObjectKey(DtMailObjectKey key)
  686. {
  687. return(_valid_keys.indexof(key) < 0 ? DTM_FALSE : DTM_TRUE);
  688. }
  689. DtMailObjectKey
  690. DtMail::Session::newObjectKey(void)
  691. {
  692. MutexLock lock_scope(_obj_mutex);
  693. _cur_key += 1;
  694. _valid_keys.append(_cur_key);
  695. return(_cur_key);
  696. }
  697. void
  698. DtMail::Session::removeObjectKey(DtMailObjectKey key)
  699. {
  700. MutexLock lock_scope(_obj_mutex);
  701. int slot = _valid_keys.indexof(key);
  702. if (slot >= 0) {
  703. _valid_keys.remove(slot);
  704. }
  705. }
  706. void
  707. DtMail::Session::registerDisableGroupPrivilegesCallback(
  708. DisableGroupPrivilegesCallback cb,
  709. void * cb_data)
  710. {
  711. _disableGroupPrivileges_cb = cb;
  712. _disableGroupPrivileges_cb_data = cb_data;
  713. }
  714. #ifdef DEAD_WOOD
  715. void
  716. DtMail::Session::unregisterDisableGroupPrivilegesCallback(void)
  717. {
  718. _disableGroupPrivileges_cb = NULL;
  719. _disableGroupPrivileges_cb_data = NULL;
  720. }
  721. #endif /* DEAD_WOOD */
  722. void
  723. DtMail::Session::disableGroupPrivileges(void)
  724. {
  725. if (_disableGroupPrivileges_cb) {
  726. _disableGroupPrivileges_cb(_disableGroupPrivileges_cb_data);
  727. }
  728. }
  729. void
  730. DtMail::Session::registerEnableGroupPrivilegesCallback(
  731. EnableGroupPrivilegesCallback cb,
  732. void * cb_data)
  733. {
  734. _enableGroupPrivileges_cb = cb;
  735. _enableGroupPrivileges_cb_data = cb_data;
  736. }
  737. #ifdef DEAD_WOOD
  738. void
  739. DtMail::Session::unregisterEnableGroupPrivilegesCallback(void)
  740. {
  741. _enableGroupPrivileges_cb = NULL;
  742. _enableGroupPrivileges_cb_data = NULL;
  743. }
  744. #endif /* DEAD_WOOD */
  745. void
  746. DtMail::Session::enableGroupPrivileges(void)
  747. {
  748. if (_enableGroupPrivileges_cb) {
  749. _enableGroupPrivileges_cb(_enableGroupPrivileges_cb_data);
  750. }
  751. }
  752. void
  753. DtMail::Session::registerBusyCallback(DtMailEnv&,
  754. BusyApplicationCallback cb,
  755. void * cb_data)
  756. {
  757. _busy_cb = cb;
  758. _busy_cb_data = cb_data;
  759. }
  760. #ifdef DEAD_WOOD
  761. void
  762. DtMail::Session::unregisterBusyCallback(DtMailEnv & error)
  763. {
  764. _busy_cb = NULL;
  765. _busy_cb_data = NULL;
  766. }
  767. #endif /* DEAD_WOOD */
  768. void
  769. DtMail::Session::setBusyState(DtMailEnv &error, DtMailBusyState busy_state)
  770. {
  771. if (_busy_cb) {
  772. _busy_cb(error, busy_state, _busy_cb_data);
  773. }
  774. }
  775. void
  776. DtMail::Session::registerLastInteractiveEventTimeCallback(
  777. LastInteractiveEventTimeCallback cb,
  778. void * cb_data)
  779. {
  780. _interactive_time_cb = cb;
  781. _interactive_time_cb_data = cb_data;
  782. }
  783. long
  784. DtMail::Session::lastInteractiveEventTime(void)
  785. {
  786. if (_interactive_time_cb) {
  787. return(_interactive_time_cb(_interactive_time_cb_data));
  788. }
  789. else
  790. return(0);
  791. }
  792. void
  793. DtMail::Session::buildImplTable(DtMailEnv & error)
  794. {
  795. error.clear();
  796. // Let's pick a ridiculous number of implementations.
  797. _impls = (Impls *)malloc(sizeof(Impls) * MaxImpls);
  798. _impl_names = (const char **)malloc(sizeof(char *) * (MaxImpls + 1));
  799. // We will simply walk through the default implementations
  800. // to start, adding them to the impl table.
  801. int tbl;
  802. for (tbl = 0, _num_impls = 0; initial_impls[tbl].meta_entry_point; tbl++) {
  803. // Get the library handle.
  804. DynamicLib * dl = CreatePlatformDl(initial_impls[tbl].lib_name);
  805. if (dl) { // We are only interested in libraries we can load.
  806. _impls[_num_impls].impl_lib = dl;
  807. _impls[_num_impls].impl_meta_factory =
  808. (MetaImplFactory)dl->getSym(initial_impls[tbl].meta_entry_point);
  809. if (_impls[_num_impls].impl_meta_factory == NULL) {
  810. delete dl;
  811. continue;
  812. }
  813. _impls[_num_impls].impl_name = strdup(initial_impls[tbl].impl_name);
  814. _impl_names[_num_impls] = _impls[_num_impls].impl_name;
  815. _num_impls += 1;
  816. }
  817. }
  818. _impl_names[_num_impls] = NULL;
  819. if (_num_impls == 0) {
  820. error.setError(DTME_NoImplementations);
  821. }
  822. }
  823. int
  824. DtMail::Session::lookupImpl(const char * impl)
  825. {
  826. MutexLock lock_scope(_obj_mutex);
  827. for(int i = 0; i < _num_impls; i++) {
  828. if (strcmp(_impls[i].impl_name, impl) == 0) {
  829. return(i);
  830. }
  831. }
  832. return(-1);
  833. }
  834. void
  835. DtMail::Session::setAutoSaveFlag(
  836. DtMailBoolean flag
  837. )
  838. {
  839. _canAutoSave = flag;
  840. }
  841. DtMailBoolean
  842. DtMail::Session::getAutoSaveFlag()
  843. {
  844. return(_canAutoSave);
  845. }
  846. extern "C" void
  847. ChildExitNotify(const int pid, const int status)
  848. {
  849. // We need to lookup the child, and set the status of the
  850. // correct condition variable. We will remove the slot, but
  851. // the thread will destroy the buffer in the slot.
  852. //
  853. for (int slot = 0; slot < DtMailSigChldList->length(); slot++) {
  854. if ((*DtMailSigChldList)[slot]->pid == pid) {
  855. (*DtMailSigChldList)[slot]->cond = status;
  856. DtMailSigChldList->remove(slot);
  857. return;
  858. }
  859. }
  860. // Not finding the pid is not a problem. Just means it wasn't
  861. // one of ours.
  862. //
  863. return;
  864. }
  865. // For CHARSET
  866. /*
  867. * Wrapper functions taken from libHelp/CEUtil.c
  868. *
  869. * We took these functions and renamed them because
  870. * 1. Originally these are called _DtHelpCeXlate* and thus they are private
  871. * to libHelp and not exported to outside of libHelp.
  872. * 2. When these functions are moved to another library, then users of these
  873. * functions would only need to link with a different library. The caller
  874. * doesn't have to modify code.
  875. */
  876. static const char *DfltStdCharset = "us-ascii";
  877. static const char *DfltStdLang = "C";
  878. static char MyPlatform[_DtPLATFORM_MAX_LEN+1];
  879. static _DtXlateDb MyDb = NULL;
  880. static char MyProcess = False;
  881. static char MyFirst = True;
  882. static int ExecVer;
  883. static int CompVer;
  884. /******************************************************************************
  885. * Function: static int OpenLcxDb ()
  886. *
  887. * Parameters: none
  888. *
  889. * Return Value: 0: ok
  890. * -1: error
  891. *
  892. * errno Values:
  893. *
  894. * Purpose: Opens the Ce-private Lcx database
  895. *
  896. *****************************************************************************/
  897. int
  898. DtMail::Session::OpenLcxDb (void)
  899. {
  900. time_t time1 = 0;
  901. time_t time2 = 0;
  902. while (MyProcess == True)
  903. {
  904. /* if time out, return */
  905. if (time(&time2) == (time_t)-1)
  906. return -1;
  907. if (time1 == 0)
  908. time1 = time2;
  909. else if (time2 - time1 >= (time_t)30)
  910. return -1;
  911. }
  912. if (MyFirst == True)
  913. {
  914. MyProcess = True;
  915. if (_DtLcxOpenAllDbs(&MyDb) == 0 &&
  916. _DtXlateGetXlateEnv(MyDb,MyPlatform,&ExecVer,&CompVer) != 0)
  917. {
  918. _DtLcxCloseDb(&MyDb);
  919. MyDb = NULL;
  920. }
  921. MyFirst = False;
  922. MyProcess = False;
  923. }
  924. return (MyDb == NULL ? -1 : 0 );
  925. }
  926. /******************************************************************************
  927. * Function: int DtXlateOpToStdLocale(char *operation, char *opLocale,
  928. * char **ret_stdLocale,
  929. * char **ret_stdLang,
  930. * char **ret_stdSet)
  931. *
  932. * Parameters:
  933. * operation Operation associated with the locale value
  934. * opLocale An operation-specific locale string
  935. * ret_locale Returns the std locale
  936. * Caller must free this string.
  937. * ret_stdLang Returns the std language & territory string.
  938. * Caller must free this string.
  939. * ret_stdSet Returns the std code set string.
  940. * Caller must free this string.
  941. *
  942. * Return Value:
  943. *
  944. * Purpose: Gets the standard locale given an operation and its locale
  945. *
  946. *****************************************************************************/
  947. void
  948. DtMail::Session::DtXlateOpToStdLocale (
  949. char *operation,
  950. char *opLocale,
  951. char **ret_stdLocale,
  952. char **ret_stdLang,
  953. char **ret_stdSet)
  954. {
  955. int result = OpenLcxDb();
  956. if (result == 0) {
  957. (void) _DtLcxXlateOpToStd(
  958. MyDb, MyPlatform, CompVer,
  959. operation, opLocale,
  960. ret_stdLocale, ret_stdLang, ret_stdSet, NULL);
  961. }
  962. /* if failed, give default values */
  963. if (ret_stdLocale != NULL && (result != 0 || *ret_stdLocale == NULL))
  964. {
  965. *ret_stdLocale =
  966. (char *)malloc(strlen(DfltStdLang)+strlen(DfltStdCharset)+3);
  967. sprintf(*ret_stdLocale,"%s.%s",DfltStdLang,DfltStdCharset);
  968. }
  969. if (ret_stdLang != NULL && (result != 0 || *ret_stdLang == NULL))
  970. *ret_stdLang = (char *)strdup(DfltStdLang);
  971. if (ret_stdSet != NULL && (result != 0 || *ret_stdSet == NULL))
  972. *ret_stdSet = (char *)strdup(DfltStdCharset);
  973. }
  974. /******************************************************************************
  975. * Function: int DtXlateStdToOpLocale(char *operation,
  976. * char *stdLocale,
  977. * char *dflt_opLocale,
  978. * char **ret_opLocale)
  979. *
  980. * Parameters:
  981. * operation operation whose locale value will be retrieved
  982. * stdLocale standard locale value
  983. * dflt_opLocale operation-specific locale-value
  984. * This is the default value used in error case
  985. * ret_opLocale operation-specific locale-value placed here
  986. * Caller must free this string.
  987. *
  988. * Return Value:
  989. *
  990. * Purpose: Gets an operation-specific locale string given the standard string
  991. *
  992. *****************************************************************************/
  993. void
  994. DtMail::Session::DtXlateStdToOpLocale (
  995. char *operation,
  996. char *stdLocale,
  997. char *dflt_opLocale,
  998. char **ret_opLocale)
  999. {
  1000. int result = this->OpenLcxDb();
  1001. if (ret_opLocale)
  1002. *ret_opLocale = NULL;
  1003. if (result == 0) {
  1004. (void) _DtLcxXlateStdToOp(
  1005. MyDb, MyPlatform, CompVer,
  1006. operation, stdLocale,
  1007. NULL, NULL, NULL,
  1008. ret_opLocale);
  1009. }
  1010. /* if translation fails, use a default value */
  1011. if (ret_opLocale && (result != 0 || *ret_opLocale == NULL))
  1012. {
  1013. if (dflt_opLocale) *ret_opLocale = (char *)strdup(dflt_opLocale);
  1014. else if (stdLocale) *ret_opLocale = (char *)strdup(stdLocale);
  1015. }
  1016. }
  1017. /******************************************************************************
  1018. * Function: int DtXlateStdToOpCodeset (
  1019. * char *operation,
  1020. * char *stdCodeset,
  1021. * char *dflt_opCodeset,
  1022. * char **ret_opCodeset)
  1023. *
  1024. * Parameters:
  1025. * operation operation whose codeset value will be retrieved
  1026. * stdCodeset standard codeset value
  1027. * dflt_opCodeset operation-specific codeset-value
  1028. * This is the default value used in error case
  1029. * ret_opCodeset operation-specific codeset-value placed here
  1030. * Caller must free this string.
  1031. *
  1032. * Return Value:
  1033. *
  1034. * Purpose: Gets an operation-specific locale string given the standard string
  1035. *
  1036. *****************************************************************************/
  1037. void
  1038. DtMail::Session::DtXlateStdToOpCodeset (
  1039. char *operation,
  1040. char *stdCodeset,
  1041. char *dflt_opCodeset,
  1042. char **ret_opCodeset)
  1043. {
  1044. int result = this->OpenLcxDb();
  1045. if (ret_opCodeset)
  1046. *ret_opCodeset = NULL;
  1047. if (result == 0)
  1048. {
  1049. (void) _DtLcxXlateStdToOp(
  1050. MyDb, MyPlatform, CompVer,
  1051. operation,
  1052. NULL, NULL, stdCodeset, NULL,
  1053. ret_opCodeset);
  1054. }
  1055. /* if translation fails, use a default value */
  1056. if (ret_opCodeset && (result != 0 || *ret_opCodeset == NULL))
  1057. {
  1058. if (dflt_opCodeset) *ret_opCodeset = (char *)strdup(dflt_opCodeset);
  1059. else if (stdCodeset) *ret_opCodeset = (char *)strdup(stdCodeset);
  1060. }
  1061. }
  1062. void
  1063. DtMail::Session::DtXlateMimeToIconv(
  1064. const char *mimeId,
  1065. const char *defaultCommonCS,
  1066. const char *defaultIconvCS,
  1067. char **ret_commonCS,
  1068. char **ret_platformIconv)
  1069. {
  1070. int exists = -1;
  1071. this->OpenLcxDb();
  1072. exists = _DtLcxXlateOpToStd(
  1073. MyDb, MyPlatform, CompVer,
  1074. DtLCX_OPER_MIME, mimeId,
  1075. NULL, NULL, ret_commonCS, NULL);
  1076. if (exists == -1)
  1077. {
  1078. exists = _DtLcxXlateOpToStd(
  1079. MyDb, "CDE", 0,
  1080. DtLCX_OPER_MIME, mimeId,
  1081. NULL, NULL, ret_commonCS, NULL);
  1082. if (exists == -1)
  1083. *ret_commonCS = (char *)strdup(defaultCommonCS);
  1084. }
  1085. exists = _DtLcxXlateStdToOp(
  1086. MyDb, MyPlatform, CompVer,
  1087. DtLCX_OPER_ICONV3,
  1088. NULL, NULL, *ret_commonCS, NULL,
  1089. ret_platformIconv);
  1090. if (exists == -1)
  1091. *ret_platformIconv = (char *)strdup(defaultIconvCS);
  1092. }
  1093. void
  1094. DtMail::Session::DtXlateLocaleToMime(
  1095. const char * locale,
  1096. const char * defaultCommonCS,
  1097. const char * defaultMimeCS,
  1098. char ** ret_mimeCS)
  1099. {
  1100. char * commonCS = NULL;
  1101. this->OpenLcxDb();
  1102. /* look for platform-specific locale to CDE translation */
  1103. _DtLcxXlateOpToStd(
  1104. MyDb, MyPlatform, CompVer,
  1105. DtLCX_OPER_SETLOCALE, locale,
  1106. NULL, NULL, &commonCS, NULL);
  1107. if (!commonCS)
  1108. commonCS = (char *)strdup(defaultCommonCS);
  1109. /* look for platform-specific MIME types; by default, there is none */
  1110. _DtLcxXlateStdToOp(
  1111. MyDb, MyPlatform, CompVer,
  1112. DtLCX_OPER_MIME,
  1113. NULL, NULL, commonCS, NULL,
  1114. ret_mimeCS);
  1115. if (!(*ret_mimeCS))
  1116. {
  1117. _DtLcxXlateStdToOp(
  1118. MyDb, "CDE", 0,
  1119. DtLCX_OPER_MIME,
  1120. NULL, NULL, commonCS, NULL,
  1121. ret_mimeCS);
  1122. if (!(*ret_mimeCS))
  1123. *ret_mimeCS = (char *)strdup(defaultMimeCS);
  1124. }
  1125. if (commonCS)
  1126. free(commonCS);
  1127. }
  1128. // Return iconv name of the given codeset.
  1129. // If iconv name does not exist, return NULL.
  1130. char *
  1131. DtMail::Session::csToConvName(char *cs)
  1132. {
  1133. int exists = -1;
  1134. char *commonCS = NULL;
  1135. char *convName = NULL;
  1136. char *ret_target = NULL;
  1137. this->OpenLcxDb();
  1138. // Convert charset to upper case first because charset table is
  1139. // case sensitive.
  1140. if (cs)
  1141. {
  1142. int len_cs = strlen(cs);
  1143. for ( int num_cs = 0; num_cs < len_cs; num_cs++ )
  1144. *(cs+num_cs) = toupper(*(cs+num_cs));
  1145. }
  1146. exists = _DtLcxXlateOpToStd(
  1147. MyDb, MyPlatform, CompVer,
  1148. DtLCX_OPER_MIME, cs,
  1149. NULL, NULL, &commonCS, NULL);
  1150. if (exists == -1) {
  1151. exists = _DtLcxXlateOpToStd(
  1152. MyDb, "CDE", 0,
  1153. DtLCX_OPER_MIME, cs,
  1154. NULL, NULL, &commonCS, NULL);
  1155. if (exists == -1)
  1156. return NULL;
  1157. }
  1158. DtXlateStdToOpCodeset(DtLCX_OPER_INTERCHANGE_CODESET,
  1159. commonCS,
  1160. NULL,
  1161. &ret_target);
  1162. DtXlateStdToOpCodeset(DtLCX_OPER_ICONV3,
  1163. ret_target,
  1164. NULL,
  1165. &convName);
  1166. if ( ret_target )
  1167. free( ret_target );
  1168. if ( commonCS )
  1169. free( commonCS );
  1170. // Workaround for libDtHelp
  1171. // Case of no iconv name for a particular locale, eg. C,
  1172. // check for empty string.
  1173. if ( convName != NULL )
  1174. {
  1175. if ( strlen(convName) > 0 )
  1176. return convName;
  1177. else
  1178. free( convName );
  1179. }
  1180. return NULL;
  1181. }
  1182. // Return current locale's iconv name.
  1183. char *
  1184. DtMail::Session::locToConvName()
  1185. {
  1186. char *ret_locale = NULL;
  1187. char *ret_lang = NULL;
  1188. char *ret_codeset = NULL;
  1189. DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
  1190. setlocale(LC_CTYPE, NULL),
  1191. &ret_locale,
  1192. &ret_lang,
  1193. &ret_codeset);
  1194. if (ret_codeset) {
  1195. free(ret_codeset);
  1196. ret_codeset = NULL;
  1197. }
  1198. if (ret_lang) {
  1199. free(ret_lang);
  1200. ret_lang = NULL;
  1201. }
  1202. DtXlateStdToOpLocale(DtLCX_OPER_ICONV3,
  1203. ret_locale,
  1204. NULL,
  1205. &ret_codeset);
  1206. if (ret_locale)
  1207. free(ret_locale);
  1208. // Workaround for libDtHelp
  1209. // Case of no iconv name for a particular locale, eg. C,
  1210. // check for empty string.
  1211. if ( ret_codeset != NULL )
  1212. {
  1213. if ( strlen(ret_codeset) > 0 )
  1214. return ret_codeset;
  1215. else
  1216. free(ret_codeset);
  1217. }
  1218. return NULL;
  1219. }
  1220. // Return target codeset's iconv name.
  1221. char *
  1222. DtMail::Session::targetConvName()
  1223. {
  1224. char *ret_locale = NULL;
  1225. char *ret_lang = NULL;
  1226. char *ret_codeset = NULL;
  1227. char *ret_target = NULL;
  1228. char *ret_convName = NULL;
  1229. DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
  1230. setlocale(LC_CTYPE, NULL),
  1231. &ret_locale,
  1232. &ret_lang,
  1233. &ret_codeset);
  1234. DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
  1235. ret_locale,
  1236. NULL,
  1237. &ret_target);
  1238. // Or do I call csToConvName() here??
  1239. DtXlateStdToOpCodeset(DtLCX_OPER_ICONV3,
  1240. ret_target,
  1241. NULL,
  1242. &ret_convName);
  1243. if (ret_locale)
  1244. free(ret_locale);
  1245. if (ret_lang)
  1246. free(ret_lang);
  1247. if (ret_codeset)
  1248. free(ret_codeset);
  1249. if (ret_target)
  1250. free(ret_target);
  1251. // Workaround for libDtHelp
  1252. // Case of no iconv name for a particular locale, eg. C,
  1253. // check for empty string.
  1254. if ( ret_convName != NULL )
  1255. {
  1256. if ( strlen(ret_convName) > 0 )
  1257. return ret_convName;
  1258. else
  1259. free(ret_convName);
  1260. }
  1261. return NULL;
  1262. }
  1263. // Return target codeset's MIME (tag) name.
  1264. char *
  1265. DtMail::Session::targetTagName()
  1266. {
  1267. char *ret_locale = NULL;
  1268. char *ret_lang = NULL;
  1269. char *ret_codeset = NULL;
  1270. char *ret_target = NULL;
  1271. DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
  1272. setlocale(LC_CTYPE, NULL),
  1273. &ret_locale,
  1274. &ret_lang,
  1275. NULL);
  1276. DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
  1277. ret_locale,
  1278. NULL,
  1279. &ret_target);
  1280. DtXlateStdToOpCodeset(DtLCX_OPER_MIME,
  1281. ret_target,
  1282. NULL,
  1283. &ret_codeset);
  1284. if (ret_locale)
  1285. free(ret_locale);
  1286. if (ret_lang)
  1287. free(ret_lang);
  1288. if (ret_target)
  1289. free(ret_target);
  1290. return ret_codeset;
  1291. }
  1292. // Given an extension to the interchange codeset name.
  1293. // Return target codeset's MIME (tag) name.
  1294. // The extension is for Sun V3 backward compatibility so that
  1295. // reverse mapping of out-going charset tag is the same as
  1296. // OpenWindows Mailtool.
  1297. char *
  1298. DtMail::Session::targetTagName(char *special)
  1299. {
  1300. char *ret_locale = NULL;
  1301. char *ret_lang = NULL;
  1302. char *ret_codeset = NULL;
  1303. char *ret_target = NULL;
  1304. DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
  1305. setlocale(LC_CTYPE, NULL),
  1306. &ret_locale,
  1307. &ret_lang,
  1308. &ret_codeset);
  1309. // Allocate two more bytes for "." and null terminator.
  1310. char *special_locale;
  1311. special_locale = (char *)calloc(
  1312. strlen(ret_locale) + strlen(special) + 2,
  1313. sizeof(char));
  1314. sprintf(special_locale, "%s%s%s", ret_locale, ".", special);
  1315. DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
  1316. special_locale,
  1317. NULL,
  1318. &ret_target);
  1319. DtXlateStdToOpCodeset(DtLCX_OPER_MIME,
  1320. ret_target,
  1321. NULL,
  1322. &ret_codeset);
  1323. free(ret_locale);
  1324. if (ret_lang)
  1325. free(ret_lang);
  1326. if (ret_target)
  1327. free(ret_target);
  1328. return ret_codeset;
  1329. }
  1330. // Given a message text and codesets
  1331. // Convert message text from one codeset to another
  1332. // Return 1 if conversion is successful else return 0.
  1333. int
  1334. DtMail::Session::csConvert(char **bp, unsigned long &bp_len, int free_bp,
  1335. char *from_cs, char *to_cs)
  1336. {
  1337. DtMailEnv error;
  1338. iconv_t cd;
  1339. size_t ileft = (size_t) bp_len, oleft = (size_t) bp_len, ret = 0;
  1340. #if defined(_AIX) || defined(sun) || defined(CSRG_BASED)
  1341. const char *ip = (const char *) *bp;
  1342. #else
  1343. char *ip = *bp;
  1344. #endif
  1345. char *op = NULL;
  1346. char *op_start = NULL;
  1347. int mb_ret = 0;
  1348. size_t delta;
  1349. if ( *bp == NULL || **bp == '\0' || bp_len <= 0 )
  1350. return 0;
  1351. if ( to_cs == NULL || from_cs == NULL )
  1352. return 0;
  1353. if ( (cd = iconv_open(to_cs, from_cs)) == (iconv_t) -1 ) {
  1354. switch (errno) {
  1355. case EINVAL:
  1356. error.logError(DTM_FALSE,
  1357. "DtMail: Conversion from %s to %s is not supported.\n",
  1358. from_cs, to_cs);
  1359. break;
  1360. } // end of switch statement
  1361. return 0;
  1362. }
  1363. // Caller will set _must_free_body to DTM_TRUE if this routine
  1364. // succeeds. Then this space will be freed appropriately.
  1365. // Add 1 to buffer size for null terminator.
  1366. op_start = op = (char *)calloc((unsigned int) bp_len + 1, sizeof(char));
  1367. // When ileft finally reaches 0, the conversion still might not be
  1368. // complete. Here's why we also need to check for E2BIG: Let's
  1369. // say we're converting from eucJP to ISO-2022-JP, and there's just
  1370. // enough room in the output buffer for the last input character,
  1371. // but not enough room for the trailing "ESC ( B" (for switching
  1372. // back to ASCII). In that case, iconv() will convert the last
  1373. // input character, decrement ileft to zero, and then set errno to
  1374. // E2BIG to tell us that it still needs more room for the "ESC ( B".
  1375. errno = 0;
  1376. while ( ileft > 0 || errno == E2BIG ) {
  1377. errno = 0;
  1378. if ((ret = iconv(cd, &ip, &ileft, &op, &oleft)) == (size_t) -1) {
  1379. switch (errno) {
  1380. case E2BIG: // increase output buffer size
  1381. delta = ileft ? ileft : 3;
  1382. bp_len += delta;
  1383. op_start = (char *)realloc(
  1384. (char *)op_start,
  1385. (unsigned int) bp_len + 1);
  1386. op = op_start + bp_len - delta - oleft;
  1387. oleft += delta;
  1388. // realloc does not clear out unused space.
  1389. // Therefore, garbage shows up in output buffer.
  1390. memset(op, 0, oleft + 1);
  1391. break;
  1392. case EILSEQ: // input byte does not belong to input codeset
  1393. case EINVAL: // invalid input
  1394. mb_ret = mblen(ip, MB_LEN_MAX);
  1395. if ( (mb_ret > 0) && (oleft >= mb_ret) ) {
  1396. strncat(op_start, ip, mb_ret);
  1397. ip += mb_ret;
  1398. op += mb_ret;
  1399. oleft -= mb_ret;
  1400. ileft -= mb_ret;
  1401. mb_ret = 0;
  1402. } else {
  1403. // mb_ret is either 0 or -1 at this point,
  1404. // then skip one byte
  1405. // and try conversion again.
  1406. ip++;
  1407. ileft--;
  1408. }
  1409. break;
  1410. case EBADF: // bad conversion descriptor
  1411. break;
  1412. } // end of switch statement
  1413. }
  1414. } // end of while loop
  1415. iconv_close(cd);
  1416. // Is this necessary?? Is _body_decode_len == strlen(_body)??
  1417. // Or can _body_decode_len contain spaces??
  1418. // Check to see if a body had been allocated by prior decoding.
  1419. if (free_bp) {
  1420. free(*bp);
  1421. }
  1422. *bp = op_start;
  1423. bp_len = strlen(*bp);
  1424. return 1;
  1425. }
  1426. // End of For CHARSET