]> granicus.if.org Git - php/commitdiff
merging parts of the old com extension to the new rpc extension
authorHarald Radi <phanto@php.net>
Wed, 10 Jul 2002 20:27:17 +0000 (20:27 +0000)
committerHarald Radi <phanto@php.net>
Wed, 10 Jul 2002 20:27:17 +0000 (20:27 +0000)
ext/rpc/com/com.c

index 0b51925ed762d95c2b432d896501fc59b8ade7a7..c597e7a86986ac2fffe720e408ff4838556e2edb 100644 (file)
@@ -1,8 +1,18 @@
+#define _WIN32_DCOM
+
+#include "../handler.h"
+#include "../php_rpc.h"
+
 #include "com.h"
+#include "com_wrapper.h"
+#include "conversion.h"
+
+#include <oleauto.h>
+
 
 /* protos */
-static int com_hash(rpc_string, rpc_string *, int, char *, int);
-static int com_name(rpc_string, rpc_string *, int);
+static int com_hash(rpc_string, rpc_string *, void *, int, char *, int);
+static int com_name(rpc_string, rpc_string *, void *, int);
 static int com_ctor(rpc_string, void **, int , zval ***);
 static int com_dtor(void **);
 static int com_call(rpc_string, void **, zval **, int, zval ***);
@@ -13,6 +23,12 @@ static int com_has_property(rpc_string, void **);
 static int com_unset_property(rpc_string, void **);
 static int com_get_properties(HashTable **, void **);
 
+static PHP_INI_MH(OnTypelibFileChange);
+
+
+/* globals */
+static IBindCtx *pBindCtx;
+
 
 /* register rpc callback function */
 RPC_REGISTER_HANDLERS_START(com)
