On 04/07/11 07:47, Milan Crha wrote:
On Wed, 2011-04-06 at 14:12 +0200, Alois Schloegl wrote:
find_mapi_SPropValue_data() provides the PT_STRING8 values, the
corresponding PT_UNICODE fields
   e.g PR_COMPANY_NAME_UNICODE
are empty.

        Hi,
it makes sense, if you do not request these with GetProps, then they are
not fetched from the server, if you use GetPropsAll, then that's
slightly harder, because the function itself has set "fetch unicode
values", but the openchange API does not allow you to request it (check
openchange limapi source code of that GetPropsAll function), and keeps
it with non-unicode fetching.


Hi Milan,

thanks for the hints. When using openchangeclient, the GetPropsAll(&obj_message, &properties_array); function is used on
  ./utils/openchangeclient.c: line 1812

The properties_array is then passed on to mapidump_contact(&properties_array, id);


Though the former applies for GetGALTable,
which is using list of properties to be fetched, thus provide their
_UNICODE versions instead. Libmapi returns UTF8 encoded strings for them
(as you surely know).

Actually, no; I'm quite new to openchange and just trying to get into it. GetPropsAll seem to be part of libmapi, but it does not return UTF8 (i.e. PtypString) but returns PtypString8.


The string conversion rules in the [MS-NSPI].pdf (3.1.1.2.3) says

>>  If the native type of a property is PtypString8 and the client
>>  has requested that property with the
>>  type PtypString, the server MUST convert the 8-bit character
>>  representation to a Unicode
>>  representation prior to returning the value.

and further below

>> The 8-bit character representation is considered to be in
>>  the codepage CP_TELETEX.

Now, CP_TELETEX is not known to iconv. So, the easiest way is to ask the server to return the data in PtypString (UNICODE) format instead of PtypString8. Accordingly, I changed

Index: libmapi/IMAPIProp.c
===================================================================
--- libmapi/IMAPIProp.c (revision 2748)
+++ libmapi/IMAPIProp.c (working copy)
@@ -512,7 +512,7 @@
        /* Fill the GetPropsAll operation */
        request.PropertySizeLimit = 0;
        size += sizeof (uint16_t);
-       request.WantUnicode = 0;
+       request.WantUnicode = 1;
        size += sizeof (uint16_t);

        /* Fill the MAPI_REQ request */


and change also the requested values in functions mapidump_contact().
An it works just fine, the output is clean UTF8.

Because this change is likely to break the code in other parts, I introduced the function GetPropsAllUnicode() and enabled it only for mapidump_contacts (see attached patch against current SVN). The patch contains also the changes to export e-mail addresses and distribution lists, and improves the utf16->utf8 conversion (now using iconv) for the e-mail addresses in the distribution lists.


   Alois

Index: libmapi/IMAPIProp.c
===================================================================
--- libmapi/IMAPIProp.c	(revision 2756)
+++ libmapi/IMAPIProp.c	(working copy)
@@ -548,7 +548,77 @@
 	return MAPI_E_SUCCESS;
 }
 
