1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /*
- *+SNOTICE
- *
- *
- * $TOG: RFCBodyPart.C /main/16 1998/04/06 13:27:40 mgreess $
- *
- * RESTRICTED CONFIDENTIAL INFORMATION:
- *
- * The information in this document is subject to special
- * restrictions in a confidential disclosure agreement bertween
- * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
- * document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
- * Sun's specific written approval. This documment and all copies
- * and derivative works thereof must be returned or destroyed at
- * Sun's request.
- *
- * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
- *
- *+ENOTICE
- */
- #ifndef I_HAVE_NO_IDENT
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <Dt/Dts.h>
- #include <DtMail/DtMail.hh>
- #include "RFCImpl.hh"
- #include <DtMail/Threads.hh>
- // For CHARSET
- //-------------------------------------
- // HACK ALERT
- // Any code change within "For CHARSET" should be changed in
- // RFCBodyPart and Session because the same methods are duplicated
- // in both of these classes.
- // See RFCImpl.hh or DtMail/DtMail.hh for more explanation.
- //-------------------------------------
- #include <locale.h>
- #include <time.h>
- #include <DtHelp/LocaleXlate.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <limits.h>
- #include <ctype.h>
-
- #ifndef True
- #define True 1
- #endif
- #ifndef False
- #define False 0
- #endif
- #if defined(SunOS) && (SunOS < 55)
- extern "C" {
- #endif
- #include <iconv.h>
- #if defined(SunOS) && (SunOS < 55)
- }
- #endif
- // End of For CHARSET
- RFCBodyPart::RFCBodyPart(DtMailEnv & error,
- DtMail::Message * parent,
- const char * start,
- const int len,
- RFCEnvelope * body_env)
- : DtMail::BodyPart(error, parent)
- {
- _body_lock = MutexInit();
- _body_start = _body_text = start;
- _body_len = len > 0 ? len : 0;
- // If we have no body to start, then we will want to create
- // a body envelope. We do this to make sure we can always
- // set headers for the body part.
- //
- if (_body_start == NULL) {
- _body_env = new RFCEnvelope(error, parent, NULL, 0);
- _my_env = DTM_TRUE;
- }
- else {
- _body_env = body_env;
- _my_env = _body_env ? DTM_FALSE : DTM_TRUE;
- }
- _body = NULL;
- _body_decoded_len = 0;
- _body_type = NULL;
- _must_free_body = DTM_FALSE;
- }
- RFCBodyPart::~RFCBodyPart(void)
- {
- if (_my_env == DTM_TRUE) {
- delete _body_env;
- }
- if (_must_free_body) {
- free(_body);
- }
- if (_body_type) {
- free(_body_type);
- }
- }
- void
- RFCBodyPart::getContents(DtMailEnv & error,
- const void ** contents,
- unsigned long * length,
- char ** type,
- char ** name,
- int * mode,
- char ** description)
- {
- // First things first, for each possible return, zero out the
- // pointer so that if the caller does not check for errors it
- // will be caught by a null dereference
- //
- if (name)
- *name = (char *)0;
- if (description)
- *description = (char *)0;
- if (type)
- *type = (char *)0;
- if (contents)
- *contents = (void *)0;
-
- // The caller can ask for a hodge podge of information.
- // The only real rule here is that you can not ask for
- // the contents without requesting the length.
- if (contents && !length) {
- error.setError(DTME_OperationInvalid);
- return;
- }
- // No need to clear the error here because it should be clear already.
- // error.clear();
- // MIME currently doesn't have body part names and RFC
- // doesn't let us at arbitrary message headers. Name
- // therefore can not be retrieved.
- //
- if (name) {
- *name = getName(error);
- if (error.isSet()) {
- // don't care about the error condition returned by getName()
- // because it returns a valid string no matter what error
- // condition occurs.
- error.clear();
- }
- }
- // Ditto for mode.
- //
- if (mode) {
- *mode = 0;
- }
- if (description) {
- // getDescription should not be passed a DtMailEnv object.
- // Neither implementation of getDescription (MIME or V3)
- // sets the error before returning. Besides being unnecessary,
- // it requires the caller of getDescription to check the error
- // status upon its return.
- //
- *description = getDescription(error);
- if (error.isSet()) {
- // Don't care about the error condition returned by getDescription
- // because it returns a valid string no matter what error
- // condition occurs.
- error.clear();
- }
- }
- // Types for DtMail are in the Dt name space. RFC returns
- // mime types. We will have to convert from the RFC name
- // space to the Dt name space.
- //
- if (type) {
- if (!_body_type) {
- getDtType(error);
- // Do we want to propogate this error back up to the
- // function that called us? If not, we need to call
- // error.clear() before returning.
- if (error.isSet()) {
- return;
- }
- }
- *type = strdup(_body_type);
- }
- if (length) {
- *length = getLength(error);
- if (error.isSet()) {
- // propogate the error back up to the caller
- return;
- }
- }
- if (contents) {
- *contents = getBody(error);
- if (error.isSet()) {
- // propogate the error back up to the caller
- return;
- }
- }
- }
- void
- RFCBodyPart::setContents(DtMailEnv & error,
- const void * contents,
- const unsigned long length,
- const char * type,
- const char * name,
- const int, // mode,
- const char *) // description)
- {
- error.clear();
- MutexLock lock_scope(_body_lock);
- if (name) {
- setName(error, name);
- }
- if (contents && !length) {
- error.setError(DTME_OperationInvalid);
- return;
- }
- if (!contents && !length) {
- if (_body && _must_free_body) {
- free(_body);
- _body = NULL;
- _must_free_body = DTM_FALSE;
- }
- _body_decoded_len = _body_len = 0;
- if (_body_type) {
- free(_body_type);
- _body_type = NULL;
- }
- // _must_free_body = DTM_FALSE;
- return;
- }
- if (contents) {
- if (_body && _must_free_body) {
- free(_body);
- _body = NULL;
- }
- _body = (char *)malloc((int)length);
- memcpy(_body, contents, (int)length);
- _body_decoded_len = _body_len = (int)length;
- _must_free_body = DTM_TRUE;
- // Reset the type. We don't know what it is!
- if (_body_type) {
- free(_body_type);
- _body_type = NULL;
- }
- }
- if (type) {
- if (_body_type)
- free(_body_type);
- _body_type = strdup(type);
- }
- }
- void
- RFCBodyPart::lockContents(DtMailEnv & error, const DtMailLock)
- {
- error.clear();
- }
- void
- RFCBodyPart::unlockContents(DtMailEnv & error)
- {
- error.clear();
- }
- void
- RFCBodyPart::getHeader(DtMailEnv & error,
- const char * name,
- const DtMailBoolean abstract,
- DtMailValueSeq & value)
- {
- error.clear();
- // If this is not our envelope, then we will not set the flag.
- //
- if (_my_env == DTM_FALSE) {
- error.setError(DTME_NotSupported);
- return;
- }
- if (_body_env == (RFCEnvelope *)NULL) {
- error.setError(DTME_NoObjectValue);
- return;
- }
- _body_env->getHeader(error, name, abstract, value);
- }
- void
- RFCBodyPart::setFlag(DtMailEnv & error,
- DtMailBodyPartState state)
- {
- error.clear();
- // If this is not our envelope, then we will not set the flag.
- //
- if (_my_env == DTM_FALSE) {
- error.setError(DTME_NotSupported);
- return;
- }
- DtMailEnv my_error;
- time_t now;
- char str_time[40];
- switch (state) {
- case DtMailBodyPartDeletePending:
- now = time(NULL);
- sprintf(str_time, "%08lX", (long)now);
- _body_env->setHeader(my_error, RFCDeleteHeader, DTM_TRUE, str_time);
- break;
- default:
- error.setError(DTME_OperationInvalid);
- }
- }
- void
- RFCBodyPart::resetFlag(DtMailEnv & error,
- DtMailBodyPartState state)
- {
- error.clear();
- // If this is not our envelope, then we will not set the flag.
- //
- if (_my_env == DTM_FALSE) {
- error.setError(DTME_NotSupported);
- return;
- }
- DtMailEnv my_error;
- switch (state) {
- case DtMailBodyPartDeletePending:
- _body_env->removeHeader(my_error, RFCDeleteHeader);
- break;
- default:
- error.setError(DTME_OperationInvalid);
- }
- }
- DtMailBoolean
- RFCBodyPart::flagIsSet(DtMailEnv & error,
- DtMailBodyPartState state)
- {
- error.clear();
- // If this is not our envelope, then we will not set the flag.
- //
- if (_my_env == DTM_FALSE) {
- error.setError(DTME_NotSupported);
- return(DTM_FALSE);
- }
- DtMailEnv my_error;
- DtMailValueSeq value;
- DtMailBoolean answer;
- switch (state) {
- case DtMailBodyPartDeletePending:
- _body_env->getHeader(my_error, RFCDeleteHeader, DTM_FALSE, value);
- if (my_error.isNotSet()) {
- answer = DTM_TRUE;
- }
- else {
- answer = DTM_FALSE;
- }
- break;
- default:
- error.setError(DTME_OperationInvalid);
- }
- return(answer);
- }
- time_t
- RFCBodyPart::getDeleteTime(DtMailEnv & error)
- {
- time_t delete_time = 0;
- DtMailValueSeq value;
- _body_env->getHeader(error, RFCDeleteHeader, DTM_FALSE, value);
- if (error.isNotSet()) {
- delete_time = (time_t) strtol(*(value[0]), NULL, 16);
- }
- error.clear();
- return(delete_time);
- }
- void
- RFCBodyPart::adjustBodyPartsLocation(char * start)
- {
- MutexLock lock_scope(_body_lock);
- _body_text = (_body_text - _body_start) + start;
- _body_start = start;
- if (_must_free_body == DTM_FALSE) {
- //_body = (char *)_body_text;
- _body = NULL;
- }
- if (_body_env && _my_env == DTM_TRUE) {
- // CMVC bug 2807
- // start points at the body part separator. Need to
- // Skip separator. Put in a sanity check until we know
- // this is the right fix
- if (*start != '-' && *(start + 1) != '-') {
- fprintf(
- stderr,
- "RFCBodyPart::adjustBodyPartLocation(%.20s): Not a separator\n",
- start);
- } else {
- while (*start != '\n')
- start++;
- start++;
- }
- // End Of fix for 2807
- _body_env->adjustHeaderLocation(start, (int)(_body_text-_body_start));
- }
- }
- DtMailBoolean
- RFCBodyPart::isTerm(const char * start)
- {
- if (*start == '\n' || (*start == '\r' && *(start + 1) == '\n')) {
- return(DTM_TRUE);
- }
- else {
- return(DTM_FALSE);
- }
- }
- const void *
- RFCBodyPart::getBody(DtMailEnv & error)
- {
- error.clear();
- if (!_body) {
- loadBody(error);
- if (error.isSet()) {
- return(NULL);
- }
- }
- return(_body);
- }
- // For CHARSET
- /*
- * Wrapper functions taken from libHelp/CEUtil.c
- *
- * We took these functions and renamed them because
- * 1. Originally these are called _DtHelpCeXlate* and thus they are private
- * to libHelp and not exported to outside of libHelp.
- * 2. When these functions are moved to another library, then users of these
- * functions would only need to link with a different library. The caller
- * doesn't have to modify code.
- */
- static const char *DfltStdCharset = "us-ascii";
- static const char *DfltStdLang = "C";
- static char MyPlatform[_DtPLATFORM_MAX_LEN+1];
- static _DtXlateDb MyDb = NULL;
- static char MyProcess = False;
- static char MyFirst = True;
- static int ExecVer;
- static int CompVer;
- /******************************************************************************
- * Function: static int OpenLcxDb ()
- *
- * Parameters: none
- *
- * Return Value: 0: ok
- * -1: error
- *
- * errno Values:
- *
- * Purpose: Opens the Ce-private Lcx database
- *
- *****************************************************************************/
- int
- RFCBodyPart::OpenLcxDb (void)
- {
- time_t time1 = 0;
- time_t time2 = 0;
- while (MyProcess == True)
- {
- /* if time out, return */
- if (time(&time2) == (time_t)-1)
- return -1;
- if (time1 == 0)
- time1 = time2;
- else if (time2 - time1 >= (time_t)30)
- return -1;
- }
- if (MyFirst == True)
- {
- MyProcess = True;
- if (_DtLcxOpenAllDbs(&MyDb) == 0 &&
- _DtXlateGetXlateEnv(MyDb,MyPlatform,&ExecVer,&CompVer) != 0)
- {
- _DtLcxCloseDb(&MyDb);
- MyDb = NULL;
- }
- MyFirst = False;
- MyProcess = False;
- }
- return (MyDb == NULL ? -1 : 0 );
- }
- /******************************************************************************
- * Function: int DtXlateOpToStdLocale(char *operation, char *opLocale,
- * char **ret_stdLocale,
- * char **ret_stdLang, char **ret_stdSet)
- *
- * Parameters:
- * operation Operation associated with the locale value
- * opLocale An operation-specific locale string
- * ret_locale Returns the std locale
- * Caller must free this string.
- * ret_stdLang Returns the std language & territory string.
- * Caller must free this string.
- * ret_stdSet Returns the std code set string.
- * Caller must free this string.
- *
- * Return Value:
- *
- * Purpose: Gets the standard locale given an operation and its locale
- *
- *****************************************************************************/
- void
- RFCBodyPart::DtXlateOpToStdLocale (
- char *operation,
- char *opLocale,
- char **ret_stdLocale,
- char **ret_stdLang,
- char **ret_stdSet)
- {
- int result = OpenLcxDb();
- if (result == 0) {
- (void) _DtLcxXlateOpToStd(
- MyDb, MyPlatform, CompVer,
- operation, opLocale,
- ret_stdLocale, ret_stdLang, ret_stdSet, NULL);
- }
- /* if failed, give default values */
- if (ret_stdLocale != NULL && (result != 0 || *ret_stdLocale == NULL))
- {
- *ret_stdLocale =
- (char *)malloc(strlen(DfltStdLang)+strlen(DfltStdCharset)+3);
- sprintf(*ret_stdLocale,"%s.%s",DfltStdLang,DfltStdCharset);
- }
- if (ret_stdLang != NULL && (result != 0 || *ret_stdLang == NULL))
- *ret_stdLang = (char *)strdup(DfltStdLang);
- if (ret_stdSet != NULL && (result != 0 || *ret_stdSet == NULL))
- *ret_stdSet = (char *)strdup(DfltStdCharset);
- }
- /******************************************************************************
- * Function: int DtXlateStdToOpLocale ( char *operation, char *stdLocale,
- * char *dflt_opLocale, char **ret_opLocale)
- *
- * Parameters:
- * operation operation whose locale value will be retrieved
- * stdLocale standard locale value
- * dflt_opLocale operation-specific locale-value
- * This is the default value used in error case
- * ret_opLocale operation-specific locale-value placed here
- * Caller must free this string.
- *
- * Return Value:
- *
- * Purpose: Gets an operation-specific locale string given the standard string
- *
- *****************************************************************************/
- void
- RFCBodyPart::DtXlateStdToOpLocale (
- char *operation,
- char *stdLocale,
- char *dflt_opLocale,
- char **ret_opLocale)
- {
- int result = this->OpenLcxDb();
- if (ret_opLocale)
- *ret_opLocale = NULL;
- if (result == 0)
- {
- (void) _DtLcxXlateStdToOp(
- MyDb, MyPlatform, CompVer,
- operation,
- stdLocale, NULL, NULL, NULL,
- ret_opLocale);
- }
- /* if translation fails, use a default value */
- if (ret_opLocale && (result != 0 || *ret_opLocale == NULL))
- {
- if (dflt_opLocale) *ret_opLocale = (char *)strdup(dflt_opLocale);
- else if (stdLocale) *ret_opLocale = (char *)strdup(stdLocale);
- }
- }
- /******************************************************************************
- * Function: int DtXlateStdToOpCodeset (
- * char *operation,
- * char *stdCodeset,
- * char *dflt_opCodeset,
- * char **ret_opCodeset)
- *
- * Parameters:
- * operation operation whose codeset value will be retrieved
- * stdCodeset standard codeset value
- * dflt_opCodeset operation-specific codeset-value
- * This is the default value used in error case
- * ret_opCodeset operation-specific codeset-value placed here
- * Caller must free this string.
- *
- * Return Value:
- *
- * Purpose: Gets an operation-specific locale string given the standard string
- *
- *****************************************************************************/
- void
- RFCBodyPart::DtXlateStdToOpCodeset (
- char *operation,
- char *stdCodeset,
- char *dflt_opCodeset,
- char **ret_opCodeset)
- {
- int result = this->OpenLcxDb();
- if (ret_opCodeset)
- *ret_opCodeset = NULL;
- if (result == 0)
- {
- (void) _DtLcxXlateStdToOp(
- MyDb, MyPlatform, CompVer,
- operation,
- NULL, NULL, stdCodeset, NULL,
- ret_opCodeset);
- }
- /* if translation fails, use a default value */
- if (ret_opCodeset && (result != 0 || *ret_opCodeset == NULL))
- {
- if (dflt_opCodeset) *ret_opCodeset = (char *)strdup(dflt_opCodeset);
- else if (stdCodeset) *ret_opCodeset = (char *)strdup(stdCodeset);
- }
- }
- void
- RFCBodyPart::DtXlateMimeToIconv(
- const char *mimeId,
- const char *defaultCommonCS,
- const char *defaultIconvCS,
- char **ret_commonCS,
- char **ret_platformIconv)
- {
- int exists = -1;
- this->OpenLcxDb();
-
- exists = _DtLcxXlateOpToStd(
- MyDb, MyPlatform, CompVer,
- DtLCX_OPER_MIME, mimeId,
- NULL, NULL, ret_commonCS, NULL);
- if (exists == -1)
- {
- exists = _DtLcxXlateOpToStd(
- MyDb, "CDE", 0,
- DtLCX_OPER_MIME, mimeId,
- NULL, NULL, ret_commonCS, NULL);
- if (exists == -1)
- *ret_commonCS = (char *)strdup(defaultCommonCS);
- }
- exists = _DtLcxXlateStdToOp(
- MyDb, MyPlatform, CompVer,
- DtLCX_OPER_ICONV3,
- NULL, NULL, *ret_commonCS, NULL,
- ret_platformIconv);
- if (exists == -1)
- *ret_platformIconv = (char *)strdup(defaultIconvCS);
- }
- void
- RFCBodyPart::DtXlateLocaleToMime(
- const char * locale,
- const char * defaultCommonCS,
- const char * defaultMimeCS,
- char ** ret_mimeCS)
- {
- char * commonCS = NULL;
- this->OpenLcxDb();
- /* look for platform-specific locale to CDE translation */
- _DtLcxXlateOpToStd(
- MyDb, MyPlatform, CompVer,
- DtLCX_OPER_SETLOCALE, locale,
- NULL, NULL, &commonCS, NULL);
- if (!commonCS)
- commonCS = (char *)strdup(defaultCommonCS);
- /* look for platform-specific MIME types; by default, there is none */
- _DtLcxXlateStdToOp(
- MyDb, MyPlatform, CompVer,
- DtLCX_OPER_MIME,
- NULL, NULL, commonCS, NULL,
- ret_mimeCS);
- if (!(*ret_mimeCS))
- {
- _DtLcxXlateStdToOp(
- MyDb, "CDE", 0,
- DtLCX_OPER_MIME,
- NULL, NULL, commonCS, NULL,
- ret_mimeCS);
- if (!(*ret_mimeCS))
- *ret_mimeCS = (char *)strdup(defaultMimeCS);
- }
- if (commonCS)
- free(commonCS);
- }
- // Return iconv name of the given codeset.
- // If iconv name does not exist, return NULL.
- char *
- RFCBodyPart::csToConvName(char *cs)
- {
- int exists = -1;
- char *commonCS = NULL;
- char *convName = NULL;
- char *ret_target = NULL;
-
- this->OpenLcxDb();
-
- // Convert charset to upper case first because charset table is
- // case sensitive.
- if (cs)
- {
- int len_cs = strlen(cs);
- for (int num_cs = 0; num_cs < len_cs; num_cs++)
- *(cs+num_cs) = toupper(*(cs+num_cs));
- }
- exists = _DtLcxXlateOpToStd(
- MyDb, MyPlatform, CompVer,
- DtLCX_OPER_MIME, cs,
- NULL, NULL, &commonCS, NULL);
- if (exists == -1) {
- exists = _DtLcxXlateOpToStd(
- MyDb, "CDE", 0,
- DtLCX_OPER_MIME, cs,
- NULL, NULL, &commonCS, NULL);
- if (exists == -1)
- return NULL;
- }
-
- DtXlateStdToOpCodeset(DtLCX_OPER_INTERCHANGE_CODESET,
- commonCS,
- NULL,
- &ret_target);
- DtXlateStdToOpCodeset(DtLCX_OPER_ICONV3,
- ret_target,
- NULL,
- &convName);
- if ( ret_target )
- free( ret_target );
- if ( commonCS )
- free( commonCS );
- // Workaround for libDtHelp
- // Case of no iconv name for a particular locale, eg. C,
- // check for empty string.
- if ( convName != NULL )
- {
- if ( strlen(convName) > 0 )
- return convName;
- else
- free( convName );
- }
- return NULL;
- }
- // Return current locale's iconv name.
- char *
- RFCBodyPart::locToConvName()
- {
- char *ret_locale = NULL;
- char *ret_lang = NULL;
- char *ret_codeset = NULL;
-
- DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
- setlocale(LC_CTYPE, NULL),
- &ret_locale,
- &ret_lang,
- &ret_codeset);
- if (ret_codeset) {
- free(ret_codeset);
- ret_codeset = NULL;
- }
-
- if (ret_lang) {
- free(ret_lang);
- ret_lang = NULL;
- }
-
- DtXlateStdToOpLocale(DtLCX_OPER_ICONV3,
- ret_locale,
- NULL,
- &ret_codeset);
- if (ret_locale)
- free(ret_locale);
- // Workaround for libDtHelp
- // Case of no iconv name for a particular locale, eg. C,
- // check for empty string.
- if ( ret_codeset != NULL ) {
- if (strlen(ret_codeset) > 0)
- return ret_codeset;
- else
- free(ret_codeset);
- }
- return NULL;
- }
- // Return target codeset's iconv name.
- char *
- RFCBodyPart::targetConvName()
- {
- char *ret_locale = NULL;
- char *ret_lang = NULL;
- char *ret_codeset = NULL;
- char *ret_target = NULL;
- char *ret_convName = NULL;
-
- DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
- setlocale(LC_CTYPE, NULL),
- &ret_locale,
- &ret_lang,
- &ret_codeset);
- DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
- ret_locale,
- NULL,
- &ret_target);
- // Or do I call csToConvName() here??
- DtXlateStdToOpCodeset(DtLCX_OPER_ICONV3,
- ret_target,
- NULL,
- &ret_convName);
-
- if (ret_locale)
- free(ret_locale);
- if (ret_lang)
- free(ret_lang);
- if (ret_codeset)
- free(ret_codeset);
- if (ret_target)
- free(ret_target);
- // Workaround for libDtHelp
- // Case of no iconv name for a particular locale, eg. C,
- // check for empty string.
- if ( ret_convName != NULL )
- {
- if (strlen(ret_convName) > 0)
- return ret_convName;
- else
- free(ret_convName);
- }
- return NULL;
- }
- // Return target codeset's MIME (tag) name.
- char *
- RFCBodyPart::targetTagName()
- {
- char *ret_locale = NULL;
- char *ret_lang = NULL;
- char *ret_codeset = NULL;
- char *ret_target = NULL;
- DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
- setlocale(LC_CTYPE, NULL),
- &ret_locale,
- &ret_lang,
- &ret_codeset);
- DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
- ret_locale,
- NULL,
- &ret_target);
- DtXlateStdToOpCodeset(DtLCX_OPER_MIME,
- ret_target,
- NULL,
- &ret_codeset);
- if (ret_locale)
- free(ret_locale);
- if (ret_lang)
- free(ret_lang);
- if (ret_target)
- free(ret_target);
- return ret_codeset;
- }
- // Given a message text and codesets
- // Convert message text from one codeset to another
- // Return 1 if conversion is successful else return 0.
- int
- RFCBodyPart::csConvert(char **bp, unsigned long &bp_len, int free_bp,
- char *from_cs, char *to_cs)
- {
- DtMailEnv error;
- iconv_t cd;
- size_t ileft = (size_t) bp_len, oleft = (size_t) bp_len, ret = 0;
- #if defined(_aix) || defined(sun) || defined(CSRG_BASED)
- const char *ip = (const char *) *bp;
- #else
- char *ip = *bp;
- #endif
- char *op = NULL;
- char *op_start = NULL;
- int mb_ret = 0;
- size_t delta;
- if ( *bp == NULL || **bp == '\0' || bp_len <= 0 )
- return 0;
- if ( to_cs == NULL || from_cs == NULL )
- return 0;
- if ( (cd = iconv_open(to_cs, from_cs)) == (iconv_t) -1 ) {
- switch (errno) {
- case EINVAL:
- error.logError(DTM_FALSE,
- "DtMail: Conversion from %s to %s is not supported.\n",
- from_cs, to_cs);
- break;
- } // end of switch statement
- return 0;
- }
- // Caller will set _must_free_body to DTM_TRUE if this routine
- // succeeds. Then this space will be freed appropriately.
- // Add 1 to buffer size for null terminator.
- op_start = op = (char *)calloc((unsigned int) bp_len + 1, sizeof(char));
- // When ileft finally reaches 0, the conversion still might not be
- // complete. Here's why we also need to check for E2BIG: Let's
- // say we're converting from eucJP to ISO-2022-JP, and there's just
- // enough room in the output buffer for the last input character,
- // but not enough room for the trailing "ESC ( B" (for switching
- // back to ASCII). In that case, iconv() will convert the last
- // input character, decrement ileft to zero, and then set errno to
- // E2BIG to tell us that it still needs more room for the "ESC ( B".
- errno = 0;
- while ( ileft > 0 || errno == E2BIG ) {
- errno = 0;
- ret = iconv(cd, &ip, &ileft, &op, &oleft);
- if ( ret == (size_t) -1 ) {
- switch (errno) {
- case E2BIG: // increase output buffer size
- delta = ileft ? ileft : 3;
- bp_len += delta;
- op_start = (char *)realloc(
- (char *)op_start,
- (unsigned int) bp_len + 1);
- op = op_start + bp_len - delta - oleft;
- oleft += delta;
- // realloc does not clear out unused space.
- // Therefore, garbage shows up in output buffer.
- memset(op, 0, oleft + 1);
- break;
- case EILSEQ: // input byte does not belong to input codeset
- case EINVAL: // invalid input
- mb_ret = mblen(ip, MB_LEN_MAX);
- if ( (mb_ret > 0) && (oleft >= mb_ret) ) {
- strncat(op_start, ip, mb_ret);
- ip += mb_ret;
- op += mb_ret;
- oleft -= mb_ret;
- ileft -= mb_ret;
- mb_ret = 0;
- } else {
- // mb_ret is either 0 or -1 at this point,
- // then skip one byte
- // and try conversion again.
- ip++;
- ileft--;
- }
- break;
- case EBADF: // bad conversion descriptor
- break;
- } // end of switch statement
- }
- } // end of while loop
- iconv_close(cd);
- // Is this necessary?? Is _body_decode_len == strlen(_body)??
- // Or can _body_decode_len contain spaces??
- // Check to see if a body had been allocated by prior decoding.
- if (free_bp) {
- free(*bp);
- }
- *bp = op_start;
- bp_len = strlen(*bp);
- return 1;
- }
- // End of For CHARSET
|