@@ -37,6 +53,7 @@ PHP_INI_ENTRY_EX("com.allow_dcom", "0", PHP_INI_SYSTEM, NULL, php_ini_boolean_di
 PHP_INI_ENTRY_EX("com.autoregister_typelib", "0", PHP_INI_SYSTEM, NULL, php_ini_boolean_displayer_cb)
 PHP_INI_ENTRY_EX("com.autoregister_verbose", "0", PHP_INI_SYSTEM, NULL, php_ini_boolean_displayer_cb)
 PHP_INI_ENTRY_EX("com.autoregister_casesensitive", "1", PHP_INI_SYSTEM, NULL, php_ini_boolean_displayer_cb)
+PHP_INI_ENTRY("com.typelib_file", "", PHP_INI_SYSTEM, OnTypelibFileChange)
 RPC_INI_END()
 
 /* register userspace functions */
@@ -52,33 +69,351 @@ RPC_METHOD_ENTRY_START(com)
        ZEND_FALIAS(release, com_release, NULL)
 RPC_METHOD_ENTRY_END()
 
+
 /* init function that is called before the class is registered
  * so you can do any tricky stuff in here
  */
 RPC_INIT_FUNCTION(com)
 {
+       CreateBindCtx(0, &pBindCtx);
+}
+
+RPC_SHUTDOWN_FUNCTION(com)
+{
+       pBindCtx->lpVtbl->Release(pBindCtx);
 }
 
 /* rpc handler functions */
 
-static int com_hash(rpc_string name, rpc_string *hash, int num_args, char *arg_types, int type)
+static int com_hash(rpc_string name, rpc_string *hash, void *data, int num_args, char *arg_types, int type)
 {
-       hash->str = strdup(name.str);
-       hash->len = name.len;
+       OLECHAR *olestr = php_char_to_OLECHAR(name.str, name.len, CP_ACP, FALSE);
 
-       return SUCCESS;
+       switch (type) {
+               case CLASS:
+               {
+                       CLSID *clsid = malloc(sizeof(CLSID));
+
+                       if (FAILED(CLSIDFromString(olestr, clsid))) {
+                               /* Perhaps this is a Moniker? */
+                               free(clsid);
+
+                               hash->str = strdup(name.str);
+                               hash->len = name.len;
+                       } else {
+                               hash->str = (char *) clsid;
+                               /* str is actually not a string but a CLSID struct, thus set len to 0.
+                                * nevertheless clsid is freed by the rpc_string_dtor
+                                */
+                               hash->len = 0;
+                       }
+
+                       efree(olestr);
+
+                       return SUCCESS;
+               }
+
+               case METHOD:
+               case PROPERTY:
+               {
+                       DISPID *dispid = malloc(sizeof(DISPID));
+                       
+                       if(SUCCEEDED(php_COM_get_ids_of_names((comval *) data, olestr, dispid))) {
+                               hash->str = (char *) dispid;
+                               /* str is actually not a string but a DISPID struct, thus set len to 0.
+                                * nevertheless dispid is freed by the rpc_string_dtor
+                                */
+                               hash->len = 0;
+
+                               efree(olestr);
+
+                               return SUCCESS;
+                       } else {
+                               free(dispid);
+                               efree(olestr);
+
+                               return FAILURE;
+                       }
+               }
+       }
+
+       efree(olestr);
+
+       return FAILURE;
 }
 
-static int com_name(rpc_string hash, rpc_string *name, int type)
+static int com_name(rpc_string hash, rpc_string *name, void *data, int type)
 {
-       name->str = strdup(hash.str);
-       name->len = hash.len;
+       if (hash.len != 0) {
+               /* not a GUID, perhaps a Moniker */
+               name->str = strdup(hash.str);
+               name->len = hash.len;
 
-       return SUCCESS;
+               return SUCCESS;
+       } else {
+               switch (type) {
+                       case CLASS:
+                       {
+                               OLECHAR *olestr;
+
+                               StringFromCLSID((CLSID *) hash.str, &olestr);
+                               name->str = php_OLECHAR_to_char(olestr, &(name->len), CP_ACP, TRUE);
+                               CoTaskMemFree(olestr);
+
+                               return SUCCESS;
+                       }
+
+                       case METHOD:
+                       case PROPERTY:
+                               /* not used yet */
+                               break;
+               }
+       }
+
+       return FAILURE;
 }
 
 static int com_ctor(rpc_string class_name, void **data, int num_args, zval **args[])
 {
+       zval **server_name = NULL;
+       zval **code_page = NULL;
+       zval **typelib = NULL;
+       zval **user_name=NULL;
+       zval **password=NULL;
+       zval **domain=NULL;
+       int mode = 0;
+       comval *obj;
+       HRESULT hr;
+       CLSCTX flags = CLSCTX_SERVER;
+
+       switch (num_args) {
+               case 3:
+                       typelib = args[2];
+                       convert_to_string_ex(typelib);
+                       /* break missing intentionally */
+               case 2:
+                       code_page = args[1];
+                       convert_to_long_ex(code_page);
+                       /* break missing intentionally */
+               case 1:
+                       server_name = args[0];
+                       /* break missing intentionally */
+                       break;
+
+               case 0:
+                       /* nothing to do */
+                       break;
+
+               default:
+                       /* exception */
+                       return FAILURE;
+       }
+
+       if (server_name != NULL) {
+               /* What is server name? A String or an array? */
+               if (Z_TYPE_PP(server_name) == IS_NULL) {
+                       server_name = NULL;
+               } else if (Z_TYPE_PP(server_name) == IS_ARRAY) {
+                       zval **tmp;
+                       /* Aha - we have a number of possible arguments.
+                        * They are in the hash By name: Server, Domain, Username, Password
+                        * Flags.
+                        * This has been crafted to maintian maximum backward compatability.
+                        * If the server name is specified as a string, then the function
+                        * should behave as before by defaulting username and password and
+                        * using the (I believe) incorrect CLSCTX_SERVER instantiation
+                        * paramter. However if server is specified in this array then we
+                        * use either CLSCTX_REMOTE_SERVER or whatever flags are specified
+                        * in the array
+                        */
+                       HashTable *ht = Z_ARRVAL_PP(server_name);
+                       if (FAILURE == zend_hash_find(ht, "Server", 7, (void **) &tmp)) {
+                               server_name = NULL;
+                       } else {
+                               server_name = tmp;
+                               convert_to_string_ex(server_name);
+                               /* CLSCTX_SERVER includes INPROC and LOCAL SERVER. This means
+                                * that any local server will be instantiated BEFORE even
+                                * looking on a remote server. Thus if we have a server name,
+                                * probably we want to access a remote machine or we would not
+                                * have bothered specifying it. So it would be wrong to to
+                                * connect locally. Futher, unless the name passed is a GUID,
+                                * there has to be something to map the Prog.Id to GUID and
+                                * unless that has been modified to remove the information
+                                * about local instantiation CLSCTX_SERVER would force a local
+                                * instantiation This setting can be overridden below if the
+                                * user specifies a flags element */
+                               flags = CLSCTX_REMOTE_SERVER;
+                       }
+                       if (FAILURE == zend_hash_find(ht, "username", 9, (void **) &tmp)) {
+                               user_name = NULL;
+                       } else {
+                               user_name = tmp;
+                               convert_to_string_ex(user_name);
+                       }
+                       if (FAILURE == zend_hash_find(ht, "domain", 7, (void **) &tmp)) {
+                               domain = NULL;
+                       } else {
+                               domain = tmp;
+                               convert_to_string_ex(domain);
+                       }
+                       if (FAILURE == zend_hash_find(ht, "password", 9, (void **) &tmp)) {
+                               password=NULL;
+                       } else {
+                               password = tmp;
+                               convert_to_string_ex(password);
+                       }
+                       if (SUCCESS == zend_hash_find(ht, "flags", 6, (void **) &tmp)) {
+                               convert_to_long_ex(tmp);
+                               flags = (CLSCTX) Z_LVAL_PP(tmp);
+                       }
+               }
+
+               if (server_name != NULL) {
+                       if (!INI_INT("com.allow_dcom")) {
+                               rpc_error(E_WARNING, "DCOM is disabled");
+                               return FAILURE;
+                       } else {
+                               flags = CLSCTX_REMOTE_SERVER;
+                               convert_to_string_ex(server_name);
+                       }
+               }
+       }
+
+       ALLOC_COM(obj);
+       *data = obj;
+
+       if (code_page != NULL) {
+               C_CODEPAGE(obj) = Z_LVAL_PP(code_page);
+       }
+
+       if (class_name.len) {
+               /* Perhaps this is a Moniker? */
+               IMoniker *pMoniker;
+               ULONG ulEaten;
+
+               if (server_name) {
+                       hr = MK_E_SYNTAX;
+               } else {
+                       OLECHAR *olestr = php_char_to_OLECHAR(class_name.str, class_name.len, obj->codepage, FALSE);
+
+                       if (SUCCEEDED(hr = MkParseDisplayNameEx(pBindCtx, olestr, &ulEaten, &pMoniker))) {
+                               hr = pMoniker->lpVtbl->BindToObject(pMoniker, pBindCtx, NULL, &IID_IDispatch, (LPVOID *) &C_DISPATCH(obj));
+                               pMoniker->lpVtbl->Release(pMoniker);
+                       }
+
+                       efree(olestr);
+               }
+
+               if (FAILED(hr)) {
+                       char *error_message;
+
+                       php_COM_destruct(obj);
+                       error_message = php_COM_error_message(hr);  
+                       rpc_error(E_WARNING,"Invalid ProgID, GUID string, or Moniker: %s", error_message);
+                       LocalFree(error_message);
+                       
+                       return FAILURE;
+               }
+       } else {
+               /* obtain IDispatch */
+               if (!server_name) {
+                       hr = CoCreateInstance((CLSID *) class_name.str, NULL, flags, &IID_IDispatch, (LPVOID *) &C_DISPATCH(obj));
+               } else {
+                       COSERVERINFO server_info;
+                       MULTI_QI pResults;
+                       COAUTHIDENTITY authid;
+                       COAUTHINFO authinfo = {RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, &authid, EOAC_NONE};
+
+                       server_info.dwReserved1=0;
+                       server_info.dwReserved2=0;
+                       server_info.pwszName = php_char_to_OLECHAR(Z_STRVAL_PP(server_name), Z_STRLEN_PP(server_name), obj->codepage, FALSE);
+                       if (user_name) {
+                               /* Parse Username into domain\username */
+                               authid.User = (WCHAR *) Z_STRVAL_PP(user_name);
+                               authid.UserLength = Z_STRLEN_PP(user_name);
+                               if (password) {
+                                       authid.Password = (USHORT *) Z_STRVAL_PP(password);
+                                       authid.PasswordLength = Z_STRLEN_PP(password);
+                               } else {
+                                       authid.Password = (USHORT *) "";
+                                       authid.PasswordLength = 0;
+                               }
+                               if (domain) {
+                                       authid.Domain = (USHORT *) Z_STRVAL_PP(domain);
+                                       authid.DomainLength = Z_STRLEN_PP(domain);
+                               } else {
+                                       authid.Domain = (USHORT *) "";
+                                       authid.DomainLength = 0;
+                               }
+                               authid.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
+
+                               server_info.pAuthInfo=&authinfo;
+                       } else {
+                               server_info.pAuthInfo=NULL;
+                       }
+
+                       pResults.pIID = &IID_IDispatch;
+                       pResults.pItf = NULL;
+                       pResults.hr = S_OK;
+                       hr=CoCreateInstanceEx((CLSID *) class_name.str, NULL, flags, &server_info, 1, &pResults);
+                       if (SUCCEEDED(hr)) {
+                               hr = pResults.hr;
+                               C_DISPATCH(obj) = (IDispatch *) pResults.pItf;
+                       }
+                       efree(server_info.pwszName);
+               }
+
+               if (FAILED(hr)) {
+                       char *error_message, *clsid;
+
+                       php_COM_destruct(obj);
+                       error_message = php_COM_error_message(hr);
+                       clsid = php_COM_string_from_CLSID((CLSID *)class_name.str);
+                       rpc_error(E_WARNING,"Unable to obtain IDispatch interface for CLSID %s: %s", clsid, error_message);
+                       LocalFree(error_message);
+                       efree(clsid);
+
+                       return FAILURE;
+               }
+       }
+
+       php_COM_set(obj, &C_DISPATCH(obj), TRUE);
+
+       if (INI_INT("com.autoregister_casesensitive")) {
+               mode |= CONST_CS;
+       }
+
+       if (C_HASTLIB(obj)) {
+               if (INI_INT("com.autoregister_typelib")) {
+                       ITypeLib *pTL;
+                       unsigned int idx;
+
+                       /* @todo check if typlib isn't already loaded */
+                       if (C_TYPEINFO_VT(obj)->GetContainingTypeLib(C_TYPEINFO(obj), &pTL, &idx) == S_OK) {
+                               php_COM_load_typelib(pTL, mode);
+                               pTL->lpVtbl->Release(pTL);
+                       }
+               }
+       } else {
+               if (typelib != NULL) {
+                       ITypeLib *pTL;
+
+                       if ((pTL = php_COM_find_typelib(Z_STRVAL_PP(typelib), mode)) != NULL) {
+                               C_HASTLIB(obj) = SUCCEEDED(pTL->lpVtbl->GetTypeInfo(pTL, 0, &C_TYPEINFO(obj)));
+                               /* idx 0 should deliver the ITypeInfo for the IDispatch Interface */
+                               if (INI_INT("com.autoregister_typelib")) {
+                                       php_COM_load_typelib(pTL, mode);
+                               }
+                               pTL->lpVtbl->Release(pTL);
+                       }
+               }
+       }
+
+#if 0
+       RETURN_RESOURCE(zend_list_insert(obj, IS_COM));
+#endif
+
        return SUCCESS;
 }
 
@@ -129,4 +464,75 @@ ZEND_FUNCTION(com_addref)
 
 ZEND_FUNCTION(com_release)
 {
-}
\ No newline at end of file
+}
+
+/* ini callbacks */
+static PHP_INI_MH(OnTypelibFileChange)
+{
+       FILE *typelib_file;
+       char *typelib_name_buffer;
+       char *strtok_buf = NULL;
+       int interactive;
+       interactive = CG(interactive);
+
+       if (!new_value || (typelib_file = VCWD_FOPEN(new_value, "r"))==NULL) {
+               return FAILURE;
+       }
+
+       if (interactive) {
+               printf("Loading type libraries...");
+               fflush(stdout);
+       }
+
+       typelib_name_buffer = (char *) emalloc(sizeof(char)*1024);
+
+       while (fgets(typelib_name_buffer, 1024, typelib_file)) {
+               ITypeLib *pTL;
+               char *typelib_name;
+               char *modifier, *ptr;
+               int mode = CONST_CS | CONST_PERSISTENT; /* CONST_PERSISTENT is ok here */
+
+               if (typelib_name_buffer[0]==';') {
+                       continue;
+               }
+               typelib_name = php_strtok_r(typelib_name_buffer, "\r\n", &strtok_buf); /* get rid of newlines */
+               if (typelib_name == NULL) {
+                       continue;
+               }
+               typelib_name = php_strtok_r(typelib_name, "#", &strtok_buf);
+               modifier = php_strtok_r(NULL, "#", &strtok_buf);
+               if (modifier != NULL) {
+                       if (!strcmp(modifier, "cis") || !strcmp(modifier, "case_insensitive")) {
+                               mode &= ~CONST_CS;
+                       }
+               }
+
+               /* Remove leading/training white spaces on search_string */
+               while (isspace(*typelib_name)) {/* Ends on '\0' in worst case */
+                       typelib_name ++;
+               }
+               ptr = typelib_name + strlen(typelib_name) - 1;
+               while ((ptr != typelib_name) && isspace(*ptr)) {
+                       *ptr = '\0';
+                       ptr--;
+               }
+
+               if (interactive) {
+                       printf("\rLoading %-60s\r", typelib_name);
+               }
+
+               if ((pTL = php_COM_find_typelib(typelib_name, mode)) != NULL) {
+                       php_COM_load_typelib(pTL, mode);
+                       pTL->lpVtbl->Release(pTL);
+               }
+       }
+
+       efree(typelib_name_buffer);
+       fclose(typelib_file);
+
+       if (interactive) {
+               printf("\r%70s\r", "");
+       }
+
+       return SUCCESS;
+}