+/**
+	same as GetPropsAll except 
+	for the fact that UNICODE strings instead of STRING8 are requested
+*/
+_PUBLIC_ enum MAPISTATUS GetPropsAllUnicode(mapi_object_t *obj,
+				     struct mapi_SPropValue_array *properties)
+{
+	TALLOC_CTX		*mem_ctx;
+	struct mapi_request	*mapi_request;
+	struct mapi_response	*mapi_response;
+	struct EcDoRpc_MAPI_REQ	*mapi_req;
+	struct GetPropsAll_req	request;
+	struct GetPropsAll_repl	*reply;
+	struct mapi_session	*session;
+	NTSTATUS		status;
+	enum MAPISTATUS		retval;
+	uint32_t		size;
+	uint8_t			logon_id;
 
+	/* Sanity checks */
+	OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
+
+	session = mapi_object_get_session(obj);
+	OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
+
+	if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
+		return retval;
+
+	mem_ctx = talloc_named(NULL, 0, "GetPropsAll");
+	size = 0;
+
+	/* Fill the GetPropsAll operation */
+	request.PropertySizeLimit = 0;
+	size += sizeof (uint16_t);
+	request.WantUnicode = 1;
+	size += sizeof (uint16_t);
+
+	/* Fill the MAPI_REQ request */
+	mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
+	mapi_req->opnum = op_MAPI_GetPropsAll;
+	mapi_req->logon_id = logon_id;
+	mapi_req->handle_idx = 0;
+	mapi_req->u.mapi_GetPropsAll = request;
+	size += 5;
+
+	/* Fill the mapi_request structure */
+	mapi_request = talloc_zero(mem_ctx, struct mapi_request);
+	mapi_request->mapi_len = size + sizeof (uint32_t);
+	mapi_request->length = size;
+	mapi_request->mapi_req = mapi_req;
+	mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
+	mapi_request->handles[0] = mapi_object_get_handle(obj);
+
+	status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
+	OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
+	OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
+	retval = mapi_response->mapi_repl->error_code;
+	OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
+
+	OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
+
+	reply = &mapi_response->mapi_repl->u.mapi_GetPropsAll;
+	properties->cValues = reply->properties.cValues;
+	properties->lpProps = talloc_steal((TALLOC_CTX *)session, reply->properties.lpProps);
+
+	talloc_free(mapi_response);
+	talloc_free(mem_ctx);
+	return MAPI_E_SUCCESS;
+}
+
+
 /**
    \details Delete one or more properties from an object
 
Index: libmapi/mapidump.c
===================================================================
--- libmapi/mapidump.c	(revision 2756)
+++ libmapi/mapidump.c	(working copy)
@@ -2,6 +2,7 @@
    OpenChange MAPI implementation.
 
    Copyright (C) Julien Kerihuel 2007-2011.
+   Copyright (C) Alois Schloegl, IST Austria, 2011.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -20,6 +21,7 @@
 #include "libmapi/libmapi.h"
 #include "libmapi/libmapi_private.h"
 #include "libmapi/mapidump.h"
+#include <iconv.h>
 #include <time.h>
 
 #ifdef ENABLE_ASSERTS
@@ -548,7 +550,9 @@
 	const char	*given_name = NULL;
 	const char	*surname = NULL;
 	const char	*company = NULL;
-	const char	*email = NULL;
+	const char	*email1 = NULL;
+	const char	*email2 = NULL;
+	const char	*email3 = NULL;
 	const char	*title = NULL;
 	const char      *office_phone = NULL;
 	const char      *home_phone = NULL;
@@ -561,36 +565,90 @@
 	const char      *department = NULL;
 	const char      *business_fax = NULL;
 	const char      *business_home_page = NULL;
+	const char 	*distribution_list = NULL;
 
+        size_t buflen = 300;       	                        
+      	char buf[buflen + 1];
+
 	card_name = (const char *)find_mapi_SPropValue_data(properties, PidLidFileUnder);
-	topic = (const char *)find_mapi_SPropValue_data(properties, PR_CONVERSATION_TOPIC);
-	company = (const char *)find_mapi_SPropValue_data(properties, PR_COMPANY_NAME);
-	title = (const char *)find_mapi_SPropValue_data(properties, PR_TITLE);
-	full_name = (const char *)find_mapi_SPropValue_data(properties, PR_DISPLAY_NAME);
-	given_name = (const char *)find_mapi_SPropValue_data(properties, PR_GIVEN_NAME);
-	surname = (const char *)find_mapi_SPropValue_data(properties, PR_SURNAME);
-	department = (const char *)find_mapi_SPropValue_data(properties, PR_DEPARTMENT_NAME);
-	email = (const char *)find_mapi_SPropValue_data(properties, PidLidEmail1OriginalDisplayName);
-	office_phone = (const char *)find_mapi_SPropValue_data(properties, PR_OFFICE_TELEPHONE_NUMBER);
-	home_phone = (const char *)find_mapi_SPropValue_data(properties, PR_HOME_TELEPHONE_NUMBER);
-	mobile_phone = (const char *)find_mapi_SPropValue_data(properties, PR_MOBILE_TELEPHONE_NUMBER);
-	business_fax = (const char *)find_mapi_SPropValue_data(properties, PR_BUSINESS_FAX_NUMBER);
-	business_home_page = (const char *)find_mapi_SPropValue_data(properties, PR_BUSINESS_HOME_PAGE);
-	postal_address = (const char*)find_mapi_SPropValue_data(properties, PR_POSTAL_ADDRESS);
-	street_address = (const char*)find_mapi_SPropValue_data(properties, PR_STREET_ADDRESS);
-	locality = (const char*)find_mapi_SPropValue_data(properties, PR_LOCALITY);
-	state = (const char*)find_mapi_SPropValue_data(properties, PR_STATE_OR_PROVINCE);
-	country = (const char*)find_mapi_SPropValue_data(properties, PR_COUNTRY);
+	topic = (const char *)find_mapi_SPropValue_data(properties, PR_CONVERSATION_TOPIC_UNICODE);
+	company = (const char *)find_mapi_SPropValue_data(properties, PR_COMPANY_NAME_UNICODE);
+	title = (const char *)find_mapi_SPropValue_data(properties, PR_TITLE_UNICODE);
+	full_name = (const char *)find_mapi_SPropValue_data(properties, PR_DISPLAY_NAME_UNICODE);
+	given_name = (const char *)find_mapi_SPropValue_data(properties, PR_GIVEN_NAME_UNICODE);
+	surname = (const char *)find_mapi_SPropValue_data(properties, PR_SURNAME_UNICODE);
+	department = (const char *)find_mapi_SPropValue_data(properties, PR_DEPARTMENT_NAME_UNICODE);
 
+// these definitions should go somewhere else; perhaps ./libmapi/property_altnames.h but is built by script/makepropslist.py
+#if 0
+#define PR_EMAIL1_DISPLAY_NAME                                               PROP_TAG(PT_STRING8   , 0x8080)  /* 0x8080001E */
+#define PR_EMAIL1_EMAIL_ADDDESS                                              PROP_TAG(PT_STRING8   , 0x8083)  /* 0x8083001E */
+#define PR_EMAIL1_ORIGINAL_DISPLAY_NAME                                      PROP_TAG(PT_STRING8   , 0x8084)  /* 0x8084001E */
+#define PR_EMAIL2_DISPLAY_NAME                                               PROP_TAG(PT_STRING8   , 0x8090)  /* 0x9080001E */
+#define PR_EMAIL2_EMAIL_ADDRESS                                              PROP_TAG(PT_STRING8   , 0x8093)  /* 0x9083001E */
+#define PR_EMAIL2_ORIGINAL_DISPLAY_NAME                                      PROP_TAG(PT_STRING8   , 0x8094)  /* 0x9084001E */
+#define PR_EMAIL3_DISPLAY_NAME                                               PROP_TAG(PT_STRING8   , 0x80A0)  /* 0xA080001E */
+#define PR_EMAIL3_EMAIL_ADDRESS                                              PROP_TAG(PT_STRING8   , 0x80A3)  /* 0xA083001E */
+#define PR_EMAIL3_ORIGINAL_DISPLAY_NAME                                      PROP_TAG(PT_STRING8   , 0x80A4)  /* 0xA084001E */
+#define PR_DISTRIBUTION_LIST_NAME					     PROP_TAG(PT_STRING8   , 0x8053)  /* 0x8053001E */
+#else
+#define PR_EMAIL1_DISPLAY_NAME                                               PROP_TAG(PT_UNICODE   , 0x8080)  /* 0x8080001F */
+#define PR_EMAIL1_EMAIL_ADDDESS                                              PROP_TAG(PT_UNICODE   , 0x8083)  /* 0x8083001F */
+#define PR_EMAIL1_ORIGINAL_DISPLAY_NAME                                      PROP_TAG(PT_UNICODE   , 0x8084)  /* 0x8084001F */
+#define PR_EMAIL2_DISPLAY_NAME                                               PROP_TAG(PT_UNICODE   , 0x8090)  /* 0x9080001F */
+#define PR_EMAIL2_EMAIL_ADDRESS                                              PROP_TAG(PT_UNICODE   , 0x8093)  /* 0x9083001F */
+#define PR_EMAIL2_ORIGINAL_DISPLAY_NAME                                      PROP_TAG(PT_UNICODE   , 0x8094)  /* 0x9084001F */
+#define PR_EMAIL3_DISPLAY_NAME                                               PROP_TAG(PT_UNICODE   , 0x80A0)  /* 0xA080001F */
+#define PR_EMAIL3_EMAIL_ADDRESS                                              PROP_TAG(PT_UNICODE   , 0x80A3)  /* 0xA083001F */
+#define PR_EMAIL3_ORIGINAL_DISPLAY_NAME                                      PROP_TAG(PT_UNICODE   , 0x80A4)  /* 0xA084001F */
+
+#define PR_DISTRIBUTION_LIST_NAME         				     PROP_TAG(PT_UNICODE   , 0x8053)  /* 0x8053001F */
+#endif 
+
+	distribution_list = (const char *)find_mapi_SPropValue_data(properties, PR_DISTRIBUTION_LIST_NAME);
+
+        if (!email1) email1 = (const char *)find_mapi_SPropValue_data(properties, PR_EMAIL1_DISPLAY_NAME);
+        if (email1 && !strchr(email1,'@')) email1 = NULL; 
+        if (!email1) email1 = (const char *)find_mapi_SPropValue_data(properties, PR_EMAIL1_EMAIL_ADDDESS);
+        if (email1 &&!strchr(email1,'@')) email1 = NULL; 
+        if (!email1) email1 = (const char *)find_mapi_SPropValue_data(properties, PR_EMAIL1_ORIGINAL_DISPLAY_NAME);
+        if (email1 &&!strchr(email1,'@')) email1 = NULL; 
+        
+        if (!email2) email2 = (const char *)find_mapi_SPropValue_data(properties, PR_EMAIL2_DISPLAY_NAME);
+        if (email2 && !strchr(email2,'@')) email2 = NULL; 
+        if (!email2) email2 = (const char *)find_mapi_SPropValue_data(properties, PR_EMAIL2_EMAIL_ADDRESS);
+        if (email2 && !strchr(email2,'@')) email2 = NULL; 
+        if (!email2) email2 = (const char *)find_mapi_SPropValue_data(properties, PR_EMAIL2_ORIGINAL_DISPLAY_NAME);
+        if (email2 && !strchr(email2,'@')) email2 = NULL; 
+        
+        if (!email3) email3 = (const char *)find_mapi_SPropValue_data(properties, PR_EMAIL3_DISPLAY_NAME);
+        if (email3 && !strchr(email3,'@')) email3 = NULL; 
+        if (!email3) email3 = (const char *)find_mapi_SPropValue_data(properties, PR_EMAIL3_EMAIL_ADDRESS);
+        if (email3 && !strchr(email3,'@')) email3 = NULL; 
+        if (!email3) email3 = (const char *)find_mapi_SPropValue_data(properties, PR_EMAIL3_ORIGINAL_DISPLAY_NAME);
+        if (email3 && !strchr(email3,'@')) email3 = NULL; 
+
+	office_phone = (const char *)find_mapi_SPropValue_data(properties, PR_OFFICE_TELEPHONE_NUMBER_UNICODE);
+	home_phone = (const char *)find_mapi_SPropValue_data(properties, PR_HOME_TELEPHONE_NUMBER_UNICODE);
+	mobile_phone = (const char *)find_mapi_SPropValue_data(properties, PR_MOBILE_TELEPHONE_NUMBER_UNICODE);
+	business_fax = (const char *)find_mapi_SPropValue_data(properties, PR_BUSINESS_FAX_NUMBER_UNICODE);
+	business_home_page = (const char *)find_mapi_SPropValue_data(properties, PR_BUSINESS_HOME_PAGE_UNICODE);
+	postal_address = (const char*)find_mapi_SPropValue_data(properties, PR_POSTAL_ADDRESS_UNICODE);
+	street_address = (const char*)find_mapi_SPropValue_data(properties, PR_STREET_ADDRESS_UNICODE);
+	locality = (const char*)find_mapi_SPropValue_data(properties, PR_LOCALITY_UNICODE);
+	state = (const char*)find_mapi_SPropValue_data(properties, PR_STATE_OR_PROVINCE_UNICODE);
+	country = (const char*)find_mapi_SPropValue_data(properties, PR_COUNTRY_UNICODE);
+
 	if (card_name) 
 		printf("|== %s ==| %s\n", card_name, id?id:"");
 	else if (topic)
 		printf("|== %s ==| %s\n", topic, id?id:"");
 	else 
