Datum convert_to_UTF8(PG_FUNCTION_ARGS) { // things we need to deal with constructing our composite type TupleDesc tupdesc; Datum values[3]; bool nulls[3]; HeapTuple tuple; // for char_set_detect function returns text *encoding = NULL; text *lang = NULL; int32_t confidence = 0; UErrorCode status = U_ZERO_ERROR; // output buffer for conversion to Unicode UChar* uBuf = NULL; int32_t uBuf_len = 0; // output of this function text *text_out; bool converted = false; bool dropped_bytes = false; bool dropped_bytes_toU = false; bool dropped_bytes_fromU = false; // temporary buffer for converted string char* converted_buf = NULL; // input args const text *buffer = PG_GETARG_TEXT_P(0); const bool force = PG_GETARG_BOOL(1); // C string of text* buffer const char* cbuffer = NULL; int cbuffer_len = 0; // Convert output values into a PostgreSQL composite type. if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record.\n"))); // BlessTupleDesc for Datums BlessTupleDesc(tupdesc); // return if string to convert is NULL if (NULL == buffer) { // return input string, // converted to true, // dropped_bytes to false text_out = (text *) buffer; converted = true; dropped_bytes = false; } else { // extract string from text* to C string cbuffer = text_to_cstring(buffer); cbuffer_len = strlen(cbuffer); // bail on zero-length strings // return if cbuffer has zero length or contains a blank space if ((0 == cbuffer_len) || (0 == strcmp("", cbuffer))) { text_out = (text *) buffer; converted = true; dropped_bytes = false; } else { // UTF8 output can be up to 6 bytes per input byte // palloc0 allocates and zeros bytes in array int32_t converted_buf_len = cbuffer_len * 6 * sizeof(char); converted_buf = (char *) palloc0(converted_buf_len); // int32_t converted_len = 0; // detect encoding with ICU status = detect_ICU(buffer, &encoding, &lang, &confidence); ereport(DEBUG1, (errcode(ERRCODE_SUCCESSFUL_COMPLETION), errmsg("ICU detection status: %d\n", status))); ereport(DEBUG1, (errcode(ERRCODE_SUCCESSFUL_COMPLETION), errmsg("Detected encoding: %s, language: %s, confidence: %d\n", text_to_cstring(encoding), text_to_cstring(lang), confidence))); // return without attempting a conversion if UTF8 is detected if ( (0 == strcmp("UTF-8", text_to_cstring(encoding))) || (0 == strcmp("utf-8", text_to_cstring(encoding))) || (0 == strcmp("UTF8", text_to_cstring(encoding))) || (0 == strcmp("utf8", text_to_cstring(encoding))) ) { ereport(DEBUG1, (errcode(ERRCODE_SUCCESSFUL_COMPLETION), errmsg("ICU detected %s. No conversion necessary.\n", text_to_cstring(encoding)))); text_out = (text *) buffer; converted = true; dropped_bytes = false; } else { // ICU uses UTF16 internally, so need to convert to Unicode first // then convert to UTF8 if (U_SUCCESS(status)) status = convert_to_unicode(buffer, (const text*) encoding, &uBuf, (int32_t*) &uBuf_len, force, &dropped_bytes_toU); if (U_SUCCESS(status)) status = convert_to_utf8((const UChar*) uBuf, uBuf_len, &converted_buf, (int32_t*) &converted_buf_len, force, &dropped_bytes_fromU); if (U_SUCCESS(status)) { text_out = cstring_to_text(converted_buf); converted = true; dropped_bytes = (dropped_bytes_toU || dropped_bytes_fromU); } else { ereport(WARNING, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), errmsg("ICU conversion failed - returning original input"))); text_out = (text *) buffer; converted = false; dropped_bytes = false; } } // already UTF8 } // zero-length string } // return if buffer is NULL values[0] = PointerGetDatum(text_out); values[1] = BoolGetDatum(converted); values[2] = BoolGetDatum(dropped_bytes); // check if pointers are still NULL; if so Datum is NULL and // confidence is meaningless (also NULL) (text_out == NULL || ! VARSIZE_ANY_EXHDR(text_out)) ? (nulls[0] = true) : (nulls[0] = false); // converted will never be NULL nulls[1] = false; nulls[2] = false; // build tuple from datum array tuple = heap_form_tuple(tupdesc, values, nulls); // cleanup if (NULL != encoding) pfree((void *) encoding); if (NULL != lang) pfree((void *) lang); if (NULL != cbuffer) pfree((void *) cbuffer); if (NULL != converted_buf) pfree((void *) converted_buf); PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); }
/************************************************************************** * MAPISendMail (MAPI32.211) * * Send a mail. * * PARAMS * session [I] Handle to a MAPI session. * uiparam [I] Parent window handle. * message [I] Pointer to a MAPIMessage structure. * flags [I] Flags. * reserved [I] Reserved, pass 0. * * RETURNS * Success: SUCCESS_SUCCESS * Failure: MAPI_E_FAILURE * */ ULONG WINAPI MAPISendMail( LHANDLE session, ULONG_PTR uiparam, lpMapiMessage message, FLAGS flags, ULONG reserved ) { WCHAR msg_title[READ_BUF_SIZE], error_msg[READ_BUF_SIZE]; /* Check to see if we have a Simple MAPI provider loaded */ if (mapiFunctions.MAPISendMail) return mapiFunctions.MAPISendMail(session, uiparam, message, flags, reserved); /* Check if we have an Extended MAPI provider - if so, use our wrapper */ if (MAPIInitialize(NULL) == S_OK) { MapiMessageW messageW; ULONG ret; ZeroMemory(&messageW, sizeof(MapiMessageW)); /* Convert the entries we need to Unicode */ messageW.lpszSubject = convert_to_unicode(message->lpszSubject); messageW.lpszNoteText = convert_to_unicode(message->lpszNoteText); messageW.nFileCount = message->nFileCount; if (message->nFileCount && message->lpFiles) { lpMapiFileDescW filesW; unsigned int i; filesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MapiFileDescW) * message->nFileCount); for (i = 0; i < message->nFileCount; i++) { filesW[i].lpszPathName = convert_to_unicode(message->lpFiles[i].lpszPathName); filesW[i].lpszFileName = convert_to_unicode(message->lpFiles[i].lpszFileName); } messageW.lpFiles = filesW; } ret = sendmail_extended_mapi(session, uiparam, &messageW, flags); /* Now free everything we allocated */ if (message->nFileCount && message->lpFiles) { unsigned int i; for (i = 0; i < message->nFileCount; i++) { HeapFree(GetProcessHeap(), 0, messageW.lpFiles[i].lpszPathName); HeapFree(GetProcessHeap(), 0, messageW.lpFiles[i].lpszFileName); } HeapFree(GetProcessHeap(), 0, messageW.lpFiles); } HeapFree(GetProcessHeap(), 0, messageW.lpszSubject); HeapFree(GetProcessHeap(), 0, messageW.lpszNoteText); return ret; } /* Display an error message since we apparently have no mail clients */ LoadStringW(hInstMAPI32, IDS_NO_MAPI_CLIENT, error_msg, sizeof(error_msg) / sizeof(WCHAR)); LoadStringW(hInstMAPI32, IDS_SEND_MAIL, msg_title, sizeof(msg_title) / sizeof(WCHAR)); MessageBoxW((HWND) uiparam, error_msg, msg_title, MB_ICONEXCLAMATION); return MAPI_E_NOT_SUPPORTED; }