RFCBodyPart.C 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  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: RFCBodyPart.C /main/16 1998/04/06 13:27:40 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. #ifndef I_HAVE_NO_IDENT
  44. #endif
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include <Dt/Dts.h>
  49. #include <DtMail/DtMail.hh>
  50. #include "RFCImpl.hh"
  51. #include <DtMail/Threads.hh>
  52. // For CHARSET
  53. //-------------------------------------
  54. // HACK ALERT
  55. // Any code change within "For CHARSET" should be changed in
  56. // RFCBodyPart and Session because the same methods are duplicated
  57. // in both of these classes.
  58. // See RFCImpl.hh or DtMail/DtMail.hh for more explanation.
  59. //-------------------------------------
  60. #include <locale.h>
  61. #include <time.h>
  62. #include <DtHelp/LocaleXlate.h>
  63. #include <errno.h>
  64. #include <stdlib.h>
  65. #include <limits.h>
  66. #include <ctype.h>
  67. #ifndef True
  68. #define True 1
  69. #endif
  70. #ifndef False
  71. #define False 0
  72. #endif
  73. #if defined(SunOS) && (SunOS < 55)
  74. extern "C" {
  75. #endif
  76. #include <iconv.h>
  77. #if defined(SunOS) && (SunOS < 55)
  78. }
  79. #endif
  80. // End of For CHARSET
  81. RFCBodyPart::RFCBodyPart(DtMailEnv & error,
  82. DtMail::Message * parent,
  83. const char * start,
  84. const int len,
  85. RFCEnvelope * body_env)
  86. : DtMail::BodyPart(error, parent)
  87. {
  88. _body_lock = MutexInit();
  89. _body_start = _body_text = start;
  90. _body_len = len > 0 ? len : 0;
  91. // If we have no body to start, then we will want to create
  92. // a body envelope. We do this to make sure we can always
  93. // set headers for the body part.
  94. //
  95. if (_body_start == NULL) {
  96. _body_env = new RFCEnvelope(error, parent, NULL, 0);
  97. _my_env = DTM_TRUE;
  98. }
  99. else {
  100. _body_env = body_env;
  101. _my_env = _body_env ? DTM_FALSE : DTM_TRUE;
  102. }
  103. _body = NULL;
  104. _body_decoded_len = 0;
  105. _body_type = NULL;
  106. _must_free_body = DTM_FALSE;
  107. }
  108. RFCBodyPart::~RFCBodyPart(void)
  109. {
  110. if (_my_env == DTM_TRUE) {
  111. delete _body_env;
  112. }
  113. if (_must_free_body) {
  114. free(_body);
  115. }
  116. if (_body_type) {
  117. free(_body_type);
  118. }
  119. }
  120. void
  121. RFCBodyPart::getContents(DtMailEnv & error,
  122. const void ** contents,
  123. unsigned long * length,
  124. char ** type,
  125. char ** name,
  126. int * mode,
  127. char ** description)
  128. {
  129. // First things first, for each possible return, zero out the
  130. // pointer so that if the caller does not check for errors it
  131. // will be caught by a null dereference
  132. //
  133. if (name)
  134. *name = (char *)0;
  135. if (description)
  136. *description = (char *)0;
  137. if (type)
  138. *type = (char *)0;
  139. if (contents)
  140. *contents = (void *)0;
  141. // The caller can ask for a hodge podge of information.
  142. // The only real rule here is that you can not ask for
  143. // the contents without requesting the length.
  144. if (contents && !length) {
  145. error.setError(DTME_OperationInvalid);
  146. return;
  147. }
  148. // No need to clear the error here because it should be clear already.
  149. // error.clear();
  150. // MIME currently doesn't have body part names and RFC
  151. // doesn't let us at arbitrary message headers. Name
  152. // therefore can not be retrieved.
  153. //
  154. if (name) {
  155. *name = getName(error);
  156. if (error.isSet()) {
  157. // don't care about the error condition returned by getName()
  158. // because it returns a valid string no matter what error
  159. // condition occurs.
  160. error.clear();
  161. }
  162. }
  163. // Ditto for mode.
  164. //
  165. if (mode) {
  166. *mode = 0;
  167. }
  168. if (description) {
  169. // getDescription should not be passed a DtMailEnv object.
  170. // Neither implementation of getDescription (MIME or V3)
  171. // sets the error before returning. Besides being unnecessary,
  172. // it requires the caller of getDescription to check the error
  173. // status upon its return.
  174. //
  175. *description = getDescription(error);
  176. if (error.isSet()) {
  177. // Don't care about the error condition returned by getDescription
  178. // because it returns a valid string no matter what error
  179. // condition occurs.
  180. error.clear();
  181. }
  182. }
  183. // Types for DtMail are in the Dt name space. RFC returns
  184. // mime types. We will have to convert from the RFC name
  185. // space to the Dt name space.
  186. //
  187. if (type) {
  188. if (!_body_type) {
  189. getDtType(error);
  190. // Do we want to propogate this error back up to the
  191. // function that called us? If not, we need to call
  192. // error.clear() before returning.
  193. if (error.isSet()) {
  194. return;
  195. }
  196. }
  197. *type = strdup(_body_type);
  198. }
  199. if (length) {
  200. *length = getLength(error);
  201. if (error.isSet()) {
  202. // propogate the error back up to the caller
  203. return;
  204. }
  205. }
  206. if (contents) {
  207. *contents = getBody(error);
  208. if (error.isSet()) {
  209. // propogate the error back up to the caller
  210. return;
  211. }
  212. }
  213. }
  214. void
  215. RFCBodyPart::setContents(DtMailEnv & error,
  216. const void * contents,
  217. const unsigned long length,
  218. const char * type,
  219. const char * name,
  220. const int, // mode,
  221. const char *) // description)
  222. {
  223. error.clear();
  224. MutexLock lock_scope(_body_lock);
  225. if (name) {
  226. setName(error, name);
  227. }
  228. if (contents && !length) {
  229. error.setError(DTME_OperationInvalid);
  230. return;
  231. }
  232. if (!contents && !length) {
  233. if (_body && _must_free_body) {
  234. free(_body);
  235. _body = NULL;
  236. _must_free_body = DTM_FALSE;
  237. }
  238. _body_decoded_len = _body_len = 0;
  239. if (_body_type) {
  240. free(_body_type);
  241. _body_type = NULL;
  242. }
  243. // _must_free_body = DTM_FALSE;
  244. return;
  245. }
  246. if (contents) {
  247. if (_body && _must_free_body) {
  248. free(_body);
  249. _body = NULL;
  250. }
  251. _body = (char *)malloc((int)length);
  252. memcpy(_body, contents, (int)length);
  253. _body_decoded_len = _body_len = (int)length;
  254. _must_free_body = DTM_TRUE;
  255. // Reset the type. We don't know what it is!
  256. if (_body_type) {
  257. free(_body_type);
  258. _body_type = NULL;
  259. }
  260. }
  261. if (type) {
  262. if (_body_type)
  263. free(_body_type);
  264. _body_type = strdup(type);
  265. }
  266. }
  267. void
  268. RFCBodyPart::lockContents(DtMailEnv & error, const DtMailLock)
  269. {
  270. error.clear();
  271. }
  272. void
  273. RFCBodyPart::unlockContents(DtMailEnv & error)
  274. {
  275. error.clear();
  276. }
  277. void
  278. RFCBodyPart::getHeader(DtMailEnv & error,
  279. const char * name,
  280. const DtMailBoolean abstract,
  281. DtMailValueSeq & value)
  282. {
  283. error.clear();
  284. // If this is not our envelope, then we will not set the flag.
  285. //
  286. if (_my_env == DTM_FALSE) {
  287. error.setError(DTME_NotSupported);
  288. return;
  289. }
  290. if (_body_env == (RFCEnvelope *)NULL) {
  291. error.setError(DTME_NoObjectValue);
  292. return;
  293. }
  294. _body_env->getHeader(error, name, abstract, value);
  295. }
  296. void
  297. RFCBodyPart::setFlag(DtMailEnv & error,
  298. DtMailBodyPartState state)
  299. {
  300. error.clear();
  301. // If this is not our envelope, then we will not set the flag.
  302. //
  303. if (_my_env == DTM_FALSE) {
  304. error.setError(DTME_NotSupported);
  305. return;
  306. }
  307. DtMailEnv my_error;
  308. time_t now;
  309. char str_time[40];
  310. switch (state) {
  311. case DtMailBodyPartDeletePending:
  312. now = time(NULL);
  313. sprintf(str_time, "%08lX", (long)now);
  314. _body_env->setHeader(my_error, RFCDeleteHeader, DTM_TRUE, str_time);
  315. break;
  316. default:
  317. error.setError(DTME_OperationInvalid);
  318. }
  319. }
  320. void
  321. RFCBodyPart::resetFlag(DtMailEnv & error,
  322. DtMailBodyPartState state)
  323. {
  324. error.clear();
  325. // If this is not our envelope, then we will not set the flag.
  326. //
  327. if (_my_env == DTM_FALSE) {
  328. error.setError(DTME_NotSupported);
  329. return;
  330. }
  331. DtMailEnv my_error;
  332. switch (state) {
  333. case DtMailBodyPartDeletePending:
  334. _body_env->removeHeader(my_error, RFCDeleteHeader);
  335. break;
  336. default:
  337. error.setError(DTME_OperationInvalid);
  338. }
  339. }
  340. DtMailBoolean
  341. RFCBodyPart::flagIsSet(DtMailEnv & error,
  342. DtMailBodyPartState state)
  343. {
  344. error.clear();
  345. // If this is not our envelope, then we will not set the flag.
  346. //
  347. if (_my_env == DTM_FALSE) {
  348. error.setError(DTME_NotSupported);
  349. return(DTM_FALSE);
  350. }
  351. DtMailEnv my_error;
  352. DtMailValueSeq value;
  353. DtMailBoolean answer;
  354. switch (state) {
  355. case DtMailBodyPartDeletePending:
  356. _body_env->getHeader(my_error, RFCDeleteHeader, DTM_FALSE, value);
  357. if (my_error.isNotSet()) {
  358. answer = DTM_TRUE;
  359. }
  360. else {
  361. answer = DTM_FALSE;
  362. }
  363. break;
  364. default:
  365. error.setError(DTME_OperationInvalid);
  366. }
  367. return(answer);
  368. }
  369. time_t
  370. RFCBodyPart::getDeleteTime(DtMailEnv & error)
  371. {
  372. time_t delete_time = 0;
  373. DtMailValueSeq value;
  374. _body_env->getHeader(error, RFCDeleteHeader, DTM_FALSE, value);
  375. if (error.isNotSet()) {
  376. delete_time = (time_t) strtol(*(value[0]), NULL, 16);
  377. }
  378. error.clear();
  379. return(delete_time);
  380. }
  381. void
  382. RFCBodyPart::adjustBodyPartsLocation(char * start)
  383. {
  384. MutexLock lock_scope(_body_lock);
  385. _body_text = (_body_text - _body_start) + start;
  386. _body_start = start;
  387. if (_must_free_body == DTM_FALSE) {
  388. //_body = (char *)_body_text;
  389. _body = NULL;
  390. }
  391. if (_body_env && _my_env == DTM_TRUE) {
  392. // CMVC bug 2807
  393. // start points at the body part separator. Need to
  394. // Skip separator. Put in a sanity check until we know
  395. // this is the right fix
  396. if (*start != '-' && *(start + 1) != '-') {
  397. fprintf(
  398. stderr,
  399. "RFCBodyPart::adjustBodyPartLocation(%.20s): Not a separator\n",
  400. start);
  401. } else {
  402. while (*start != '\n')
  403. start++;
  404. start++;
  405. }
  406. // End Of fix for 2807
  407. _body_env->adjustHeaderLocation(start, (int)(_body_text-_body_start));
  408. }
  409. }
  410. DtMailBoolean
  411. RFCBodyPart::isTerm(const char * start)
  412. {
  413. if (*start == '\n' || (*start == '\r' && *(start + 1) == '\n')) {
  414. return(DTM_TRUE);
  415. }
  416. else {
  417. return(DTM_FALSE);
  418. }
  419. }
  420. const void *
  421. RFCBodyPart::getBody(DtMailEnv & error)
  422. {
  423. error.clear();
  424. if (!_body) {
  425. loadBody(error);
  426. if (error.isSet()) {
  427. return(NULL);
  428. }
  429. }
  430. return(_body);
  431. }
  432. // For CHARSET
  433. /*
  434. * Wrapper functions taken from libHelp/CEUtil.c
  435. *
  436. * We took these functions and renamed them because
  437. * 1. Originally these are called _DtHelpCeXlate* and thus they are private
  438. * to libHelp and not exported to outside of libHelp.
  439. * 2. When these functions are moved to another library, then users of these
  440. * functions would only need to link with a different library. The caller
  441. * doesn't have to modify code.
  442. */
  443. static const char *DfltStdCharset = "us-ascii";
  444. static const char *DfltStdLang = "C";
  445. static char MyPlatform[_DtPLATFORM_MAX_LEN+1];
  446. static _DtXlateDb MyDb = NULL;
  447. static char MyProcess = False;
  448. static char MyFirst = True;
  449. static int ExecVer;
  450. static int CompVer;
  451. /******************************************************************************
  452. * Function: static int OpenLcxDb ()
  453. *
  454. * Parameters: none
  455. *
  456. * Return Value: 0: ok
  457. * -1: error
  458. *
  459. * errno Values:
  460. *
  461. * Purpose: Opens the Ce-private Lcx database
  462. *
  463. *****************************************************************************/
  464. int
  465. RFCBodyPart::OpenLcxDb (void)
  466. {
  467. time_t time1 = 0;
  468. time_t time2 = 0;
  469. while (MyProcess == True)
  470. {
  471. /* if time out, return */
  472. if (time(&time2) == (time_t)-1)
  473. return -1;
  474. if (time1 == 0)
  475. time1 = time2;
  476. else if (time2 - time1 >= (time_t)30)
  477. return -1;
  478. }
  479. if (MyFirst == True)
  480. {
  481. MyProcess = True;
  482. if (_DtLcxOpenAllDbs(&MyDb) == 0 &&
  483. _DtXlateGetXlateEnv(MyDb,MyPlatform,&ExecVer,&CompVer) != 0)
  484. {
  485. _DtLcxCloseDb(&MyDb);
  486. MyDb = NULL;
  487. }
  488. MyFirst = False;
  489. MyProcess = False;
  490. }
  491. return (MyDb == NULL ? -1 : 0 );
  492. }
  493. /******************************************************************************
  494. * Function: int DtXlateOpToStdLocale(char *operation, char *opLocale,
  495. * char **ret_stdLocale,
  496. * char **ret_stdLang, char **ret_stdSet)
  497. *
  498. * Parameters:
  499. * operation Operation associated with the locale value
  500. * opLocale An operation-specific locale string
  501. * ret_locale Returns the std locale
  502. * Caller must free this string.
  503. * ret_stdLang Returns the std language & territory string.
  504. * Caller must free this string.
  505. * ret_stdSet Returns the std code set string.
  506. * Caller must free this string.
  507. *
  508. * Return Value:
  509. *
  510. * Purpose: Gets the standard locale given an operation and its locale
  511. *
  512. *****************************************************************************/
  513. void
  514. RFCBodyPart::DtXlateOpToStdLocale (
  515. char *operation,
  516. char *opLocale,
  517. char **ret_stdLocale,
  518. char **ret_stdLang,
  519. char **ret_stdSet)
  520. {
  521. int result = OpenLcxDb();
  522. if (result == 0) {
  523. (void) _DtLcxXlateOpToStd(
  524. MyDb, MyPlatform, CompVer,
  525. operation, opLocale,
  526. ret_stdLocale, ret_stdLang, ret_stdSet, NULL);
  527. }
  528. /* if failed, give default values */
  529. if (ret_stdLocale != NULL && (result != 0 || *ret_stdLocale == NULL))
  530. {
  531. *ret_stdLocale =
  532. (char *)malloc(strlen(DfltStdLang)+strlen(DfltStdCharset)+3);
  533. sprintf(*ret_stdLocale,"%s.%s",DfltStdLang,DfltStdCharset);
  534. }
  535. if (ret_stdLang != NULL && (result != 0 || *ret_stdLang == NULL))
  536. *ret_stdLang = (char *)strdup(DfltStdLang);
  537. if (ret_stdSet != NULL && (result != 0 || *ret_stdSet == NULL))
  538. *ret_stdSet = (char *)strdup(DfltStdCharset);
  539. }
  540. /******************************************************************************
  541. * Function: int DtXlateStdToOpLocale ( char *operation, char *stdLocale,
  542. * char *dflt_opLocale, char **ret_opLocale)
  543. *
  544. * Parameters:
  545. * operation operation whose locale value will be retrieved
  546. * stdLocale standard locale value
  547. * dflt_opLocale operation-specific locale-value
  548. * This is the default value used in error case
  549. * ret_opLocale operation-specific locale-value placed here
  550. * Caller must free this string.
  551. *
  552. * Return Value:
  553. *
  554. * Purpose: Gets an operation-specific locale string given the standard string
  555. *
  556. *****************************************************************************/
  557. void
  558. RFCBodyPart::DtXlateStdToOpLocale (
  559. char *operation,
  560. char *stdLocale,
  561. char *dflt_opLocale,
  562. char **ret_opLocale)
  563. {
  564. int result = this->OpenLcxDb();
  565. if (ret_opLocale)
  566. *ret_opLocale = NULL;
  567. if (result == 0)
  568. {
  569. (void) _DtLcxXlateStdToOp(
  570. MyDb, MyPlatform, CompVer,
  571. operation,
  572. stdLocale, NULL, NULL, NULL,
  573. ret_opLocale);
  574. }
  575. /* if translation fails, use a default value */
  576. if (ret_opLocale && (result != 0 || *ret_opLocale == NULL))
  577. {
  578. if (dflt_opLocale) *ret_opLocale = (char *)strdup(dflt_opLocale);
  579. else if (stdLocale) *ret_opLocale = (char *)strdup(stdLocale);
  580. }
  581. }
  582. /******************************************************************************
  583. * Function: int DtXlateStdToOpCodeset (
  584. * char *operation,
  585. * char *stdCodeset,
  586. * char *dflt_opCodeset,
  587. * char **ret_opCodeset)
  588. *
  589. * Parameters:
  590. * operation operation whose codeset value will be retrieved
  591. * stdCodeset standard codeset value
  592. * dflt_opCodeset operation-specific codeset-value
  593. * This is the default value used in error case
  594. * ret_opCodeset operation-specific codeset-value placed here
  595. * Caller must free this string.
  596. *
  597. * Return Value:
  598. *
  599. * Purpose: Gets an operation-specific locale string given the standard string
  600. *
  601. *****************************************************************************/
  602. void
  603. RFCBodyPart::DtXlateStdToOpCodeset (
  604. char *operation,
  605. char *stdCodeset,
  606. char *dflt_opCodeset,
  607. char **ret_opCodeset)
  608. {
  609. int result = this->OpenLcxDb();
  610. if (ret_opCodeset)
  611. *ret_opCodeset = NULL;
  612. if (result == 0)
  613. {
  614. (void) _DtLcxXlateStdToOp(
  615. MyDb, MyPlatform, CompVer,
  616. operation,
  617. NULL, NULL, stdCodeset, NULL,
  618. ret_opCodeset);
  619. }
  620. /* if translation fails, use a default value */
  621. if (ret_opCodeset && (result != 0 || *ret_opCodeset == NULL))
  622. {
  623. if (dflt_opCodeset) *ret_opCodeset = (char *)strdup(dflt_opCodeset);
  624. else if (stdCodeset) *ret_opCodeset = (char *)strdup(stdCodeset);
  625. }
  626. }
  627. void
  628. RFCBodyPart::DtXlateMimeToIconv(
  629. const char *mimeId,
  630. const char *defaultCommonCS,
  631. const char *defaultIconvCS,
  632. char **ret_commonCS,
  633. char **ret_platformIconv)
  634. {
  635. int exists = -1;
  636. this->OpenLcxDb();
  637. exists = _DtLcxXlateOpToStd(
  638. MyDb, MyPlatform, CompVer,
  639. DtLCX_OPER_MIME, mimeId,
  640. NULL, NULL, ret_commonCS, NULL);
  641. if (exists == -1)
  642. {
  643. exists = _DtLcxXlateOpToStd(
  644. MyDb, "CDE", 0,
  645. DtLCX_OPER_MIME, mimeId,
  646. NULL, NULL, ret_commonCS, NULL);
  647. if (exists == -1)
  648. *ret_commonCS = (char *)strdup(defaultCommonCS);
  649. }
  650. exists = _DtLcxXlateStdToOp(
  651. MyDb, MyPlatform, CompVer,
  652. DtLCX_OPER_ICONV3,
  653. NULL, NULL, *ret_commonCS, NULL,
  654. ret_platformIconv);
  655. if (exists == -1)
  656. *ret_platformIconv = (char *)strdup(defaultIconvCS);
  657. }
  658. void
  659. RFCBodyPart::DtXlateLocaleToMime(
  660. const char * locale,
  661. const char * defaultCommonCS,
  662. const char * defaultMimeCS,
  663. char ** ret_mimeCS)
  664. {
  665. char * commonCS = NULL;
  666. this->OpenLcxDb();
  667. /* look for platform-specific locale to CDE translation */
  668. _DtLcxXlateOpToStd(
  669. MyDb, MyPlatform, CompVer,
  670. DtLCX_OPER_SETLOCALE, locale,
  671. NULL, NULL, &commonCS, NULL);
  672. if (!commonCS)
  673. commonCS = (char *)strdup(defaultCommonCS);
  674. /* look for platform-specific MIME types; by default, there is none */
  675. _DtLcxXlateStdToOp(
  676. MyDb, MyPlatform, CompVer,
  677. DtLCX_OPER_MIME,
  678. NULL, NULL, commonCS, NULL,
  679. ret_mimeCS);
  680. if (!(*ret_mimeCS))
  681. {
  682. _DtLcxXlateStdToOp(
  683. MyDb, "CDE", 0,
  684. DtLCX_OPER_MIME,
  685. NULL, NULL, commonCS, NULL,
  686. ret_mimeCS);
  687. if (!(*ret_mimeCS))
  688. *ret_mimeCS = (char *)strdup(defaultMimeCS);
  689. }
  690. if (commonCS)
  691. free(commonCS);
  692. }
  693. // Return iconv name of the given codeset.
  694. // If iconv name does not exist, return NULL.
  695. char *
  696. RFCBodyPart::csToConvName(char *cs)
  697. {
  698. int exists = -1;
  699. char *commonCS = NULL;
  700. char *convName = NULL;
  701. char *ret_target = NULL;
  702. this->OpenLcxDb();
  703. // Convert charset to upper case first because charset table is
  704. // case sensitive.
  705. if (cs)
  706. {
  707. int len_cs = strlen(cs);
  708. for (int num_cs = 0; num_cs < len_cs; num_cs++)
  709. *(cs+num_cs) = toupper(*(cs+num_cs));
  710. }
  711. exists = _DtLcxXlateOpToStd(
  712. MyDb, MyPlatform, CompVer,
  713. DtLCX_OPER_MIME, cs,
  714. NULL, NULL, &commonCS, NULL);
  715. if (exists == -1) {
  716. exists = _DtLcxXlateOpToStd(
  717. MyDb, "CDE", 0,
  718. DtLCX_OPER_MIME, cs,
  719. NULL, NULL, &commonCS, NULL);
  720. if (exists == -1)
  721. return NULL;
  722. }
  723. DtXlateStdToOpCodeset(DtLCX_OPER_INTERCHANGE_CODESET,
  724. commonCS,
  725. NULL,
  726. &ret_target);
  727. DtXlateStdToOpCodeset(DtLCX_OPER_ICONV3,
  728. ret_target,
  729. NULL,
  730. &convName);
  731. if ( ret_target )
  732. free( ret_target );
  733. if ( commonCS )
  734. free( commonCS );
  735. // Workaround for libDtHelp
  736. // Case of no iconv name for a particular locale, eg. C,
  737. // check for empty string.
  738. if ( convName != NULL )
  739. {
  740. if ( strlen(convName) > 0 )
  741. return convName;
  742. else
  743. free( convName );
  744. }
  745. return NULL;
  746. }
  747. // Return current locale's iconv name.
  748. char *
  749. RFCBodyPart::locToConvName()
  750. {
  751. char *ret_locale = NULL;
  752. char *ret_lang = NULL;
  753. char *ret_codeset = NULL;
  754. DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
  755. setlocale(LC_CTYPE, NULL),
  756. &ret_locale,
  757. &ret_lang,
  758. &ret_codeset);
  759. if (ret_codeset) {
  760. free(ret_codeset);
  761. ret_codeset = NULL;
  762. }
  763. if (ret_lang) {
  764. free(ret_lang);
  765. ret_lang = NULL;
  766. }
  767. DtXlateStdToOpLocale(DtLCX_OPER_ICONV3,
  768. ret_locale,
  769. NULL,
  770. &ret_codeset);
  771. if (ret_locale)
  772. free(ret_locale);
  773. // Workaround for libDtHelp
  774. // Case of no iconv name for a particular locale, eg. C,
  775. // check for empty string.
  776. if ( ret_codeset != NULL ) {
  777. if (strlen(ret_codeset) > 0)
  778. return ret_codeset;
  779. else
  780. free(ret_codeset);
  781. }
  782. return NULL;
  783. }
  784. // Return target codeset's iconv name.
  785. char *
  786. RFCBodyPart::targetConvName()
  787. {
  788. char *ret_locale = NULL;
  789. char *ret_lang = NULL;
  790. char *ret_codeset = NULL;
  791. char *ret_target = NULL;
  792. char *ret_convName = NULL;
  793. DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
  794. setlocale(LC_CTYPE, NULL),
  795. &ret_locale,
  796. &ret_lang,
  797. &ret_codeset);
  798. DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
  799. ret_locale,
  800. NULL,
  801. &ret_target);
  802. // Or do I call csToConvName() here??
  803. DtXlateStdToOpCodeset(DtLCX_OPER_ICONV3,
  804. ret_target,
  805. NULL,
  806. &ret_convName);
  807. if (ret_locale)
  808. free(ret_locale);
  809. if (ret_lang)
  810. free(ret_lang);
  811. if (ret_codeset)
  812. free(ret_codeset);
  813. if (ret_target)
  814. free(ret_target);
  815. // Workaround for libDtHelp
  816. // Case of no iconv name for a particular locale, eg. C,
  817. // check for empty string.
  818. if ( ret_convName != NULL )
  819. {
  820. if (strlen(ret_convName) > 0)
  821. return ret_convName;
  822. else
  823. free(ret_convName);
  824. }
  825. return NULL;
  826. }
  827. // Return target codeset's MIME (tag) name.
  828. char *
  829. RFCBodyPart::targetTagName()
  830. {
  831. char *ret_locale = NULL;
  832. char *ret_lang = NULL;
  833. char *ret_codeset = NULL;
  834. char *ret_target = NULL;
  835. DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
  836. setlocale(LC_CTYPE, NULL),
  837. &ret_locale,
  838. &ret_lang,
  839. &ret_codeset);
  840. DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
  841. ret_locale,
  842. NULL,
  843. &ret_target);
  844. DtXlateStdToOpCodeset(DtLCX_OPER_MIME,
  845. ret_target,
  846. NULL,
  847. &ret_codeset);
  848. if (ret_locale)
  849. free(ret_locale);
  850. if (ret_lang)
  851. free(ret_lang);
  852. if (ret_target)
  853. free(ret_target);
  854. return ret_codeset;
  855. }
  856. // Given a message text and codesets
  857. // Convert message text from one codeset to another
  858. // Return 1 if conversion is successful else return 0.
  859. int
  860. RFCBodyPart::csConvert(char **bp, unsigned long &bp_len, int free_bp,
  861. char *from_cs, char *to_cs)
  862. {
  863. DtMailEnv error;
  864. iconv_t cd;
  865. size_t ileft = (size_t) bp_len, oleft = (size_t) bp_len, ret = 0;
  866. #if defined(_aix) || defined(sun) || defined(CSRG_BASED)
  867. const char *ip = (const char *) *bp;
  868. #else
  869. char *ip = *bp;
  870. #endif
  871. char *op = NULL;
  872. char *op_start = NULL;
  873. int mb_ret = 0;
  874. size_t delta;
  875. if ( *bp == NULL || **bp == '\0' || bp_len <= 0 )
  876. return 0;
  877. if ( to_cs == NULL || from_cs == NULL )
  878. return 0;
  879. if ( (cd = iconv_open(to_cs, from_cs)) == (iconv_t) -1 ) {
  880. switch (errno) {
  881. case EINVAL:
  882. error.logError(DTM_FALSE,
  883. "DtMail: Conversion from %s to %s is not supported.\n",
  884. from_cs, to_cs);
  885. break;
  886. } // end of switch statement
  887. return 0;
  888. }
  889. // Caller will set _must_free_body to DTM_TRUE if this routine
  890. // succeeds. Then this space will be freed appropriately.
  891. // Add 1 to buffer size for null terminator.
  892. op_start = op = (char *)calloc((unsigned int) bp_len + 1, sizeof(char));
  893. // When ileft finally reaches 0, the conversion still might not be
  894. // complete. Here's why we also need to check for E2BIG: Let's
  895. // say we're converting from eucJP to ISO-2022-JP, and there's just
  896. // enough room in the output buffer for the last input character,
  897. // but not enough room for the trailing "ESC ( B" (for switching
  898. // back to ASCII). In that case, iconv() will convert the last
  899. // input character, decrement ileft to zero, and then set errno to
  900. // E2BIG to tell us that it still needs more room for the "ESC ( B".
  901. errno = 0;
  902. while ( ileft > 0 || errno == E2BIG ) {
  903. errno = 0;
  904. ret = iconv(cd, &ip, &ileft, &op, &oleft);
  905. if ( ret == (size_t) -1 ) {
  906. switch (errno) {
  907. case E2BIG: // increase output buffer size
  908. delta = ileft ? ileft : 3;
  909. bp_len += delta;
  910. op_start = (char *)realloc(
  911. (char *)op_start,
  912. (unsigned int) bp_len + 1);
  913. op = op_start + bp_len - delta - oleft;
  914. oleft += delta;
  915. // realloc does not clear out unused space.
  916. // Therefore, garbage shows up in output buffer.
  917. memset(op, 0, oleft + 1);
  918. break;
  919. case EILSEQ: // input byte does not belong to input codeset
  920. case EINVAL: // invalid input
  921. mb_ret = mblen(ip, MB_LEN_MAX);
  922. if ( (mb_ret > 0) && (oleft >= mb_ret) ) {
  923. strncat(op_start, ip, mb_ret);
  924. ip += mb_ret;
  925. op += mb_ret;
  926. oleft -= mb_ret;
  927. ileft -= mb_ret;
  928. mb_ret = 0;
  929. } else {
  930. // mb_ret is either 0 or -1 at this point,
  931. // then skip one byte
  932. // and try conversion again.
  933. ip++;
  934. ileft--;
  935. }
  936. break;
  937. case EBADF: // bad conversion descriptor
  938. break;
  939. } // end of switch statement
  940. }
  941. } // end of while loop
  942. iconv_close(cd);
  943. // Is this necessary?? Is _body_decode_len == strlen(_body)??
  944. // Or can _body_decode_len contain spaces??
  945. // Check to see if a body had been allocated by prior decoding.
  946. if (free_bp) {
  947. free(*bp);
  948. }
  949. *bp = op_start;
  950. bp_len = strlen(*bp);
  951. return 1;
  952. }
  953. // End of For CHARSET