-	  printf("|== <Unknown> ==| %s\n", id?id:"");
+	        printf("|== <Unknown> ==| %s\n", id?id:"");
 	fflush(0);
 	if (topic) printf("Topic: %s\n", topic);
 	fflush(0);
+
 	if (full_name)
 		printf("Full Name: %s\n", full_name);
 	else if (given_name && surname)
@@ -602,8 +660,77 @@
 	fflush(0);
 	if (company) printf("Company: %s\n", company);
 	fflush(0);
-	if (email) printf("E-mail: %s\n", email);
+
+	if (distribution_list) {
+ 	        printf("Distribution List: %s\nE-mail: ", distribution_list);
+
+        	struct mapi_SBinaryArray *ptr;
+        	ptr = (struct mapi_SBinaryArray*) find_mapi_SPropValue_data(properties, PidLidDistributionListOneOffMembers);
+
+     	        iconv_t utf8_utf16 = iconv_open("UTF8","UTF16");
+        	int k; 
+        	for (k=0; k < ptr->cValues; k++) {
+        	        struct SBinary_short SBinS = ptr->bin[k];
+
+	                char *s0, *s1; 
+                        s0 = SBinS.lpb + 24; 
+
+	                // decode OneOff EntryId's [MS-OXCDATA] -- v20101026: section 2.2.5.1 One-Off EntryID        
+         	        if (SBinS.lpb[23] & 0x80) {
+         	                // Unicode (UTF16) to UTF8 conversion
+                	        size_t s0len = SBinS.cb - 24;
+                	        size_t s1len = buflen;
+                	        s1 = buf; 
+                	        iconv(utf8_utf16, NULL, NULL,  &s1, &s1len);	// initialize iconv
+                	        iconv(utf8_utf16, &s0, &s0len, &s1, &s1len);
+                	        s0 = buf;
+        	        } 
+        	        // else // Multibyte character set (MBCS)
+
+       	                // s0 contains 3 consecutive, \0-terminated strings, the third contains the e-mail address. 
+               	        s1 = strchr(s0,0) + 1;
+                        s1 = strchr(s1,0) + 1;
+	                if (k) printf(", ");
+        	        printf("%s",s1);
+        	}
+        	printf("\n\n");       
+        	fflush(0); 
+     	        iconv_close(utf8_utf16);
+        	return;
+        }
+        
+	// convert to unix style e-mail addresses "Fffff Nnnnnn (i.na...@domain.net)" to "Fffff Nnnnn <i.n...@domain.net>"
+	int i;	
+	char *tmpemail = NULL; 
+	if (email1) {
+	        tmpemail = realloc(tmpemail,strlen(email1)+1);
+	        strcpy(tmpemail,email1);        
+                for (i=0; i<strlen(tmpemail); i++) 
+                        if (tmpemail[i]=='(') tmpemail[i]='<';
+                        else if (tmpemail[i]==')') tmpemail[i]='>';
+	        printf("E-mail1: %s\n", tmpemail);
+	}        
 	fflush(0);
