最近更新: 2009-04-12

Openchange 開發工具補遺

日前有一項工作,需要從 Microsoft Exchange Server 中轉出行事曆、連絡人等等資料。我嘗試使用 Openchage 這套工具來處理。它透過 Exchange 預設的 SMB 封包協定交換資訊。應用軟體開發人員可使用其 libmapi 函數庫設計一般用戶程式。

OpenChange aims to provide a portable Open Source implementation of Microsoft Exchange Server and Exchange protocols.
Openchange

不過 Openchange 仍未臻成熟,在使用前必須修正不少地方。本文說明 header 檔路徑修正、常數定義修正與中日韓語系修正的內容。

路徑修正

Ubuntu 8.1 是目前極少數提供 Openchange 套件的 GNU/Linux 散佈套件。即便如此,它的套件仍然有許多 header 檔案放置的路徑未經修正。若未修正路徑,在編譯源碼時,你將會得到許多找不到檔案的錯誤訊息。 Ubuntu 8.1 安裝套件: libmapi-dev, samba4-dev。路徑修正:

sudo ln -s /usr/include/samba-4.0/*.h /usr/include
sudo ln -s /usr/include/samba-4.0/gen_ndr/* /usr/include/gen_ndr
sudo ln -s /usr/include/samba-4.0/core /usr/include
sudo ln -s /usr/include/samba-4.0/samba /usr/include
sudo ln -s /usr/include/samba-4.0/util /usr/include

常數定義修正

如果你是透過 SVN 取得最新版本的 Openchange 源碼(https://svn.openchange.org/openchange/trunk,那麼你將發現其中並未定義 PidLid 開頭的各個常數 (如 PidLidAttendeeCriticalChange, PidLidEmail1DisplayName),那些代表屬性的 ID 值。請下載 libmapi-0.8.2-ROMULUS.tar.gz,使用其中的 libmapi/mapi_nameid.h 檔案。

不幸的是,定義在 mapi_nameid.h 中的屬性 ID 值也存在不少錯誤。幾乎所有 001f 結尾的 ID 值都應改成 001e。例如:

//#define PidLidEmail1DisplayName                             0x8080001f

#define PidLidEmail1DisplayName                             0x8080001e

//#define PidLidEmail1AddressType                             0x8082001f

#define PidLidEmail1AddressType                             0x8082001e

//#define PidLidEmail1EmailAddress                            0x8083001f

#define PidLidEmail1EmailAddress                            0x8083001e

//#define PidLidEmail1OriginalDisplayName                     0x8084001f

#define PidLidEmail1OriginalDisplayName                     0x8084001e

//#define PidLidEmail1EmailType                               0x8087001f

#define PidLidEmail1EmailType                               0x8087001e

要怪就怪微軟吧,因為他們放出的 Exchange protocols 規格書並未講明這些屬性 ID 值是多少。

在 /usr/include/libmapi/libmapi.h 亦未定義 PRIx64,請補下列定義程式碼。

/* These are essentially local versions of part of the
   C99 __STDC_FORMAT_MACROS */
#ifndef PRIx64
#if __WORDSIZE == 64
  #define PRIx64        "lx"
#else
  #define PRIx64        "llx"
#endif
#endif

中日韓(CJK)語系修正

Openchange 提供 mapiprofile 此工具建置帳號簡介。然而這個工具所設定的 Codepage 與 method 不適用於中日韓語系環境。

mapiprofile.c
/* This is only convenient here and should be replaced at some point */
	mapi_profile_add_string_attr(profname, "codepage", "0x4e4");
	mapi_profile_add_string_attr(profname, "language", lcid );
	mapi_profile_add_string_attr(profname, "method", "0x409");

Codepage 決定字元集 (charset),Method 決定內碼 (encoding),Language 僅僅表示本地用符號。在中日韓(CJK)語系環境中,Codepage 與 method 才是最重要的參數。Language 基本無用。Mapiprofile 卻將 Codepage 與 method 寫死。在未經修正的情形下,它不能應用於中日韓環境。簡單地說,如果沒有經過修改,它的預設狀態無法支援中文系統。

若要符合中日韓環境,建議將 Codepage 與 method 設為 0xFDE9 (65001),這是微軟系統為 UTF-8 所設定的代號。至於 language ,正體中文使用者可以設為 0x404。其實 language 的影響微乎其微,對中文環境使用者而言可隨意設定。

Openchage 字元轉碼程序是錯的

然而,因為 Openchange 內部的字元轉碼程序錯誤,就算我們設定了正確的 Codepage 與 method, Openchange 仍然不支援中日韓環境。對於多位元組字元, Openchange 的 IO 函數會轉換成錯誤的未知內碼。在開發人員修正字元轉碼程序之前, Opehcnage 不支援中日韓環境。亦即,不能使用中文檔案、中文訊息內容。

依據我所抓出的內碼表,舉兩個字為例。「味」的 UTF-8 內碼為 (\xE5\x91\xB3),「呿」的 UTF-8 內碼為 (\xE5\x91\xBF)。而 Openchange 的字元轉碼程序之輸出為 (\xC3\x95\xC3\xA6\xE2\x94\x82)、(\xC3\x95\xC3\xA6\xE2\x94\x90)。

以下為我個人抓出的內碼對照表之一份小表,第一欄是正確的 UTF-8 內碼,第二欄是 Openchange 輸出的錯誤內碼:

static _sCode_oCode_t secterC383[] = {
	{"\xC7\x9C", "\xC3\x83\xC2\xA3"},
	{"\xC7\x8E", "\xC3\x83\xC3\x84"},
	{"\xC7\x92", "\xC3\x83\xC3\x86"},
	{"\xC7\x90", "\xC3\x83\xC3\x89"},
	{"\xC7\x9A", "\xC3\x83\xC3\x9C"},
	{"\xC7\x94", "\xC3\x83\xC3\xB6"},
	{"\xC7\x96", "\xC3\x83\xC3\xBB"},
	{"\xC7\x98", "\xC3\x83\xC3\xBF"},
	{"\xC7\xB9", "\xC3\x83\xE2\x95\xA3"},
	{NULL, NULL}
};

我彙整了 BIG5 與 GB2312 兩份字元集約一萬五千多字後,編製出來的內碼對照表約有600KB,這是經過編譯後的大小。

樂多舊網址: http://blog.roodo.com/rocksaying/archives/8689105.html