+	if (email2) {
+	        tmpemail = realloc(tmpemail,strlen(email2)+1);
+	        strcpy(tmpemail,email2);        
+                for (i=0; i<strlen(tmpemail); i++) 
+                        if (tmpemail[i]=='(') tmpemail[i]='<';
+                        else if (tmpemail[i]==')') tmpemail[i]='>';
+	        printf("E-mail2: %s\n", tmpemail);
+	}        
+	fflush(0);
+	if (email3) {
+	        tmpemail = realloc(tmpemail,strlen(email3)+1);
+	        strcpy(tmpemail,email3);        
+                for (i=0; i<strlen(tmpemail); i++) 
+                        if (tmpemail[i]=='(') tmpemail[i]='<';
+                        else if (tmpemail[i]==')') tmpemail[i]='>';
+	        printf("E-mail3: %s\n", tmpemail);
+	}        
+	if (tmpemail) free(tmpemail); 
+	fflush(0);
+
 	if (office_phone) printf("Office phone number: %s\n", office_phone);
 	fflush(0);
 	if (home_phone) printf("Work phone number: %s\n", home_phone);
Index: utils/openchangeclient.c
===================================================================
--- utils/openchangeclient.c	(revision 2756)
+++ utils/openchangeclient.c	(working copy)
@@ -1809,7 +1809,11 @@
 				if (oclient->summary) {
 					mapidump_message_summary(&obj_message);
 				} else {
-					retval = GetPropsAll(&obj_message, &properties_array);
+					if (olFolder==olFolderContacts)
+						retval = GetPropsAllUnicode(&obj_message, &properties_array);
+					else
+						retval = GetPropsAll(&obj_message, &properties_array);
+						
 					if (retval == MAPI_E_SUCCESS) {
 						id = talloc_asprintf(mem_ctx, ": %"PRIX64"/%"PRIX64,
 								     SRowSet.aRow[i].lpProps[0].value.d,
_______________________________________________
devel mailing list
devel@lists.openchange.org
http://mailman.openchange.org/listinfo/devel

Reply via email to