mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-21 23:43:17 +01:00
removed outdated xmlrpc and soap service, it is off by default since couple of versions
This commit is contained in:
parent
41abf2cc21
commit
edd07a9729
@ -295,17 +295,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
-->
|
||||
<tr class="row_off">
|
||||
<td>{lang_Enable_the_xmlrpc_service} {lang_(default_No,_leave_it_off_if_you_dont_use_it)}:</td>
|
||||
<td>
|
||||
<select name="newsettings[xmlrpc_enabled]">
|
||||
<option value="">{lang_No}</option>
|
||||
<option value="True"{selected_xmlrpc_enabled_True}>{lang_Yes}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="row_on">
|
||||
<tr class="row_off">
|
||||
<td>{lang_Enable_the_soap_service} {lang_(default_No,_leave_it_off_if_you_dont_use_it)}:</td>
|
||||
<td>
|
||||
<select name="newsettings[soap_enabled]">
|
||||
@ -314,19 +305,19 @@
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="row_off">
|
||||
<tr class="row_on">
|
||||
<td>{lang_How_many_entries_should_non-admins_be_able_to_export_(empty_=_no_limit,_no_=_no_export)}:<br />{lang_This_controls_exports_and_merging.}</td>
|
||||
<td><input name="newsettings[export_limit]" value="{value_export_limit}" size="5"></td>
|
||||
</tr>
|
||||
<tr class="row_on">
|
||||
<tr class="row_off">
|
||||
<td>{lang_Group_excepted_from_above_export_limit_(admins_are_always_excepted)}:</td>
|
||||
<td>{call_bo_merge::hook_export_limit_excepted}</td>
|
||||
</tr>
|
||||
<tr class="row_off">
|
||||
<tr class="row_on">
|
||||
<td>{lang_Allow_remote_administration_from_following_install_ID's_(comma_separated)}:<br />{lang_Own_install_ID:_}{value_install_id}</td>
|
||||
<td><input name="newsettings[allow_remote_admin]" value="{value_allow_remote_admin}" size="40"></td>
|
||||
</tr>
|
||||
<tr class="row_on">
|
||||
<tr class="row_off">
|
||||
<td>{lang_Should_exceptions_contain_a_trace_(including_function_arguments)}:</td>
|
||||
<td>
|
||||
<select name="newsettings[exception_show_trace]">
|
||||
@ -335,7 +326,7 @@
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="row_off">
|
||||
<tr class="row_on">
|
||||
<td>{lang_Disable_minifying_of_javascript_and_CSS_files}:</td>
|
||||
<td>
|
||||
<select name="newsettings[debug_minify]">
|
||||
|
Binary file not shown.
@ -1,505 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
> Proposal for a Common Groupware Interface Standard
|
||||
</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"></HEAD
|
||||
><BODY
|
||||
CLASS="ARTICLE"
|
||||
><DIV
|
||||
CLASS="ARTICLE"
|
||||
><DIV
|
||||
CLASS="TITLEPAGE"
|
||||
><H1
|
||||
CLASS="TITLE"
|
||||
><A
|
||||
NAME="AEN2"
|
||||
>Proposal for a Common Groupware Interface Standard</A
|
||||
></H1
|
||||
><H3
|
||||
CLASS="AUTHOR"
|
||||
><A
|
||||
NAME="AEN4"
|
||||
></A
|
||||
></H3
|
||||
><HR></DIV
|
||||
><DIV
|
||||
CLASS="SECT1"
|
||||
><H2
|
||||
CLASS="SECT1"
|
||||
><A
|
||||
NAME="AEN8"
|
||||
>Scope</A
|
||||
></H2
|
||||
><P
|
||||
> As many different opensource and freesoftware groupware systems are being developed, the full realization of the dream of a connected world should be prefaced by an agreement to interoperate. There are limited ways in which cooperation with these and commercial groupware systems may be achecived, the majority if not all of which were derived via the establishment of open standards. These might include email (POP3/IMAP), contacts(LDAP,vcard), or scheduling(ical/vcal). It is felt that while these have proven themselves to be very useful, they are insufficient to satisfy the real needs of a typical business environment.
|
||||
</P
|
||||
><P
|
||||
> This document hopes to provide a reasonable, if limited, recommendation for a set of standardized methods to be used for groupware services interaction. More specifically, it hopes to address the need for such a standard as well as to spur discussion about the common service names and methods themselves.
|
||||
</P
|
||||
><P
|
||||
> Examples will be given for implementations in XML-RPC, since this standard is relatively fixed and open.
|
||||
</P
|
||||
><P
|
||||
> This document does not provide recommendations for the underlying access control system which would allow or deny a particular action.
|
||||
</P
|
||||
><P
|
||||
> Also not discussed here is login and authorization to be used for initial access to a service provider.
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT1"
|
||||
><HR><H2
|
||||
CLASS="SECT1"
|
||||
><A
|
||||
NAME="AEN15"
|
||||
>The Services</A
|
||||
></H2
|
||||
><DIV
|
||||
CLASS="SECT2"
|
||||
><H3
|
||||
CLASS="SECT2"
|
||||
><A
|
||||
NAME="AEN17"
|
||||
>Overview</A
|
||||
></H3
|
||||
><P
|
||||
> There are a few common services types that will be needed for minimum useability of a groupware server or application. They are:
|
||||
</P
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> Contacts
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> Schedule
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> Notes
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> Todo
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
><P
|
||||
> These services are represented already in places such as existing groupware client-server applications and also in the PalmOS basic-4 buttons and applications. Different systems may have different names for these services internally, e.g. Contacts - addresses, addressbook, people, Schedule - calendar, agenda, meetings.
|
||||
</P
|
||||
><P
|
||||
> Within each of these services are some common methods that would be called to store, retreive, or update data:
|
||||
</P
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> read_list
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> read
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> save
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> delete
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT2"
|
||||
><HR><H3
|
||||
CLASS="SECT2"
|
||||
><A
|
||||
NAME="AEN40"
|
||||
>Detail</A
|
||||
></H3
|
||||
><DIV
|
||||
CLASS="SECT3"
|
||||
><H4
|
||||
CLASS="SECT3"
|
||||
><A
|
||||
NAME="AEN42"
|
||||
>Contacts</A
|
||||
></H4
|
||||
><P
|
||||
> The concept of contacts may encompass local addressbooks, LDAP, and lists stored in other media. The purpose of the contacts service is not to duplicate or attempt to replace these. In some respects, it might do just that. But its goal is more so to provide a common and shareable way for the other core services to create, edit, and read a common user and address list. All of the other services may use the contact service to obtain record owner information to be used in access control. They would also use them when it is required to share this data, as with a meeting where other local and non-local users will be invited to attend.
|
||||
</P
|
||||
><P
|
||||
> Contacts may include the local installed user base, users on other cooperative servers, or email addresses used for limited cooperation with other groupware services that are not compliant with this service scheme or implementations thereof. It could also include individuals using web-based or local ISP email services. The scope of this document, however, is to define the service with regard to the common methods to be used for server-server and client-server communications:
|
||||
</P
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> read_list
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
><P
|
||||
> This method is used to list contacts, with or without limits, filters, or search criteria. In this way it can be used for simple lists or to search for contact records and their identifiers. The optional search criteria includes:
|
||||
</P
|
||||
><P
|
||||
></P
|
||||
><OL
|
||||
TYPE="1"
|
||||
><LI
|
||||
><P
|
||||
> start - Start at this identifier (integer: default 0)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> limit - Limit to this number of records returned(integer: unlimited by default)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> fieldlist - limit to showing only these fields (array: default to identifier, owner identifier, possibly firstname and lastname)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> filter - Show records that are public or private only, or other system-specific filters, e.g group or company(string: default '')
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> query - Search internal fieldlist for a value (string: default '')
|
||||
</P
|
||||
></LI
|
||||
></OL
|
||||
><P
|
||||
> The return for this method includes:
|
||||
</P
|
||||
><P
|
||||
></P
|
||||
><OL
|
||||
TYPE="1"
|
||||
><LI
|
||||
><P
|
||||
> count of number of records returned(integer)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> array consisting of: array: identifier => (array: fieldlist key => value pairs)
|
||||
</P
|
||||
></LI
|
||||
></OL
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> read
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
><P
|
||||
> Once the identifier for a single contact record is known, the contact may be read for more detail using this method. This takes two parameters:
|
||||
</P
|
||||
><P
|
||||
></P
|
||||
><OL
|
||||
TYPE="1"
|
||||
><LI
|
||||
><P
|
||||
> identifier - (integer: no default)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> fieldlist - limit to showing only these fields (array: default to identifier, owner identifier, possibly firstname and lastname)
|
||||
</P
|
||||
></LI
|
||||
></OL
|
||||
><P
|
||||
> And returns:
|
||||
</P
|
||||
><P
|
||||
></P
|
||||
><OL
|
||||
TYPE="1"
|
||||
><LI
|
||||
><P
|
||||
> array consisting of: array: identifier => (array: fieldlist key => value pairs)
|
||||
</P
|
||||
></LI
|
||||
></OL
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> save
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
><P
|
||||
> This is a method used to save an existing record or create a new one. If the identifier for an existing record is not passed, a new entry will be created.
|
||||
</P
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> delete
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
><P
|
||||
> This will allow deletion of a record by passing its identifier.
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT3"
|
||||
><HR><H4
|
||||
CLASS="SECT3"
|
||||
><A
|
||||
NAME="AEN88"
|
||||
>Schedule</A
|
||||
></H4
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT3"
|
||||
><HR><H4
|
||||
CLASS="SECT3"
|
||||
><A
|
||||
NAME="AEN90"
|
||||
>Notes</A
|
||||
></H4
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT3"
|
||||
><HR><H4
|
||||
CLASS="SECT3"
|
||||
><A
|
||||
NAME="AEN92"
|
||||
>Todo</A
|
||||
></H4
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT2"
|
||||
><HR><H3
|
||||
CLASS="SECT2"
|
||||
><A
|
||||
NAME="AEN94"
|
||||
>Examples in XML-RPC</A
|
||||
></H3
|
||||
><P
|
||||
> Query the contacts service for read_list, using only start and limit to grab the first 5 records, starting with identifier 1. Additionally, return only the firstname and lastname fields n_given and n_family (firstname and lastname in pseudo vcard format):
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><methodCall>
|
||||
<methodName>service.contacts.read_list</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>start</name>
|
||||
<value><string>1</string></value>
|
||||
</member>
|
||||
<member><name>limit</name>
|
||||
<value><string>5</string></value>
|
||||
</member>
|
||||
<member><name>fields</name>
|
||||
<value><struct>
|
||||
<member><name>n_given</name>
|
||||
<value><string>n_given</string></value>
|
||||
</member>
|
||||
<member><name>n_family</name>
|
||||
<value><string>n_family</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</member>
|
||||
<member><name>query</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>filter</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT1"
|
||||
><HR><H2
|
||||
CLASS="SECT1"
|
||||
><A
|
||||
NAME="AEN98"
|
||||
>Conclusion</A
|
||||
></H2
|
||||
><P
|
||||
> This document outlined the following services and methods:
|
||||
</P
|
||||
><DIV
|
||||
CLASS="SECT2"
|
||||
><HR><H3
|
||||
CLASS="SECT2"
|
||||
><A
|
||||
NAME="AEN101"
|
||||
>Contacts:</A
|
||||
></H3
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> service.contacts.read_list([search criteria])
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.contacts.read(identifier,[fieldlist])
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.contacts.save(fields)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.contacts.delete(identifier)
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT2"
|
||||
><HR><H3
|
||||
CLASS="SECT2"
|
||||
><A
|
||||
NAME="AEN112"
|
||||
>Schedule:</A
|
||||
></H3
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> service.schedule.read_list([search criteria])
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.schedule.read(identifier,[fieldlist])
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.schedule.save(fields)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.schedule.delete(identifier)
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT2"
|
||||
><HR><H3
|
||||
CLASS="SECT2"
|
||||
><A
|
||||
NAME="AEN123"
|
||||
>Notes:</A
|
||||
></H3
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> service.notes.read_list([search criteria])
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.notes.read(identifier,[fieldlist])
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.notes.save(fields)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.notes.delete(identifier)
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT2"
|
||||
><HR><H3
|
||||
CLASS="SECT2"
|
||||
><A
|
||||
NAME="AEN134"
|
||||
>Todo:</A
|
||||
></H3
|
||||
><P
|
||||
></P
|
||||
><UL
|
||||
><LI
|
||||
><P
|
||||
> service.todo.read_list(search criteria)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.todo.read(identifer,[fieldlist])
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.todo.save(fields)
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
> service.todo.delete(identifier)
|
||||
</P
|
||||
></LI
|
||||
></UL
|
||||
></DIV
|
||||
></DIV
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
@ -1,403 +0,0 @@
|
||||
#LyX 1.1 created this file. For more info see http://www.lyx.org/
|
||||
\lyxformat 218
|
||||
\textclass docbook
|
||||
\language english
|
||||
\inputencoding auto
|
||||
\fontscheme default
|
||||
\graphics default
|
||||
\paperfontsize default
|
||||
\spacing single
|
||||
\papersize Default
|
||||
\paperpackage a4
|
||||
\use_geometry 0
|
||||
\use_amsmath 0
|
||||
\paperorientation portrait
|
||||
\secnumdepth 3
|
||||
\tocdepth 3
|
||||
\paragraph_separation indent
|
||||
\defskip medskip
|
||||
\quotes_language english
|
||||
\quotes_times 2
|
||||
\papercolumns 1
|
||||
\papersides 1
|
||||
\paperpagestyle default
|
||||
|
||||
\layout Title
|
||||
|
||||
Proposal for a Common Groupware Interface Standard
|
||||
\layout Author
|
||||
|
||||
(C) 2001-2004 Miles Lott <milos@groupwhere.org>
|
||||
\layout Date
|
||||
|
||||
September 13, 2001 and December 29, 2003
|
||||
\layout Standard
|
||||
|
||||
|
||||
\begin_inset LatexCommand \tableofcontents{}
|
||||
|
||||
\end_inset
|
||||
|
||||
|
||||
\layout Section
|
||||
|
||||
Scope
|
||||
\layout Standard
|
||||
|
||||
As many different opensource and freesoftware groupware systems are being
|
||||
developed, the full realization of the dream of a connected world should
|
||||
be prefaced by an agreement to interoperate.
|
||||
There are limited ways in which cooperation with these and commercial groupware
|
||||
systems may be achecived, the majority if not all of which were derived
|
||||
via the establishment of open standards.
|
||||
These might include email (POP3/IMAP), contacts(LDAP,vcard), or scheduling(ical
|
||||
/vcal).
|
||||
It is felt that while these have proven themselves to be very useful, they
|
||||
are insufficient to satisfy the real needs of a typical business environment.
|
||||
\layout Standard
|
||||
|
||||
This document hopes to provide a reasonable, if limited, recommendation
|
||||
for a set of standardized methods to be used for groupware services interaction.
|
||||
More specifically, it hopes to address the need for such a standard as
|
||||
well as to spur discussion about the common service names and methods themselve
|
||||
s.
|
||||
\layout Standard
|
||||
|
||||
Examples will be given for implementations in XML-RPC, since this standard
|
||||
is relatively fixed and open.
|
||||
\layout Standard
|
||||
|
||||
This document does not provide recommendations for the underlying access
|
||||
control system which would allow or deny a particular action.
|
||||
\layout Standard
|
||||
|
||||
Also not discussed here is login and authorization to be used for initial
|
||||
access to a service provider.
|
||||
\layout Section
|
||||
|
||||
The Services
|
||||
\layout Subsection
|
||||
|
||||
Overview
|
||||
\layout Standard
|
||||
|
||||
There are a few common services types that will be needed for minimum useability
|
||||
of a groupware server or application.
|
||||
They are:
|
||||
\layout Itemize
|
||||
|
||||
Contacts
|
||||
\layout Itemize
|
||||
|
||||
Schedule
|
||||
\layout Itemize
|
||||
|
||||
Notes
|
||||
\layout Itemize
|
||||
|
||||
Todo
|
||||
\layout Standard
|
||||
|
||||
These services are represented already in places such as existing groupware
|
||||
client-server applications and also in the PalmOS basic-4 buttons and applicati
|
||||
ons.
|
||||
Different systems may have different names for these services internally,
|
||||
e.g.
|
||||
Contacts - addresses, addressbook, people, Schedule - calendar, agenda,
|
||||
meetings.
|
||||
\layout Standard
|
||||
|
||||
Within each of these services are some common methods that would be called
|
||||
to store, retreive, or update data:
|
||||
\layout Itemize
|
||||
|
||||
read_list
|
||||
\layout Itemize
|
||||
|
||||
read
|
||||
\layout Itemize
|
||||
|
||||
save
|
||||
\layout Itemize
|
||||
|
||||
delete
|
||||
\layout Subsection
|
||||
|
||||
Detail
|
||||
\layout Subsubsection
|
||||
|
||||
Contacts
|
||||
\layout Standard
|
||||
|
||||
The concept of contacts may encompass local addressbooks, LDAP, and lists
|
||||
stored in other media.
|
||||
The purpose of the contacts service is not to duplicate or attempt to replace
|
||||
these.
|
||||
In some respects, it might do just that.
|
||||
But its goal is more so to provide a common and shareable way for the other
|
||||
core services to create, edit, and read a common user and address list.
|
||||
All of the other services may use the contact service to obtain record
|
||||
owner information to be used in access control.
|
||||
They would also use them when it is required to share this data, as with
|
||||
a meeting where other local and non-local users will be invited to attend.
|
||||
\layout Standard
|
||||
|
||||
Contacts may include the local installed user base, users on other cooperative
|
||||
servers, or email addresses used for limited cooperation with other groupware
|
||||
services that are not compliant with this service scheme or implementations
|
||||
thereof.
|
||||
It could also include individuals using web-based or local ISP email services.
|
||||
The scope of this document, however, is to define the service with regard
|
||||
to the common methods to be used for server-server and client-server communicat
|
||||
ions:
|
||||
\layout Itemize
|
||||
|
||||
read_list
|
||||
\layout Standard
|
||||
|
||||
This method is used to list contacts, with or without limits, filters, or
|
||||
search criteria.
|
||||
In this way it can be used for simple lists or to search for contact records
|
||||
and their identifiers.
|
||||
The optional search criteria includes:
|
||||
\layout Enumerate
|
||||
|
||||
start - Start at this identifier (integer: default 0)
|
||||
\layout Enumerate
|
||||
|
||||
limit - Limit to this number of records returned(integer: unlimited by default)
|
||||
\layout Enumerate
|
||||
|
||||
fieldlist - limit to showing only these fields (array: default to identifier,
|
||||
owner identifier, possibly firstname and lastname)
|
||||
\layout Enumerate
|
||||
|
||||
filter - Show records that are public or private only, or other system-specific
|
||||
filters, e.g group or company(string: default '')
|
||||
\layout Enumerate
|
||||
|
||||
query - Search internal fieldlist for a value (string: default '')
|
||||
\layout Standard
|
||||
|
||||
The return for this method includes:
|
||||
\layout Enumerate
|
||||
|
||||
count of number of records returned(integer)
|
||||
\layout Enumerate
|
||||
|
||||
array consisting of: array: identifier => (array: fieldlist key => value
|
||||
pairs)
|
||||
\layout Itemize
|
||||
|
||||
read
|
||||
\layout Standard
|
||||
|
||||
Once the identifier for a single contact record is known, the contact may
|
||||
be read for more detail using this method.
|
||||
This takes two parameters:
|
||||
\layout Enumerate
|
||||
|
||||
identifier - (integer: no default)
|
||||
\layout Enumerate
|
||||
|
||||
fieldlist - limit to showing only these fields (array: default to identifier,
|
||||
owner identifier, possibly firstname and lastname)
|
||||
\layout Standard
|
||||
|
||||
And returns:
|
||||
\layout Enumerate
|
||||
|
||||
array consisting of: array: identifier => (array: fieldlist key => value
|
||||
pairs)
|
||||
\layout Itemize
|
||||
|
||||
save
|
||||
\layout Standard
|
||||
|
||||
This is a method used to save an existing record or create a new one.
|
||||
If the identifier for an existing record is not passed, a new entry will
|
||||
be created.
|
||||
\layout Itemize
|
||||
|
||||
delete
|
||||
\layout Standard
|
||||
|
||||
This will allow deletion of a record by passing its identifier.
|
||||
\layout Subsubsection
|
||||
|
||||
Schedule
|
||||
\layout Subsubsection
|
||||
|
||||
Notes
|
||||
\layout Subsubsection
|
||||
|
||||
Todo
|
||||
\layout Subsection
|
||||
|
||||
Examples in XML-RPC
|
||||
\layout Standard
|
||||
|
||||
Query the contacts service for read_list, using only start and limit to
|
||||
grab the first 5 records, starting with identifier 1.
|
||||
Additionally, return only the firstname and lastname fields n_given and
|
||||
n_family (firstname and lastname in pseudo vcard format):
|
||||
\layout Code
|
||||
|
||||
<methodCall>
|
||||
\layout Code
|
||||
|
||||
<methodName>service.contacts.read_list</methodName>
|
||||
\layout Code
|
||||
|
||||
<params>
|
||||
\layout Code
|
||||
|
||||
<param>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>start</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>1</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>limit</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>5</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>fields</name>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>n_given</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>n_given</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>n_family</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>n_family</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>query</name>
|
||||
\layout Code
|
||||
|
||||
<value><string></string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>filter</name>
|
||||
\layout Code
|
||||
|
||||
<value><string></string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</param>
|
||||
\layout Code
|
||||
|
||||
</params>
|
||||
\layout Code
|
||||
|
||||
</methodCall>
|
||||
\layout Section
|
||||
|
||||
Conclusion
|
||||
\layout Standard
|
||||
|
||||
This document outlined the following services and methods:
|
||||
\layout Subsection
|
||||
|
||||
Contacts:
|
||||
\layout Itemize
|
||||
|
||||
service.contacts.read_list([search criteria])
|
||||
\layout Itemize
|
||||
|
||||
service.contacts.read(identifier,[fieldlist])
|
||||
\layout Itemize
|
||||
|
||||
service.contacts.save(fields)
|
||||
\layout Itemize
|
||||
|
||||
service.contacts.delete(identifier)
|
||||
\layout Subsection
|
||||
|
||||
Schedule:
|
||||
\layout Itemize
|
||||
|
||||
service.schedule.read_list([search criteria])
|
||||
\layout Itemize
|
||||
|
||||
service.schedule.read(identifier,[fieldlist])
|
||||
\layout Itemize
|
||||
|
||||
service.schedule.save(fields)
|
||||
\layout Itemize
|
||||
|
||||
service.schedule.delete(identifier)
|
||||
\layout Subsection
|
||||
|
||||
Notes:
|
||||
\layout Itemize
|
||||
|
||||
service.notes.read_list([search criteria])
|
||||
\layout Itemize
|
||||
|
||||
service.notes.read(identifier,[fieldlist])
|
||||
\layout Itemize
|
||||
|
||||
service.notes.save(fields)
|
||||
\layout Itemize
|
||||
|
||||
service.notes.delete(identifier)
|
||||
\layout Subsection
|
||||
|
||||
Todo:
|
||||
\layout Itemize
|
||||
|
||||
service.todo.read_list(search criteria)
|
||||
\layout Itemize
|
||||
|
||||
service.todo.read(identifer,[fieldlist])
|
||||
\layout Itemize
|
||||
|
||||
service.todo.save(fields)
|
||||
\layout Itemize
|
||||
|
||||
service.todo.delete(identifier)
|
||||
\the_end
|
Binary file not shown.
@ -1,397 +0,0 @@
|
||||
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN">
|
||||
|
||||
<article lang="en">
|
||||
<!-- DocBook file was created by LyX 1.1
|
||||
See http://www.lyx.org/ for more information -->
|
||||
<artheader>
|
||||
<title>
|
||||
Proposal for a Common Groupware Interface Standard
|
||||
</title>
|
||||
<author>
|
||||
(C) 2001-2004 Miles Lott <milos@groupwhere.org>
|
||||
</author>
|
||||
<date>
|
||||
September 13, 2001 and December 29, 2003
|
||||
</date>
|
||||
<para>
|
||||
<toc></toc>
|
||||
</para>
|
||||
</artheader>
|
||||
<sect1>
|
||||
<title>
|
||||
Scope
|
||||
</title>
|
||||
<para>
|
||||
As many different opensource and freesoftware groupware systems are being developed, the full realization of the dream of a connected world should be prefaced by an agreement to interoperate. There are limited ways in which cooperation with these and commercial groupware systems may be achecived, the majority if not all of which were derived via the establishment of open standards. These might include email (POP3/IMAP), contacts(LDAP,vcard), or scheduling(ical/vcal). It is felt that while these have proven themselves to be very useful, they are insufficient to satisfy the real needs of a typical business environment.
|
||||
</para>
|
||||
<para>
|
||||
This document hopes to provide a reasonable, if limited, recommendation for a set of standardized methods to be used for groupware services interaction. More specifically, it hopes to address the need for such a standard as well as to spur discussion about the common service names and methods themselves.
|
||||
</para>
|
||||
<para>
|
||||
Examples will be given for implementations in XML-RPC, since this standard is relatively fixed and open.
|
||||
</para>
|
||||
<para>
|
||||
This document does not provide recommendations for the underlying access control system which would allow or deny a particular action.
|
||||
</para>
|
||||
<para>
|
||||
Also not discussed here is login and authorization to be used for initial access to a service provider.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>
|
||||
The Services
|
||||
</title>
|
||||
<sect2>
|
||||
<title>
|
||||
Overview
|
||||
</title>
|
||||
<para>
|
||||
There are a few common services types that will be needed for minimum useability of a groupware server or application. They are:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Contacts
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Schedule
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Notes
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Todo
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
These services are represented already in places such as existing groupware client-server applications and also in the PalmOS basic-4 buttons and applications. Different systems may have different names for these services internally, e.g. Contacts - addresses, addressbook, people, Schedule - calendar, agenda, meetings.
|
||||
</para>
|
||||
<para>
|
||||
Within each of these services are some common methods that would be called to store, retreive, or update data:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
read_list
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
read
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
save
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
delete
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>
|
||||
Detail
|
||||
</title>
|
||||
<sect3>
|
||||
<title>
|
||||
Contacts
|
||||
</title>
|
||||
<para>
|
||||
The concept of contacts may encompass local addressbooks, LDAP, and lists stored in other media. The purpose of the contacts service is not to duplicate or attempt to replace these. In some respects, it might do just that. But its goal is more so to provide a common and shareable way for the other core services to create, edit, and read a common user and address list. All of the other services may use the contact service to obtain record owner information to be used in access control. They would also use them when it is required to share this data, as with a meeting where other local and non-local users will be invited to attend.
|
||||
</para>
|
||||
<para>
|
||||
Contacts may include the local installed user base, users on other cooperative servers, or email addresses used for limited cooperation with other groupware services that are not compliant with this service scheme or implementations thereof. It could also include individuals using web-based or local ISP email services. The scope of this document, however, is to define the service with regard to the common methods to be used for server-server and client-server communications:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
read_list
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
This method is used to list contacts, with or without limits, filters, or search criteria. In this way it can be used for simple lists or to search for contact records and their identifiers. The optional search criteria includes:
|
||||
</para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
start - Start at this identifier (integer: default 0)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
limit - Limit to this number of records returned(integer: unlimited by default)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
fieldlist - limit to showing only these fields (array: default to identifier, owner identifier, possibly firstname and lastname)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
filter - Show records that are public or private only, or other system-specific filters, e.g group or company(string: default '')
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
query - Search internal fieldlist for a value (string: default '')
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<para>
|
||||
The return for this method includes:
|
||||
</para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
count of number of records returned(integer)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
array consisting of: array: identifier => (array: fieldlist key => value pairs)
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
read
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Once the identifier for a single contact record is known, the contact may be read for more detail using this method. This takes two parameters:
|
||||
</para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
identifier - (integer: no default)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
fieldlist - limit to showing only these fields (array: default to identifier, owner identifier, possibly firstname and lastname)
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<para>
|
||||
And returns:
|
||||
</para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
array consisting of: array: identifier => (array: fieldlist key => value pairs)
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
save
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
This is a method used to save an existing record or create a new one. If the identifier for an existing record is not passed, a new entry will be created.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
delete
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
This will allow deletion of a record by passing its identifier.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>
|
||||
Schedule
|
||||
</title>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>
|
||||
Notes
|
||||
</title>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>
|
||||
Todo
|
||||
</title>
|
||||
</sect3>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>
|
||||
Examples in XML-RPC
|
||||
</title>
|
||||
<para>
|
||||
Query the contacts service for read_list, using only start and limit to grab the first 5 records, starting with identifier 1. Additionally, return only the firstname and lastname fields n_given and n_family (firstname and lastname in pseudo vcard format):
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<methodCall>
|
||||
]]><![ CDATA [<methodName>service.contacts.read_list</methodName>
|
||||
]]><![ CDATA [<params>
|
||||
]]><![ CDATA [<param>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>start</name>
|
||||
]]><![ CDATA [<value><string>1</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>limit</name>
|
||||
]]><![ CDATA [<value><string>5</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>fields</name>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>n_given</name>
|
||||
]]><![ CDATA [<value><string>n_given</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>n_family</name>
|
||||
]]><![ CDATA [<value><string>n_family</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>query</name>
|
||||
]]><![ CDATA [<value><string></string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>filter</name>
|
||||
]]><![ CDATA [<value><string></string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</param>
|
||||
]]><![ CDATA [</params>
|
||||
]]><![ CDATA [</methodCall>
|
||||
]]> </programlisting>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>
|
||||
Conclusion
|
||||
</title>
|
||||
<para>
|
||||
This document outlined the following services and methods:
|
||||
</para>
|
||||
<sect2>
|
||||
<title>
|
||||
Contacts:
|
||||
</title>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
service.contacts.read_list([search criteria])
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.contacts.read(identifier,[fieldlist])
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.contacts.save(fields)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.contacts.delete(identifier)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>
|
||||
Schedule:
|
||||
</title>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
service.schedule.read_list([search criteria])
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.schedule.read(identifier,[fieldlist])
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.schedule.save(fields)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.schedule.delete(identifier)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>
|
||||
Notes:
|
||||
</title>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
service.notes.read_list([search criteria])
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.notes.read(identifier,[fieldlist])
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.notes.save(fields)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.notes.delete(identifier)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>
|
||||
Todo:
|
||||
</title>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
service.todo.read_list(search criteria)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.todo.read(identifer,[fieldlist])
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.todo.save(fields)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
service.todo.delete(identifier)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
|
||||
</article>
|
@ -1,293 +0,0 @@
|
||||
|
||||
|
||||
Proposal for a Common Groupware Interface Standard
|
||||
|
||||
(C) 2001-2004 Miles Lott <milos@groupwhere.org>
|
||||
|
||||
September 13, 2001 and December 29, 2003
|
||||
|
||||
Table of Contents
|
||||
|
||||
1 Scope
|
||||
2 The Services
|
||||
2.1 Overview
|
||||
2.2 Detail
|
||||
2.2.1 Contacts
|
||||
2.2.2 Schedule
|
||||
2.2.3 Notes
|
||||
2.2.4 Todo
|
||||
2.3 Examples in XML-RPC
|
||||
3 Conclusion
|
||||
3.1 Contacts:
|
||||
3.2 Schedule:
|
||||
3.3 Notes:
|
||||
3.4 Todo:
|
||||
|
||||
|
||||
|
||||
1 Scope
|
||||
|
||||
As many different opensource and freesoftware groupware systems
|
||||
are being developed, the full realization of the dream of
|
||||
a connected world should be prefaced by an agreement to
|
||||
interoperate. There are limited ways in which cooperation
|
||||
with these and commercial groupware systems may be achecived,
|
||||
the majority if not all of which were derived via the establishment
|
||||
of open standards. These might include email (POP3/IMAP),
|
||||
contacts(LDAP,vcard), or scheduling(ical/vcal). It is felt
|
||||
that while these have proven themselves to be very useful,
|
||||
they are insufficient to satisfy the real needs of a typical
|
||||
business environment.
|
||||
|
||||
This document hopes to provide a reasonable, if limited,
|
||||
recommendation for a set of standardized methods to be used
|
||||
for groupware services interaction. More specifically, it
|
||||
hopes to address the need for such a standard as well as
|
||||
to spur discussion about the common service names and methods
|
||||
themselves.
|
||||
|
||||
Examples will be given for implementations in XML-RPC, since
|
||||
this standard is relatively fixed and open.
|
||||
|
||||
This document does not provide recommendations for the underlying
|
||||
access control system which would allow or deny a particular
|
||||
action.
|
||||
|
||||
Also not discussed here is login and authorization to be
|
||||
used for initial access to a service provider.
|
||||
|
||||
2 The Services
|
||||
|
||||
2.1 Overview
|
||||
|
||||
There are a few common services types that will be needed
|
||||
for minimum useability of a groupware server or application.
|
||||
They are:
|
||||
|
||||
* Contacts
|
||||
|
||||
* Schedule
|
||||
|
||||
* Notes
|
||||
|
||||
* Todo
|
||||
|
||||
These services are represented already in places such as
|
||||
existing groupware client-server applications and also in
|
||||
the PalmOS basic-4 buttons and applications. Different systems
|
||||
may have different names for these services internally,
|
||||
e.g. Contacts - addresses, addressbook, people, Schedule
|
||||
- calendar, agenda, meetings.
|
||||
|
||||
Within each of these services are some common methods that
|
||||
would be called to store, retreive, or update data:
|
||||
|
||||
* read_list
|
||||
|
||||
* read
|
||||
|
||||
* save
|
||||
|
||||
* delete
|
||||
|
||||
2.2 Detail
|
||||
|
||||
2.2.1 Contacts
|
||||
|
||||
The concept of contacts may encompass local addressbooks,
|
||||
LDAP, and lists stored in other media. The purpose of the
|
||||
contacts service is not to duplicate or attempt to replace
|
||||
these. In some respects, it might do just that. But its
|
||||
goal is more so to provide a common and shareable way for
|
||||
the other core services to create, edit, and read a common
|
||||
user and address list. All of the other services may use
|
||||
the contact service to obtain record owner information to
|
||||
be used in access control. They would also use them when
|
||||
it is required to share this data, as with a meeting where
|
||||
other local and non-local users will be invited to attend.
|
||||
|
||||
Contacts may include the local installed user base, users
|
||||
on other cooperative servers, or email addresses used for
|
||||
limited cooperation with other groupware services that are
|
||||
not compliant with this service scheme or implementations
|
||||
thereof. It could also include individuals using web-based
|
||||
or local ISP email services. The scope of this document,
|
||||
however, is to define the service with regard to the common
|
||||
methods to be used for server-server and client-server communications:
|
||||
|
||||
* read_list
|
||||
|
||||
This method is used to list contacts, with or without limits,
|
||||
filters, or search criteria. In this way it can be used
|
||||
for simple lists or to search for contact records and their
|
||||
identifiers. The optional search criteria includes:
|
||||
|
||||
1. start - Start at this identifier (integer: default 0)
|
||||
|
||||
2. limit - Limit to this number of records returned(integer:
|
||||
unlimited by default)
|
||||
|
||||
3. fieldlist - limit to showing only these fields (array:
|
||||
default to identifier, owner identifier, possibly firstname
|
||||
and lastname)
|
||||
|
||||
4. filter - Show records that are public or private only,
|
||||
or other system-specific filters, e.g group or company(string:
|
||||
default '')
|
||||
|
||||
5. query - Search internal fieldlist for a value (string:
|
||||
default '')
|
||||
|
||||
The return for this method includes:
|
||||
|
||||
1. count of number of records returned(integer)
|
||||
|
||||
2. array consisting of: array: identifier => (array: fieldlist
|
||||
key => value pairs)
|
||||
|
||||
* read
|
||||
|
||||
Once the identifier for a single contact record is known,
|
||||
the contact may be read for more detail using this method.
|
||||
This takes two parameters:
|
||||
|
||||
1. identifier - (integer: no default)
|
||||
|
||||
2. fieldlist - limit to showing only these fields (array:
|
||||
default to identifier, owner identifier, possibly firstname
|
||||
and lastname)
|
||||
|
||||
And returns:
|
||||
|
||||
1. array consisting of: array: identifier => (array: fieldlist
|
||||
key => value pairs)
|
||||
|
||||
* save
|
||||
|
||||
This is a method used to save an existing record or create
|
||||
a new one. If the identifier for an existing record is not
|
||||
passed, a new entry will be created.
|
||||
|
||||
* delete
|
||||
|
||||
This will allow deletion of a record by passing its identifier.
|
||||
|
||||
2.2.2 Schedule
|
||||
|
||||
2.2.3 Notes
|
||||
|
||||
2.2.4 Todo
|
||||
|
||||
2.3 Examples in XML-RPC
|
||||
|
||||
Query the contacts service for read_list, using only start
|
||||
and limit to grab the first 5 records, starting with identifier
|
||||
1. Additionally, return only the firstname and lastname
|
||||
fields n_given and n_family (firstname and lastname in pseudo
|
||||
vcard format):
|
||||
|
||||
<methodCall>
|
||||
|
||||
<methodName>service.contacts.read_list</methodName>
|
||||
|
||||
<params>
|
||||
|
||||
<param>
|
||||
|
||||
<value><struct>
|
||||
|
||||
<member><name>start</name>
|
||||
|
||||
<value><string>1</string></value>
|
||||
|
||||
</member>
|
||||
|
||||
<member><name>limit</name>
|
||||
|
||||
<value><string>5</string></value>
|
||||
|
||||
</member>
|
||||
|
||||
<member><name>fields</name>
|
||||
|
||||
<value><struct>
|
||||
|
||||
<member><name>n_given</name>
|
||||
|
||||
<value><string>n_given</string></value>
|
||||
|
||||
</member>
|
||||
|
||||
<member><name>n_family</name>
|
||||
|
||||
<value><string>n_family</string></value>
|
||||
|
||||
</member>
|
||||
|
||||
</struct></value>
|
||||
|
||||
</member>
|
||||
|
||||
<member><name>query</name>
|
||||
|
||||
<value><string></string></value>
|
||||
|
||||
</member>
|
||||
|
||||
<member><name>filter</name>
|
||||
|
||||
<value><string></string></value>
|
||||
|
||||
</member>
|
||||
|
||||
</struct></value>
|
||||
|
||||
</param>
|
||||
|
||||
</params>
|
||||
|
||||
</methodCall>
|
||||
|
||||
3 Conclusion
|
||||
|
||||
This document outlined the following services and methods:
|
||||
|
||||
3.1 Contacts:
|
||||
|
||||
* service.contacts.read_list([search criteria])
|
||||
|
||||
* service.contacts.read(identifier,[fieldlist])
|
||||
|
||||
* service.contacts.save(fields)
|
||||
|
||||
* service.contacts.delete(identifier)
|
||||
|
||||
3.2 Schedule:
|
||||
|
||||
* service.schedule.read_list([search criteria])
|
||||
|
||||
* service.schedule.read(identifier,[fieldlist])
|
||||
|
||||
* service.schedule.save(fields)
|
||||
|
||||
* service.schedule.delete(identifier)
|
||||
|
||||
3.3 Notes:
|
||||
|
||||
* service.notes.read_list([search criteria])
|
||||
|
||||
* service.notes.read(identifier,[fieldlist])
|
||||
|
||||
* service.notes.save(fields)
|
||||
|
||||
* service.notes.delete(identifier)
|
||||
|
||||
3.4 Todo:
|
||||
|
||||
* service.todo.read_list(search criteria)
|
||||
|
||||
* service.todo.read(identifer,[fieldlist])
|
||||
|
||||
* service.todo.save(fields)
|
||||
|
||||
* service.todo.delete(identifier)
|
@ -1,107 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
Perl interfacing to egroupware updated for Frontier-RPC-0.07b4:
|
||||
|
||||
The Frontier::RPC module available at CPAN is capable of logging into an
|
||||
egroupware server. To authenticate your session after the initial login,
|
||||
however, requires a patch to Frontier. This patch causes Frontier to create
|
||||
an Authentication header using username/password values. We use the assigned
|
||||
sessionid and kp3 for this.
|
||||
|
||||
NOTE: sessionid/kp3 values in this file are not valid.
|
||||
|
||||
TODO:
|
||||
|
||||
1. Apply the patch at the end of this file to Frontier-RPC-0.07b4.
|
||||
2. Install Frontier.
|
||||
3. Try the following method using rpc-client.pl in the examples subdirectory for
|
||||
the Frontier source:
|
||||
|
||||
rpc-client.pl \
|
||||
http://www.egroupware.org/egroupware/xmlrpc.php \
|
||||
system.login \
|
||||
"{domain => '',username => 'demo', password => 'guest'}"
|
||||
|
||||
4. Take the returned sessionid and kp3, e.g.:
|
||||
|
||||
$result = HASH(0x826d4b0)
|
||||
'domain' => 'default'
|
||||
'kp3' => 'e0219714614769x25bc92286016c60c2'
|
||||
'sessionid' => '36f9ec1e4ad78bxd8bc902b1c38d3e14'
|
||||
|
||||
5. Place these on the commandline for a new request, with sessionid for
|
||||
username and kp3 for password:
|
||||
|
||||
rpc-client.pl \
|
||||
http://www.egroupware.org/egroupware/xmlrpc.php \
|
||||
--username 36f9ec1e4ad78bxd8bc902b1c38d3e14 \
|
||||
--password e0219714614769x25bc92286016c60c2 \
|
||||
service.contacts.read \
|
||||
"{ id => '4'}"
|
||||
|
||||
6. This should return record #4 from the addressbook application.
|
||||
|
||||
Other requests may require different types on the command line, e.g.:
|
||||
|
||||
preferences.bosettings.read "addressbook,'','user'"
|
||||
|
||||
Here is the patch:
|
||||
|
||||
----CUT HERE----
|
||||
diff -aur Frontier-RPC-0.07b4/examples/rpc-client.pl Frontier-RPC-0.07b4-milos/examples/rpc-client.pl
|
||||
--- Frontier-RPC-0.07b4/examples/rpc-client.pl 1999-09-02 15:16:49.000000000 -0500
|
||||
+++ Frontier-RPC-0.07b4-milos/examples/rpc-client.pl 2005-07-30 05:25:36.309201144 -0500
|
||||
@@ -1,4 +1,4 @@
|
||||
-#
|
||||
+#!/usr/bin/perl
|
||||
# Copyright (C) 1998 Ken MacLeod
|
||||
# See the file COPYING for distribution terms.
|
||||
#
|
||||
@@ -59,7 +59,9 @@
|
||||
|
||||
GetOptions( 'debug' => \$debug,
|
||||
'encoding=s' => \$encoding,
|
||||
- 'proxy=s' => \$proxy );
|
||||
+ 'proxy=s' => \$proxy,
|
||||
+ 'username=s' => \$username,
|
||||
+ 'password=s' => \$password);
|
||||
|
||||
die "usage: rpc-client URL METHOD [\"ARGLIST\"]\n"
|
||||
if ($#ARGV != 1 && $#ARGV != 2);
|
||||
@@ -71,12 +73,18 @@
|
||||
$server = Frontier::Client->new( 'url' => $url,
|
||||
'debug' => $debug,
|
||||
'encoding' => $encoding,
|
||||
- 'proxy' => $proxy );
|
||||
+ 'proxy' => $proxy,
|
||||
+ 'username' => $username,
|
||||
+ 'password' => $password);
|
||||
+
|
||||
+use Data::Dumper;
|
||||
+print Dumper($server);
|
||||
|
||||
my @arglist;
|
||||
eval "\@arglist = ($arglist)";
|
||||
|
||||
$result = $server->call ($method, @arglist);
|
||||
+print Dumper($result);
|
||||
|
||||
-require 'dumpvar.pl';
|
||||
-dumpvar ('main', 'result');
|
||||
+#require 'dumpvar.pl';
|
||||
+#dumpvar ('main', 'result');
|
||||
diff -aur Frontier-RPC-0.07b4/lib/Frontier/Client.pm Frontier-RPC-0.07b4-milos/lib/Frontier/Client.pm
|
||||
--- Frontier-RPC-0.07b4/lib/Frontier/Client.pm 2002-08-02 19:48:06.000000000 -0500
|
||||
+++ Frontier-RPC-0.07b4-milos/lib/Frontier/Client.pm 2005-07-30 04:52:35.000000000 -0500
|
||||
@@ -42,6 +42,11 @@
|
||||
push @options, 'use_objects' => $self->{'use_objects'};
|
||||
}
|
||||
|
||||
+ if(defined $self->{'username'} and defined $self->{'password'})
|
||||
+ {
|
||||
+ use MIME::Base64;
|
||||
+ $self->{'rq'}->header('Authorization' => 'Basic ' . encode_base64($self->{'username'} . ":" . $self->{'password'}));
|
||||
+ }
|
||||
$self->{'enc'} = Frontier::RPC2->new(@options);
|
||||
|
||||
return $self;
|
@ -1,296 +0,0 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
> Business layer requests
|
||||
</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE=" eGroupWare XML-RPC/SOAP Methodology
|
||||
"
|
||||
HREF="phpgw_server.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE=" eGroupWare XML-RPC/SOAP Methodology
|
||||
"
|
||||
HREF="phpgw_server.html"><LINK
|
||||
REL="NEXT"
|
||||
TITLE=" More to come...
|
||||
"
|
||||
HREF="phpgw_server-2.html"></HEAD
|
||||
><BODY
|
||||
CLASS="SECT1"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>eGroupWare XML-RPC/SOAP Methodology</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="phpgw_server.html"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="phpgw_server-2.html"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="SECT1"
|
||||
><H1
|
||||
CLASS="SECT1"
|
||||
><A
|
||||
NAME="AEN33"
|
||||
>Business layer requests</A
|
||||
></H1
|
||||
><P
|
||||
> Once a successful login return packet has been received and sessionid/kp3 have been extracted, every subsequent packet sent to the egroupware server must be preceded by an Authorization header. Here is a sample header:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
>POST /egroupware/xmlrpc.php HTTP/1.0
|
||||
User-Agent: PHP XMLRPC 1.0
|
||||
Host: my.local.host
|
||||
Authorization: Basic ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYzAxZmY6NTU3YzkyYjBmNGE4ZDVlOTUzMzI2YmU2OTQyNjM3YjQ=
|
||||
Content-Type: text/xml
|
||||
Content-Length: 875
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> The longish string is a base64 encoding of the $sessionid . ':' . $kp3. For now this is our only supported authentication method. Additional methods would probably also affect the methodCalls. This is certainly open to discussion. Following is a typical request for some contact data:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>addressbook.boaddressbook.read_entries</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>start</name>
|
||||
<value><string>1</string></value>
|
||||
</member>
|
||||
<member><name>limit</name>
|
||||
<value><string>5</string></value>
|
||||
</member>
|
||||
<member><name>fields</name>
|
||||
<value><struct>
|
||||
<member><name>n_given</name>
|
||||
<value><string>n_given</string></value>
|
||||
</member>
|
||||
<member><name>n_family</name>
|
||||
<value><string>n_family</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</member>
|
||||
<member><name>query</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>filter</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>sort</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>order</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> Successful response:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><?xml version="1.0"?>
|
||||
<methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>0</name>
|
||||
<value><struct>
|
||||
<member><name>id</name>
|
||||
<value><string>1</string></value>
|
||||
</member>
|
||||
<member><name>lid</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>tid</name>
|
||||
<value><string>n</string></value>
|
||||
</member>
|
||||
<member><name>owner</name>
|
||||
<value><string>500</string></value>
|
||||
</member>
|
||||
<member><name>access</name>
|
||||
<value><string>private</string></value>
|
||||
</member>
|
||||
<member><name>cat_id</name>
|
||||
<value><string>1</string></value>
|
||||
</member>
|
||||
<member><name>n_given</name>
|
||||
<value><string>Alan</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</member>
|
||||
<member><name>1</name>
|
||||
<value><struct>
|
||||
<member><name>id</name>
|
||||
<value><string>2</string></value>
|
||||
</member>
|
||||
<member><name>lid</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>tid</name>
|
||||
<value><string>n</string></value>
|
||||
</member>
|
||||
<member><name>owner</name>
|
||||
<value><string>500</string></value>
|
||||
</member>
|
||||
<member><name>access</name>
|
||||
<value><string>private</string></value>
|
||||
</member>
|
||||
<member><name>cat_id</name>
|
||||
<value><string>1</string></value>
|
||||
</member>
|
||||
<member><name>n_given</name>
|
||||
<value><string>Andy</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</member>
|
||||
...
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> Unauthorized access attempt returns:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><string>UNAUTHORIZED</string></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="phpgw_server.html"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="phpgw_server.html"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="phpgw_server-2.html"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>eGroupWare XML-RPC/SOAP Methodology</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
> </TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>More to come...</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
@ -1,122 +0,0 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
> More to come...
|
||||
</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE=" eGoupWare XML-RPC/SOAP Methodology
|
||||
"
|
||||
HREF="phpgw_server.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE=" Business layer requests
|
||||
"
|
||||
HREF="phpgw_server-1.html"></HEAD
|
||||
><BODY
|
||||
CLASS="SECT1"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>eGoupWare XML-RPC/SOAP Methodology</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="phpgw_server-1.html"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
> </TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="SECT1"
|
||||
><H1
|
||||
CLASS="SECT1"
|
||||
><A
|
||||
NAME="AEN43"
|
||||
>More to come...</A
|
||||
></H1
|
||||
><P
|
||||
> Documenting every single call will be difficult, but should be done. In leiu of this, please see the class.bo{APPNAME}.inc.php files in each application/inc directory in the egroupware cvs. In this file will be a list_methods() function, which returns the information to the server about input/output structure for each call. If the file does not have this function, then it is not yet workable via this interface. As for the actual functions, they are also in this file. Generally, they will all accept associative array input and return same, but not always. This code is in flux, have fun.
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="phpgw_server-1.html"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="phpgw_server.html"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
> </TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>Business layer requests</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
> </TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
> </TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
Binary file not shown.
@ -1,305 +0,0 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
> eGroupWare XML-RPC/SOAP Methodology
|
||||
</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
|
||||
"><LINK
|
||||
REL="NEXT"
|
||||
TITLE=" Business layer requests
|
||||
"
|
||||
HREF="phpgw_server-1.html"></HEAD
|
||||
><BODY
|
||||
CLASS="ARTICLE"
|
||||
><DIV
|
||||
CLASS="ARTICLE"
|
||||
><DIV
|
||||
CLASS="TITLEPAGE"
|
||||
><H1
|
||||
CLASS="TITLE"
|
||||
><A
|
||||
NAME="AEN2"
|
||||
>eGroupWare XML-RPC/SOAP Methodology</A
|
||||
></H1
|
||||
><H3
|
||||
CLASS="AUTHOR"
|
||||
><A
|
||||
NAME="AEN4"
|
||||
></A
|
||||
></H3
|
||||
><HR></DIV
|
||||
><DIV
|
||||
CLASS="SECT1"
|
||||
><H1
|
||||
CLASS="SECT1"
|
||||
><A
|
||||
NAME="AEN8"
|
||||
>System level requests</A
|
||||
></H1
|
||||
><DIV
|
||||
CLASS="SECT2"
|
||||
><H2
|
||||
CLASS="SECT2"
|
||||
><A
|
||||
NAME="AEN10"
|
||||
>Login and authentication</A
|
||||
></H2
|
||||
><P
|
||||
> Authentication for user logins is handled internally no differently than for the typical eGroupWare login via web browser. Server logins, added for XML-RPC and SOAP, are only slightly different. For either protocol, user and server login and authentication and subsequent requests are handled by their respective server apps, xmlrpc.php and soap.php. A server is identified by a custom HTTP header, without which a normal user login will be undertaken.
|
||||
</P
|
||||
><P
|
||||
> A client or server sends the appropriate XML-RPC or SOAP packet containing host, user, and password information to the phpgw server. The server then assigns a sessionid and key, which is returned to the client in the appropriate format.
|
||||
</P
|
||||
><P
|
||||
> Our current method for authenticating requests after successful login is via the Authorization: Basic HTTP header to be sent by the client or requesting server. The format of this header is a base64 encoding of the assigned sessionid and kp3 variables, seperated by a ':'.
|
||||
</P
|
||||
><P
|
||||
> Further security may be obtained by using SSL on the client and server. In the future, we may encrypt/descrypt the data on either end, or at least provide this as an option. The sessionid and key variables will make this possible, and relatively secure.
|
||||
</P
|
||||
><DIV
|
||||
CLASS="SECT3"
|
||||
><H3
|
||||
CLASS="SECT3"
|
||||
><A
|
||||
NAME="AEN16"
|
||||
>system.login</A
|
||||
></H3
|
||||
><P
|
||||
> The first request a client will make is the system.login method. Here is a sample of a server login packet in XML-RPC:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>system.login</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>server_name</name>
|
||||
<value><string>my.host.name</string></value>
|
||||
</member>
|
||||
<member><name>username</name>
|
||||
<value><string>bubba</string></value>
|
||||
</member>
|
||||
<member><name>password</name>
|
||||
<value><string>gump</string></value>
|
||||
</member> </struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> And the same in SOAP:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><?xml version="1.0"?>
|
||||
<SOAP-ENV:Envelope
|
||||
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:si="http://soapinterop.org/xsd"
|
||||
xmlns:ns6="http://soapinterop.org" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<SOAP-ENV:Body> <ns6:system_login>
|
||||
<server_name xsi:type=":string">my.host.name</server_name>
|
||||
<username xsi:type=":string">bubba</username>
|
||||
<password xsi:type=":string">gump</password>
|
||||
</ns6:system_login>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> The same style of packet would be required for a user/client login. A successful login should yield the following reply:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>sessionid</name>
|
||||
<value><string>cf5c5534307562fc57915608377db007</string></value>
|
||||
</member>
|
||||
<member><name>kp3</name>
|
||||
<value><string>2fe54daa11c8d52116788aa3f93cb70e</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> And a failed login:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>GOAWAY</name>
|
||||
<value><string>XOXO</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> eqweqw
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="SECT3"
|
||||
><H3
|
||||
CLASS="SECT3"
|
||||
><A
|
||||
NAME="AEN27"
|
||||
>system.logout</A
|
||||
></H3
|
||||
><P
|
||||
> Logout:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>system.logout</methodName>
|
||||
<params> <param>
|
||||
<value><struct>
|
||||
<member><name>sessionid</name>
|
||||
<value><string>ea35cac53d2c12bd05caecd97304478a</string></value>
|
||||
</member>
|
||||
<member><name>kp3</name>
|
||||
<value><string>4f2b256e0da4e7cbbebaac9f1fc8ca4a</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> Logout worked:
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><PRE
|
||||
CLASS="PROGRAMLISTING"
|
||||
><methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>GOODBYE</name>
|
||||
<value><string>XOXO</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>
|
||||
</PRE
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></DIV
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
> </TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
> </TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="phpgw_server-1.html"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
> </TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
> </TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>Business layer requests</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
@ -1,713 +0,0 @@
|
||||
#LyX 1.1 created this file. For more info see http://www.lyx.org/
|
||||
\lyxformat 218
|
||||
\textclass docbook
|
||||
\language english
|
||||
\inputencoding auto
|
||||
\fontscheme default
|
||||
\graphics default
|
||||
\paperfontsize default
|
||||
\spacing single
|
||||
\papersize Default
|
||||
\paperpackage a4
|
||||
\use_geometry 0
|
||||
\use_amsmath 0
|
||||
\paperorientation portrait
|
||||
\secnumdepth 3
|
||||
\tocdepth 3
|
||||
\paragraph_separation indent
|
||||
\defskip medskip
|
||||
\quotes_language english
|
||||
\quotes_times 2
|
||||
\papercolumns 1
|
||||
\papersides 1
|
||||
\paperpagestyle default
|
||||
|
||||
\layout Title
|
||||
|
||||
eGroupWare XML-RPC/SOAP Methodology
|
||||
\layout Author
|
||||
|
||||
(C) 2001-2004 Miles Lott
|
||||
\layout Author
|
||||
|
||||
milos@groupwhere.org
|
||||
\layout Date
|
||||
|
||||
August 23, 2001 and December 29, 2003
|
||||
\layout Standard
|
||||
|
||||
additions made September 3, 2001.
|
||||
\layout Standard
|
||||
|
||||
This document is very preliminary, but describes a working system.
|
||||
\layout Section
|
||||
|
||||
System level requests
|
||||
\layout Subsection
|
||||
|
||||
Login and authentication
|
||||
\layout Standard
|
||||
|
||||
Authentication for user logins is handled internally no differently than
|
||||
for the typical eGroupWare login via web browser.
|
||||
Server logins, added for XML-RPC and SOAP, are only slightly different.
|
||||
For either protocol, user and server login and authentication and subsequent
|
||||
requests are handled by their respective server apps, xmlrpc.php and soap.php.
|
||||
A server is identified by a custom HTTP header, without which a normal
|
||||
user login will be undertaken.
|
||||
\layout Standard
|
||||
|
||||
A client or server sends the appropriate XML-RPC or SOAP packet containing
|
||||
host, user, and password information to the phpgw server.
|
||||
The server then assigns a sessionid and key, which is returned to the client
|
||||
in the appropriate format.
|
||||
\layout Standard
|
||||
|
||||
Our current method for authenticating requests after successful login is
|
||||
via the Authorization: Basic HTTP header to be sent by the client or requesting
|
||||
server.
|
||||
The format of this header is a base64 encoding of the assigned sessionid
|
||||
and kp3 variables, seperated by a ':'.
|
||||
\layout Standard
|
||||
|
||||
Further security may be obtained by using SSL on the client and server.
|
||||
In the future, we may encrypt/descrypt the data on either end, or at least
|
||||
provide this as an option.
|
||||
The sessionid and key variables will make this possible, and relatively
|
||||
secure.
|
||||
\layout Subsubsection
|
||||
|
||||
system.login
|
||||
\layout Standard
|
||||
|
||||
The first request a client will make is the system.login method.
|
||||
Here is a sample of a server login packet in XML-RPC:
|
||||
\layout Code
|
||||
|
||||
<?xml version="1.0"?>
|
||||
\layout Code
|
||||
|
||||
<methodCall>
|
||||
\layout Code
|
||||
|
||||
<methodName>system.login</methodName>
|
||||
\layout Code
|
||||
|
||||
<params>
|
||||
\layout Code
|
||||
|
||||
<param>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>server_name</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>my.host.name</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>username</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>bubba</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>password</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>gump</string></value>
|
||||
\layout Code
|
||||
|
||||
</member> </struct></value>
|
||||
\layout Code
|
||||
|
||||
</param>
|
||||
\layout Code
|
||||
|
||||
</params>
|
||||
\layout Code
|
||||
|
||||
</methodCall>
|
||||
\layout Standard
|
||||
|
||||
And the same in SOAP:
|
||||
\layout Code
|
||||
|
||||
<?xml version="1.0"?>
|
||||
\layout Code
|
||||
|
||||
<SOAP-ENV:Envelope
|
||||
\layout Code
|
||||
|
||||
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.
|
||||
org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"
|
||||
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:si="http://soapi
|
||||
nterop.org/xsd"
|
||||
\layout Code
|
||||
|
||||
xmlns:ns6="http://soapinterop.org" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.o
|
||||
rg/soap/encoding/">
|
||||
\layout Code
|
||||
|
||||
<SOAP-ENV:Body> <ns6:system_login>
|
||||
\layout Code
|
||||
|
||||
<server_name xsi:type=":string">my.host.name</server_name>
|
||||
\layout Code
|
||||
|
||||
<username xsi:type=":string">bubba</username>
|
||||
\layout Code
|
||||
|
||||
<password xsi:type=":string">gump</password>
|
||||
\layout Code
|
||||
|
||||
</ns6:system_login>
|
||||
\layout Code
|
||||
|
||||
</SOAP-ENV:Body>
|
||||
\layout Code
|
||||
|
||||
</SOAP-ENV:Envelope>
|
||||
\layout Standard
|
||||
|
||||
The same style of packet would be required for a user/client login.
|
||||
A successful login should yield the following reply:
|
||||
\layout Code
|
||||
|
||||
<methodResponse>
|
||||
\layout Code
|
||||
|
||||
<params>
|
||||
\layout Code
|
||||
|
||||
<param>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>sessionid</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>cf5c5534307562fc57915608377db007</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>kp3</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>2fe54daa11c8d52116788aa3f93cb70e</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</param>
|
||||
\layout Code
|
||||
|
||||
</params>
|
||||
\layout Code
|
||||
|
||||
</methodResponse>
|
||||
\layout Standard
|
||||
|
||||
And a failed login:
|
||||
\layout Code
|
||||
|
||||
<methodResponse>
|
||||
\layout Code
|
||||
|
||||
<params>
|
||||
\layout Code
|
||||
|
||||
<param>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>GOAWAY</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>XOXO</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</param>
|
||||
\layout Code
|
||||
|
||||
</params>
|
||||
\layout Code
|
||||
|
||||
</methodResponse>
|
||||
\layout Standard
|
||||
|
||||
eqweqw
|
||||
\layout Subsubsection
|
||||
|
||||
system.logout
|
||||
\layout Standard
|
||||
|
||||
Logout:
|
||||
\layout Code
|
||||
|
||||
<?xml version="1.0"?>
|
||||
\layout Code
|
||||
|
||||
<methodCall>
|
||||
\layout Code
|
||||
|
||||
<methodName>system.logout</methodName>
|
||||
\layout Code
|
||||
|
||||
<params> <param>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>sessionid</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>ea35cac53d2c12bd05caecd97304478a</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>kp3</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>4f2b256e0da4e7cbbebaac9f1fc8ca4a</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</param>
|
||||
\layout Code
|
||||
|
||||
</params>
|
||||
\layout Code
|
||||
|
||||
</methodCall>
|
||||
\layout Standard
|
||||
|
||||
Logout worked:
|
||||
\layout Code
|
||||
|
||||
<methodResponse>
|
||||
\layout Code
|
||||
|
||||
<params>
|
||||
\layout Code
|
||||
|
||||
<param>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>GOODBYE</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>XOXO</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</param>
|
||||
\layout Code
|
||||
|
||||
</params>
|
||||
\layout Code
|
||||
|
||||
</methodResponse>
|
||||
\layout Section
|
||||
|
||||
Business layer requests
|
||||
\layout Standard
|
||||
|
||||
Once a successful login return packet has been received and sessionid/kp3
|
||||
have been extracted, every subsequent packet sent to the egroupware server
|
||||
must be preceded by an Authorization header.
|
||||
Here is a sample header:
|
||||
\layout Code
|
||||
|
||||
POST /egroupware/xmlrpc.php HTTP/1.0
|
||||
\layout Code
|
||||
|
||||
User-Agent: PHP XMLRPC 1.0
|
||||
\layout Code
|
||||
|
||||
Host: my.local.host
|
||||
\layout Code
|
||||
|
||||
Authorization: Basic ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYzAxZmY6NTU3YzkyYjBmNGE
|
||||
4ZDVlOTUzMzI2YmU2OTQyNjM3YjQ=
|
||||
\layout Code
|
||||
|
||||
Content-Type: text/xml
|
||||
\layout Code
|
||||
|
||||
Content-Length: 875
|
||||
\layout Standard
|
||||
|
||||
The longish string is a base64 encoding of the $sessionid .
|
||||
':' .
|
||||
$kp3.
|
||||
For now this is our only supported authentication method.
|
||||
Additional methods would probably also affect the methodCalls.
|
||||
This is certainly open to discussion.
|
||||
Following is a typical request for some contact data:
|
||||
\layout Code
|
||||
|
||||
<?xml version="1.0"?>
|
||||
\layout Code
|
||||
|
||||
<methodCall>
|
||||
\layout Code
|
||||
|
||||
<methodName>addressbook.boaddressbook.read_entries</methodName>
|
||||
\layout Code
|
||||
|
||||
<params>
|
||||
\layout Code
|
||||
|
||||
<param>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>start</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>1</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>limit</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>5</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>fields</name>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>n_given</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>n_given</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>n_family</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>n_family</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>query</name>
|
||||
\layout Code
|
||||
|
||||
<value><string></string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>filter</name>
|
||||
\layout Code
|
||||
|
||||
<value><string></string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>sort</name>
|
||||
\layout Code
|
||||
|
||||
<value><string></string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>order</name>
|
||||
\layout Code
|
||||
|
||||
<value><string></string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</param>
|
||||
\layout Code
|
||||
|
||||
</params>
|
||||
\layout Code
|
||||
|
||||
</methodCall>
|
||||
\layout Standard
|
||||
|
||||
Successful response:
|
||||
\layout Code
|
||||
|
||||
<?xml version="1.0"?>
|
||||
\layout Code
|
||||
|
||||
<methodResponse>
|
||||
\layout Code
|
||||
|
||||
<params>
|
||||
\layout Code
|
||||
|
||||
<param>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>0</name>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>id</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>1</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>lid</name>
|
||||
\layout Code
|
||||
|
||||
<value><string></string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>tid</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>n</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>owner</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>500</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>access</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>private</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>cat_id</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>1</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>n_given</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>Alan</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>1</name>
|
||||
\layout Code
|
||||
|
||||
<value><struct>
|
||||
\layout Code
|
||||
|
||||
<member><name>id</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>2</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>lid</name>
|
||||
\layout Code
|
||||
|
||||
<value><string></string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>tid</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>n</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>owner</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>500</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>access</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>private</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>cat_id</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>1</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
<member><name>n_given</name>
|
||||
\layout Code
|
||||
|
||||
<value><string>Andy</string></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
</struct></value>
|
||||
\layout Code
|
||||
|
||||
</member>
|
||||
\layout Code
|
||||
|
||||
...
|
||||
\layout Standard
|
||||
|
||||
Unauthorized access attempt returns:
|
||||
\layout Code
|
||||
|
||||
<methodResponse>
|
||||
\layout Code
|
||||
|
||||
<params>
|
||||
\layout Code
|
||||
|
||||
<param>
|
||||
\layout Code
|
||||
|
||||
<value><string>UNAUTHORIZED</string></value>
|
||||
\layout Code
|
||||
|
||||
</param>
|
||||
\layout Code
|
||||
|
||||
</params>
|
||||
\layout Code
|
||||
|
||||
</methodResponse>
|
||||
\layout Section
|
||||
|
||||
More to come...
|
||||
\layout Standard
|
||||
|
||||
Documenting every single call will be difficult, but should be done.
|
||||
In leiu of this, please see the class.bo{APPNAME}.inc.php files in each applicatio
|
||||
n/inc directory in the egroupware cvs.
|
||||
In this file will be a list_methods() function, which returns the information
|
||||
to the server about input/output structure for each call.
|
||||
If the file does not have this function, then it is not yet workable via
|
||||
this interface.
|
||||
As for the actual functions, they are also in this file.
|
||||
Generally, they will all accept associative array input and return same,
|
||||
but not always.
|
||||
This code is in flux, have fun.
|
||||
\the_end
|
Binary file not shown.
@ -1,568 +0,0 @@
|
||||
%!PS-Adobe-2.0
|
||||
%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software
|
||||
%%Title: phpgw_server.dvi
|
||||
%%Pages: 6
|
||||
%%PageOrder: Ascend
|
||||
%%BoundingBox: 0 0 612 792
|
||||
%%DocumentFonts: Helvetica-Bold Times-Roman Courier Times-Italic
|
||||
%%EndComments
|
||||
%DVIPSWebPage: (www.radicaleye.com)
|
||||
%DVIPSCommandLine: dvips -t letter -o phpgw_server.ps phpgw_server.dvi
|
||||
%DVIPSParameters: dpi=600, compressed
|
||||
%DVIPSSource: TeX output 2003.12.28:0956
|
||||
%%BeginProcSet: texc.pro
|
||||
%!
|
||||
/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
|
||||
N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
|
||||
mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
|
||||
0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
|
||||
landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
|
||||
mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
|
||||
matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
|
||||
exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
|
||||
statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
|
||||
N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
|
||||
/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
|
||||
/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
|
||||
array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
|
||||
df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
|
||||
definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
|
||||
}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
|
||||
B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
|
||||
1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
|
||||
1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
|
||||
0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
|
||||
sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
|
||||
rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
|
||||
gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
|
||||
/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
|
||||
/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
|
||||
A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
|
||||
get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
|
||||
ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
|
||||
fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
|
||||
{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
|
||||
chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
|
||||
1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
|
||||
forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
|
||||
/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
|
||||
}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
|
||||
bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
|
||||
mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
|
||||
SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
|
||||
userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
|
||||
1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
|
||||
index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
|
||||
/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
|
||||
/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
|
||||
(LaserWriter 16/600)]{A length product length le{A length product exch 0
|
||||
exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
|
||||
end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
|
||||
grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
|
||||
imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
|
||||
exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
|
||||
fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
|
||||
delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
|
||||
B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
|
||||
p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
|
||||
rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
|
||||
|
||||
%%EndProcSet
|
||||
%%BeginProcSet: 8r.enc
|
||||
% @@psencodingfile@{
|
||||
% author = "S. Rahtz, P. MacKay, Alan Jeffrey, B. Horn, K. Berry",
|
||||
% version = "0.6",
|
||||
% date = "22 June 1996",
|
||||
% filename = "8r.enc",
|
||||
% email = "kb@@mail.tug.org",
|
||||
% address = "135 Center Hill Rd. // Plymouth, MA 02360",
|
||||
% codetable = "ISO/ASCII",
|
||||
% checksum = "119 662 4424",
|
||||
% docstring = "Encoding for TrueType or Type 1 fonts to be used with TeX."
|
||||
% @}
|
||||
%
|
||||
% Idea is to have all the characters normally included in Type 1 fonts
|
||||
% available for typesetting. This is effectively the characters in Adobe
|
||||
% Standard Encoding + ISO Latin 1 + extra characters from Lucida.
|
||||
%
|
||||
% Character code assignments were made as follows:
|
||||
%
|
||||
% (1) the Windows ANSI characters are almost all in their Windows ANSI
|
||||
% positions, because some Windows users cannot easily reencode the
|
||||
% fonts, and it makes no difference on other systems. The only Windows
|
||||
% ANSI characters not available are those that make no sense for
|
||||
% typesetting -- rubout (127 decimal), nobreakspace (160), softhyphen
|
||||
% (173). quotesingle and grave are moved just because it's such an
|
||||
% irritation not having them in TeX positions.
|
||||
%
|
||||
% (2) Remaining characters are assigned arbitrarily to the lower part
|
||||
% of the range, avoiding 0, 10 and 13 in case we meet dumb software.
|
||||
%
|
||||
% (3) Y&Y Lucida Bright includes some extra text characters; in the
|
||||
% hopes that other PostScript fonts, perhaps created for public
|
||||
% consumption, will include them, they are included starting at 0x12.
|
||||
%
|
||||
% (4) Remaining positions left undefined are for use in (hopefully)
|
||||
% upward-compatible revisions, if someday more characters are generally
|
||||
% available.
|
||||
%
|
||||
% (5) hyphen appears twice for compatibility with both ASCII and Windows.
|
||||
%
|
||||
/TeXBase1Encoding [
|
||||
% 0x00 (encoded characters from Adobe Standard not in Windows 3.1)
|
||||
/.notdef /dotaccent /fi /fl
|
||||
/fraction /hungarumlaut /Lslash /lslash
|
||||
/ogonek /ring /.notdef
|
||||
/breve /minus /.notdef
|
||||
% These are the only two remaining unencoded characters, so may as
|
||||
% well include them.
|
||||
/Zcaron /zcaron
|
||||
% 0x10
|
||||
/caron /dotlessi
|
||||
% (unusual TeX characters available in, e.g., Lucida Bright)
|
||||
/dotlessj /ff /ffi /ffl
|
||||
/.notdef /.notdef /.notdef /.notdef
|
||||
/.notdef /.notdef /.notdef /.notdef
|
||||
% very contentious; it's so painful not having quoteleft and quoteright
|
||||
% at 96 and 145 that we move the things normally found there down to here.
|
||||
/grave /quotesingle
|
||||
% 0x20 (ASCII begins)
|
||||
/space /exclam /quotedbl /numbersign
|
||||
/dollar /percent /ampersand /quoteright
|
||||
/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash
|
||||
% 0x30
|
||||
/zero /one /two /three /four /five /six /seven
|
||||
/eight /nine /colon /semicolon /less /equal /greater /question
|
||||
% 0x40
|
||||
/at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O
|
||||
% 0x50
|
||||
/P /Q /R /S /T /U /V /W
|
||||
/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore
|
||||
% 0x60
|
||||
/quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o
|
||||
% 0x70
|
||||
/p /q /r /s /t /u /v /w
|
||||
/x /y /z /braceleft /bar /braceright /asciitilde
|
||||
/.notdef % rubout; ASCII ends
|
||||
% 0x80
|
||||
/.notdef /.notdef /quotesinglbase /florin
|
||||
/quotedblbase /ellipsis /dagger /daggerdbl
|
||||
/circumflex /perthousand /Scaron /guilsinglleft
|
||||
/OE /.notdef /.notdef /.notdef
|
||||
% 0x90
|
||||
/.notdef /.notdef /.notdef /quotedblleft
|
||||
/quotedblright /bullet /endash /emdash
|
||||
/tilde /trademark /scaron /guilsinglright
|
||||
/oe /.notdef /.notdef /Ydieresis
|
||||
% 0xA0
|
||||
/.notdef % nobreakspace
|
||||
/exclamdown /cent /sterling
|
||||
/currency /yen /brokenbar /section
|
||||
/dieresis /copyright /ordfeminine /guillemotleft
|
||||
/logicalnot
|
||||
/hyphen % Y&Y (also at 45); Windows' softhyphen
|
||||
/registered
|
||||
/macron
|
||||
% 0xD0
|
||||
/degree /plusminus /twosuperior /threesuperior
|
||||
/acute /mu /paragraph /periodcentered
|
||||
/cedilla /onesuperior /ordmasculine /guillemotright
|
||||
/onequarter /onehalf /threequarters /questiondown
|
||||
% 0xC0
|
||||
/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla
|
||||
/Egrave /Eacute /Ecircumflex /Edieresis
|
||||
/Igrave /Iacute /Icircumflex /Idieresis
|
||||
% 0xD0
|
||||
/Eth /Ntilde /Ograve /Oacute
|
||||
/Ocircumflex /Otilde /Odieresis /multiply
|
||||
/Oslash /Ugrave /Uacute /Ucircumflex
|
||||
/Udieresis /Yacute /Thorn /germandbls
|
||||
% 0xE0
|
||||
/agrave /aacute /acircumflex /atilde
|
||||
/adieresis /aring /ae /ccedilla
|
||||
/egrave /eacute /ecircumflex /edieresis
|
||||
/igrave /iacute /icircumflex /idieresis
|
||||
% 0xF0
|
||||
/eth /ntilde /ograve /oacute
|
||||
/ocircumflex /otilde /odieresis /divide
|
||||
/oslash /ugrave /uacute /ucircumflex
|
||||
/udieresis /yacute /thorn /ydieresis
|
||||
] def
|
||||
|
||||
%%EndProcSet
|
||||
%%BeginProcSet: texps.pro
|
||||
%!
|
||||
TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2
|
||||
index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll
|
||||
exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]/Metrics
|
||||
exch def dict begin Encoding{exch dup type/integertype ne{pop pop 1 sub
|
||||
dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get div def}
|
||||
ifelse}forall Metrics/Metrics currentdict end def[2 index currentdict
|
||||
end definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{
|
||||
dup sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1
|
||||
roll mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def
|
||||
dup[exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}
|
||||
if}forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}
|
||||
def end
|
||||
|
||||
%%EndProcSet
|
||||
%%BeginProcSet: special.pro
|
||||
%!
|
||||
TeXDict begin/SDict 200 dict N SDict begin/@SpecialDefaults{/hs 612 N
|
||||
/vs 792 N/ho 0 N/vo 0 N/hsc 1 N/vsc 1 N/ang 0 N/CLIP 0 N/rwiSeen false N
|
||||
/rhiSeen false N/letter{}N/note{}N/a4{}N/legal{}N}B/@scaleunit 100 N
|
||||
/@hscale{@scaleunit div/hsc X}B/@vscale{@scaleunit div/vsc X}B/@hsize{
|
||||
/hs X/CLIP 1 N}B/@vsize{/vs X/CLIP 1 N}B/@clip{/CLIP 2 N}B/@hoffset{/ho
|
||||
X}B/@voffset{/vo X}B/@angle{/ang X}B/@rwi{10 div/rwi X/rwiSeen true N}B
|
||||
/@rhi{10 div/rhi X/rhiSeen true N}B/@llx{/llx X}B/@lly{/lly X}B/@urx{
|
||||
/urx X}B/@ury{/ury X}B/magscale true def end/@MacSetUp{userdict/md known
|
||||
{userdict/md get type/dicttype eq{userdict begin md length 10 add md
|
||||
maxlength ge{/md md dup length 20 add dict copy def}if end md begin
|
||||
/letter{}N/note{}N/legal{}N/od{txpose 1 0 mtx defaultmatrix dtransform S
|
||||
atan/pa X newpath clippath mark{transform{itransform moveto}}{transform{
|
||||
itransform lineto}}{6 -2 roll transform 6 -2 roll transform 6 -2 roll
|
||||
transform{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll
|
||||
curveto}}{{closepath}}pathforall newpath counttomark array astore/gc xdf
|
||||
pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}
|
||||
if}N/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1
|
||||
-1 scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3
|
||||
get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip
|
||||
yflip not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub
|
||||
neg 0 TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{
|
||||
noflips{TR pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop
|
||||
90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get
|
||||
neg sub neg TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr
|
||||
1 get neg sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr
|
||||
2 get ppr 0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4
|
||||
-1 roll add 2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S
|
||||
TR}if}N/cp{pop pop showpage pm restore}N end}if}if}N/normalscale{
|
||||
Resolution 72 div VResolution 72 div neg scale magscale{DVImag dup scale
|
||||
}if 0 setgray}N/psfts{S 65781.76 div N}N/startTexFig{/psf$SavedState
|
||||
save N userdict maxlength dict begin/magscale true def normalscale
|
||||
currentpoint TR/psf$ury psfts/psf$urx psfts/psf$lly psfts/psf$llx psfts
|
||||
/psf$y psfts/psf$x psfts currentpoint/psf$cy X/psf$cx X/psf$sx psf$x
|
||||
psf$urx psf$llx sub div N/psf$sy psf$y psf$ury psf$lly sub div N psf$sx
|
||||
psf$sy scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub
|
||||
TR/showpage{}N/erasepage{}N/copypage{}N/p 3 def @MacSetUp}N/doclip{
|
||||
psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2
|
||||
roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath
|
||||
moveto}N/endTexFig{end psf$SavedState restore}N/@beginspecial{SDict
|
||||
begin/SpecialSave save N gsave normalscale currentpoint TR
|
||||
@SpecialDefaults count/ocount X/dcount countdictstack N}N/@setspecial{
|
||||
CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto
|
||||
closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx
|
||||
sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR
|
||||
}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse
|
||||
CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury
|
||||
lineto closepath clip}if/showpage{}N/erasepage{}N/copypage{}N newpath}N
|
||||
/@endspecial{count ocount sub{pop}repeat countdictstack dcount sub{end}
|
||||
repeat grestore SpecialSave restore end}N/@defspecial{SDict begin}N
|
||||
/@fedspecial{end}B/li{lineto}B/rl{rlineto}B/rc{rcurveto}B/np{/SaveX
|
||||
currentpoint/SaveY X N 1 setlinecap newpath}N/st{stroke SaveX SaveY
|
||||
moveto}N/fil{fill SaveX SaveY moveto}N/ellipse{/endangle X/startangle X
|
||||
/yrad X/xrad X/savematrix matrix currentmatrix N TR xrad yrad scale 0 0
|
||||
1 startangle endangle arc savematrix setmatrix}N end
|
||||
|
||||
%%EndProcSet
|
||||
%%BeginProcSet: color.pro
|
||||
%!
|
||||
TeXDict begin/setcmykcolor where{pop}{/setcmykcolor{dup 10 eq{pop
|
||||
setrgbcolor}{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll
|
||||
}repeat setrgbcolor pop}ifelse}B}ifelse/TeXcolorcmyk{setcmykcolor}def
|
||||
/TeXcolorrgb{setrgbcolor}def/TeXcolorgrey{setgray}def/TeXcolorgray{
|
||||
setgray}def/TeXcolorhsb{sethsbcolor}def/currentcmykcolor where{pop}{
|
||||
/currentcmykcolor{currentrgbcolor 10}B}ifelse/DC{exch dup userdict exch
|
||||
known{pop pop}{X}ifelse}B/GreenYellow{0.15 0 0.69 0 setcmykcolor}DC
|
||||
/Yellow{0 0 1 0 setcmykcolor}DC/Goldenrod{0 0.10 0.84 0 setcmykcolor}DC
|
||||
/Dandelion{0 0.29 0.84 0 setcmykcolor}DC/Apricot{0 0.32 0.52 0
|
||||
setcmykcolor}DC/Peach{0 0.50 0.70 0 setcmykcolor}DC/Melon{0 0.46 0.50 0
|
||||
setcmykcolor}DC/YellowOrange{0 0.42 1 0 setcmykcolor}DC/Orange{0 0.61
|
||||
0.87 0 setcmykcolor}DC/BurntOrange{0 0.51 1 0 setcmykcolor}DC
|
||||
/Bittersweet{0 0.75 1 0.24 setcmykcolor}DC/RedOrange{0 0.77 0.87 0
|
||||
setcmykcolor}DC/Mahogany{0 0.85 0.87 0.35 setcmykcolor}DC/Maroon{0 0.87
|
||||
0.68 0.32 setcmykcolor}DC/BrickRed{0 0.89 0.94 0.28 setcmykcolor}DC/Red{
|
||||
0 1 1 0 setcmykcolor}DC/OrangeRed{0 1 0.50 0 setcmykcolor}DC/RubineRed{
|
||||
0 1 0.13 0 setcmykcolor}DC/WildStrawberry{0 0.96 0.39 0 setcmykcolor}DC
|
||||
/Salmon{0 0.53 0.38 0 setcmykcolor}DC/CarnationPink{0 0.63 0 0
|
||||
setcmykcolor}DC/Magenta{0 1 0 0 setcmykcolor}DC/VioletRed{0 0.81 0 0
|
||||
setcmykcolor}DC/Rhodamine{0 0.82 0 0 setcmykcolor}DC/Mulberry{0.34 0.90
|
||||
0 0.02 setcmykcolor}DC/RedViolet{0.07 0.90 0 0.34 setcmykcolor}DC
|
||||
/Fuchsia{0.47 0.91 0 0.08 setcmykcolor}DC/Lavender{0 0.48 0 0
|
||||
setcmykcolor}DC/Thistle{0.12 0.59 0 0 setcmykcolor}DC/Orchid{0.32 0.64 0
|
||||
0 setcmykcolor}DC/DarkOrchid{0.40 0.80 0.20 0 setcmykcolor}DC/Purple{
|
||||
0.45 0.86 0 0 setcmykcolor}DC/Plum{0.50 1 0 0 setcmykcolor}DC/Violet{
|
||||
0.79 0.88 0 0 setcmykcolor}DC/RoyalPurple{0.75 0.90 0 0 setcmykcolor}DC
|
||||
/BlueViolet{0.86 0.91 0 0.04 setcmykcolor}DC/Periwinkle{0.57 0.55 0 0
|
||||
setcmykcolor}DC/CadetBlue{0.62 0.57 0.23 0 setcmykcolor}DC
|
||||
/CornflowerBlue{0.65 0.13 0 0 setcmykcolor}DC/MidnightBlue{0.98 0.13 0
|
||||
0.43 setcmykcolor}DC/NavyBlue{0.94 0.54 0 0 setcmykcolor}DC/RoyalBlue{1
|
||||
0.50 0 0 setcmykcolor}DC/Blue{1 1 0 0 setcmykcolor}DC/Cerulean{0.94 0.11
|
||||
0 0 setcmykcolor}DC/Cyan{1 0 0 0 setcmykcolor}DC/ProcessBlue{0.96 0 0 0
|
||||
setcmykcolor}DC/SkyBlue{0.62 0 0.12 0 setcmykcolor}DC/Turquoise{0.85 0
|
||||
0.20 0 setcmykcolor}DC/TealBlue{0.86 0 0.34 0.02 setcmykcolor}DC
|
||||
/Aquamarine{0.82 0 0.30 0 setcmykcolor}DC/BlueGreen{0.85 0 0.33 0
|
||||
setcmykcolor}DC/Emerald{1 0 0.50 0 setcmykcolor}DC/JungleGreen{0.99 0
|
||||
0.52 0 setcmykcolor}DC/SeaGreen{0.69 0 0.50 0 setcmykcolor}DC/Green{1 0
|
||||
1 0 setcmykcolor}DC/ForestGreen{0.91 0 0.88 0.12 setcmykcolor}DC
|
||||
/PineGreen{0.92 0 0.59 0.25 setcmykcolor}DC/LimeGreen{0.50 0 1 0
|
||||
setcmykcolor}DC/YellowGreen{0.44 0 0.74 0 setcmykcolor}DC/SpringGreen{
|
||||
0.26 0 0.76 0 setcmykcolor}DC/OliveGreen{0.64 0 0.95 0.40 setcmykcolor}
|
||||
DC/RawSienna{0 0.72 1 0.45 setcmykcolor}DC/Sepia{0 0.83 1 0.70
|
||||
setcmykcolor}DC/Brown{0 0.81 1 0.60 setcmykcolor}DC/Tan{0.14 0.42 0.56 0
|
||||
setcmykcolor}DC/Gray{0 0 0 0.50 setcmykcolor}DC/Black{0 0 0 1
|
||||
setcmykcolor}DC/White{0 0 0 0 setcmykcolor}DC end
|
||||
|
||||
%%EndProcSet
|
||||
TeXDict begin 40258431 52099146 1000 600 600 (phpgw_server.dvi)
|
||||
@start /Fa 134[37 3[42 23 1[32 1[42 42 2[23 3[42 42 1[37
|
||||
42 2[42 8[51 69 3[42 51 1[51 60 1[69 46 4[60 3[55 1[51
|
||||
10[42 42 42 42 42 42 1[23 1[28 45[{TeXBase1Encoding ReEncodeFont}31
|
||||
83.022 /Times-Italic rf /Fb 133[45 45 45 45 45 45 45
|
||||
45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45
|
||||
45 1[45 4[45 45 45 45 45 45 45 45 45 45 45 45 45 45 45
|
||||
2[45 45 45 1[45 45 45 45 45 1[45 45 45 45 1[45 45 45
|
||||
45 45 45 45 45 45 45 45 45 45 45 10[45 34[{
|
||||
TeXBase1Encoding ReEncodeFont}69 74.7198 /Courier rf
|
||||
/Fc 134[46 3[51 28 46 3[51 51 74 23 2[23 1[51 1[46 50[46
|
||||
46 2[23 46[{TeXBase1Encoding ReEncodeFont}14 83.022 /Helvetica-Bold
|
||||
rf /Fd 130[40 1[40 37 42 42 60 42 42 23 32 28 42 42 42
|
||||
42 65 23 42 1[23 42 42 28 37 42 37 42 37 1[42 6[60 78
|
||||
1[60 51 46 55 1[46 60 60 74 51 2[28 60 60 46 51 60 55
|
||||
55 60 6[23 3[42 1[42 42 3[23 21 28 21 2[28 28 28 2[42
|
||||
32[46 46 2[{TeXBase1Encoding ReEncodeFont}62 83.022 /Times-Roman
|
||||
rf /Fe 138[61 33 4[61 61 4[28 61 61 1[55 61 55 1[55 20[61
|
||||
26[55 2[28 46[{TeXBase1Encoding ReEncodeFont}14 99.6264
|
||||
/Helvetica-Bold rf /Ff 134[66 2[66 73 40 66 47 73 1[73
|
||||
73 106 33 2[33 3[66 1[66 1[66 13[80 5[100 10[86 14[66
|
||||
66 66 2[33 46[{TeXBase1Encoding ReEncodeFont}22 119.552
|
||||
/Helvetica-Bold rf /Fg 134[115 3[126 69 1[80 1[126 126
|
||||
2[57 3[126 126 1[115 126 2[115 8[138 195 3[138 149 1[138
|
||||
161 1[172 126 4[161 3[149 1[149 17[57 1[69 45[{
|
||||
TeXBase1Encoding ReEncodeFont}25 206.584 /Helvetica-Bold
|
||||
rf end
|
||||
%%EndProlog
|
||||
%%BeginSetup
|
||||
%%Feature: *Resolution 600dpi
|
||||
TeXDict begin
|
||||
%%BeginPaperSize: Letter
|
||||
letter
|
||||
%%EndPaperSize
|
||||
|
||||
%%EndSetup
|
||||
%%Page: 1 1
|
||||
1 0 bop Black 0 TeXcolorgray Black Black 711 140 a Fg(eGr)l(oupW)-8
|
||||
b(are)57 b(XML-RPC/SO)-10 b(AP)1497 409 y(Methodology)-2
|
||||
826 y Ff(1.)34 b(System)g(le)n(vel)h(requests)396 1114
|
||||
y Fe(1.1.)28 b(Login)f(and)h(authentication)396 1271
|
||||
y Fd(Authentication)18 b(for)i(user)g(logins)g(is)h(handled)e
|
||||
(internally)g(no)g(dif)n(ferently)f(than)i(for)g(the)g(typical)g
|
||||
(eGroupW)-7 b(are)19 b(login)396 1379 y(via)h(web)h(bro)n(wser)-5
|
||||
b(.)19 b(Serv)o(er)g(logins,)h(added)f(for)g(XML-RPC)i(and)f(SO)m(AP)-9
|
||||
b(,)20 b(are)g(only)g(slightly)f(dif)n(ferent.)g(F)o(or)h(either)396
|
||||
1487 y(protocol,)e(user)j(and)e(serv)o(er)h(login)f(and)h
|
||||
(authentication)e(and)h(subsequent)g(requests)h(are)g(handled)f(by)g
|
||||
(their)396 1595 y(respecti)n(v)o(e)g(serv)o(er)h(apps,)f(xmlrpc.php)f
|
||||
(and)h(soap.php.)f(A)j(serv)o(er)e(is)i(identi\002ed)f(by)f(a)i(custom)
|
||||
f(HTTP)g(header)m(,)396 1703 y(without)g(which)f(a)i(normal)e(user)h
|
||||
(login)f(will)i(be)g(undertak)o(en.)396 1853 y(A)g(client)f(or)g(serv)o
|
||||
(er)f(sends)i(the)f(appropriate)e(XML-RPC)i(or)g(SO)m(AP)h(pack)o(et)f
|
||||
(containing)e(host,)i(user)m(,)g(and)f(passw)o(ord)396
|
||||
1961 y(information)f(to)i(the)h(phpgw)d(serv)o(er)-5
|
||||
b(.)20 b(The)g(serv)o(er)f(then)h(assigns)g(a)h(sessionid)f(and)g(k)o
|
||||
(e)o(y)-5 b(,)19 b(which)g(is)j(returned)c(to)i(the)396
|
||||
2068 y(client)g(in)h(the)f(appropriate)e(format.)396
|
||||
2218 y(Our)i(current)f(method)g(for)g(authenticating)g(requests)g
|
||||
(after)h(successful)g(login)g(is)h(via)f(the)g(Authorization:)e(Basic)
|
||||
396 2326 y(HTTP)i(header)f(to)i(be)f(sent)g(by)g(the)g(client)g(or)f
|
||||
(requesting)g(serv)o(er)-5 b(.)19 b(The)h(format)f(of)h(this)g(header)f
|
||||
(is)i(a)g(base64)e(encoding)396 2434 y(of)h(the)g(assigned)g(sessionid)
|
||||
g(and)g(kp3)f(v)n(ariables,)g(seperated)h(by)f(a)i(':'.)396
|
||||
2583 y(Further)e(security)h(may)g(be)g(obtained)f(by)g(using)h(SSL)h
|
||||
(on)f(the)g(client)g(and)g(serv)o(er)-5 b(.)19 b(In)h(the)g(future,)f
|
||||
(we)i(may)396 2691 y(encrypt/descrypt)c(the)k(data)f(on)f(either)h
|
||||
(end,)g(or)g(at)g(least)h(pro)o(vide)d(this)j(as)g(an)f(option.)f(The)h
|
||||
(sessionid)g(and)f(k)o(e)o(y)396 2799 y(v)n(ariables)h(will)h(mak)o(e)e
|
||||
(this)i(possible,)f(and)f(relati)n(v)o(ely)g(secure.)396
|
||||
3052 y Fc(1.1.1.)24 b(system.login)396 3202 y Fd(The)c(\002rst)h
|
||||
(request)f(a)g(client)g(will)h(mak)o(e)f(is)h(the)f(system.login)f
|
||||
(method.)g(Here)h(is)h(a)g(sample)f(of)g(a)g(serv)o(er)f(login)h(pack)o
|
||||
(et)396 3310 y(in)h(XML-RPC:)396 3490 y Fb(<?xml)44 b(version="1.0"?>)
|
||||
396 3587 y(<methodCall>)396 3684 y
|
||||
(<methodName>system.login</methodName>)396 3781 y(<params>)396
|
||||
3878 y(<param>)396 3976 y(<value><struct>)396 4073 y
|
||||
(<member><name>server_name</name>)396 4170 y
|
||||
(<value><string>my.host.name</string></val)o(ue>)396
|
||||
4267 y(</member>)396 4364 y(<member><name>username</name>)396
|
||||
4461 y(<value><string>bubba</string></value>)396 4558
|
||||
y(</member>)396 4655 y(<member><name>password</name>)396
|
||||
4753 y(<value><string>gump</string></value>)396 4850
|
||||
y(</member>)g(</struct></value>)396 4947 y(</param>)396
|
||||
5044 y(</params>)396 5141 y(</methodCall>)p Black 3842
|
||||
5638 a Fa(1)p Black eop
|
||||
%%Page: 2 2
|
||||
2 1 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
|
||||
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
|
||||
Black 396 263 a Fd(And)g(the)g(same)h(in)f(SO)m(AP:)396
|
||||
444 y Fb(<?xml)44 b(version="1.0"?>)396 541 y(<SOAP-ENV:Envelope)396
|
||||
638 y(xmlns:SOAP-ENV="http://schemas.xmlsoap.or)o(g/soap)o(/envel)o
|
||||
(ope/")38 b(xmlns:xsi="http://www.w3.org/1999/XMLSche)o(ma-ins)o
|
||||
(tance")g(xmlns:xsd="http://www.w3.org/1999/XMLSche)o(ma")h
|
||||
(xmlns:SOAP-ENC="http://schemas.xmlsoa)o(p.org/)o(soap/e)o(ncodin)o
|
||||
(g/")g(xmlns:si="http://soapinterop.org/xsd")396 735
|
||||
y(xmlns:ns6="http://soapinterop.org")g
|
||||
(SOAP-ENV:encodingStyle="http://schemas.xm)o(lsoap.)o(org/so)o(ap/enc)o
|
||||
(oding/)o(">)396 832 y(<SOAP-ENV:Body>)k(<ns6:system_login>)396
|
||||
929 y(<server_name)g(xsi:type=":string">my.host.name</server_)o(name>)
|
||||
396 1026 y(<username)h(xsi:type=":string">bubba</username>)396
|
||||
1124 y(<password)g(xsi:type=":string">gump</password>)396
|
||||
1221 y(</ns6:system_login>)396 1318 y(</SOAP-ENV:Body>)396
|
||||
1415 y(</SOAP-ENV:Envelope>)396 1703 y Fd(The)20 b(same)g(style)h(of)f
|
||||
(pack)o(et)g(w)o(ould)f(be)h(required)f(for)g(a)i(user/client)e(login.)
|
||||
h(A)g(successful)g(login)g(should)f(yield)h(the)396 1811
|
||||
y(follo)n(wing)f(reply:)396 1991 y Fb(<methodResponse>)396
|
||||
2088 y(<params>)396 2185 y(<param>)396 2283 y(<value><struct>)396
|
||||
2380 y(<member><name>sessionid</name>)396 2477 y
|
||||
(<value><string>cf5c5534307562fc5791560837)o(7db007)o(</stri)o(ng></v)o
|
||||
(alue>)396 2574 y(</member>)396 2671 y(<member><name>kp3</name>)396
|
||||
2768 y(<value><string>2fe54daa11c8d52116788aa3f9)o(3cb70e)o(</stri)o
|
||||
(ng></v)o(alue>)396 2865 y(</member>)396 2962 y(</struct></value>)396
|
||||
3060 y(</param>)396 3157 y(</params>)396 3254 y(</methodResponse>)396
|
||||
3542 y Fd(And)h(a)h(f)o(ailed)f(login:)396 3722 y Fb(<methodResponse>)
|
||||
396 3819 y(<params>)396 3916 y(<param>)396 4014 y(<value><struct>)396
|
||||
4111 y(<member><name>GOAWAY</name>)396 4208 y
|
||||
(<value><string>XOXO</string></value>)396 4305 y(</member>)396
|
||||
4402 y(</struct></value>)396 4499 y(</param>)396 4596
|
||||
y(</params>)396 4693 y(</methodResponse>)396 4982 y Fd(eqweqw)p
|
||||
Black 3842 5569 a Fa(2)p Black eop
|
||||
%%Page: 3 3
|
||||
3 2 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
|
||||
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
|
||||
Black 396 72 a Fc(1.1.2.)k(system.logout)396 222 y Fd(Logout:)396
|
||||
402 y Fb(<?xml)44 b(version="1.0"?>)396 499 y(<methodCall>)396
|
||||
596 y(<methodName>system.logout</methodName>)396 693
|
||||
y(<params>)g(<param>)396 791 y(<value><struct>)396 888
|
||||
y(<member><name>sessionid</name>)396 985 y
|
||||
(<value><string>ea35cac53d2c12bd05caecd973)o(04478a)o(</stri)o(ng></v)o
|
||||
(alue>)396 1082 y(</member>)396 1179 y(<member><name>kp3</name>)396
|
||||
1276 y(<value><string>4f2b256e0da4e7cbbebaac9f1f)o(c8ca4a)o(</stri)o
|
||||
(ng></v)o(alue>)396 1373 y(</member>)396 1471 y(</struct></value>)396
|
||||
1568 y(</param>)396 1665 y(</params>)396 1762 y(</methodCall>)396
|
||||
2050 y Fd(Logout)19 b(w)o(ork)o(ed:)396 2230 y Fb(<methodResponse>)396
|
||||
2327 y(<params>)396 2424 y(<param>)396 2522 y(<value><struct>)396
|
||||
2619 y(<member><name>GOODBYE</name>)396 2716 y
|
||||
(<value><string>XOXO</string></value>)396 2813 y(</member>)396
|
||||
2910 y(</struct></value>)396 3007 y(</param>)396 3104
|
||||
y(</params>)396 3202 y(</methodResponse>)-2 3876 y Ff(2.)34
|
||||
b(Business)h(la)n(y)o(er)f(requests)396 4044 y Fd(Once)20
|
||||
b(a)h(successful)f(login)f(return)g(pack)o(et)h(has)g(been)g(recei)n(v)
|
||||
o(ed)e(and)i(sessionid/kp3)f(ha)n(v)o(e)g(been)h(e)o(xtracted,)e(e)n(v)
|
||||
o(ery)396 4152 y(subsequent)h(pack)o(et)g(sent)h(to)g(the)g(egroupw)o
|
||||
(are)c(serv)o(er)j(must)h(be)g(preceded)e(by)h(an)h(Authorization)d
|
||||
(header)-5 b(.)19 b(Here)h(is)396 4259 y(a)h(sample)f(header:)396
|
||||
4440 y Fb(POST)44 b(/egroupware/xmlrpc.php)d(HTTP/1.0)396
|
||||
4537 y(User-Agent:)i(PHP)i(XMLRPC)e(1.0)396 4634 y(Host:)h
|
||||
(my.local.host)396 4731 y(Authorization:)f(Basic)h
|
||||
(ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYz)o(AxZmY6)o(NTU3Y)o(zkyYjB)o
|
||||
(mNGE4Z)o(DVlOTU)o(zMzI2Y)o(mU2OTQ)o(yNjM3Y)o(jQ=)396
|
||||
4828 y(Content-Type:)f(text/xml)396 4925 y(Content-Length:)g(875)p
|
||||
Black 3842 5569 a Fa(3)p Black eop
|
||||
%%Page: 4 4
|
||||
4 3 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
|
||||
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
|
||||
Black 396 72 a Fd(The)g(longish)f(string)h(is)h(a)g(base64)e(encoding)f
|
||||
(of)i(the)h($sessionid)e(.)i(':')f(.)g($kp3.)f(F)o(or)h(no)n(w)f(this)i
|
||||
(is)g(our)f(only)f(supported)396 180 y(authentication)f(method.)h
|
||||
(Additional)g(methods)g(w)o(ould)h(probably)d(also)k(af)n(fect)f(the)g
|
||||
(methodCalls.)f(This)h(is)i(certainly)396 288 y(open)d(to)i
|
||||
(discussion.)e(F)o(ollo)n(wing)g(is)i(a)g(typical)f(request)f(for)h
|
||||
(some)g(contact)f(data:)396 468 y Fb(<?xml)44 b(version="1.0"?>)396
|
||||
566 y(<methodCall>)396 663 y(<methodName>addressbook.boaddressbook.rea)
|
||||
o(d_entr)o(ies</m)o(ethodN)o(ame>)396 760 y(<params>)396
|
||||
857 y(<param>)396 954 y(<value><struct>)396 1051 y
|
||||
(<member><name>start</name>)396 1148 y
|
||||
(<value><string>1</string></value>)396 1246 y(</member>)396
|
||||
1343 y(<member><name>limit</name>)396 1440 y
|
||||
(<value><string>5</string></value>)396 1537 y(</member>)396
|
||||
1634 y(<member><name>fields</name>)396 1731 y(<value><struct>)396
|
||||
1828 y(<member><name>n_given</name>)396 1926 y
|
||||
(<value><string>n_given</string></value>)396 2023 y(</member>)396
|
||||
2120 y(<member><name>n_family</name>)396 2217 y
|
||||
(<value><string>n_family</string></value>)396 2314 y(</member>)396
|
||||
2411 y(</struct></value>)396 2508 y(</member>)396 2605
|
||||
y(<member><name>query</name>)396 2703 y
|
||||
(<value><string></string></value>)396 2800 y(</member>)396
|
||||
2897 y(<member><name>filter</name>)396 2994 y
|
||||
(<value><string></string></value>)396 3091 y(</member>)396
|
||||
3188 y(<member><name>sort</name>)396 3285 y
|
||||
(<value><string></string></value>)396 3383 y(</member>)396
|
||||
3480 y(<member><name>order</name>)396 3577 y
|
||||
(<value><string></string></value>)396 3674 y(</member>)396
|
||||
3771 y(</struct></value>)396 3868 y(</param>)396 3965
|
||||
y(</params>)396 4063 y(</methodCall>)396 4351 y Fd(Successful)20
|
||||
b(response:)396 4531 y Fb(<?xml)44 b(version="1.0"?>)396
|
||||
4628 y(<methodResponse>)396 4725 y(<params>)396 4822
|
||||
y(<param>)396 4919 y(<value><struct>)396 5016 y(<member><name>0</name>)
|
||||
396 5114 y(<value><struct>)p Black 3842 5569 a Fa(4)p
|
||||
Black eop
|
||||
%%Page: 5 5
|
||||
5 4 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
|
||||
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
|
||||
Black 396 72 a Fb(<member><name>id</name>)396 170 y
|
||||
(<value><string>1</string></value>)396 267 y(</member>)396
|
||||
364 y(<member><name>lid</name>)396 461 y
|
||||
(<value><string></string></value>)396 558 y(</member>)396
|
||||
655 y(<member><name>tid</name>)396 752 y
|
||||
(<value><string>n</string></value>)396 850 y(</member>)396
|
||||
947 y(<member><name>owner</name>)396 1044 y
|
||||
(<value><string>500</string></value>)396 1141 y(</member>)396
|
||||
1238 y(<member><name>access</name>)396 1335 y
|
||||
(<value><string>private</string></value>)396 1432 y(</member>)396
|
||||
1530 y(<member><name>cat_id</name>)396 1627 y
|
||||
(<value><string>1</string></value>)396 1724 y(</member>)396
|
||||
1821 y(<member><name>n_given</name>)396 1918 y
|
||||
(<value><string>Alan</string></value>)396 2015 y(</member>)396
|
||||
2112 y(</struct></value>)396 2209 y(</member>)396 2307
|
||||
y(<member><name>1</name>)396 2404 y(<value><struct>)396
|
||||
2501 y(<member><name>id</name>)396 2598 y
|
||||
(<value><string>2</string></value>)396 2695 y(</member>)396
|
||||
2792 y(<member><name>lid</name>)396 2889 y
|
||||
(<value><string></string></value>)396 2987 y(</member>)396
|
||||
3084 y(<member><name>tid</name>)396 3181 y
|
||||
(<value><string>n</string></value>)396 3278 y(</member>)396
|
||||
3375 y(<member><name>owner</name>)396 3472 y
|
||||
(<value><string>500</string></value>)396 3569 y(</member>)396
|
||||
3666 y(<member><name>access</name>)396 3764 y
|
||||
(<value><string>private</string></value>)396 3861 y(</member>)396
|
||||
3958 y(<member><name>cat_id</name>)396 4055 y
|
||||
(<value><string>1</string></value>)396 4152 y(</member>)396
|
||||
4249 y(<member><name>n_given</name>)396 4346 y
|
||||
(<value><string>Andy</string></value>)396 4444 y(</member>)396
|
||||
4541 y(</struct></value>)396 4638 y(</member>)396 4735
|
||||
y(...)396 5023 y Fd(Unauthorized)e(access)j(attempt)f(returns:)p
|
||||
Black 3842 5569 a Fa(5)p Black eop
|
||||
%%Page: 6 6
|
||||
6 5 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
|
||||
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
|
||||
Black 396 72 a Fb(<methodResponse>)396 170 y(<params>)396
|
||||
267 y(<param>)396 364 y(<value><string>UNAUTHORIZED</string></val)o
|
||||
(ue>)396 461 y(</param>)396 558 y(</params>)396 655 y
|
||||
(</methodResponse>)-2 1164 y Ff(3.)34 b(More)f(to)g(come)r(...)396
|
||||
1331 y Fd(Documenting)18 b(e)n(v)o(ery)h(single)h(call)h(will)f(be)h
|
||||
(dif)n(\002cult,)e(b)n(ut)h(should)f(be)h(done.)f(In)h(leiu)h(of)e
|
||||
(this,)i(please)f(see)h(the)396 1439 y(class.bo{APPN)m(AME}.inc.php)c
|
||||
(\002les)k(in)g(each)f(application/inc)e(directory)g(in)j(the)f(e)o
|
||||
(groupw)o(are)d(cvs.)j(In)g(this)h(\002le)396 1547 y(will)g(be)f(a)h
|
||||
(list_methods\(\))d(function,)g(which)i(returns)f(the)h(information)e
|
||||
(to)i(the)h(serv)o(er)e(about)g(input/output)f(structure)396
|
||||
1655 y(for)i(each)g(call.)g(If)g(the)g(\002le)h(does)f(not)g(ha)n(v)o
|
||||
(e)g(this)g(function,)f(then)g(it)i(is)g(not)f(yet)g(w)o(orkable)f(via)
|
||||
h(this)h(interf)o(ace.)e(As)i(for)396 1763 y(the)f(actual)g(functions,)
|
||||
f(the)o(y)g(are)i(also)f(in)g(this)h(\002le.)g(Generally)-5
|
||||
b(,)18 b(the)o(y)i(will)h(all)f(accept)g(associati)n(v)o(e)g(array)f
|
||||
(input)h(and)396 1871 y(return)f(same,)h(b)n(ut)h(not)e(al)o(w)o(ays.)i
|
||||
(This)f(code)g(is)h(in)f(\003ux,)g(ha)n(v)o(e)f(fun.)p
|
||||
Black 3840 5569 a Fa(6)p Black eop
|
||||
%%Trailer
|
||||
end
|
||||
userdict /end-hook known{end-hook}if
|
||||
%%EOF
|
@ -1,311 +0,0 @@
|
||||
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN">
|
||||
|
||||
<article lang="en">
|
||||
<!-- DocBook file was created by LyX 1.1
|
||||
See http://www.lyx.org/ for more information -->
|
||||
<artheader>
|
||||
<title>
|
||||
eGroupWare XML-RPC/SOAP Methodology
|
||||
</title>
|
||||
<author>
|
||||
(C) 2001-2004 Miles Lott
|
||||
milos@groupwhere.org
|
||||
</author>
|
||||
<date>
|
||||
August 23, 2001 and December 29, 2003
|
||||
</date>
|
||||
<para>
|
||||
additions made September 3, 2001.
|
||||
</para>
|
||||
<para>
|
||||
This document is very preliminary, but describes a working system.
|
||||
</para>
|
||||
</artheader>
|
||||
<sect1>
|
||||
<title>
|
||||
System level requests
|
||||
</title>
|
||||
<sect2>
|
||||
<title>
|
||||
Login and authentication
|
||||
</title>
|
||||
<para>
|
||||
Authentication for user logins is handled internally no differently than for the typical eGroupWare login via web browser. Server logins, added for XML-RPC and SOAP, are only slightly different. For either protocol, user and server login and authentication and subsequent requests are handled by their respective server apps, xmlrpc.php and soap.php. A server is identified by a custom HTTP header, without which a normal user login will be undertaken.
|
||||
</para>
|
||||
<para>
|
||||
A client or server sends the appropriate XML-RPC or SOAP packet containing host, user, and password information to the phpgw server. The server then assigns a sessionid and key, which is returned to the client in the appropriate format.
|
||||
</para>
|
||||
<para>
|
||||
Our current method for authenticating requests after successful login is via the Authorization: Basic HTTP header to be sent by the client or requesting server. The format of this header is a base64 encoding of the assigned sessionid and kp3 variables, seperated by a ':'.
|
||||
</para>
|
||||
<para>
|
||||
Further security may be obtained by using SSL on the client and server. In the future, we may encrypt/descrypt the data on either end, or at least provide this as an option. The sessionid and key variables will make this possible, and relatively secure.
|
||||
</para>
|
||||
<sect3>
|
||||
<title>
|
||||
system.login
|
||||
</title>
|
||||
<para>
|
||||
The first request a client will make is the system.login method. Here is a sample of a server login packet in XML-RPC:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<?xml version="1.0"?>
|
||||
]]><![ CDATA [<methodCall>
|
||||
]]><![ CDATA [<methodName>system.login</methodName>
|
||||
]]><![ CDATA [<params>
|
||||
]]><![ CDATA [<param>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>server_name</name>
|
||||
]]><![ CDATA [<value><string>my.host.name</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>username</name>
|
||||
]]><![ CDATA [<value><string>bubba</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>password</name>
|
||||
]]><![ CDATA [<value><string>gump</string></value>
|
||||
]]><![ CDATA [</member> </struct></value>
|
||||
]]><![ CDATA [</param>
|
||||
]]><![ CDATA [</params>
|
||||
]]><![ CDATA [</methodCall>
|
||||
]]> </programlisting>
|
||||
<para>
|
||||
And the same in SOAP:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<?xml version="1.0"?>
|
||||
]]><![ CDATA [<SOAP-ENV:Envelope
|
||||
]]><![ CDATA [xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:si="http://soapinterop.org/xsd"
|
||||
]]><![ CDATA [xmlns:ns6="http://soapinterop.org" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
]]><![ CDATA [<SOAP-ENV:Body> <ns6:system_login>
|
||||
]]><![ CDATA [<server_name xsi:type=":string">my.host.name</server_name>
|
||||
]]><![ CDATA [<username xsi:type=":string">bubba</username>
|
||||
]]><![ CDATA [<password xsi:type=":string">gump</password>
|
||||
]]><![ CDATA [</ns6:system_login>
|
||||
]]><![ CDATA [</SOAP-ENV:Body>
|
||||
]]><![ CDATA [</SOAP-ENV:Envelope>
|
||||
]]> </programlisting>
|
||||
<para>
|
||||
The same style of packet would be required for a user/client login. A successful login should yield the following reply:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<methodResponse>
|
||||
]]><![ CDATA [<params>
|
||||
]]><![ CDATA [<param>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>sessionid</name>
|
||||
]]><![ CDATA [<value><string>cf5c5534307562fc57915608377db007</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>kp3</name>
|
||||
]]><![ CDATA [<value><string>2fe54daa11c8d52116788aa3f93cb70e</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</param>
|
||||
]]><![ CDATA [</params>
|
||||
]]><![ CDATA [</methodResponse>
|
||||
]]> </programlisting>
|
||||
<para>
|
||||
And a failed login:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<methodResponse>
|
||||
]]><![ CDATA [<params>
|
||||
]]><![ CDATA [<param>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>GOAWAY</name>
|
||||
]]><![ CDATA [<value><string>XOXO</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</param>
|
||||
]]><![ CDATA [</params>
|
||||
]]><![ CDATA [</methodResponse>
|
||||
]]> </programlisting>
|
||||
<para>
|
||||
eqweqw
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>
|
||||
system.logout
|
||||
</title>
|
||||
<para>
|
||||
Logout:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<?xml version="1.0"?>
|
||||
]]><![ CDATA [<methodCall>
|
||||
]]><![ CDATA [<methodName>system.logout</methodName>
|
||||
]]><![ CDATA [<params> <param>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>sessionid</name>
|
||||
]]><![ CDATA [<value><string>ea35cac53d2c12bd05caecd97304478a</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>kp3</name>
|
||||
]]><![ CDATA [<value><string>4f2b256e0da4e7cbbebaac9f1fc8ca4a</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</param>
|
||||
]]><![ CDATA [</params>
|
||||
]]><![ CDATA [</methodCall>
|
||||
]]> </programlisting>
|
||||
<para>
|
||||
Logout worked:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<methodResponse>
|
||||
]]><![ CDATA [<params>
|
||||
]]><![ CDATA [<param>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>GOODBYE</name>
|
||||
]]><![ CDATA [<value><string>XOXO</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</param>
|
||||
]]><![ CDATA [</params>
|
||||
]]><![ CDATA [</methodResponse>
|
||||
]]> </programlisting>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>
|
||||
Business layer requests
|
||||
</title>
|
||||
<para>
|
||||
Once a successful login return packet has been received and sessionid/kp3 have been extracted, every subsequent packet sent to the egroupware server must be preceded by an Authorization header. Here is a sample header:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [POST /egroupware/xmlrpc.php HTTP/1.0
|
||||
]]><![ CDATA [User-Agent: PHP XMLRPC 1.0
|
||||
]]><![ CDATA [Host: my.local.host
|
||||
]]><![ CDATA [Authorization: Basic ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYzAxZmY6NTU3YzkyYjBmNGE4ZDVlOTUzMzI2YmU2OTQyNjM3YjQ=
|
||||
]]><![ CDATA [Content-Type: text/xml
|
||||
]]><![ CDATA [Content-Length: 875
|
||||
]]> </programlisting>
|
||||
<para>
|
||||
The longish string is a base64 encoding of the $sessionid . ':' . $kp3. For now this is our only supported authentication method. Additional methods would probably also affect the methodCalls. This is certainly open to discussion. Following is a typical request for some contact data:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<?xml version="1.0"?>
|
||||
]]><![ CDATA [<methodCall>
|
||||
]]><![ CDATA [<methodName>addressbook.boaddressbook.read_entries</methodName>
|
||||
]]><![ CDATA [<params>
|
||||
]]><![ CDATA [<param>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>start</name>
|
||||
]]><![ CDATA [<value><string>1</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>limit</name>
|
||||
]]><![ CDATA [<value><string>5</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>fields</name>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>n_given</name>
|
||||
]]><![ CDATA [<value><string>n_given</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>n_family</name>
|
||||
]]><![ CDATA [<value><string>n_family</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>query</name>
|
||||
]]><![ CDATA [<value><string></string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>filter</name>
|
||||
]]><![ CDATA [<value><string></string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>sort</name>
|
||||
]]><![ CDATA [<value><string></string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>order</name>
|
||||
]]><![ CDATA [<value><string></string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</param>
|
||||
]]><![ CDATA [</params>
|
||||
]]><![ CDATA [</methodCall>
|
||||
]]> </programlisting>
|
||||
<para>
|
||||
Successful response:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<?xml version="1.0"?>
|
||||
]]><![ CDATA [<methodResponse>
|
||||
]]><![ CDATA [<params>
|
||||
]]><![ CDATA [<param>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>0</name>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>id</name>
|
||||
]]><![ CDATA [<value><string>1</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>lid</name>
|
||||
]]><![ CDATA [<value><string></string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>tid</name>
|
||||
]]><![ CDATA [<value><string>n</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>owner</name>
|
||||
]]><![ CDATA [<value><string>500</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>access</name>
|
||||
]]><![ CDATA [<value><string>private</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>cat_id</name>
|
||||
]]><![ CDATA [<value><string>1</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>n_given</name>
|
||||
]]><![ CDATA [<value><string>Alan</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>1</name>
|
||||
]]><![ CDATA [<value><struct>
|
||||
]]><![ CDATA [<member><name>id</name>
|
||||
]]><![ CDATA [<value><string>2</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>lid</name>
|
||||
]]><![ CDATA [<value><string></string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>tid</name>
|
||||
]]><![ CDATA [<value><string>n</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>owner</name>
|
||||
]]><![ CDATA [<value><string>500</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>access</name>
|
||||
]]><![ CDATA [<value><string>private</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>cat_id</name>
|
||||
]]><![ CDATA [<value><string>1</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [<member><name>n_given</name>
|
||||
]]><![ CDATA [<value><string>Andy</string></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [</struct></value>
|
||||
]]><![ CDATA [</member>
|
||||
]]><![ CDATA [...
|
||||
]]> </programlisting>
|
||||
<para>
|
||||
Unauthorized access attempt returns:
|
||||
</para>
|
||||
<programlisting>
|
||||
<![ CDATA [<methodResponse>
|
||||
]]><![ CDATA [<params>
|
||||
]]><![ CDATA [<param>
|
||||
]]><![ CDATA [<value><string>UNAUTHORIZED</string></value>
|
||||
]]><![ CDATA [</param>
|
||||
]]><![ CDATA [</params>
|
||||
]]><![ CDATA [</methodResponse>
|
||||
]]> </programlisting>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>
|
||||
More to come...
|
||||
</title>
|
||||
<para>
|
||||
Documenting every single call will be difficult, but should be done. In leiu of this, please see the class.bo{APPNAME}.inc.php files in each application/inc directory in the egroupware cvs. In this file will be a list_methods() function, which returns the information to the server about input/output structure for each call. If the file does not have this function, then it is not yet workable via this interface. As for the actual functions, they are also in this file. Generally, they will all accept associative array input and return same, but not always. This code is in flux, have fun.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
|
||||
</article>
|
@ -1,293 +0,0 @@
|
||||
eGroupWare XML-RPC/SOAP Methodology
|
||||
|
||||
(C) 2001-2004 Miles Lott
|
||||
|
||||
milos@groupwhere.org
|
||||
|
||||
August 23, 2001 and December 29, 2003
|
||||
|
||||
additions made September 3, 2001.
|
||||
|
||||
This document is very preliminary, but describes a working
|
||||
system.
|
||||
|
||||
1 System level requests
|
||||
|
||||
1.1 Login and authentication
|
||||
|
||||
Authentication for user logins is handled internally no differently
|
||||
than for the typical eGroupWare login via web browser. Server
|
||||
logins, added for XML-RPC and SOAP, are only slightly different.
|
||||
For either protocol, user and server login and authentication
|
||||
and subsequent requests are handled by their respective
|
||||
server apps, xmlrpc.php and soap.php. A server is identified
|
||||
by a custom HTTP header, without which a normal user login
|
||||
will be undertaken.
|
||||
|
||||
A client or server sends the appropriate XML-RPC or SOAP
|
||||
packet containing host, user, and password information to
|
||||
the egroupware server. The server then assigns a sessionid and
|
||||
key, which is returned to the client in the appropriate
|
||||
format.
|
||||
|
||||
Our current method for authenticating requests after successful
|
||||
login is via the Authorization: Basic HTTP header to be
|
||||
sent by the client or requesting server. The format of this
|
||||
header is a base64 encoding of the assigned sessionid and
|
||||
kp3 variables, seperated by a ':'.
|
||||
|
||||
Further security may be obtained by using SSL on the client
|
||||
and server. In the future, we may encrypt/decrypt the data
|
||||
on either end, or at least provide this as an option. The
|
||||
sessionid and key variables will make this possible, and
|
||||
relatively secure.
|
||||
|
||||
1.1.1 system.login
|
||||
|
||||
The first request a client will make is the system.login
|
||||
method. Here is a sample of a server login packet in XML-RPC:
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>system.login</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>server_name</name>
|
||||
<value><string>my.host.name</string></value>
|
||||
</member>
|
||||
<member><name>username</name>
|
||||
<value><string>bubba</string></value>
|
||||
</member>
|
||||
<member><name>password</name>
|
||||
<value><string>gump</string></value>
|
||||
</member> </struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
|
||||
And the same in SOAP:
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<SOAP-ENV:Envelope
|
||||
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"
|
||||
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
|
||||
xmlns:si="http://soapinterop.org/xsd"
|
||||
xmlns:ns6="http://soapinterop.org" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<SOAP-ENV:Body> <ns6:system_login>
|
||||
<server_name xsi:type=":string">my.host.name</server_name>
|
||||
<username xsi:type=":string">bubba</username>
|
||||
<password xsi:type=":string">gump</password>
|
||||
</ns6:system_login>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>
|
||||
|
||||
The same style of packet would be required for a user/client
|
||||
login. A successful login should yield the following reply:
|
||||
|
||||
<methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>sessionid</name>
|
||||
<value><string>cf5c5534307562fc57915608377db007</string></value>
|
||||
</member>
|
||||
<member><name>kp3</name>
|
||||
<value><string>2fe54daa11c8d52116788aa3f93cb70e</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>
|
||||
|
||||
And a failed login:
|
||||
|
||||
<methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>GOAWAY</name>
|
||||
<value><string>XOXO</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>
|
||||
|
||||
1.1.2 system.logout
|
||||
|
||||
Logout:
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>system.logout</methodName>
|
||||
<params> <param>
|
||||
<value><struct>
|
||||
<member><name>sessionid</name>
|
||||
<value><string>ea35cac53d2c12bd05caecd97304478a</string></value>
|
||||
</member>
|
||||
<member><name>kp3</name>
|
||||
<value><string>4f2b256e0da4e7cbbebaac9f1fc8ca4a</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
|
||||
Logout worked:
|
||||
|
||||
<methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>GOODBYE</name>
|
||||
<value><string>XOXO</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>
|
||||
|
||||
2 Business layer requests
|
||||
|
||||
Once a successful login return packet has been received and
|
||||
sessionid/kp3 have been extracted, every subsequent packet
|
||||
sent to the egroupware server must be preceded by an Authorization
|
||||
header. Here is a sample header:
|
||||
|
||||
POST /egroupware/xmlrpc.php HTTP/1.0
|
||||
User-Agent: PHP XMLRPC 1.0
|
||||
Host: my.local.host
|
||||
Authorization: Basic ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYzAxZmY6NTU3YzkyYjBmNGE4ZDVlOTUzMzI2YmU2OTQyNjM3YjQ=
|
||||
Content-Type: text/xml
|
||||
Content-Length: 875
|
||||
|
||||
The longish string is a base64 encoding of the $sessionid
|
||||
. ':' . $kp3. For now this is our only supported authentication
|
||||
method. Additional methods would probably also affect the
|
||||
methodCalls. This is certainly open to discussion. Following
|
||||
is a typical request for some contact data:
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>addressbook.boaddressbook.read_entries</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>start</name>
|
||||
<value><string>1</string></value>
|
||||
</member>
|
||||
<member><name>limit</name>
|
||||
<value><string>5</string></value>
|
||||
</member>
|
||||
<member><name>fields</name>
|
||||
<value><struct>
|
||||
<member><name>n_given</name>
|
||||
<value><string>n_given</string></value>
|
||||
</member>
|
||||
<member><name>n_family</name>
|
||||
<value><string>n_family</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</member>
|
||||
<member><name>query</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>filter</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>sort</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>order</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
|
||||
Successful response:
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member><name>0</name>
|
||||
<value><struct>
|
||||
<member><name>id</name>
|
||||
<value><string>1</string></value>
|
||||
</member>
|
||||
<member><name>lid</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>tid</name>
|
||||
<value><string>n</string></value>
|
||||
</member>
|
||||
<member><name>owner</name>
|
||||
<value><string>500</string></value>
|
||||
</member>
|
||||
<member><name>access</name>
|
||||
<value><string>private</string></value>
|
||||
</member>
|
||||
<member><name>cat_id</name>
|
||||
<value><string>1</string></value>
|
||||
</member>
|
||||
<member><name>n_given</name>
|
||||
<value><string>Alan</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</member>
|
||||
<member><name>1</name>
|
||||
<value><struct>
|
||||
<member><name>id</name>
|
||||
<value><string>2</string></value>
|
||||
</member>
|
||||
<member><name>lid</name>
|
||||
<value><string></string></value>
|
||||
</member>
|
||||
<member><name>tid</name>
|
||||
<value><string>n</string></value>
|
||||
</member>
|
||||
<member><name>owner</name>
|
||||
<value><string>500</string></value>
|
||||
</member>
|
||||
<member><name>access</name>
|
||||
<value><string>private</string></value>
|
||||
</member>
|
||||
<member><name>cat_id</name>
|
||||
<value><string>1</string></value>
|
||||
</member>
|
||||
<member><name>n_given</name>
|
||||
<value><string>Andy</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</member>
|
||||
|
||||
...
|
||||
|
||||
Unauthorized access attempt returns:
|
||||
|
||||
<methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><string>UNAUTHORIZED</string></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>
|
||||
|
||||
3 More to come...
|
||||
|
||||
Documenting every single call will be difficult, but should
|
||||
be done. In leiu of this, please see the class.bo{APPNAME}.inc.php
|
||||
files in each application/inc directory in the egroupware
|
||||
cvs. In this file will be a list_methods() function, which
|
||||
returns the information to the server about input/output
|
||||
structure for each call. If the file does not have this
|
||||
function, then it is not yet workable via this interface.
|
||||
As for the actual functions, they are also in this file.
|
||||
Generally, they will all accept associative array input
|
||||
and return same, but not always. This code is in flux, have
|
||||
fun.
|
@ -1,40 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# $Id$
|
||||
|
||||
from xmlrpclib import *
|
||||
import sys
|
||||
|
||||
server = Server("http://www.egroupware.org/egroupware/xmlrpc.php");
|
||||
|
||||
try:
|
||||
print "Listing methods:\n"
|
||||
r = server.system.listMethods();
|
||||
print r
|
||||
|
||||
print "\nTrying to login:\n"
|
||||
up = {'domain': 'default', 'username': 'demo', 'password': 'guest'}
|
||||
l = server.system.login(up);
|
||||
print l
|
||||
|
||||
print "\nTrying name/age struct/array test:\n"
|
||||
# name/age example. this exercises structs and arrays
|
||||
a = [ {'name': 'Dave', 'age': 35}, {'name': 'Edd', 'age': 45 },
|
||||
{'name': 'Fred', 'age': 23}, {'name': 'Barney', 'age': 36 }]
|
||||
r = server.examples.sortByAge(a)
|
||||
print r
|
||||
|
||||
print "\nTrying base 64 test:\n"
|
||||
# test base 64
|
||||
b = Binary("Mary had a little lamb She tied it to a pylon")
|
||||
b.encode(sys.stdout)
|
||||
r = server.examples.decode64(b)
|
||||
print r
|
||||
|
||||
print "\nTrying to logout:\n"
|
||||
sk = {'sessionid': l['sessionid'], 'kp3': l['kp3']}
|
||||
r = server.system.logout(sk);
|
||||
print r
|
||||
|
||||
except Error, v:
|
||||
print "XML-RPC Error:",v
|
@ -1,225 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
|
||||
SOAPx4
|
||||
by Dietrich Ayala (C) 2001 dietrich@ganx4.com
|
||||
|
||||
This project began based on code from the 2 projects below,
|
||||
and still contains some original code. The licenses of both must be respected.
|
||||
|
||||
XML-RPC for PHP
|
||||
originally by Edd Dumbill (C) 1999-2000
|
||||
|
||||
SOAP for PHP
|
||||
by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn>
|
||||
|
||||
*/
|
||||
|
||||
/* changelog:
|
||||
2001-07-04
|
||||
- abstract type system to support either 1999 or 2001 schema (arg, typing still needs much
|
||||
solidification.)
|
||||
- implemented proxy support, based on sample code from miles lott <milos@speakeasy.net>
|
||||
- much general cleanup of code & cleaned out what was left of original xml-rpc/gigaideas code
|
||||
- implemented a transport argument into send() that allows you to specify different transports
|
||||
(assuming you have implemented the function, and added it to the conditional statement in send()
|
||||
- abstracted the determination of charset in Content-type header
|
||||
2001-07-5
|
||||
- fixed more weird type/namespace issues
|
||||
*/
|
||||
|
||||
// $path can be a complete endpoint url, with the other parameters left blank:
|
||||
// $soap_client = new soap_client("http://path/to/soap/server");
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
class soap_client
|
||||
{
|
||||
function soap_client($path,$server=False,$port=False)
|
||||
{
|
||||
$this->port = 80;
|
||||
$this->path = $path;
|
||||
$this->server = $server;
|
||||
$this->errno;
|
||||
$this->errstring;
|
||||
$this->debug_flag = True;
|
||||
$this->debug_str = '';
|
||||
$this->username = '';
|
||||
$this->password = '';
|
||||
$this->action = '';
|
||||
$this->incoming_payload = '';
|
||||
$this->outgoing_payload = '';
|
||||
$this->response = '';
|
||||
$this->action = '';
|
||||
|
||||
// endpoint mangling
|
||||
if(preg_match('/'."^http:\\/\\/".'/',$path))
|
||||
{
|
||||
$path = str_replace('http://','',$path);
|
||||
$this->path = strstr($path,'/');
|
||||
$this->debug("path = $this->path");
|
||||
if(preg_match('/:/',$path))
|
||||
{
|
||||
$this->server = substr($path,0,strpos($path,':'));
|
||||
$this->port = substr(strstr($path,':'),1);
|
||||
$this->port = substr($this->port,0,strpos($this->port,'/'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->server = substr($path,0,strpos($path,'/'));
|
||||
}
|
||||
}
|
||||
if($port)
|
||||
{
|
||||
$this->port = $port;
|
||||
}
|
||||
}
|
||||
|
||||
function setCredentials($u, $p)
|
||||
{
|
||||
$this->username = $u;
|
||||
$this->password = $p;
|
||||
}
|
||||
|
||||
function send($msg, $action, $timeout=0, $ssl=False)
|
||||
{
|
||||
// where msg is an soapmsg
|
||||
$msg->debug_flag = $this->debug_flag;
|
||||
$this->action = $action;
|
||||
if($ssl)
|
||||
{
|
||||
return $this->ssl_sendPayloadHTTP10(
|
||||
$msg,
|
||||
$this->server,
|
||||
$this->port,
|
||||
$timeout,
|
||||
$this->username,
|
||||
$this->password
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->sendPayloadHTTP10(
|
||||
$msg,
|
||||
$this->server,
|
||||
$this->port,
|
||||
$timeout,
|
||||
$this->username,
|
||||
$this->password
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function sendPayloadHTTP10($msg, $server, $port, $timeout=0, $username='', $password='')
|
||||
{
|
||||
if($timeout > 0)
|
||||
{
|
||||
$fp = fsockopen($server, $port,&$this->errno, &$this->errstr, $timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
$fp = fsockopen($server, $port,&$this->errno, &$this->errstr);
|
||||
}
|
||||
if (!$fp)
|
||||
{
|
||||
$this->debug("Couldn't open socket connection to server!");
|
||||
$this->debug("Server: $this->server");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// thanks to Grant Rauscher <grant7@firstworld.net> for this
|
||||
$credentials = '';
|
||||
if ($username != '')
|
||||
{
|
||||
$credentials = "Authorization: Basic " . base64_encode($username . ":" . $password) . "\r\n";
|
||||
}
|
||||
|
||||
$soap_data = $msg->serialize();
|
||||
$this->outgoing_payload = 'POST '
|
||||
. $this->path
|
||||
. " HTTP/1.0\r\n"
|
||||
. 'User-Agent: eGroupware/' . $cliversion . '(PHP) ' . "\r\n"
|
||||
. 'X-EGW-Server: ' . $this->server . "\r\n"
|
||||
. 'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'] . "\r\n"
|
||||
. 'Host: '.$this->server . "\r\n"
|
||||
. $credentials
|
||||
. "Content-Type: text/xml\r\nContent-Length: " . strlen($soap_data) . "\r\n"
|
||||
. 'SOAPAction: "' . $this->action . '"' . "\r\n\r\n"
|
||||
. $soap_data;
|
||||
// send
|
||||
if(!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload)))
|
||||
{
|
||||
$this->debug('Write error');
|
||||
}
|
||||
|
||||
// get reponse
|
||||
while($data = fread($fp, 32768))
|
||||
{
|
||||
$incoming_payload .= $data;
|
||||
}
|
||||
|
||||
fclose($fp);
|
||||
$this->incoming_payload = $incoming_payload;
|
||||
// $response is a soapmsg object
|
||||
$this->response = $msg->parseResponse($incoming_payload);
|
||||
$this->debug($msg->debug_str);
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
function ssl_sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='')
|
||||
{
|
||||
if(!function_exists(curl_init))
|
||||
{
|
||||
$this->errstr = 'No curl functions available - use of ssl is invalid';
|
||||
return False;
|
||||
}
|
||||
/* curl Method borrowed from:
|
||||
http://sourceforge.net/tracker/index.php?func=detail&aid=427359&group_id=23199&atid=377731
|
||||
*/
|
||||
|
||||
// thanks to Grant Rauscher <grant7@firstworld.net>
|
||||
// for this
|
||||
$credentials = '';
|
||||
if ($username!='')
|
||||
{
|
||||
$credentials = "Authorization: Basic " . base64_encode($username . ':' . $password) . "\r\n";
|
||||
}
|
||||
|
||||
$soap_data = $msg->serialize();
|
||||
$this->outgoing_payload = 'POST '
|
||||
. $this->path
|
||||
. " HTTP/1.0\r\n"
|
||||
. 'User-Agent: eGroupware/' . $cliversion . '(PHP) ' . "\r\n"
|
||||
. 'X-EGW-Server: ' . $this->server . "\r\n"
|
||||
. 'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'] . "\r\n"
|
||||
. 'Host: ' . $this->server . "\r\n"
|
||||
. $credentials
|
||||
. "Content-Type: text/xml\r\nContent-Length: " . strlen($soap_data) . "\r\n"
|
||||
. 'SOAPAction: "' . $this->action . '"' . "\r\n\r\n"
|
||||
. $soap_data;
|
||||
|
||||
// send
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL,$this->server);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
|
||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
$incoming_payload = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$this->incoming_payload = $incoming_payload;
|
||||
// $response is a soapmsg object
|
||||
$this->response = $msg->parseResponse($incoming_payload);
|
||||
$this->debug($msg->debug_str);
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
function debug($string)
|
||||
{
|
||||
if($this->debug_flag)
|
||||
{
|
||||
$this->debug_str .= "$string\n";
|
||||
}
|
||||
}
|
||||
} // end class soap_client
|
||||
?>
|
@ -1,375 +0,0 @@
|
||||
<?php
|
||||
/* $Id$ */
|
||||
|
||||
class soap_parser
|
||||
{
|
||||
function soap_parser($xml='',$encoding='UTF-8')
|
||||
{
|
||||
global $soapTypes;
|
||||
|
||||
$this->soapTypes = $soapTypes;
|
||||
$this->xml = $xml;
|
||||
$this->xml_encoding = $encoding;
|
||||
$this->root_struct = "";
|
||||
// options: envelope,header,body,method
|
||||
// determines where in the message we are (envelope,header,body,method)
|
||||
$this->status = '';
|
||||
$this->position = 0;
|
||||
$this->pos_stat = 0;
|
||||
$this->depth = 0;
|
||||
$this->default_namespace = '';
|
||||
$this->namespaces = array();
|
||||
$this->message = array();
|
||||
$this->fault = false;
|
||||
$this->fault_code = '';
|
||||
$this->fault_str = '';
|
||||
$this->fault_detail = '';
|
||||
$this->eval_str = '';
|
||||
$this->depth_array = array();
|
||||
$this->debug_flag = True;
|
||||
$this->debug_str = '';
|
||||
$this->previous_element = '';
|
||||
|
||||
$this->entities = array (
|
||||
'&' => '&',
|
||||
'<' => '<',
|
||||
'>' => '>',
|
||||
"'" => ''',
|
||||
'"' => '"'
|
||||
);
|
||||
|
||||
// Check whether content has been read.
|
||||
if(!empty($xml))
|
||||
{
|
||||
$this->debug('Entering soap_parser()');
|
||||
//$this->debug("DATA DUMP:\n\n$xml");
|
||||
// Create an XML parser.
|
||||
$this->parser = xml_parser_create($this->xml_encoding);
|
||||
// Set the options for parsing the XML data.
|
||||
//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
|
||||
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
|
||||
// Set the object for the parser.
|
||||
xml_set_object($this->parser, &$this);
|
||||
// Set the element handlers for the parser.
|
||||
xml_set_element_handler($this->parser, 'start_element','end_element');
|
||||
xml_set_character_data_handler($this->parser,'character_data');
|
||||
xml_set_default_handler($this->parser, 'default_handler');
|
||||
|
||||
// Parse the XML file.
|
||||
if(!xml_parse($this->parser,$xml,true))
|
||||
{
|
||||
// Display an error message.
|
||||
$this->debug(sprintf("XML error on line %d: %s",
|
||||
xml_get_current_line_number($this->parser),
|
||||
xml_error_string(xml_get_error_code($this->parser))));
|
||||
$this->fault = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get final eval string
|
||||
$this->eval_str = "\$response = ".trim($this->build_eval($this->root_struct)).";";
|
||||
}
|
||||
xml_parser_free($this->parser);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug("xml was empty, didn't parse!");
|
||||
}
|
||||
}
|
||||
|
||||
// loop through msg, building eval_str
|
||||
function build_eval($pos)
|
||||
{
|
||||
$this->debug("inside build_eval() for $pos: ".$this->message[$pos]["name"]);
|
||||
$eval_str = $this->message[$pos]['eval_str'];
|
||||
// loop through children, building...
|
||||
if($this->message[$pos]['children'] != '')
|
||||
{
|
||||
$this->debug('children string = '.$this->message[$pos]['children']);
|
||||
$children = explode('|',$this->message[$pos]['children']);
|
||||
$this->debug('it has '.count($children).' children');
|
||||
@reset($children);
|
||||
while(list($c,$child_pos) = @each($children))
|
||||
/* foreach($children as $c => $child_pos) */
|
||||
{
|
||||
//$this->debug("child pos $child_pos: ".$this->message[$child_pos]["name"]);
|
||||
if($this->message[$child_pos]['eval_str'] != '')
|
||||
{
|
||||
$this->debug('entering build_eval() for '.$this->message[$child_pos]['name'].", array pos $c, pos: $child_pos");
|
||||
$eval_str .= $this->build_eval($child_pos).', ';
|
||||
}
|
||||
}
|
||||
$eval_str = substr($eval_str,0,strlen($eval_str)-2);
|
||||
}
|
||||
// add current node's eval_str
|
||||
$eval_str .= $this->message[$pos]['end_eval_str'];
|
||||
return $eval_str;
|
||||
}
|
||||
|
||||
// start-element handler
|
||||
function start_element($parser, $name, $attrs)
|
||||
{
|
||||
// position in a total number of elements, starting from 0
|
||||
// update class level pos
|
||||
$pos = $this->position++;
|
||||
// and set mine
|
||||
$this->message[$pos]['pos'] = $pos;
|
||||
|
||||
// parent/child/depth determinations
|
||||
|
||||
// depth = how many levels removed from root?
|
||||
// set mine as current global depth and increment global depth value
|
||||
$this->message[$pos]['depth'] = $this->depth++;
|
||||
|
||||
// else add self as child to whoever the current parent is
|
||||
if($pos != 0)
|
||||
{
|
||||
$this->message[$this->parent]['children'] .= "|$pos";
|
||||
}
|
||||
// set my parent
|
||||
$this->message[$pos]['parent'] = $this->parent;
|
||||
// set self as current value for this depth
|
||||
$this->depth_array[$this->depth] = $pos;
|
||||
// set self as current parent
|
||||
$this->parent = $pos;
|
||||
|
||||
// set status
|
||||
if(preg_match('/'.":Envelope$".'/',$name))
|
||||
{
|
||||
$this->status = 'envelope';
|
||||
}
|
||||
elseif(preg_match('/'.":Header$".'/',$name))
|
||||
{
|
||||
$this->status = 'header';
|
||||
}
|
||||
elseif(preg_match('/'.":Body$".'/',$name))
|
||||
{
|
||||
$this->status = 'body';
|
||||
// set method
|
||||
}
|
||||
elseif($this->status == 'body')
|
||||
{
|
||||
$this->status = 'method';
|
||||
if(preg_match('/:/',$name))
|
||||
{
|
||||
$this->root_struct_name = substr(strrchr($name,':'),1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->root_struct_name = $name;
|
||||
}
|
||||
$this->root_struct = $pos;
|
||||
$this->message[$pos]['type'] = 'struct';
|
||||
}
|
||||
// set my status
|
||||
$this->message[$pos]['status'] = $this->status;
|
||||
|
||||
// set name
|
||||
$this->message[$pos]['name'] = htmlspecialchars($name);
|
||||
// set attrs
|
||||
$this->message[$pos]['attrs'] = $attrs;
|
||||
// get namespace
|
||||
if(preg_match('/'.":".'/',$name))
|
||||
{
|
||||
$namespace = substr($name,0,strpos($name,':'));
|
||||
$this->message[$pos]['namespace'] = $namespace;
|
||||
$this->default_namespace = $namespace;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->message[$pos]['namespace'] = $this->default_namespace;
|
||||
}
|
||||
// loop through atts, logging ns and type declarations
|
||||
@reset($attrs);
|
||||
while (list($key,$value) = @each($attrs))
|
||||
/* foreach($attrs as $key => $value) */
|
||||
{
|
||||
// if ns declarations, add to class level array of valid namespaces
|
||||
if(preg_match('/xmlns:/',$key))
|
||||
{
|
||||
$namespaces[substr(strrchr($key,':'),1)] = $value;
|
||||
if($name == $this->root_struct_name)
|
||||
{
|
||||
$this->methodNamespace = $value;
|
||||
}
|
||||
}
|
||||
// if it's a type declaration, set type
|
||||
elseif($key == 'xsi:type')
|
||||
{
|
||||
// then get attname and set $type
|
||||
$type = substr(strrchr($value,':'),1);
|
||||
}
|
||||
}
|
||||
|
||||
// set type if available
|
||||
if($type)
|
||||
{
|
||||
$this->message[$pos]['type'] = $type;
|
||||
}
|
||||
|
||||
// debug
|
||||
//$this->debug("parsed $name start, eval = '".$this->message[$pos]["eval_str"]."'");
|
||||
}
|
||||
|
||||
// end-element handler
|
||||
function end_element($parser, $name)
|
||||
{
|
||||
// position of current element is equal to the last value left in depth_array for my depth
|
||||
$pos = $this->depth_array[$this->depth];
|
||||
// bring depth down a notch
|
||||
$this->depth--;
|
||||
|
||||
// get type if not set already
|
||||
if($this->message[$pos]['type'] == '')
|
||||
{
|
||||
// if($this->message[$pos]['cdata'] == '' && $this->message[$pos]['children'] != '')
|
||||
if($this->message[$pos]['children'] != '')
|
||||
{
|
||||
$this->message[$pos]['type'] = 'SOAPStruct';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->message[$pos]['type'] = 'string';
|
||||
}
|
||||
}
|
||||
|
||||
// set eval str start if it has a valid type and is inside the method
|
||||
if($pos >= $this->root_struct)
|
||||
{
|
||||
$this->message[$pos]['eval_str'] .= "\n CreateObject(\"phpgwapi.soapval\",\"".htmlspecialchars($name)."\", \"".$this->message[$pos]["type"]."\" ";
|
||||
$this->message[$pos]['end_eval_str'] = ')';
|
||||
$this->message[$pos]['inval'] = 'true';
|
||||
/*
|
||||
if($this->message[$pos]["name"] == $this->root_struct_name){
|
||||
$this->message[$pos]["end_eval_str"] .= " ,\"$this->methodNamespace\"";
|
||||
}
|
||||
*/
|
||||
if($this->message[$pos]['children'] != '')
|
||||
{
|
||||
$this->message[$pos]['eval_str'] .= ', array( ';
|
||||
$this->message[$pos]['end_eval_str'] .= ' )';
|
||||
}
|
||||
}
|
||||
|
||||
// if i have no children and have cdata...then i must be a scalar value, so add my data to the eval_str
|
||||
if($this->status == 'method' && $this->message[$pos]['children'] == '')
|
||||
{
|
||||
// add cdata w/ no quotes if only int/float/dbl
|
||||
if($this->message[$pos]['type'] == 'string')
|
||||
{
|
||||
$this->message[$pos]['eval_str'] .= ", \"".$this->message[$pos]['cdata']."\"";
|
||||
}
|
||||
elseif($this->message[$pos]['type'] == 'int' || $this->message[$pos]['type'] == 'float' || $this->message[$pos]['type'] == 'double')
|
||||
{
|
||||
//$this->debug("adding cdata w/o quotes");
|
||||
$this->message[$pos]['eval_str'] .= ', '.trim($this->message[$pos]['cdata']);
|
||||
}
|
||||
elseif(is_string($this->message[$pos]['cdata']))
|
||||
{
|
||||
//$this->debug("adding cdata w/ quotes");
|
||||
$this->message[$pos]['eval_str'] .= ", \"".$this->message[$pos]['cdata']."\"";
|
||||
}
|
||||
}
|
||||
// if in the process of making a soap_val, close the parentheses and move on...
|
||||
if($this->message[$pos]['inval'] == 'true')
|
||||
{
|
||||
$this->message[$pos]['inval'] == 'false';
|
||||
}
|
||||
// if tag we are currently closing is the method wrapper
|
||||
if($pos == $this->root_struct)
|
||||
{
|
||||
$this->status = 'body';
|
||||
}
|
||||
elseif(preg_match('/:Body/',$name))
|
||||
{
|
||||
$this->status = 'header';
|
||||
}
|
||||
elseif(preg_match('/:Header/',$name))
|
||||
{
|
||||
$this->status = 'envelope';
|
||||
}
|
||||
// set parent back to my parent
|
||||
$this->parent = $this->message[$pos]['parent'];
|
||||
$this->debug("parsed $name end, type '".$this->message[$pos]['type']."'eval_str = '".trim($this->message[$pos]['eval_str'])."' and children = ".$this->message[$pos]['children']);
|
||||
}
|
||||
|
||||
// element content handler
|
||||
function character_data($parser, $data)
|
||||
{
|
||||
$pos = $this->depth_array[$this->depth];
|
||||
$this->message[$pos]['cdata'] .= $data;
|
||||
//$this->debug("parsed ".$this->message[$pos]["name"]." cdata, eval = '$this->eval_str'");
|
||||
}
|
||||
|
||||
// default handler
|
||||
function default_handler($parser, $data)
|
||||
{
|
||||
//$this->debug("DEFAULT HANDLER: $data");
|
||||
}
|
||||
|
||||
// function to get fault code
|
||||
function fault()
|
||||
{
|
||||
if($this->fault)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// have this return a soap_val object
|
||||
function get_response()
|
||||
{
|
||||
$this->debug("eval()ing eval_str: $this->eval_str");
|
||||
@eval("$this->eval_str");
|
||||
if($response)
|
||||
{
|
||||
$this->debug("successfully eval'd msg");
|
||||
return $response;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug('ERROR: did not successfully eval the msg');
|
||||
$this->fault = true;
|
||||
return CreateObject('phpgwapi.soapval',
|
||||
'Fault',
|
||||
'struct',
|
||||
array(
|
||||
CreateObject('phpgwapi.soapval',
|
||||
'faultcode',
|
||||
'string',
|
||||
'SOAP-ENV:Server'
|
||||
),
|
||||
CreateObject('phpgwapi.soapval',
|
||||
'faultstring',
|
||||
'string',
|
||||
"couldn't eval \"$this->eval_str\""
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function debug($string)
|
||||
{
|
||||
if($this->debug_flag)
|
||||
{
|
||||
$this->debug_str .= "$string\n";
|
||||
}
|
||||
}
|
||||
|
||||
function decode_entities($text)
|
||||
{
|
||||
@reset($this->entities);
|
||||
while(list($entity,$encoded) = @each($this->entities))
|
||||
/* foreach($this->entities as $entity => $encoded) */
|
||||
{
|
||||
$text = str_replace($encoded,$entity,$text);
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,444 +0,0 @@
|
||||
<?php
|
||||
// SOAP server class
|
||||
|
||||
// for example usage, see the test_server.php file.
|
||||
|
||||
class soap_server
|
||||
{
|
||||
function soap_server($data='',$serviceNow=False)
|
||||
{
|
||||
// create empty dispatch map
|
||||
$this->dispatch_map = array();
|
||||
$this->debug_flag = True;
|
||||
$this->debug_str = '';
|
||||
$this->headers = '';
|
||||
$this->request = '';
|
||||
$this->result = 'successful';
|
||||
$this->fault = false;
|
||||
$this->fault_code = '';
|
||||
$this->fault_str = '';
|
||||
$this->fault_actor = '';
|
||||
|
||||
if($serviceNow == 1)
|
||||
{
|
||||
$this->service($data);
|
||||
}
|
||||
}
|
||||
|
||||
// parses request and posts response
|
||||
function service($data)
|
||||
{
|
||||
// $response is a soap_msg object
|
||||
$response = get_class($data) == 'soapmsg' ? $date : $this->parseRequest($data);
|
||||
$this->debug("parsed request and got an object of this class '".get_class($response)."'");
|
||||
$this->debug("server sending...");
|
||||
// pass along the debug string
|
||||
if($this->debug_flag)
|
||||
{
|
||||
$response->debug($this->debug_str);
|
||||
}
|
||||
$payload = $response->serialize();
|
||||
// print headers
|
||||
if($this->fault)
|
||||
{
|
||||
$header[] = "HTTP/1.0 500 Internal Server Error\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$header[] = "HTTP/1.0 200 OK\r\n";
|
||||
$header[] = "Status: 200\r\n";
|
||||
}
|
||||
$header[] = "Server: SOAPx4 Server v0.344359s\r\n";
|
||||
$header[] = "Connection: Close\r\n";
|
||||
$header[] = "Content-Type: text/xml; charset=UTF-8\r\n";
|
||||
$header[] = "Content-Length: ".strlen($payload)."\r\n\r\n";
|
||||
reset($header);
|
||||
foreach($header as $hdr)
|
||||
{
|
||||
header($hdr);
|
||||
}
|
||||
print $payload;
|
||||
}
|
||||
|
||||
function parseRequest($data="")
|
||||
{
|
||||
global $HTTP_SERVER_VARS;
|
||||
|
||||
$this->debug("entering parseRequest() on ".date("H:i Y-m-d"));
|
||||
$request_uri = $HTTP_SERVER_VARS["REQUEST_URI"];
|
||||
$this->debug("request uri: $request_uri");
|
||||
// get headers
|
||||
$headers_array = getallheaders();
|
||||
foreach($headers_array as $k=>$v)
|
||||
{
|
||||
$dump .= "$k: $v\r\n";
|
||||
}
|
||||
$dump .= "\r\n\r\n".$data;
|
||||
$this->headers = $headers_array;
|
||||
$this->request = $dump;
|
||||
|
||||
// get SOAPAction header -> methodname
|
||||
if($headers_array["SOAPAction"])
|
||||
{
|
||||
$action = str_replace('"','',$headers_array["SOAPAction"]);
|
||||
if(preg_match('/'."^urn:".'/',$action))
|
||||
{
|
||||
$this->service = substr($action,4);
|
||||
}
|
||||
elseif(preg_match('/'.".php".'/',$action))
|
||||
{
|
||||
$this->service = preg_replace('/"|\\//','',substr(strrchr($action,".php"),4,strlen(strrchr($action,"/"))));
|
||||
}
|
||||
$this->debug("got service: $this->service");
|
||||
}
|
||||
else
|
||||
{
|
||||
// throw a fault if no soapaction
|
||||
$this->debug("ERROR: no SOAPAction header found");
|
||||
}
|
||||
// NOTE:::: throw a fault for no/bad soapaction here?
|
||||
|
||||
// parse response, get soap parser obj
|
||||
$parser = CreateObject('phpgwapi.soap_parser',$data);
|
||||
// get/set methodname
|
||||
$this->methodname = $parser->root_struct_name;
|
||||
$this->debug("method name: $this->methodname");
|
||||
|
||||
// does method exist?
|
||||
$test = preg_replace('/'."\.".'/','_',$this->methodname);
|
||||
if(function_exists($test))
|
||||
{
|
||||
$method = $this->methodname = $test;
|
||||
$this->debug("method '$this->methodname' exists");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* egroupware customization - createobject based on methodname */
|
||||
list($app,$class,$method) = explode('.',$this->methodname);
|
||||
if(preg_match('/'."^service".'/',$app))
|
||||
{
|
||||
$args = $class;
|
||||
$class = 'service';
|
||||
$app = 'phpgwapi';
|
||||
$obj = CreateObject(sprintf('%s.%s',$app,$class),$args);
|
||||
unset($args);
|
||||
}
|
||||
else
|
||||
{
|
||||
$obj = CreateObject(sprintf('%s.%s',$app,$class));
|
||||
}
|
||||
$this->debug('app: ' . $app . ', class: ' . $class . ', method: ' . $method);
|
||||
/*
|
||||
// "method not found" fault here
|
||||
$this->debug("method '$obj->method' not found!");
|
||||
$this->result = "fault: method not found";
|
||||
$this->make_fault("Server","method '$obj->method' not defined in service '$this->service'");
|
||||
return $this->fault();
|
||||
*/
|
||||
}
|
||||
|
||||
// if fault occurred during message parsing
|
||||
if($parser->fault())
|
||||
{
|
||||
// parser debug
|
||||
$this->debug($parser->debug_str);
|
||||
$this->result = "fault: error in msg parsing or eval";
|
||||
$this->make_fault("Server","error in msg parsing or eval:\n".$parser->get_response());
|
||||
// return soapresp
|
||||
return $this->fault();
|
||||
// else successfully parsed request into soapval object
|
||||
}
|
||||
else
|
||||
{
|
||||
// get eval_str
|
||||
$this->debug("calling parser->get_response()");
|
||||
// evaluate it, getting back a soapval object
|
||||
if(!$request_val = $parser->get_response())
|
||||
{
|
||||
return $this->fault();
|
||||
}
|
||||
// parser debug
|
||||
$this->debug($parser->debug_str);
|
||||
if(get_class($request_val) == "soapval")
|
||||
{
|
||||
if (is_object($obj))
|
||||
{
|
||||
/* Add the function to the server map */
|
||||
$in = "array('" . implode("','",$obj->soap_functions[$method]['in']) . "')";
|
||||
$out = "array('" . implode("','",$obj->soap_functions[$method]['out']) . "')";
|
||||
$evalmap = "\$this->add_to_map(\$this->methodname,$in,$out);";
|
||||
eval($evalmap);
|
||||
}
|
||||
/* verify that soapval objects in request match the methods signature */
|
||||
if($this->verify_method($request_val))
|
||||
{
|
||||
$this->debug("request data - name: $request_val->name, type: $request_val->type, value: $request_val->value");
|
||||
if($this->input_value)
|
||||
{
|
||||
/* decode the soapval object, and pass resulting values to the requested method */
|
||||
if(!$request_data = $request_val->decode())
|
||||
{
|
||||
$this->make_fault("Server","Unable to decode response from soapval object into native php type.");
|
||||
return $this->fault();
|
||||
}
|
||||
$this->debug("request data: $request_data");
|
||||
}
|
||||
|
||||
/* if there are return values */
|
||||
if($this->return_type = $this->get_return_type())
|
||||
{
|
||||
$this->debug("got return type: '$this->return_type'");
|
||||
/* if there are parameters to pass */
|
||||
if($request_data)
|
||||
{
|
||||
if (is_object($obj))
|
||||
{
|
||||
$code = "\$method_response = call_user_func(array($obj,$method),";
|
||||
$this->debug("about to call object method '$class\-\>$method' with args");
|
||||
}
|
||||
else
|
||||
{
|
||||
$code = '$method_response = ' . $this->methodname . "('";
|
||||
$args = implode("','",$request_data['return']);
|
||||
$this->debug("about to call method '$this->methodname' with args: $args");
|
||||
}
|
||||
/* call method with parameters */
|
||||
$code .= implode("','",$request_data['return']);
|
||||
/*
|
||||
while(list($x,$y) = each($request_data))
|
||||
{
|
||||
$code .= "\$request_data[$x]" . ',';
|
||||
}
|
||||
$code = substr($code,0,-1) .");";
|
||||
*/
|
||||
$code .= "');";
|
||||
$this->debug('CODE: ' . $code);
|
||||
if(eval($code))
|
||||
{
|
||||
if (is_object($obj))
|
||||
{
|
||||
$this->make_fault("Server","Object method call failed for '$class\-\>$method' with params: ".join(',',$request_data));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->make_fault("Server","Method call failed for '$this->methodname' with params: ".join(',',$request_data));
|
||||
}
|
||||
return $this->fault();
|
||||
}
|
||||
$this->debug('Response: ' . $method_response);
|
||||
// _debug_array($method_response);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* call method w/ no parameters */
|
||||
if (is_object($obj))
|
||||
{
|
||||
$this->debug("about to call object method '$obj\-\>$method'");
|
||||
if(!$method_response = call_user_func(array($obj,$method)))
|
||||
{
|
||||
$this->make_fault("Server","Method call failed for '$obj->method' with no params");
|
||||
return $this->fault();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug("about to call method '$this->methodname'");
|
||||
if(!$method_response = call_user_func($this->methodname))
|
||||
{
|
||||
$this->make_fault("Server","Method call failed for '$this->methodname' with no params");
|
||||
return $this->fault();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no return values */
|
||||
}
|
||||
else
|
||||
{
|
||||
if($request_data)
|
||||
{
|
||||
/* call method with parameters */
|
||||
$code = "\$method_response = call_user_func(array(\$obj,\$method),";
|
||||
while(list($x,$y) = each($request_data))
|
||||
{
|
||||
$code .= "\$request_data[$x]" . ',';
|
||||
}
|
||||
$code = substr($code,0,-1) .");";
|
||||
$this->debug("about to call object method '$obj\-\>$method'");
|
||||
eval($code);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* call method w/ no parameters */
|
||||
if(is_object($obj))
|
||||
{
|
||||
$this->debug("about to call object method '$obj\-\>$method'");
|
||||
call_user_func(array($obj,$method));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug("about to call method '$method'");
|
||||
call_user_func($method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* create soap_val object w/ return values from method, use method signature to determine type */
|
||||
if(get_class($method_response) != 'soapval')
|
||||
{
|
||||
$return_val = CreateObject('phpgwapi.soapval',$method,$this->return_type,$method_response);
|
||||
}
|
||||
else
|
||||
{
|
||||
$return_val = $method_response;
|
||||
}
|
||||
$this->debug($return_val->debug_str);
|
||||
/* response object is a soap_msg object */
|
||||
$return_msg = CreateObject('phpgwapi.soapmsg',$method.'Response',array($return_val),$this->service);
|
||||
if($this->debug_flag)
|
||||
{
|
||||
$return_msg->debug_flag = true;
|
||||
}
|
||||
$this->result = "successful";
|
||||
return $return_msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
// debug
|
||||
$this->debug("ERROR: request not verified against method signature");
|
||||
$this->result = "fault: request failed validation against method signature";
|
||||
// return soapresp
|
||||
return $this->fault();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// debug
|
||||
$this->debug("ERROR: parser did not return soapval object: $request_val ".get_class($request_val));
|
||||
$this->result = "fault: parser did not return soapval object: $request_val";
|
||||
// return fault
|
||||
$this->make_fault("Server","parser did not return soapval object: $request_val");
|
||||
return $this->fault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function verify_method($request)
|
||||
{
|
||||
//return true;
|
||||
$this->debug("entered verify_method() w/ request name: ".$request->name);
|
||||
$params = $request->value;
|
||||
// if there are input parameters required...
|
||||
if($sig = $this->dispatch_map[$this->methodname]["in"])
|
||||
{
|
||||
$this->input_value = count($sig);
|
||||
if(is_array($params))
|
||||
{
|
||||
$this->debug("entered verify_method() with ".count($params)." parameters");
|
||||
foreach($params as $v)
|
||||
{
|
||||
$this->debug("param '$v->name' of type '$v->type'");
|
||||
}
|
||||
// validate the number of parameters
|
||||
if(count($params) == count($sig))
|
||||
{
|
||||
$this->debug("got correct number of parameters: ".count($sig));
|
||||
// make array of param types
|
||||
foreach($params as $param)
|
||||
{
|
||||
$p[] = strtolower($param->type);
|
||||
}
|
||||
// validate each param's type
|
||||
for($i=0; $i < count($p); $i++)
|
||||
{
|
||||
// type not match
|
||||
if(strtolower($sig[$i]) != strtolower($p[$i]))
|
||||
{
|
||||
$this->debug("mismatched parameter types: $sig[$i] != $p[$i]");
|
||||
$this->make_fault("Client","soap request contained mismatching parameters of name $v->name had type $p[$i], which did not match signature's type: $sig[$i]");
|
||||
return false;
|
||||
}
|
||||
$this->debug("parameter type match: $sig[$i] = $p[$i]");
|
||||
}
|
||||
return true;
|
||||
// oops, wrong number of paramss
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug("oops, wrong number of parameter!");
|
||||
$this->make_fault("Client","soap request contained incorrect number of parameters. method '$this->methodname' required ".count($sig)." and request provided ".count($params));
|
||||
return false;
|
||||
}
|
||||
// oops, no params...
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug("oops, no parameters sent! Method '$this->methodname' requires ".count($sig)." input parameters!");
|
||||
$this->make_fault("Client","soap request contained incorrect number of parameters. method '$this->methodname' requires ".count($sig)." parameters, and request provided none");
|
||||
return false;
|
||||
}
|
||||
// no params
|
||||
}
|
||||
elseif( (count($params)==0) && (count($sig) <= 1) )
|
||||
{
|
||||
$this->input_values = 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//$this->debug("well, request passed parameters to a method that requires none?");
|
||||
//$this->make_fault("Client","method '$this->methodname' requires no parameters. The request passed in ".count($params).": ".@implode(" param: ",$params) );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// get string return type from dispatch map
|
||||
function get_return_type()
|
||||
{
|
||||
if(count($this->dispatch_map[$this->methodname]["out"]) >= 1)
|
||||
{
|
||||
$type = array_shift($this->dispatch_map[$this->methodname]["out"]);
|
||||
$this->debug("got return type from dispatch map: '$type'");
|
||||
return $type;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// dbg
|
||||
function debug($string)
|
||||
{
|
||||
if($this->debug_flag)
|
||||
{
|
||||
$this->debug_str .= "$string\n";
|
||||
}
|
||||
}
|
||||
|
||||
// add a method to the dispatch map
|
||||
function add_to_map($methodname,$in,$out)
|
||||
{
|
||||
$this->dispatch_map[$methodname]["in"] = $in;
|
||||
$this->dispatch_map[$methodname]["out"] = $out;
|
||||
}
|
||||
|
||||
// set up a fault
|
||||
function fault()
|
||||
{
|
||||
return CreateObject('phpgwapi.soapmsg',
|
||||
"Fault",
|
||||
array(
|
||||
"faultcode" => $this->fault_code,
|
||||
"faultstring" => $this->fault_str,
|
||||
"faultactor" => $this->fault_actor,
|
||||
"faultdetail" => $this->fault_detail.$this->debug_str
|
||||
),
|
||||
"http://schemas.xmlphpgwapi.org/soap/envelope/"
|
||||
);
|
||||
}
|
||||
|
||||
function make_fault($fault_code,$fault_string)
|
||||
{
|
||||
$this->fault_code = $fault_code;
|
||||
$this->fault_str = $fault_string;
|
||||
$this->fault = true;
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,185 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
|
||||
SOAPx4
|
||||
by Dietrich Ayala (C) 2001 dietrich@ganx4.com
|
||||
|
||||
This project began based on code from the 2 projects below,
|
||||
and still contains some original code. The licenses of both must be respected.
|
||||
|
||||
XML-RPC for PHP
|
||||
originally by Edd Dumbill (C) 1999-2000
|
||||
|
||||
SOAP for PHP
|
||||
by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn>
|
||||
|
||||
*/
|
||||
|
||||
/* changelog:
|
||||
2001-07-04
|
||||
- abstract type system to support either 1999 or 2001 schema (arg, typing still needs much
|
||||
solidification.)
|
||||
- implemented proxy support, based on sample code from miles lott <milos@speakeasy.net>
|
||||
- much general cleanup of code & cleaned out what was left of original xml-rpc/gigaideas code
|
||||
- implemented a transport argument into send() that allows you to specify different transports
|
||||
(assuming you have implemented the function, and added it to the conditional statement in send()
|
||||
- abstracted the determination of charset in Content-type header
|
||||
2001-07-5
|
||||
- fixed more weird type/namespace issues
|
||||
*/
|
||||
|
||||
// $path can be a complete endpoint url, with the other parameters left blank:
|
||||
// $soap_client = new soap_client("http://path/to/soap/server");
|
||||
|
||||
/* soapx4 high level class
|
||||
|
||||
usage:
|
||||
|
||||
// instantiate client with server info
|
||||
$soapclient = new soapclient( string path [ ,boolean wsdl] );
|
||||
|
||||
// call method, get results
|
||||
echo $soapclient->call( string methodname [ ,array parameters] );
|
||||
|
||||
// bye bye client
|
||||
unset($soapclient);
|
||||
|
||||
*/
|
||||
/* $Id$ */
|
||||
|
||||
class soapclient
|
||||
{
|
||||
function soapclient($endpoint,$wsdl=False,$portName=False)
|
||||
{
|
||||
$this->debug_flag = True;
|
||||
$this->endpoint = $endpoint;
|
||||
$this->portName = False;
|
||||
|
||||
// make values
|
||||
if($wsdl)
|
||||
{
|
||||
$this->endpointType = 'wsdl';
|
||||
if($portName)
|
||||
{
|
||||
$this->portName = $portName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function call($method,$params='',$namespace=false,$soapAction=false)
|
||||
{
|
||||
if($this->endpointType == 'wsdl')
|
||||
{
|
||||
// instantiate wsdl class
|
||||
$this->wsdl = CreateObject('phpgwapi.wsdl',$this->endpoint);
|
||||
// get portName
|
||||
if(!$this->portName)
|
||||
{
|
||||
$this->portName = $this->wsdl->getPortName($method);
|
||||
}
|
||||
// get endpoint
|
||||
if(!$this->endpoint = $this->wsdl->getEndpoint($this->portName))
|
||||
{
|
||||
die("no port of name '$this->portName' in the wsdl at that location!");
|
||||
}
|
||||
$this->debug("endpoint: $this->endpoint");
|
||||
$this->debug("portName: $this->portName");
|
||||
}
|
||||
// get soapAction
|
||||
if(!$soapAction)
|
||||
{
|
||||
if($this->endpointType != 'wsdl')
|
||||
{
|
||||
die("method call requires soapAction if wsdl is not available!");
|
||||
}
|
||||
if(!$soapAction = $this->wsdl->getSoapAction($this->portName,$method))
|
||||
{
|
||||
die("no soapAction for operation: $method!");
|
||||
}
|
||||
}
|
||||
$this->debug("soapAction: $soapAction");
|
||||
// get namespace
|
||||
if(!$namespace)
|
||||
{
|
||||
if($this->endpointType != 'wsdl')
|
||||
{
|
||||
die("method call requires namespace if wsdl is not available!");
|
||||
}
|
||||
if(!$namespace = $this->wsdl->getNamespace($this->portName,$method))
|
||||
{
|
||||
die("no soapAction for operation: $method!");
|
||||
}
|
||||
}
|
||||
$this->debug("namespace: $namespace");
|
||||
|
||||
// make message
|
||||
$soapmsg = CreateObject('phpgwapi.soapmsg',$method,$params,$namespace);
|
||||
/* _debug_array($soapmsg); */
|
||||
|
||||
// instantiate client
|
||||
$dbg = "calling server at '$this->endpoint'...";
|
||||
if($soap_client = CreateObject('phpgwapi.soap_client',$this->endpoint))
|
||||
{
|
||||
//$soap_client->debug_flag = true;
|
||||
$this->debug($dbg.'instantiated client successfully');
|
||||
$this->debug("client data:<br>server: $soap_client->server<br>path: $soap_client->path<br>port: $soap_client->port");
|
||||
// send
|
||||
$dbg = "sending msg w/ soapaction '$soapAction'...";
|
||||
if($return = $soap_client->send($soapmsg,$soapAction))
|
||||
{
|
||||
$this->request = $soap_client->outgoing_payload;
|
||||
$this->response = $soap_client->incoming_payload;
|
||||
$this->debug($dbg . "sent message successfully and got a '$return' back");
|
||||
// check for valid response
|
||||
if(get_class($return) == 'soapval')
|
||||
{
|
||||
// fault?
|
||||
if(eregi('fault',$return->name))
|
||||
{
|
||||
$this->debug('got fault');
|
||||
$faultArray = $return->decode();
|
||||
@reset($faultArray);
|
||||
while(list($k,$v) = @each($faultArray))
|
||||
/* foreach($faultArray as $k => $v) */
|
||||
{
|
||||
print "$k = $v<br>";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$returnArray = $return->decode();
|
||||
if(is_array($returnArray))
|
||||
{
|
||||
return array_shift($returnArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug("didn't get array back from decode() for $return->name");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug("didn't get soapval object back from client");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug('client send/recieve error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function debug($string)
|
||||
{
|
||||
if($this->debug_flag)
|
||||
{
|
||||
print $string . '<br>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,183 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
|
||||
SOAPx4
|
||||
by Dietrich Ayala (C) 2001 dietrich@ganx4.com
|
||||
|
||||
This project began based on code from the 2 projects below,
|
||||
and still contains some original code. The licenses of both must be respected.
|
||||
|
||||
XML-RPC for PHP
|
||||
originally by Edd Dumbill (C) 1999-2000
|
||||
|
||||
SOAP for PHP
|
||||
by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn>
|
||||
|
||||
*/
|
||||
|
||||
/* changelog:
|
||||
2001-07-04
|
||||
- abstract type system to support either 1999 or 2001 schema (arg, typing still needs much
|
||||
solidification.)
|
||||
- implemented proxy support, based on sample code from miles lott <milos@speakeasy.net>
|
||||
- much general cleanup of code & cleaned out what was left of original xml-rpc/gigaideas code
|
||||
- implemented a transport argument into send() that allows you to specify different transports
|
||||
(assuming you have implemented the function, and added it to the conditional statement in send()
|
||||
- abstracted the determination of charset in Content-type header
|
||||
2001-07-5
|
||||
- fixed more weird type/namespace issues
|
||||
*/
|
||||
|
||||
// $path can be a complete endpoint url, with the other parameters left blank:
|
||||
// $soap_client = new soap_client("http://path/to/soap/server");
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
// soap message class
|
||||
class soapmsg
|
||||
{
|
||||
// params is an array of soapval objects
|
||||
function soapmsg($method,$params,$method_namespace='http://testuri.org',$new_namespaces=False)
|
||||
{
|
||||
// globalize method namespace
|
||||
$GLOBALS['methodNamespace'] = $method_namespace;
|
||||
$namespaces = $GLOBALS['namespaces'];
|
||||
|
||||
// make method struct
|
||||
$this->value = CreateObject('phpgwapi.soapval',$method,"struct",$params,$method_namespace);
|
||||
if(is_array($new_namespaces))
|
||||
{
|
||||
$i = count($namespaces);
|
||||
@reset($new_namespaces);
|
||||
while(list($null,$v) = @each($new_namespaces))
|
||||
/* foreach($new_namespaces as $v) */
|
||||
{
|
||||
$namespaces[$v] = 'ns' . $i++;
|
||||
}
|
||||
$this->namespaces = $namespaces;
|
||||
}
|
||||
$this->payload = '';
|
||||
$this->debug_flag = True;
|
||||
$this->debug_str = "entering soapmsg() with soapval ".$this->value->name."\n";
|
||||
}
|
||||
|
||||
function make_envelope($payload)
|
||||
{
|
||||
$namespaces = $GLOBALS['namespaces'];
|
||||
@reset($namespaces);
|
||||
while(list($k,$v) = @each($namespaces))
|
||||
/* foreach($namespaces as $k => $v) */
|
||||
{
|
||||
$ns_string .= " xmlns:$v=\"$k\"";
|
||||
}
|
||||
return "<SOAP-ENV:Envelope $ns_string SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
|
||||
. $payload . "</SOAP-ENV:Envelope>\n";
|
||||
}
|
||||
|
||||
function make_body($payload)
|
||||
{
|
||||
return "<SOAP-ENV:Body>\n" . $payload . "</SOAP-ENV:Body>\n";
|
||||
}
|
||||
|
||||
function createPayload()
|
||||
{
|
||||
$value = $this->value;
|
||||
$payload = $this->make_envelope($this->make_body($value->serialize()));
|
||||
$this->debug($value->debug_str);
|
||||
$payload = "<?xml version=\"1.0\"?>\n".$payload;
|
||||
if($this->debug_flag)
|
||||
{
|
||||
$payload .= $this->serializeDebug();
|
||||
}
|
||||
$this->payload = str_replace("\n","\r\n", $payload);
|
||||
}
|
||||
|
||||
function serialize()
|
||||
{
|
||||
if($this->payload == '')
|
||||
{
|
||||
$this->createPayload();
|
||||
return $this->payload;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->payload;
|
||||
}
|
||||
}
|
||||
|
||||
// returns a soapval object
|
||||
function parseResponse($data)
|
||||
{
|
||||
$this->debug("Entering parseResponse()");
|
||||
//$this->debug(" w/ data $data");
|
||||
// strip headers here
|
||||
//$clean_data = preg_replace('/'."\r\n".'/',"\n", $data);
|
||||
if(preg_match('/'."^.*\r\n\r\n<".'/',$data))
|
||||
{
|
||||
$this->debug("found proper seperation of headers and document");
|
||||
$this->debug("getting rid of headers, stringlen: ".strlen($data));
|
||||
$clean_data = preg_replace('/'."^.*\r\n\r\n<".'/',"<", $data);
|
||||
$this->debug("cleaned data, stringlen: ".strlen($clean_data));
|
||||
}
|
||||
else
|
||||
{
|
||||
// return fault
|
||||
return CreateObject('phpgwapi.soapval',
|
||||
'fault',
|
||||
'SOAPStruct',
|
||||
Array(
|
||||
CreateObject('phpgwapi.soapval','faultcode','string','SOAP-MSG'),
|
||||
CreateObject('phpgwapi.soapval','faultstring','string','HTTP Error'),
|
||||
CreateObject('phpgwapi.soapval','faultdetail','string','HTTP headers were not immediately followed by \'\r\n\r\n\'')
|
||||
)
|
||||
);
|
||||
}
|
||||
/*
|
||||
// if response is a proper http response, and is not a 200
|
||||
if(preg_match('/'."^HTTP".'/',$clean_data) && !preg_match('/'."200$".'/', $clean_data))
|
||||
{
|
||||
// get error data
|
||||
$errstr = substr($clean_data, 0, strpos($clean_data, "\n")-1);
|
||||
// return fault
|
||||
return CreateObject('phpgwapi.soapval',
|
||||
"fault",
|
||||
"SOAPStruct",
|
||||
array(
|
||||
CreateObject('phpgwapi.soapval',"faultcode","string","SOAP-MSG"),
|
||||
CreateObject('phpgwapi.soapval',"faultstring","string","HTTP error")
|
||||
)
|
||||
);
|
||||
}
|
||||
*/
|
||||
$this->debug("about to create parser instance w/ data: $clean_data");
|
||||
// parse response
|
||||
$response = CreateObject('phpgwapi.soap_parser',$clean_data);
|
||||
// return array of parameters
|
||||
$ret = $response->get_response();
|
||||
$this->debug($response->debug_str);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// dbg
|
||||
function debug($string)
|
||||
{
|
||||
if($this->debug_flag)
|
||||
{
|
||||
$this->debug_str .= "$string\n";
|
||||
}
|
||||
}
|
||||
|
||||
// preps debug data for encoding into soapmsg
|
||||
function serializeDebug()
|
||||
{
|
||||
if($this->debug_flag)
|
||||
{
|
||||
return "<!-- DEBUG INFO:\n".$this->debug_str."-->\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,468 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
|
||||
SOAPx4
|
||||
by Dietrich Ayala (C) 2001 dietrich@ganx4.com
|
||||
|
||||
This project began based on code from the 2 projects below,
|
||||
and still contains some original code. The licenses of both must be respected.
|
||||
|
||||
XML-RPC for PHP
|
||||
originally by Edd Dumbill (C) 1999-2000
|
||||
|
||||
SOAP for PHP
|
||||
by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn>
|
||||
|
||||
*/
|
||||
|
||||
/* changelog:
|
||||
2001-07-04
|
||||
- abstract type system to support either 1999 or 2001 schema (arg, typing still needs much
|
||||
solidification.)
|
||||
- implemented proxy support, based on sample code from miles lott <milos@speakeasy.net>
|
||||
- much general cleanup of code & cleaned out what was left of original xml-rpc/gigaideas code
|
||||
- implemented a transport argument into send() that allows you to specify different transports
|
||||
(assuming you have implemented the function, and added it to the conditional statement in send()
|
||||
- abstracted the determination of charset in Content-type header
|
||||
2001-07-5
|
||||
- fixed more weird type/namespace issues
|
||||
*/
|
||||
|
||||
// $path can be a complete endpoint url, with the other parameters left blank:
|
||||
// $soap_client = new soap_client("http://path/to/soap/server");
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
// soap value object
|
||||
class soapval
|
||||
{
|
||||
// function soapval($name='',$type=False,$value=-1,$namespace=False,$type_namespace=False)
|
||||
function soapval($name='',$type=False,$value=0,$namespace=False,$type_namespace=False)
|
||||
{
|
||||
// detect type if not passed
|
||||
if(!$type)
|
||||
{
|
||||
if(is_array($value) && count($value) >= 1)
|
||||
{
|
||||
if(ereg("[a-zA-Z0-9\-]*",key($v)))
|
||||
{
|
||||
$type = 'struct';
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = 'array';
|
||||
}
|
||||
}
|
||||
elseif(is_int($v))
|
||||
{
|
||||
$type = 'int';
|
||||
}
|
||||
elseif(is_float($v) || $v == 'NaN' || $v == 'INF')
|
||||
{
|
||||
$type = 'float';
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = gettype($value);
|
||||
}
|
||||
}
|
||||
// php type name mangle
|
||||
if($type == 'integer')
|
||||
{
|
||||
$type = 'int';
|
||||
}
|
||||
|
||||
$this->soapTypes = $GLOBALS['soapTypes'];
|
||||
$this->name = $name;
|
||||
$this->value = '';
|
||||
$this->type = $type;
|
||||
$this->type_code = 0;
|
||||
$this->type_prefix = false;
|
||||
$this->array_type = '';
|
||||
$this->debug_flag = False;
|
||||
$this->debug_str = '';
|
||||
$this->debug("Entering soapval - name: '$name' type: '$type'");
|
||||
|
||||
if($namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
if(!isset($GLOBALS['namespaces'][$namespace]))
|
||||
{
|
||||
$GLOBALS['namespaces'][$namespace] = "ns".(count($GLOBALS['namespaces'])+1);
|
||||
}
|
||||
$this->prefix = $GLOBALS['namespaces'][$namespace];
|
||||
}
|
||||
|
||||
// get type prefix
|
||||
if(preg_match('/'.":".'/',$type))
|
||||
{
|
||||
$this->type = substr(strrchr($type,':'),1,strlen(strrchr($type,':')));
|
||||
$this->type_prefix = substr($type,0,strpos($type,':'));
|
||||
}
|
||||
elseif($type_namespace)
|
||||
{
|
||||
if(!isset($GLOBALS['namespaces'][$type_namespace]))
|
||||
{
|
||||
$GLOBALS['namespaces'][$type_namespace] = 'ns'.(count($GLOBALS['namespaces'])+1);
|
||||
}
|
||||
$this->type_prefix = $GLOBALS['namespaces'][$type_namespace];
|
||||
}
|
||||
|
||||
// if type namespace was not explicitly passed, and we're not in a method struct:
|
||||
elseif(!$this->type_prefix && !isset($this->namespace))
|
||||
{
|
||||
// try to get type prefix from typeMap
|
||||
if(!$this->type_prefix = $this->verify_type($type))
|
||||
{
|
||||
// else default to method namespace
|
||||
$this->type_prefix = $GLOBALS['namespaces'][$GLOBALS['methodNamespace']];
|
||||
}
|
||||
}
|
||||
|
||||
// if scalar
|
||||
if($this->soapTypes[$this->type] == 1)
|
||||
{
|
||||
$this->type_code = 1;
|
||||
$this->addScalar($value,$this->type,$name);
|
||||
// if array
|
||||
}
|
||||
elseif($this->soapTypes[$this->type] == 2)
|
||||
{
|
||||
$this->type_code = 2;
|
||||
$this->addArray($value);
|
||||
// if struct
|
||||
}
|
||||
elseif($this->soapTypes[$this->type] == 3)
|
||||
{
|
||||
$this->type_code = 3;
|
||||
$this->addStruct($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if($namespace == $GLOBALS['methodNamespace']){
|
||||
$this->type_code = 3;
|
||||
$this->addStruct($value);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
function addScalar($value, $type, $name="")
|
||||
{
|
||||
$this->debug("adding scalar '$name' of type '$type'");
|
||||
|
||||
// if boolean, change value to 1 or 0
|
||||
if ($type == "boolean")
|
||||
{
|
||||
if((strcasecmp($value,"true") == 0) || ($value == 1))
|
||||
{
|
||||
$value = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
function addArray($vals)
|
||||
{
|
||||
$this->debug("adding array '$this->name' with ".count($vals)." vals");
|
||||
$this->value = array();
|
||||
if(is_array($vals) && count($vals) >= 1)
|
||||
{
|
||||
@reset($vals);
|
||||
while(list($k,$v) = @each($vals))
|
||||
/* foreach($vals as $k => $v) */
|
||||
{
|
||||
$this->debug("checking value $k : $v");
|
||||
// if soapval, add..
|
||||
if(get_class($v) == 'soapval')
|
||||
{
|
||||
$this->value[] = $v;
|
||||
$this->debug($v->debug_str);
|
||||
// else make obj and serialize
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_array($v))
|
||||
{
|
||||
if(ereg("[a-zA-Z\-]*",key($v)))
|
||||
{
|
||||
$type = 'struct';
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = 'array';
|
||||
}
|
||||
}
|
||||
elseif(!preg_match('/'."^[0-9]*$".'/',$k) && in_array($k,array_keys($this->soapTypes)))
|
||||
{
|
||||
$type = $k;
|
||||
}
|
||||
elseif(is_int($v))
|
||||
{
|
||||
$type = 'int';
|
||||
}
|
||||
elseif(is_float($v) || $v == 'NaN' || $v == 'INF')
|
||||
{
|
||||
$type = 'float';
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = gettype($v);
|
||||
}
|
||||
$new_val = CreateObject('phpgwapi.soapval','item',$type,$v);
|
||||
$this->debug($new_val->debug_str);
|
||||
$this->value[] = $new_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function addStruct($vals)
|
||||
{
|
||||
$this->debug("adding struct '$this->name' with ".count($vals).' vals');
|
||||
if(is_array($vals) && count($vals) >= 1)
|
||||
{
|
||||
@reset($vals);
|
||||
while(list($k,$v) = @each($vals))
|
||||
/* foreach($vals as $k => $v) */
|
||||
{
|
||||
// if serialize, if soapval
|
||||
if(get_class($v) == 'soapval')
|
||||
{
|
||||
$this->value[] = $v;
|
||||
$this->debug($v->debug_str);
|
||||
// else make obj and serialize
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_array($v))
|
||||
{
|
||||
@reset($v);
|
||||
while(list($a,$b) = @each($v))
|
||||
/* foreach($v as $a => $b) */
|
||||
{
|
||||
if($a == "0")
|
||||
{
|
||||
$type = 'array';
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = 'struct';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// elseif(is_array($k) && in_array($k,array_keys($this->soapTypes)))
|
||||
elseif(is_array($k,in_array($k,array_keys($this->soapTypes))))
|
||||
{
|
||||
$this->debug("got type '$type' for value '$v' from soapTypes array!");
|
||||
$type = $k;
|
||||
}
|
||||
elseif(is_int($v))
|
||||
{
|
||||
$type = 'int';
|
||||
}
|
||||
elseif(is_float($v) || $v == "NaN" || $v == "INF")
|
||||
{
|
||||
$type = 'float';
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = gettype($v);
|
||||
$this->debug("got type '$type' for value '$v' from php gettype()!");
|
||||
}
|
||||
$new_val = CreateObject('phpgwapi.soapval',$k,$type,$v);
|
||||
$this->debug($new_val->debug_str);
|
||||
$this->value[] = $new_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->value = array();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// turn soapvals into xml, woohoo!
|
||||
function serializeval($soapval=false)
|
||||
{
|
||||
if(!$soapval)
|
||||
{
|
||||
$soapval = $this;
|
||||
}
|
||||
$this->debug("serializing '$soapval->name' of type '$soapval->type'");
|
||||
if($soapval->name == '')
|
||||
{
|
||||
$soapval->name = 'return';
|
||||
}
|
||||
|
||||
switch($soapval->type_code)
|
||||
{
|
||||
case 3:
|
||||
// struct
|
||||
$this->debug('got a struct');
|
||||
if($soapval->prefix && $soapval->type_prefix)
|
||||
{
|
||||
$xml .= "<$soapval->prefix:$soapval->name xsi:type=\"$soapval->type_prefix:$soapval->type\">\n";
|
||||
}
|
||||
elseif($soapval->type_prefix)
|
||||
{
|
||||
$xml .= "<$soapval->name xsi:type=\"$soapval->type_prefix:$soapval->type\">\n";
|
||||
}
|
||||
elseif($soapval->prefix)
|
||||
{
|
||||
$xml .= "<$soapval->prefix:$soapval->name>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$xml .= "<$soapval->name>\n";
|
||||
}
|
||||
if(is_array($soapval->value))
|
||||
{
|
||||
@reset($soapval->value);
|
||||
while(list($k,$v) = @each($soapval->value))
|
||||
/* foreach($soapval->value as $k => $v) */
|
||||
{
|
||||
$xml .= $this->serializeval($v);
|
||||
}
|
||||
}
|
||||
if($soapval->prefix)
|
||||
{
|
||||
$xml .= "</$soapval->prefix:$soapval->name>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$xml .= "</$soapval->name>\n";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// array
|
||||
@reset($soapval->value);
|
||||
while(list($null,$array_val) = @each($soapval->value))
|
||||
/* foreach($soapval->value as $array_val) */
|
||||
{
|
||||
$array_types[$array_val->type] = 1;
|
||||
$xml .= $this->serializeval($array_val);
|
||||
}
|
||||
if(count($array_types) > 1)
|
||||
{
|
||||
$array_type = 'xsd:ur-type';
|
||||
}
|
||||
elseif(count($array_types) >= 1)
|
||||
{
|
||||
$array_type = $array_val->type_prefix.":".$array_val->type;
|
||||
}
|
||||
|
||||
$xml = "<$soapval->name xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_type."[".sizeof($soapval->value)."]\">\n".$xml."</$soapval->name>\n";
|
||||
break;
|
||||
case 1:
|
||||
$xml .= "<$soapval->name xsi:type=\"$soapval->type_prefix:$soapval->type\">$soapval->value</$soapval->name>\n";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
// serialize
|
||||
function serialize()
|
||||
{
|
||||
return $this->serializeval($this);
|
||||
}
|
||||
|
||||
function decode($soapval=false)
|
||||
{
|
||||
if(!$soapval)
|
||||
{
|
||||
$soapval = $this;
|
||||
}
|
||||
// scalar decode
|
||||
if($soapval->type_code == 1)
|
||||
{
|
||||
return $soapval->value;
|
||||
// array decode
|
||||
}
|
||||
elseif($soapval->type_code == 2)
|
||||
{
|
||||
if(is_array($soapval->value))
|
||||
{
|
||||
@reset($soapval->value);
|
||||
while(list($null,$item) = @each($soapval->value))
|
||||
/* foreach($soapval->value as $item) */
|
||||
{
|
||||
$return[] = $this->decode($item);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
// struct decode
|
||||
}
|
||||
elseif($soapval->type_code == 3)
|
||||
{
|
||||
if(is_array($soapval->value))
|
||||
{
|
||||
@reset($soapval->value);
|
||||
while(list($null,$item) = @each($soapval->value))
|
||||
/* foreach($soapval->value as $item) */
|
||||
{
|
||||
$return[$item->name] = $this->decode($item);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// verify type
|
||||
function verify_type($type)
|
||||
{
|
||||
if ($type)
|
||||
{
|
||||
// global $GLOBALS['namespaces'],$GLOBALS['soapTypes'],$GLOBALS['typemap'];
|
||||
// global $GLOBALS['namespaces'],$GLOBALS['typemap'];
|
||||
|
||||
@reset($GLOBALS['typemap']);
|
||||
while(list($namespace,$types) = @each($GLOBALS['typemap']))
|
||||
/* foreach($GLOBALS['typemap'] as $namespace => $types) */
|
||||
{
|
||||
if(in_array($type,$types))
|
||||
{
|
||||
return $GLOBALS['namespaces'][$namespace];
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// alias for verify_type() - pass it a type, and it returns it's prefix
|
||||
function get_prefix($type)
|
||||
{
|
||||
if($prefix = $this->verify_type($type))
|
||||
{
|
||||
return $prefix;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function debug($string)
|
||||
{
|
||||
if($this->debug_flag)
|
||||
{
|
||||
$this->debug_str .= "$string\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
@ -1,742 +0,0 @@
|
||||
<?php
|
||||
// Copyright (c) 1999,2000,2001 Edd Dumbill.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// * Neither the name of the "XML-RPC for PHP" nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
class xmlrpc_client
|
||||
{
|
||||
var $path;
|
||||
var $server;
|
||||
var $port=0;
|
||||
var $method='http';
|
||||
var $errno;
|
||||
var $errstr;
|
||||
var $debug=0;
|
||||
var $username='';
|
||||
var $password='';
|
||||
var $cert='';
|
||||
var $certpass='';
|
||||
var $verifypeer=1;
|
||||
var $verifyhost=1;
|
||||
var $no_multicall=False;
|
||||
var $proxy = '';
|
||||
var $proxyport=0;
|
||||
var $proxy_user = '';
|
||||
var $proxy_pass = '';
|
||||
/**
|
||||
* List of http compression methods accepted by the client for responses.
|
||||
* NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
|
||||
*
|
||||
* NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since
|
||||
* in those cases it will be up to CURL to decide the compression methods
|
||||
* it supports. You might check for the presence of 'zlib' in the output of
|
||||
* curl_version() to determine wheter compression is supported or not
|
||||
*/
|
||||
var $accepted_compression = array();
|
||||
/**
|
||||
* Name of compression scheme to be used for sending requests.
|
||||
* Either null, gzip or deflate
|
||||
*/
|
||||
var $request_compression = '';
|
||||
/**
|
||||
* CURL handle: used for keep-alive connections (PHP 4.3.8 up, see:
|
||||
* http://curl.haxx.se/docs/faq.html#7.3)
|
||||
*/
|
||||
var $xmlrpc_curl_handle = null;
|
||||
/// Whether to use persistent connections for http 1.1 and https
|
||||
var $keepalive = false;
|
||||
|
||||
function xmlrpc_client($path, $server='', $port='', $method='')
|
||||
{
|
||||
// allow user to specify all params in $path
|
||||
if($server == '' and $port == '' and $method == '')
|
||||
{
|
||||
$parts = parse_url($path);
|
||||
$server = $parts['host'];
|
||||
$path = $parts['path'];
|
||||
if(isset($parts['query']))
|
||||
{
|
||||
$path .= '?'.$parts['query'];
|
||||
}
|
||||
if(isset($parts['fragment']))
|
||||
{
|
||||
$path .= '#'.$parts['fragment'];
|
||||
}
|
||||
if(isset($parts['port']))
|
||||
{
|
||||
$port = $parts['port'];
|
||||
}
|
||||
if(isset($parts['scheme']))
|
||||
{
|
||||
$method = $parts['scheme'];
|
||||
}
|
||||
if(isset($parts['user']))
|
||||
{
|
||||
$this->username = $parts['user'];
|
||||
}
|
||||
if(isset($parts['pass']))
|
||||
{
|
||||
$this->password = $parts['pass'];
|
||||
}
|
||||
}
|
||||
if($path == '' || $path[0] != '/')
|
||||
{
|
||||
$this->path='/'.$path;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->path=$path;
|
||||
}
|
||||
$this->server=$server;
|
||||
if($port != '')
|
||||
{
|
||||
$this->port=$port;
|
||||
}
|
||||
if($method != '')
|
||||
{
|
||||
$this->method=$method;
|
||||
}
|
||||
|
||||
// if ZLIB is enabled, let the server by default accept compressed requests
|
||||
if(function_exists('gzinflate') || (
|
||||
function_exists('curl_init') && (($info = curl_version()) &&
|
||||
((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version'])))
|
||||
))
|
||||
{
|
||||
$this->accepted_compression = array('gzip', 'deflate');
|
||||
}
|
||||
|
||||
// keepalives: enabled by default ONLY for PHP >= 4.3.8
|
||||
// (see http://curl.haxx.se/docs/faq.html#7.3)
|
||||
if(version_compare(phpversion(), '4.3.8') >= 0)
|
||||
{
|
||||
$this->keepalive = true;
|
||||
}
|
||||
}
|
||||
|
||||
function setDebug($in)
|
||||
{
|
||||
if ($in)
|
||||
{
|
||||
$this->debug = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->debug = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function setCredentials($u, $p)
|
||||
{
|
||||
$this->username=$u;
|
||||
$this->password=$p;
|
||||
}
|
||||
|
||||
function setCertificate($cert, $certpass)
|
||||
{
|
||||
$this->cert = $cert;
|
||||
$this->certpass = $certpass;
|
||||
}
|
||||
|
||||
function setSSLVerifyPeer($i)
|
||||
{
|
||||
$this->verifypeer = $i;
|
||||
}
|
||||
|
||||
function setSSLVerifyHost($i)
|
||||
{
|
||||
$this->verifyhost = $i;
|
||||
}
|
||||
/**
|
||||
* set proxy info
|
||||
*
|
||||
* @param string $proxyhost
|
||||
* @param string $proxyport. Defaults to 8080 for HTTP and 443 for HTTPS
|
||||
* @param string $proxyusername
|
||||
* @param string $proxypassword
|
||||
* @access public
|
||||
*/
|
||||
function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '')
|
||||
{
|
||||
$this->proxy = $proxyhost;
|
||||
$this->proxyport = $proxyport;
|
||||
$this->proxy_user = $proxyusername;
|
||||
$this->proxy_pass = $proxypassword;
|
||||
}
|
||||
|
||||
function& send($msg, $timeout=0, $method='')
|
||||
{
|
||||
// if user does not specify http protocol, use native method of this client
|
||||
// (i.e. method set during call to constructor)
|
||||
if($method == '')
|
||||
{
|
||||
$method = $this->method;
|
||||
}
|
||||
|
||||
if(is_array($msg))
|
||||
{
|
||||
// $msg is an array of xmlrpcmsg's
|
||||
$r =& $this->multicall($msg, $timeout, $method);
|
||||
return $r;
|
||||
}
|
||||
elseif(is_string($msg))
|
||||
{
|
||||
$n = new xmlrpcmsg('');
|
||||
$n->payload = $msg;
|
||||
$msg = $n;
|
||||
}
|
||||
|
||||
// where msg is an xmlrpcmsg
|
||||
$msg->debug=$this->debug;
|
||||
|
||||
switch($method)
|
||||
{
|
||||
case 'https':
|
||||
$r =& $this->sendPayloadHTTPS(
|
||||
$msg,
|
||||
$this->server,
|
||||
$this->port,
|
||||
$timeout,
|
||||
$this->username,
|
||||
$this->password,
|
||||
$this->cert,
|
||||
$this->certpass,
|
||||
$this->proxy,
|
||||
$this->proxyport,
|
||||
$this->proxy_user,
|
||||
$this->proxy_pass,
|
||||
'https',
|
||||
$this->keepalive
|
||||
);
|
||||
break;
|
||||
case 'http11':
|
||||
$r =& $this->sendPayloadCURL(
|
||||
$msg,
|
||||
$this->server,
|
||||
$this->port,
|
||||
$timeout,
|
||||
$this->username,
|
||||
$this->password,
|
||||
null,
|
||||
null,
|
||||
$this->proxy,
|
||||
$this->proxyport,
|
||||
$this->proxy_user,
|
||||
$this->proxy_pass,
|
||||
'http',
|
||||
$this->keepalive
|
||||
);
|
||||
break;
|
||||
case 'http10':
|
||||
default:
|
||||
$r =& $this->sendPayloadHTTP10(
|
||||
$msg,
|
||||
$this->server,
|
||||
$this->port,
|
||||
$timeout,
|
||||
$this->username,
|
||||
$this->password,
|
||||
$this->proxy,
|
||||
$this->proxyport,
|
||||
$this->proxy_user,
|
||||
$this->proxy_pass
|
||||
);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
function &sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='',
|
||||
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='')
|
||||
{
|
||||
if($port==0)
|
||||
{
|
||||
$port=80;
|
||||
}
|
||||
|
||||
// Only create the payload if it was not created previously
|
||||
if(empty($msg->payload))
|
||||
{
|
||||
$msg->createPayload();
|
||||
}
|
||||
|
||||
// Deflate request body and set appropriate request headers
|
||||
if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
|
||||
{
|
||||
if($this->request_compression == 'gzip')
|
||||
{
|
||||
$a = @gzencode($msg->payload);
|
||||
if($a)
|
||||
{
|
||||
$msg->payload = $a;
|
||||
$encoding_hdr = "Content-Encoding: gzip\r\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$a = @gzdeflate($msg->payload);
|
||||
if($a)
|
||||
{
|
||||
$msg->payload = $a;
|
||||
$encoding_hdr = "Content-Encoding: deflate\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$encoding_hdr = '';
|
||||
}
|
||||
|
||||
// thanks to Grant Rauscher <grant7@firstworld.net>
|
||||
// for this
|
||||
$credentials='';
|
||||
if($username!='')
|
||||
{
|
||||
$credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
|
||||
}
|
||||
|
||||
$accepted_encoding = '';
|
||||
if(is_array($this->accepted_compression) && count($this->accepted_compression))
|
||||
{
|
||||
$accepted_encoding = 'Accept-Encoding: ' . implode(', ', $this->accepted_compression) . "\r\n";
|
||||
}
|
||||
|
||||
$proxy_credentials = '';
|
||||
if($proxyhost)
|
||||
{
|
||||
if($proxyport == 0)
|
||||
{
|
||||
$proxyport = 8080;
|
||||
}
|
||||
$connectserver = $proxyhost;
|
||||
$connectport = $proxyport;
|
||||
$uri = 'http://'.$server.':'.$port.$this->path;
|
||||
if($proxyusername != '')
|
||||
{
|
||||
$proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$connectserver = $server;
|
||||
$connectport = $port;
|
||||
$uri = $this->path;
|
||||
}
|
||||
|
||||
$op= "POST " . $uri. " HTTP/1.0\r\n"
|
||||
. "User-Agent: " . $GLOBALS['xmlrpcName'] . " " . $GLOBALS['xmlrpcVersion'] . "\r\n"
|
||||
. 'X-EGW-Server: ' . $this->server . ' ' . "\r\n"
|
||||
. 'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'] . "\r\n"
|
||||
. "Host: ". $this->server . "\r\n"
|
||||
. $credentials
|
||||
. $proxy_credentials
|
||||
. $accepted_encoding
|
||||
. $encoding_hdr
|
||||
. "Accept-Charset: " . $GLOBALS['xmlrpc_defencoding'] . "\r\n"
|
||||
. "Content-Type: text/xml\r\nContent-Length: "
|
||||
. strlen($msg->payload) . "\r\n\r\n"
|
||||
. $msg->payload;
|
||||
|
||||
if($timeout>0)
|
||||
{
|
||||
$fp = @fsockopen($connectserver, $connectport, $this->errno, $this->errstr, $timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
$fp = @fsockopen($connectserver, $connectport, $this->errno, $this->errstr);
|
||||
}
|
||||
if($fp)
|
||||
{
|
||||
if($timeout>0 && function_exists('stream_set_timeout'))
|
||||
{
|
||||
stream_set_timeout($fp, $timeout);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errstr='Connect error: '.$this->errstr;
|
||||
$r = CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['http_error'],
|
||||
$GLOBALS['xmlrpcstr']['http_error']
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
|
||||
if(!fputs($fp, $op, strlen($op)))
|
||||
{
|
||||
$this->errstr = 'Write error';
|
||||
return CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['http_error'],
|
||||
$GLOBALS['xmlrpcstr']['http_error']
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// should we reset errno and errstr on succesful socket connection?
|
||||
}
|
||||
$resp =& $msg->parseResponseFile($fp);
|
||||
// shall we move this into parseresponsefile, cuz' we have to close the socket 1st
|
||||
// and do the parsing second if we want to have recursive calls
|
||||
// (i.e. redirects)
|
||||
fclose($fp);
|
||||
return $resp;
|
||||
}
|
||||
|
||||
// contributed by Justin Miller <justin@voxel.net>
|
||||
// requires curl to be built into PHP
|
||||
// NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers!
|
||||
function &sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='',
|
||||
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $keepalive=false)
|
||||
{
|
||||
$r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username, $password, $cert, $certpass,
|
||||
$proxyhost, $proxyport, $proxyusername, $proxypassword, $keepalive);
|
||||
return $r;
|
||||
}
|
||||
|
||||
function &sendPayloadCURL($msg, $server, $port, $timeout=0, $username='', $password='', $cert='', $certpass='',
|
||||
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $method='https', $keepalive=false)
|
||||
{
|
||||
if(!function_exists('curl_init'))
|
||||
{
|
||||
$r = CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['no_curl'],
|
||||
$GLOBALS['xmlrpcstr']['no_curl']
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
|
||||
if($method == 'https')
|
||||
{
|
||||
if(($info = curl_version()) &&
|
||||
((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version']))))
|
||||
{
|
||||
$this->errstr = 'SSL unavailable on this install';
|
||||
$r = CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['no_ssl'],
|
||||
$GLOBALS['xmlrpcstr']['no_ssl']
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
||||
if($port == 0)
|
||||
{
|
||||
if($method == 'http')
|
||||
{
|
||||
$port = 80;
|
||||
}
|
||||
else
|
||||
{
|
||||
$port = 443;
|
||||
}
|
||||
}
|
||||
|
||||
// Only create the payload if it was not created previously
|
||||
if(empty($msg->payload))
|
||||
{
|
||||
$msg->createPayload();
|
||||
}
|
||||
|
||||
// Deflate request body and set appropriate request headers
|
||||
if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
|
||||
{
|
||||
if($this->request_compression == 'gzip')
|
||||
{
|
||||
$a = @gzencode($msg->payload);
|
||||
if($a)
|
||||
{
|
||||
$msg->payload = $a;
|
||||
$encoding_hdr = "Content-Encoding: gzip";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$a = @gzdeflate($msg->payload);
|
||||
if($a)
|
||||
{
|
||||
$msg->payload = $a;
|
||||
$encoding_hdr = "Content-Encoding: deflate";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$encoding_hdr = '';
|
||||
}
|
||||
|
||||
if(!$keepalive || !$this->xmlrpc_curl_handle)
|
||||
{
|
||||
$curl = curl_init($method . '://' . $server . ':' . $port . $this->path);
|
||||
if($keepalive)
|
||||
{
|
||||
$this->xmlrpc_curl_handle = $curl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$curl = $this->xmlrpc_curl_handle;
|
||||
}
|
||||
|
||||
// results into variable
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
||||
if($this->debug)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_VERBOSE, 1);
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, $GLOBALS['xmlrpcName'].' '.$GLOBALS['xmlrpcVersion']);
|
||||
// required for XMLRPC: post the data
|
||||
curl_setopt($curl, CURLOPT_POST, 1);
|
||||
// the data
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
|
||||
|
||||
// return the header too
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
|
||||
'X-EGW-Server: ' . $this->server,
|
||||
'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'],
|
||||
'Content-Type: text/xml'
|
||||
));
|
||||
|
||||
// will only work with PHP >= 5.0
|
||||
// NB: if we set an empty string, CURL will add http header indicating
|
||||
// ALL methods it is supporting. This is possibly a better option than
|
||||
// letting the user tell what curl can / cannot do...
|
||||
if(is_array($this->accepted_compression) && count($this->accepted_compression))
|
||||
{
|
||||
//curl_setopt($curl, CURLOPT_ENCODING, implode(',', $this->accepted_compression));
|
||||
curl_setopt($curl, CURLOPT_ENCODING, '');
|
||||
}
|
||||
// extra headers
|
||||
$headers = array('Content-Type: text/xml', 'Accept-Charset: '.$GLOBALS['xmlrpc_internalencoding']);
|
||||
// if no keepalive is wanted, let the server know it in advance
|
||||
if(!$keepalive)
|
||||
{
|
||||
$headers[] = 'Connection: close';
|
||||
}
|
||||
// request compression header
|
||||
if($encoding_hdr)
|
||||
{
|
||||
$headers[] = $encoding_hdr;
|
||||
}
|
||||
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
// timeout is borked
|
||||
if($timeout)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
|
||||
}
|
||||
|
||||
if($username && $password)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_USERPWD,"$username:$password");
|
||||
}
|
||||
|
||||
if($method == 'https')
|
||||
{
|
||||
// set cert file
|
||||
if($cert)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_SSLCERT, $cert);
|
||||
}
|
||||
// set cert password
|
||||
if($certpass)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $certpass);
|
||||
}
|
||||
// whether to verify remote host's cert
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
|
||||
// whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
|
||||
}
|
||||
|
||||
// proxy info
|
||||
if($proxyhost)
|
||||
{
|
||||
if($proxyport == 0)
|
||||
{
|
||||
$proxyport = 8080; // NB: even for HTTPS, local connection is on port 8080
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_PROXY,$proxyhost.':'.$proxyport);
|
||||
//curl_setopt($curl, CURLOPT_PROXYPORT,$proxyport);
|
||||
if($proxyusername)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyusername.':'.$proxypassword);
|
||||
}
|
||||
}
|
||||
|
||||
$result = curl_exec($curl);
|
||||
|
||||
if(!$result)
|
||||
{
|
||||
$this->errstr = 'Write error';
|
||||
$resp = CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['curl_fail'],
|
||||
$GLOBALS['xmlrpcstr']['curl_fail'] . ': ' . curl_error($curl)
|
||||
);
|
||||
if(!$keepalive)
|
||||
{
|
||||
curl_close($curl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$keepalive)
|
||||
{
|
||||
curl_close($curl);
|
||||
}
|
||||
$resp =& $msg->parseResponse($result, true);
|
||||
}
|
||||
return $resp;
|
||||
}
|
||||
|
||||
function& multicall($msgs, $timeout=0, $method='http')
|
||||
{
|
||||
$results = false;
|
||||
|
||||
if(!$this->no_multicall)
|
||||
{
|
||||
$results = $this->_try_multicall($msgs, $timeout, $method);
|
||||
if($results !== false)
|
||||
{
|
||||
// Either the system.multicall succeeded, or the send
|
||||
// failed (e.g. due to HTTP timeout). In either case,
|
||||
// we're done for now.
|
||||
return $results;
|
||||
}
|
||||
else
|
||||
{
|
||||
// system.multicall unsupported by server,
|
||||
// don't try it next time...
|
||||
$this->no_multicall = true;
|
||||
}
|
||||
}
|
||||
|
||||
// system.multicall is unupported by server:
|
||||
// Emulate multicall via multiple requests
|
||||
$results = array();
|
||||
foreach($msgs as $msg)
|
||||
{
|
||||
$results[] =& $this->send($msg, $timeout, $method);
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
// Attempt to boxcar $msgs via system.multicall.
|
||||
function _try_multicall($msgs, $timeout, $method)
|
||||
{
|
||||
// Construct multicall message
|
||||
$calls = array();
|
||||
foreach($msgs as $msg)
|
||||
{
|
||||
$call['methodName'] = new xmlrpcval($msg->method(),'string');
|
||||
$numParams = $msg->getNumParams();
|
||||
$params = array();
|
||||
for($i = 0; $i < $numParams; $i++)
|
||||
{
|
||||
$params[$i] = $msg->getParam($i);
|
||||
}
|
||||
$call['params'] = new xmlrpcval($params, 'array');
|
||||
$calls[] = new xmlrpcval($call, 'struct');
|
||||
}
|
||||
$multicall = new xmlrpcmsg('system.multicall');
|
||||
$multicall->addParam(new xmlrpcval($calls, 'array'));
|
||||
|
||||
// Attempt RPC call
|
||||
$result =& $this->send($multicall, $timeout, $method);
|
||||
//if(!is_object($result))
|
||||
//{
|
||||
// return ($result || 0); // transport failed
|
||||
//}
|
||||
|
||||
if($result->faultCode() != 0)
|
||||
{
|
||||
return false; // system.multicall failed
|
||||
}
|
||||
|
||||
// Unpack responses.
|
||||
$rets = $result->value();
|
||||
if($rets->kindOf() != 'array')
|
||||
{
|
||||
return false; // bad return type from system.multicall
|
||||
}
|
||||
$numRets = $rets->arraysize();
|
||||
if($numRets != count($msgs))
|
||||
{
|
||||
return false; // wrong number of return values.
|
||||
}
|
||||
|
||||
$response = array();
|
||||
for($i = 0; $i < $numRets; $i++)
|
||||
{
|
||||
$val = $rets->arraymem($i);
|
||||
switch($val->kindOf())
|
||||
{
|
||||
case 'array':
|
||||
if($val->arraysize() != 1)
|
||||
{
|
||||
return false; // Bad value
|
||||
}
|
||||
// Normal return value
|
||||
$response[$i] = new xmlrpcresp($val->arraymem(0));
|
||||
break;
|
||||
case 'struct':
|
||||
$code = $val->structmem('faultCode');
|
||||
if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$str = $val->structmem('faultString');
|
||||
if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
} // end class xmlrpc_client
|
||||
?>
|
@ -1,177 +0,0 @@
|
||||
<?php
|
||||
/**************************************************************************\
|
||||
* eGroupWare API - XML-RPC Server *
|
||||
* ------------------------------------------------------------------------ *
|
||||
* This library is part of the eGroupWare API *
|
||||
* http://www.egroupware.org/api *
|
||||
* ------------------------------------------------------------------------ *
|
||||
* This library is free software; you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as published by *
|
||||
* the Free Software Foundation; either version 2.1 of the License, *
|
||||
* or any later version. *
|
||||
* This library is distributed in the hope that it 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 this library; if not, write to the Free Software Foundation, *
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
\**************************************************************************/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
// contains useful functions for xmlrpc methods
|
||||
class xmlrpc_server_shared
|
||||
{
|
||||
var $simpledate = False;
|
||||
|
||||
// convert a date-array or timestamp into a datetime.iso8601 string
|
||||
function date2iso8601($date)
|
||||
{
|
||||
if (!is_array($date))
|
||||
{
|
||||
if($this->simpledate)
|
||||
{
|
||||
return date('Ymd\TH:i:s',$date);
|
||||
}
|
||||
return date('Y-m-d\TH:i:s',$date);
|
||||
}
|
||||
|
||||
$formatstring = "%04d-%02d-%02dT%02d:%02d:%02d";
|
||||
if($this->simpledate)
|
||||
{
|
||||
$formatstring = "%04d%02d%02dT%02d:%02d:%02d";
|
||||
}
|
||||
return sprintf($formatstring,
|
||||
$date['year'],$date['month'],$date['mday'],
|
||||
$date['hour'],$date['min'],$date['sec']);
|
||||
}
|
||||
|
||||
// convert a datetime.iso8601 string into a datearray or timestamp
|
||||
function iso86012date($isodate,$timestamp=False)
|
||||
{
|
||||
$arr = array();
|
||||
|
||||
if (preg_match('/^([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})$/',$isodate,$arr))
|
||||
{
|
||||
// $isodate is simple ISO8601, remove the difference between split and ereg
|
||||
array_shift($arr);
|
||||
}
|
||||
elseif (($arr = preg_split('/[-:T]/',$isodate)) && count($arr) == 6)
|
||||
{
|
||||
// $isodate is extended ISO8601, do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
foreach(array('year','month','mday','hour','min','sec') as $n => $name)
|
||||
{
|
||||
$date[$name] = (int)$arr[$n];
|
||||
}
|
||||
return $timestamp ? mktime($date['hour'],$date['min'],$date['sec'],
|
||||
$date['month'],$date['mday'],$date['year']) : $date;
|
||||
}
|
||||
|
||||
// translate cat-ids to array with id-name pairs
|
||||
function cats2xmlrpc($cats)
|
||||
{
|
||||
if (!is_object($GLOBALS['egw']->categories))
|
||||
{
|
||||
$GLOBALS['egw']->categories = CreateObject('phpgwapi.categories');
|
||||
}
|
||||
$xcats = array();
|
||||
foreach($cats as $cat)
|
||||
{
|
||||
if ($cat)
|
||||
{
|
||||
$xcats[$cat] = stripslashes($GLOBALS['egw']->categories->id2name($cat));
|
||||
}
|
||||
}
|
||||
return $xcats;
|
||||
}
|
||||
|
||||
// translate cats back to cat-ids, creating / modifying cats on the fly
|
||||
function xmlrpc2cats($xcats)
|
||||
{
|
||||
if (!is_array($xcats))
|
||||
{
|
||||
$xcats = array();
|
||||
}
|
||||
elseif (!is_object($GLOBALS['egw']->categories))
|
||||
{
|
||||
$GLOBALS['egw']->categories = CreateObject('phpgwapi.categories');
|
||||
}
|
||||
$cats = array();
|
||||
foreach($xcats as $cat => $name)
|
||||
{
|
||||
if ($id = $GLOBALS['egw']->categories->name2id($name))
|
||||
{
|
||||
// existing cat-name use the id
|
||||
$cat = $id;
|
||||
}
|
||||
elseif (!($org_name = stripslashes($GLOBALS['egw']->categories->id2name($cat))) || $org_name == '--')
|
||||
{
|
||||
// new cat
|
||||
$cat = $GLOBALS['egw']->categories->add(array('name' => $name,'parent' => 0));
|
||||
}
|
||||
elseif ($org_name != $name)
|
||||
{
|
||||
// cat-name edited
|
||||
list($cat_vals) =$GLOBALS['egw']->categories->return_single($cat);
|
||||
$cat_vals['name'] = $name;
|
||||
$GLOBALS['egw']->categories->edit($cat_vals);
|
||||
}
|
||||
$cats[] = (int)$cat;
|
||||
}
|
||||
return $cats;
|
||||
}
|
||||
|
||||
// get list (array with id-name pairs) of all cats of $app
|
||||
function categories($complete = False,$app = '')
|
||||
{
|
||||
if (is_array($complete))
|
||||
{
|
||||
$complete = @$complete[0];
|
||||
}
|
||||
if (!$app)
|
||||
{
|
||||
list($app) = explode('.',$this->last_method);
|
||||
}
|
||||
|
||||
if (!is_object($GLOBALS['egw']->categories))
|
||||
{
|
||||
$GLOBALS['egw']->categories = CreateObject('phpgwapi.categories');
|
||||
}
|
||||
if ($GLOBALS['egw']->categories->app_name != $app)
|
||||
{
|
||||
$GLOBALS['egw']->categories->categories('',$app);
|
||||
}
|
||||
$cats_arr = $GLOBALS['egw']->categories->return_sorted_array(0,False,'','','',True);
|
||||
$cats = array();
|
||||
if (is_array($cats_arr))
|
||||
{
|
||||
foreach($cats_arr as $cat)
|
||||
{
|
||||
foreach(array('name','description') as $name)
|
||||
{
|
||||
$cat[$name] = stripslashes($cat[$name]);
|
||||
}
|
||||
$cats[$cat['id']] = $complete ? $cat : $cat['name'];
|
||||
}
|
||||
}
|
||||
return $cats;
|
||||
}
|
||||
|
||||
function setSimpleDate($enable=True)
|
||||
{
|
||||
$this->simpledate = $enable;
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($GLOBALS['egw_info']['server']['xmlrpc_type']))
|
||||
{
|
||||
$GLOBALS['egw_info']['server']['xmlrpc_type'] = 'php';
|
||||
}
|
||||
include_once(EGW_API_INC.SEP.'class.xmlrpc_server_' . $GLOBALS['egw_info']['server']['xmlrpc_type'] . '.inc.php');
|
@ -1,335 +0,0 @@
|
||||
<?php
|
||||
/**************************************************************************\
|
||||
* eGroupWare API - XML-RPC Server *
|
||||
* This file written by Miles Lott <milos@groupwhere.org> *
|
||||
* Copyright (C) 2003 Miles Lott *
|
||||
* -------------------------------------------------------------------------*
|
||||
* This library is free software; you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as published by *
|
||||
* the Free Software Foundation; either version 2.1 of the License, *
|
||||
* or any later version. *
|
||||
* This library is distributed in the hope that it 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 this library; if not, write to the Free Software Foundation, *
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
\**************************************************************************/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
class xmlrpc_server extends xmlrpc_server_shared
|
||||
{
|
||||
var $server = '';
|
||||
var $authed = True;
|
||||
var $log = False; //'/tmp/xmlrpc.log';
|
||||
var $last_method = '';
|
||||
|
||||
function xmlrpc_server($dispMap='', $serviceNow=0)
|
||||
{
|
||||
$this->server = xmlrpc_server_create();
|
||||
if($dispMap)
|
||||
{
|
||||
$this->dmap = $dispMap;
|
||||
if($serviceNow)
|
||||
{
|
||||
$this->service();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function serializeDebug()
|
||||
{
|
||||
}
|
||||
|
||||
function service($r = False)
|
||||
{
|
||||
if (!$r) // do we have a response, or we need to parse the request
|
||||
{
|
||||
$r = $this->parseRequest();
|
||||
}
|
||||
if(!$r)
|
||||
{
|
||||
header('WWW-Authenticate: Basic realm="eGroupWare xmlrpc"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
// for the log:
|
||||
$payload = "WWW-Authenticate: Basic realm=\"eGroupWare xmlrpc\"\nHTTP/1.0 401 Unauthorized\n";
|
||||
echo $payload;
|
||||
}
|
||||
else
|
||||
{
|
||||
// $payload = '<?xml version="1.0"?\>' . "\n" . $this->serializeDebug() . $r->serialize();
|
||||
// Header("Content-type: text/xml\r\nContent-length: " . bytes($payload));
|
||||
// print $payload;
|
||||
echo $r;
|
||||
}
|
||||
|
||||
if($this->log)
|
||||
{
|
||||
$fp = fopen($this->log,'a+');
|
||||
fwrite($fp,"\n\n" . date('Y-m-d H:i:s') . " authorized="
|
||||
. ($this->authed ? $GLOBALS['egw_info']['user']['account_lid'] : 'False')
|
||||
. ", method='$this->last_method'\n");
|
||||
fwrite($fp,"==== GOT ============================\n" . $GLOBALS['HTTP_RAW_POST_DATA']
|
||||
. "\n==== RETURNED =======================\n");
|
||||
fputs($fp,$payload);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
if($this->debug)
|
||||
{
|
||||
$this->echoInput();
|
||||
|
||||
$fp = fopen('/tmp/xmlrpc_debug.out','a+');
|
||||
fputs($fp,$payload);
|
||||
fclose($fp);
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_map($methodname,$function,$sig,$doc)
|
||||
{
|
||||
xmlrpc_server_register_method($this->server,$methodname,$function);
|
||||
// xmlrpc_server_register_method($this->server,$methodname,'xmlrpc_call_wrapper');
|
||||
// $descr = array(
|
||||
// 'function' => $function,
|
||||
// 'signature' => $sig,
|
||||
// 'docstring' => $doc
|
||||
// );
|
||||
// xmlrpc_server_set_method_description($this->server,$methodname,$descr);
|
||||
|
||||
$this->dmap[$methodname] = array(
|
||||
'function' => $function,
|
||||
'signature' => $sig,
|
||||
'docstring' => $doc
|
||||
);
|
||||
}
|
||||
|
||||
function verifySignature($in, $sig)
|
||||
{
|
||||
return array(1);
|
||||
|
||||
for($i=0; $i<sizeof($sig); $i++)
|
||||
{
|
||||
// check each possible signature in turn
|
||||
$cursig = $sig[$i];
|
||||
if (sizeof($cursig) == $in->getNumParams()+1)
|
||||
{
|
||||
$itsOK = 1;
|
||||
for($n=0; $n<$in->getNumParams(); $n++)
|
||||
{
|
||||
$p = $in->getParam($n);
|
||||
// print "<!-- $p -->\n";
|
||||
if ($p->kindOf() == 'scalar')
|
||||
{
|
||||
$pt = $p->scalartyp();
|
||||
}
|
||||
else
|
||||
{
|
||||
$pt = $p->kindOf();
|
||||
}
|
||||
// $n+1 as first type of sig is return type
|
||||
if ($pt != $cursig[$n+1])
|
||||
{
|
||||
$itsOK = 0;
|
||||
$pno = $n+1;
|
||||
$wanted = $cursig[$n+1];
|
||||
$got = $pt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($itsOK)
|
||||
{
|
||||
return array(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array(0, "Wanted $wanted, got $got at param $pno)");
|
||||
}
|
||||
|
||||
function parseRequest($data='')
|
||||
{
|
||||
if($data == '')
|
||||
{
|
||||
$data = $GLOBALS['HTTP_RAW_POST_DATA'];
|
||||
}
|
||||
// return $this->echoInput($data);
|
||||
|
||||
/* Decode to extract methodName */
|
||||
$params = xmlrpc_decode_request($data, &$methName);
|
||||
$this->last_method = $methName;
|
||||
$syscall = 0;
|
||||
|
||||
/* Setup dispatch map based on the function, if this is a system call */
|
||||
if(preg_match('/^system\./', $methName))
|
||||
{
|
||||
foreach($GLOBALS['_xmlrpcs_dmap'] as $meth => $dat)
|
||||
{
|
||||
$this->add_to_map($meth,$dat['function'],$dat['signature'],$dat['docstring']);
|
||||
}
|
||||
$sysCall = 1;
|
||||
$dmap = $this->dmap;
|
||||
}
|
||||
elseif(preg_match('/^examples\./',$methName) ||
|
||||
preg_match('/^validator1\./',$methName) ||
|
||||
ereg('^interopEchoTests\.', $methName)
|
||||
)
|
||||
{
|
||||
$dmap = $this->dmap;
|
||||
$sysCall = 1;
|
||||
}
|
||||
|
||||
/* verify dispatch map, or try to fix it for non-trivial system calls */
|
||||
if(!isset($this->dmap[$methName]['function']))
|
||||
{
|
||||
if($sysCall)
|
||||
{
|
||||
/* Bad or non-existent system call, return error */
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['unknown_method'],
|
||||
$GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
if($this->authed)
|
||||
{
|
||||
$method = $methName;
|
||||
list($app,$class,$method) = explode('.',$methName);
|
||||
|
||||
switch($app)
|
||||
{
|
||||
case 'server':
|
||||
case 'phpgwapi':
|
||||
/* Server role functions only - api access */
|
||||
if($GLOBALS['egw']->acl->get_role() >= EGW_ACL_SERVER)
|
||||
{
|
||||
$dmap = ExecMethod(sprintf('%s.%s.%s','phpgwapi',$class,'list_methods'),'xmlrpc');
|
||||
}
|
||||
break;
|
||||
case 'service':
|
||||
/* Service functions, user-level */
|
||||
$t = 'phpgwapi.' . $class . '.exec';
|
||||
$dmap = ExecMethod($t,array($service,'list_methods','xmlrpc'));
|
||||
break;
|
||||
default:
|
||||
/* User-level application access */
|
||||
if($GLOBALS['egw']->acl->check('run',EGW_ACL_READ,$app))
|
||||
{
|
||||
$dmap = ExecMethod(sprintf('',$app,$class,'list_methods'),'xmlrpc');
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['no_access'],
|
||||
$GLOBALS['xmlrpcstr']['no_access']
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add the functions from preset $dmap OR list_methods() to the server map */
|
||||
foreach($dmap as $meth => $dat)
|
||||
{
|
||||
$this->add_to_map($meth,$dat['function'],$dat['signature'],$dat['docstring']);
|
||||
}
|
||||
|
||||
/* _debug_array($this->dmap);exit; */
|
||||
|
||||
/* Now make the call */
|
||||
if(isset($dmap[$methName]['function']))
|
||||
{
|
||||
// dispatch if exists
|
||||
if(isset($dmap[$methName]['signature']))
|
||||
{
|
||||
$sr = $this->verifySignature($m, $dmap[$methName]['signature'] );
|
||||
}
|
||||
if((!isset($dmap[$methName]['signature'])) || $sr[0])
|
||||
{
|
||||
// if no signature or correct signature
|
||||
$r = xmlrpc_server_call_method($this->server,$data,$params);
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['incorrect_params'],
|
||||
$GLOBALS['xmlrpcstr']['incorrect_params'] . ': ' . $sr[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// else prepare error response
|
||||
if(!$this->authed)
|
||||
{
|
||||
// $r = False;
|
||||
// send 401 header to force authorization
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
CreateObject('phpgwapi.xmlrpcval',
|
||||
'UNAUTHORIZED',
|
||||
'string'
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['unknown_method'],
|
||||
$GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName
|
||||
);
|
||||
}
|
||||
}
|
||||
xmlrpc_server_destroy($xmlrpc_server);
|
||||
return $r;
|
||||
}
|
||||
|
||||
function echoInput()
|
||||
{
|
||||
// a debugging routine: just echos back the input
|
||||
// packet as a string value
|
||||
|
||||
/* TODO */
|
||||
// $r = CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',"'Aha said I: '" . $HTTP_RAW_POST_DATA,'string'));
|
||||
return $GLOBALS['HTTP_RAW_POST_DATA'];
|
||||
}
|
||||
|
||||
function xmlrpc_custom_error($error_number, $error_string, $filename, $line, $vars)
|
||||
{
|
||||
if(error_reporting() & $error_number)
|
||||
{
|
||||
$error_string .= sprintf("\nFilename: %s\nLine: %s",$filename,$line);
|
||||
|
||||
xmlrpc_error(1005,$error_string);
|
||||
}
|
||||
}
|
||||
/*
|
||||
function xmlrpc_error($error_number, $error_string)
|
||||
{
|
||||
$values = array(
|
||||
'faultString' => $error_string,
|
||||
'faultCode' => $error_number
|
||||
);
|
||||
|
||||
echo xmlrpc_encode_request(NULL,$values);
|
||||
|
||||
xmlrpc_server_destroy($GLOBALS['xmlrpc_server']);
|
||||
exit;
|
||||
}
|
||||
*/
|
||||
function xmlrpc_error($error_number, $error_string)
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$error_number,
|
||||
$error_string . ': ' . $this->last_method
|
||||
);
|
||||
$this->service($r);
|
||||
xmlrpc_server_destroy($GLOBALS['xmlrpc_server']);
|
||||
exit;
|
||||
}
|
||||
}
|
@ -1,503 +0,0 @@
|
||||
<?php
|
||||
// Copyright (c) 1999,2000,2001 Edd Dumbill.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// * Neither the name of the "XML-RPC for PHP" nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
* Incorporated for egroupware by Miles Lott <milos@groupwhere.org>
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/* BEGIN server class */
|
||||
class xmlrpc_server extends xmlrpc_server_shared
|
||||
{
|
||||
var $dmap = array();
|
||||
var $authed = False;
|
||||
var $req_array = array();
|
||||
var $resp_struct = array();
|
||||
var $debug = False;
|
||||
var $method_requested;
|
||||
var $log = False; //'/tmp/xmlrpc.log';
|
||||
|
||||
function xmlrpc_server($dispMap='', $serviceNow=0)
|
||||
{
|
||||
// dispMap is a dispatch array of methods
|
||||
// mapped to function names and signatures
|
||||
// if a method
|
||||
// doesn't appear in the map then an unknown
|
||||
// method error is generated
|
||||
if($dispMap)
|
||||
{
|
||||
$this->dmap = $dispMap;
|
||||
if ($serviceNow)
|
||||
{
|
||||
$this->service();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function serializeDebug()
|
||||
{
|
||||
if ($GLOBALS['_xmlrpc_debuginfo'] != '')
|
||||
{
|
||||
return "<!-- DEBUG INFO:\n\n" . $GLOBALS['_xmlrpc_debuginfo'] . "\n-->\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function service($r=False)
|
||||
{
|
||||
if (!$r) // do we have a response, or we need to parse the request
|
||||
{
|
||||
$r = $this->parseRequest();
|
||||
}
|
||||
if (!$r)
|
||||
{
|
||||
header('WWW-Authenticate: Basic realm="eGroupWare xmlrpc"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
// for the log:
|
||||
$payload = "WWW-Authenticate: Basic realm=\"eGroupWare xmlrpc\"\nHTTP/1.0 401 Unauthorized\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$payload = $GLOBALS['egw']->translation->convert("<?xml version=\"1.0\"?>\n" . $this->serializeDebug() . $r->serialize(),
|
||||
$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||
header("Content-type: text/xml");
|
||||
header("Content-length: " . bytes($payload));
|
||||
echo $payload;
|
||||
}
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
$fp = fopen($this->log,'a+');
|
||||
fwrite($fp,"\n\n".date('Y-m-d H:i:s') . " authorized="
|
||||
. ($this->authed?$GLOBALS['egw_info']['user']['account_lid']:'False')
|
||||
. ", method='$this->last_method'\n");
|
||||
fwrite($fp,"==== GOT ============================\n" . $GLOBALS['HTTP_RAW_POST_DATA']
|
||||
. "\n==== RETURNED =======================\n");
|
||||
fputs($fp,$payload);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
if ($this->debug)
|
||||
{
|
||||
$this->echoInput();
|
||||
|
||||
$fp = fopen('/tmp/xmlrpc_debug.out','w');
|
||||
fputs($fp,$payload);
|
||||
fclose($fp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* add a method to the dispatch map
|
||||
*/
|
||||
function add_to_map($methodname,$function,$sig,$doc)
|
||||
{
|
||||
$this->dmap[$methodname] = array(
|
||||
'function' => $function,
|
||||
'signature' => $sig,
|
||||
'docstring' => $doc
|
||||
);
|
||||
}
|
||||
|
||||
function verifySignature($in, $sig)
|
||||
{
|
||||
for($i=0; $i<sizeof($sig); $i++)
|
||||
{
|
||||
// check each possible signature in turn
|
||||
$cursig = $sig[$i];
|
||||
if (sizeof($cursig) == $in->getNumParams()+1)
|
||||
{
|
||||
$itsOK = 1;
|
||||
for($n=0; $n<$in->getNumParams(); $n++)
|
||||
{
|
||||
$p = $in->getParam($n);
|
||||
// print "<!-- $p -->\n";
|
||||
if ($p->kindOf() == 'scalar')
|
||||
{
|
||||
$pt = $p->scalartyp();
|
||||
}
|
||||
else
|
||||
{
|
||||
$pt = $p->kindOf();
|
||||
}
|
||||
// $n+1 as first type of sig is return type
|
||||
if ($pt != $cursig[$n+1])
|
||||
{
|
||||
$itsOK = 0;
|
||||
$pno = $n+1;
|
||||
$wanted = $cursig[$n+1];
|
||||
$got = $pt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($itsOK)
|
||||
{
|
||||
return array(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array(0, "Wanted $wanted, got $got at param $pno)");
|
||||
}
|
||||
|
||||
function reqtoarray($_req,$recursed=False)
|
||||
{
|
||||
switch(gettype($_req))
|
||||
{
|
||||
case 'object':
|
||||
if($recursed)
|
||||
{
|
||||
return $_req->getval();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->req_array = $_req->getval();
|
||||
}
|
||||
break;
|
||||
case 'array':
|
||||
@reset($_req);
|
||||
$ele = array();
|
||||
while(list($key,$val) = @each($_req))
|
||||
{
|
||||
if($recursed)
|
||||
{
|
||||
$ele[$key] = $this->reqtoarray($val,True);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->req_array[$key] = $this->reqtoarray($val,True);
|
||||
}
|
||||
}
|
||||
if($recursed)
|
||||
{
|
||||
return $ele;
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
case 'integer':
|
||||
if($recursed)
|
||||
{
|
||||
return $_req;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->req_array[] = $_req;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function build_resp($_res)
|
||||
{
|
||||
if (is_array($_res))
|
||||
{
|
||||
$i = 0;
|
||||
$is_array = True;
|
||||
foreach($_res as $key => $val)
|
||||
{
|
||||
$ele[$key] = $this->build_resp($val,True);
|
||||
$is_array = $is_array && $i === $key;
|
||||
++$i;
|
||||
}
|
||||
return CreateObject('phpgwapi.xmlrpcval',$ele,$is_array ? 'array' : 'struct');
|
||||
}
|
||||
$_type = (is_integer($_res) ? 'int' : gettype($_res));
|
||||
|
||||
if ($_type == 'string' && (preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/',$_res) ||
|
||||
preg_match('/^[0-9]{4}[0-9]{2}[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/',$_res)))
|
||||
{
|
||||
$_type = 'dateTime.iso8601';
|
||||
}
|
||||
// Passing an integer of 0 to the xmlrpcval constructor results in the value being lost. (jengo)
|
||||
if ($_type == 'int' && $_res == 0)
|
||||
{
|
||||
return CreateObject('phpgwapi.xmlrpcval','0',$_type);
|
||||
}
|
||||
return CreateObject('phpgwapi.xmlrpcval',$_res,$_type);
|
||||
}
|
||||
|
||||
function parseRequest($data='')
|
||||
{
|
||||
$r = False;
|
||||
|
||||
if ($data == '')
|
||||
{
|
||||
$data = $GLOBALS['HTTP_RAW_POST_DATA'];
|
||||
}
|
||||
$parser = xml_parser_create($GLOBALS['xmlrpc_defencoding']);
|
||||
|
||||
$GLOBALS['_xh'][$parser] = array();
|
||||
$GLOBALS['_xh'][$parser]['isf'] = 0;
|
||||
$GLOBALS['_xh'][$parser]['isf_reason'] = '';
|
||||
$GLOBALS['_xh'][$parser]['params'] = array();
|
||||
$GLOBALS['_xh'][$parser]['stack']=array();
|
||||
$GLOBALS['_xh'][$parser]['valuestack'] = array();
|
||||
$GLOBALS['_xh'][$parser]['method'] = '';
|
||||
|
||||
// decompose incoming XML into request structure
|
||||
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
|
||||
xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
|
||||
xml_set_character_data_handler($parser, 'xmlrpc_cd');
|
||||
xml_set_default_handler($parser, 'xmlrpc_dh');
|
||||
if (!xml_parse($parser, $data, 1))
|
||||
{
|
||||
// return XML error as a faultCode
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp','',
|
||||
$GLOBALS['xmlrpcerrxml'] + xml_get_error_code($parser),
|
||||
sprintf('XML error: %s at line %d',
|
||||
xml_error_string(xml_get_error_code($parser)),
|
||||
xml_get_current_line_number($parser))
|
||||
);
|
||||
xml_parser_free($parser);
|
||||
}
|
||||
elseif ($GLOBALS['_xh'][$parser]['isf'])
|
||||
{
|
||||
xml_parser_free($parser);
|
||||
$r = CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
0,
|
||||
$GLOBALS['xmlrpcerr']['invalid_request'],
|
||||
$GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh'][$parser]['isf_reason']
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
xml_parser_free($parser);
|
||||
$m = CreateObject('phpgwapi.xmlrpcmsg',$GLOBALS['_xh'][$parser]['method']);
|
||||
// now add parameters in
|
||||
$plist = '';
|
||||
for($i=0; $i<sizeof($GLOBALS['_xh'][$parser]['params']); $i++)
|
||||
{
|
||||
// print "<!-- " . $GLOBALS['_xh'][$parser]['params'][$i]. "-->\n");
|
||||
$m->addParam($GLOBALS['_xh'][$parser]['params'][$i]);
|
||||
}
|
||||
|
||||
// now to deal with the method
|
||||
$methName = $GLOBALS['_xh'][$parser]['method'];
|
||||
$_methName = $GLOBALS['_xh'][$parser]['method'];
|
||||
$this->last_method = $methName;
|
||||
|
||||
if(preg_match('/'."^system\.".'/', $methName))
|
||||
{
|
||||
$dmap = $GLOBALS['_xmlrpcs_dmap'];
|
||||
$sysCall=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dmap = $this->dmap;
|
||||
$sysCall=0;
|
||||
}
|
||||
|
||||
if(!isset($dmap[$methName]['function']))
|
||||
{
|
||||
if($sysCall && $this->authed)
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['unknown_method'],
|
||||
$GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
if($this->authed)
|
||||
{
|
||||
/* phpgw mod - fetch the (bo) class methods to create the dmap */
|
||||
// This part is to update session action to match
|
||||
$this->method_requested = $methName;
|
||||
|
||||
$method = $methName;
|
||||
$tmp = explode('.',$methName);
|
||||
$methName = $tmp[2];
|
||||
$service = $tmp[1];
|
||||
$class = $tmp[0];
|
||||
|
||||
if(preg_match('/^service/',$method))
|
||||
{
|
||||
$t = 'phpgwapi.' . $class . '.exec';
|
||||
$dmap = ExecMethod($t,array($service,'list_methods','xmlrpc'));
|
||||
}
|
||||
elseif($GLOBALS['egw']->acl->check('run',1,$class))
|
||||
{
|
||||
/* This only happens if they have app access. If not, we will
|
||||
* return a fault below.
|
||||
*/
|
||||
$listmeth = $class . '.' . $service . '.' . 'list_methods';
|
||||
$dmap = ExecMethod($listmeth,'xmlrpc');
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['no_access'],
|
||||
$GLOBALS['xmlrpcstr']['no_access']
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
|
||||
$this->dmap = $dmap;
|
||||
/* _debug_array($this->dmap);exit; */
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($dmap[$methName]['function']))
|
||||
{
|
||||
// dispatch if exists
|
||||
if (isset($dmap[$methName]['signature']))
|
||||
{
|
||||
list($sr, $errstr) = $this->verifySignature($m, $dmap[$methName]['signature']);
|
||||
if(!$sr)
|
||||
{
|
||||
// Didn't match.
|
||||
|
||||
return CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
0,
|
||||
$GLOBALS['xmlrpcerr']['incorrect_params'],
|
||||
$GLOBALS['xmlrpcstr']['incorrect_params'] . ": ${errstr}"
|
||||
);
|
||||
}
|
||||
}
|
||||
if((!isset($dmap[$methName]['signature'])) || $sr)
|
||||
{
|
||||
// if no signature or correct signature
|
||||
if($sysCall)
|
||||
{
|
||||
$r = call_user_func($dmap[$methName]['function'], $this, $m);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(function_exists($dmap[$methName]['function']))
|
||||
{
|
||||
$r = call_user_func($dmap[$methName]['function'],$m);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* phpgw mod - finally, execute the function call and return the values */
|
||||
$params = $GLOBALS['_xh'][$parser]['params'][0];
|
||||
if(count($params) != 0)
|
||||
{
|
||||
$p = $params;
|
||||
$params = $p->getval();
|
||||
}
|
||||
|
||||
// _debug_array($params);
|
||||
$this->reqtoarray($params);
|
||||
// decode from utf-8 to our charset
|
||||
$this->req_array = $GLOBALS['egw']->translation->convert($this->req_array,'utf-8');
|
||||
//_debug_array($this->req_array);
|
||||
if (preg_match('/^service/',$method))
|
||||
{
|
||||
$res = ExecMethod('phpgwapi.service.exec',array($service,$methName,$this->req_array));
|
||||
}
|
||||
else
|
||||
{
|
||||
list($s,$c,$m) = explode('.',$_methName);
|
||||
$res = ExecMethod($s . '.' . $c . '.' . $dmap[$methName]['function'],$this->req_array);
|
||||
}
|
||||
//$this->resp_struct = array($this->build_resp($res,True));
|
||||
//@reset($this->resp_struct);
|
||||
//$r = CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$this->resp_struct,'struct'));
|
||||
// this fixes the unnecessary (and not standard-conform) array/xmlrpc struct around everything
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',$this->build_resp($res,True));
|
||||
// _debug_array($r);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['incorrect_params'],
|
||||
$GLOBALS['xmlrpcstr']['incorrect_params'] . ': ' . $sr[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// else prepare error response
|
||||
if(!$this->authed)
|
||||
{
|
||||
$r = False; // send 401 header to force authorization
|
||||
/*CreateObject('phpgwapi.xmlrpcresp',
|
||||
CreateObject('phpgwapi.xmlrpcval',
|
||||
'UNAUTHORIZED',
|
||||
'string'
|
||||
)
|
||||
);*/
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['unknown_method'],
|
||||
$GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($GLOBALS['_xh'][$parser]);
|
||||
return $r;
|
||||
}
|
||||
|
||||
function echoInput()
|
||||
{
|
||||
// a debugging routine: just echos back the input
|
||||
// packet as a string value
|
||||
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',"'Aha said I: '"
|
||||
. $GLOBALS['HTTP_RAW_POST_DATA'],'string'));
|
||||
//echo $r->serialize();
|
||||
|
||||
$fp = fopen('/tmp/xmlrpc_debug.in','w');
|
||||
fputs($fp,$r->serialize);
|
||||
fputs($fp,$GLOBALS['HTTP_RAW_POST_DATA']);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
function xmlrpc_error($error_number, $error_string)
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$error_number,
|
||||
$error_string . ': ' . $this->last_method
|
||||
);
|
||||
$this->service($r);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,384 +0,0 @@
|
||||
<?php
|
||||
// by Edd Dumbill (C) 1999-2001
|
||||
// <edd@usefulinc.com>
|
||||
// xmlrpc.inc,v 1.18 2001/07/06 18:23:57 edmundd
|
||||
|
||||
// License is granted to use or modify this software ('XML-RPC for PHP')
|
||||
// for commercial or non-commercial use provided the copyright of the author
|
||||
// is preserved in any distributed or derivative work.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
class xmlrpcmsg
|
||||
{
|
||||
var $payload;
|
||||
var $methodname;
|
||||
var $params = array();
|
||||
var $debug = 0;
|
||||
|
||||
function xmlrpcmsg($meth, $pars=0)
|
||||
{
|
||||
$this->methodname=$meth;
|
||||
if(is_array($pars) && sizeof($pars)>0)
|
||||
{
|
||||
for($i=0; $i<sizeof($pars); $i++)
|
||||
{
|
||||
$this->addParam($pars[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function xml_header()
|
||||
{
|
||||
return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";
|
||||
}
|
||||
|
||||
function xml_footer()
|
||||
{
|
||||
return "</methodCall>\n";
|
||||
}
|
||||
|
||||
function createPayload()
|
||||
{
|
||||
$this->payload=$this->xml_header();
|
||||
$this->payload.='<methodName>' . $this->methodname . "</methodName>\n";
|
||||
// if(sizeof($this->params)) {
|
||||
$this->payload.="<params>\n";
|
||||
for($i=0; $i<sizeof($this->params); $i++)
|
||||
{
|
||||
$p=$this->params[$i];
|
||||
$this->payload.="<param>\n" . $p->serialize() .
|
||||
"</param>\n";
|
||||
}
|
||||
$this->payload.="</params>\n";
|
||||
// }
|
||||
$this->payload.=$this->xml_footer();
|
||||
//$this->payload=str_replace("\n", "\r\n", $this->payload);
|
||||
}
|
||||
|
||||
function method($meth='')
|
||||
{
|
||||
if($meth!='')
|
||||
{
|
||||
$this->methodname=$meth;
|
||||
}
|
||||
return $this->methodname;
|
||||
}
|
||||
|
||||
function serialize()
|
||||
{
|
||||
$this->createPayload();
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
function addParam($par)
|
||||
{
|
||||
// add check: do not add to self params which are not xmlrpcvals
|
||||
if(is_object($par) && (get_class($par) == 'xmlrpcval' || is_subclass_of($par, 'xmlrpcval')))
|
||||
{
|
||||
$this->params[]=$par;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getParam($i) { return $this->params[$i]; }
|
||||
function getNumParams() { return sizeof($this->params); }
|
||||
|
||||
function &parseResponseFile($fp)
|
||||
{
|
||||
$ipd='';
|
||||
while($data=fread($fp, 32768))
|
||||
{
|
||||
$ipd.=$data;
|
||||
}
|
||||
//fclose($fp);
|
||||
$r =& $this->parseResponse($ipd);
|
||||
return $r;
|
||||
}
|
||||
|
||||
function &parseResponse($data='', $headers_processed=false)
|
||||
{
|
||||
$parser = xml_parser_create($GLOBALS['xmlrpc_defencoding']);
|
||||
|
||||
$hdrfnd = 0;
|
||||
if($this->debug)
|
||||
{
|
||||
//by maHo, replaced htmlspecialchars with htmlentities
|
||||
print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
|
||||
}
|
||||
|
||||
if($data == '')
|
||||
{
|
||||
error_log('No response received from server.');
|
||||
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']);
|
||||
return $r;
|
||||
}
|
||||
// see if we got an HTTP 200 OK, else bomb
|
||||
// but only do this if we're using the HTTP protocol.
|
||||
if(preg_match('/'."^HTTP".'/',$data))
|
||||
{
|
||||
// Strip HTTP 1.1 100 Continue header if present
|
||||
while(preg_match('/^HTTP\\/1.1 1[0-9]{2} /', $data))
|
||||
{
|
||||
$pos = strpos($data, 'HTTP', 12);
|
||||
// server sent a Continue header without any (valid) content following...
|
||||
// give the client a chance to know it
|
||||
if(!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
|
||||
{
|
||||
break;
|
||||
}
|
||||
$data = substr($data, $pos);
|
||||
}
|
||||
if(!preg_match('/'."^HTTP\\/[0-9\\.]+ 200 ".'/', $data))
|
||||
{
|
||||
$errstr= substr($data, 0, strpos($data, "\n")-1);
|
||||
error_log('HTTP error, got response: ' .$errstr);
|
||||
$r=& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')');
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['_xh'][$parser] = array();
|
||||
$GLOBALS['_xh'][$parser]['headers'] = array();
|
||||
$GLOBALS['_xh'][$parser]['stack'] = array();
|
||||
$GLOBALS['_xh'][$parser]['valuestack'] = array();
|
||||
|
||||
// separate HTTP headers from data
|
||||
if(preg_match('/'."^HTTP".'/', $data))
|
||||
{
|
||||
// be tolerant to usage of \n instead of \r\n to separate headers and data
|
||||
// (even though it is not valid http)
|
||||
$pos = strpos($data,"\r\n\r\n");
|
||||
if($pos || is_int($pos))
|
||||
{
|
||||
$bd = $pos+4;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pos = strpos($data,"\n\n");
|
||||
if($pos || is_int($pos))
|
||||
{
|
||||
$bd = $pos+2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No separation between response headers and body: fault?
|
||||
$bd = 0;
|
||||
}
|
||||
}
|
||||
// be tolerant to line endings, and extra empty lines
|
||||
$ar = preg_split("/\r?\n/", trim(substr($data, 0, $pos)));
|
||||
while(list(,$line) = @each($ar))
|
||||
{
|
||||
// take care of multi-line headers
|
||||
$arr = explode(':',$line);
|
||||
if(count($arr) > 1)
|
||||
{
|
||||
$header_name = strtolower(trim($arr[0]));
|
||||
// TO DO: some headers (the ones that allow a CSV list of values)
|
||||
// do allow many values to be passed using multiple header lines.
|
||||
// We should add content to $GLOBALS['_xh'][$parser]['headers'][$header_name]
|
||||
// instead of replacing it for those...
|
||||
$GLOBALS['_xh'][$parser]['headers'][$header_name] = $arr[1];
|
||||
for($i = 2; $i < count($arr); $i++)
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['headers'][$header_name] .= ':'.$arr[$i];
|
||||
} // while
|
||||
$GLOBALS['_xh'][$parser]['headers'][$header_name] = trim($GLOBALS['_xh'][$parser]['headers'][$header_name]);
|
||||
}
|
||||
elseif(isset($header_name))
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['headers'][$header_name] .= ' ' . trim($line);
|
||||
}
|
||||
}
|
||||
$data = substr($data, $bd);
|
||||
|
||||
if($this->debug && count($GLOBALS['_xh'][$parser]['headers']))
|
||||
{
|
||||
print '<PRE>';
|
||||
foreach($GLOBALS['_xh'][$parser]['headers'] as $header => $value)
|
||||
{
|
||||
print "HEADER: $header: $value\n";
|
||||
}
|
||||
print "</PRE>\n";
|
||||
}
|
||||
}
|
||||
|
||||
// if CURL was used for the call, http headers have been processed,
|
||||
// and dechunking + reinflating have been carried out
|
||||
if(!$headers_processed)
|
||||
{
|
||||
// Decode chunked encoding sent by http 1.1 servers
|
||||
if(isset($GLOBALS['_xh'][$parser]['headers']['transfer-encoding']) && $GLOBALS['_xh'][$parser]['headers']['transfer-encoding'] == 'chunked')
|
||||
{
|
||||
if(!$data = decode_chunked($data))
|
||||
{
|
||||
error_log('Errors occurred when trying to rebuild the chunked data received from server');
|
||||
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']);
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode gzip-compressed stuff
|
||||
// code shamelessly inspired from nusoap library by Dietrich Ayala
|
||||
if(isset($GLOBALS['_xh'][$parser]['headers']['content-encoding']))
|
||||
{
|
||||
if($GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'gzip')
|
||||
{
|
||||
// if decoding works, use it. else assume data wasn't gzencoded
|
||||
if(function_exists('gzinflate'))
|
||||
{
|
||||
if($GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'deflate' && $degzdata = @gzinflate($data))
|
||||
{
|
||||
$data = $degzdata;
|
||||
if($this->debug)
|
||||
print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
|
||||
}
|
||||
elseif($GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
|
||||
{
|
||||
$data = $degzdata;
|
||||
if($this->debug)
|
||||
print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('Errors occurred when trying to decode the deflated data received from server');
|
||||
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']);
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
|
||||
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']);
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end of 'de-chunk, re-inflate response'
|
||||
|
||||
// be tolerant of extra whitespace in response body
|
||||
$data = trim($data);
|
||||
|
||||
// be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)
|
||||
// idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib
|
||||
$bd = false;
|
||||
$pos = strpos($data, '</methodResponse>');
|
||||
while($pos || is_int($pos))
|
||||
{
|
||||
$bd = $pos+17;
|
||||
$pos = strpos($data, '</methodResponse>', $bd);
|
||||
}
|
||||
if($bd)
|
||||
{
|
||||
$data = substr($data, 0, $bd);
|
||||
}
|
||||
|
||||
$GLOBALS['_xh'][$parser]['isf']=0;
|
||||
$GLOBALS['_xh'][$parser]['isf_reason']='';
|
||||
$GLOBALS['_xh'][$parser]['ac']='';
|
||||
$GLOBALS['_xh'][$parser]['qt']='';
|
||||
|
||||
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
|
||||
// G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
|
||||
// the xml parser to give us back data in the expected charset
|
||||
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
|
||||
|
||||
xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
|
||||
xml_set_character_data_handler($parser, 'xmlrpc_cd');
|
||||
xml_set_default_handler($parser, 'xmlrpc_dh');
|
||||
//$xmlrpc_value=new xmlrpcval;
|
||||
|
||||
if(!xml_parse($parser, $data, sizeof($data)))
|
||||
{
|
||||
// thanks to Peter Kocks <peter.kocks@baygate.com>
|
||||
if((xml_get_current_line_number($parser)) == 1)
|
||||
{
|
||||
$errstr = 'XML error at line 1, check URL';
|
||||
}
|
||||
else
|
||||
{
|
||||
$errstr = sprintf('XML error: %s at line %d',
|
||||
xml_error_string(xml_get_error_code($parser)),
|
||||
xml_get_current_line_number($parser));
|
||||
}
|
||||
error_log($errstr);
|
||||
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')');
|
||||
xml_parser_free($parser);
|
||||
if($this->debug)
|
||||
{
|
||||
print $errstr;
|
||||
}
|
||||
$r->hdrs = $GLOBALS['_xh'][$parser]['headers'];
|
||||
return $r;
|
||||
}
|
||||
xml_parser_free($parser);
|
||||
if($GLOBALS['_xh'][$parser]['isf'] > 1)
|
||||
{
|
||||
if ($this->debug)
|
||||
{
|
||||
///@todo echo something for user?
|
||||
}
|
||||
|
||||
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['invalid_return'],
|
||||
$GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh'][$parser]['isf_reason']);
|
||||
}
|
||||
elseif (!is_object($GLOBALS['_xh'][$parser]['value']))
|
||||
{
|
||||
// then something odd has happened
|
||||
// and it's time to generate a client side error
|
||||
// indicating something odd went on
|
||||
$r=& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['invalid_return'],
|
||||
$GLOBALS['xmlrpcstr']['invalid_return']);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->debug)
|
||||
{
|
||||
print "<PRE>---PARSED---\n" ;
|
||||
var_dump($GLOBALS['_xh'][$parser]['value']);
|
||||
print "\n---END---</PRE>";
|
||||
} // note that using =& will raise an error if $GLOBALS['_xh'][$parser]['st'] does not generate an object.
|
||||
|
||||
$v = $GLOBALS['_xh'][$parser]['value'];
|
||||
|
||||
if($GLOBALS['_xh'][$parser]['isf'])
|
||||
{
|
||||
$errno_v = $v->structmem('faultCode');
|
||||
$errstr_v = $v->structmem('faultString');
|
||||
$errno = $errno_v->scalarval();
|
||||
|
||||
if($errno == 0)
|
||||
{
|
||||
// FAULT returned, errno needs to reflect that
|
||||
$errno = -1;
|
||||
}
|
||||
|
||||
$r =& CreateObject('phpgwapi.xmlrpcresp',$v, $errno, $errstr_v->scalarval());
|
||||
}
|
||||
else
|
||||
{
|
||||
$r=& CreateObject('phpgwapi.xmlrpcresp',$v);
|
||||
}
|
||||
}
|
||||
|
||||
$r->hdrs = $GLOBALS['_xh'][$parser]['headers'];
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,97 +0,0 @@
|
||||
<?php
|
||||
// by Edd Dumbill (C) 1999-2001
|
||||
// <edd@usefulinc.com>
|
||||
// xmlrpc.inc,v 1.18 2001/07/06 18:23:57 edmundd
|
||||
|
||||
// License is granted to use or modify this software ("XML-RPC for PHP")
|
||||
// for commercial or non-commercial use provided the copyright of the author
|
||||
// is preserved in any distributed or derivative work.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
class xmlrpcresp
|
||||
{
|
||||
var $val = 0;
|
||||
var $errno = 0;
|
||||
var $errstr = '';
|
||||
var $hdrs = array();
|
||||
|
||||
/// @todo add check that $val is of correct type???
|
||||
function xmlrpcresp($val, $fcode = 0, $fstr = '')
|
||||
{
|
||||
if($fcode != 0)
|
||||
{
|
||||
// error
|
||||
$this->errno = $fcode;
|
||||
$this->errstr = $fstr;
|
||||
//$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.
|
||||
}
|
||||
elseif(!is_object($val) || (get_class($val) != 'xmlrpcval' && !is_subclass_of($val, 'xmlrpcval')))
|
||||
{
|
||||
// programmer error
|
||||
// TODO
|
||||
error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to xmlrpcresp. Defaulting to empty value.");
|
||||
$this->val = new xmlrpcval();
|
||||
}
|
||||
else
|
||||
{
|
||||
// success
|
||||
$this->val = $val;
|
||||
}
|
||||
}
|
||||
|
||||
function faultCode()
|
||||
{
|
||||
return $this->errno;
|
||||
}
|
||||
|
||||
function faultString()
|
||||
{
|
||||
return $this->errstr;
|
||||
}
|
||||
|
||||
function value()
|
||||
{
|
||||
return $this->val;
|
||||
}
|
||||
|
||||
function serialize()
|
||||
{
|
||||
$result = "<methodResponse>\n";
|
||||
if($this->errno)
|
||||
{
|
||||
// G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients
|
||||
$result .= '<fault>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>faultCode</name>
|
||||
<value><int>' . $this->errno . '</int></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>faultString</name>
|
||||
<value><string>' . xmlrpc_encode_entities($this->errstr) . '</string></value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</fault>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$result .= "<params>\n<param>\n" .
|
||||
$this->val->serialize() .
|
||||
"</param>\n</params>";
|
||||
}
|
||||
$result .= "\n</methodResponse>";
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -1,333 +0,0 @@
|
||||
<?php
|
||||
// by Edd Dumbill (C) 1999-2001
|
||||
// <edd@usefulinc.com>
|
||||
// xmlrpc.inc,v 1.18 2001/07/06 18:23:57 edmundd
|
||||
|
||||
// License is granted to use or modify this software ("XML-RPC for PHP")
|
||||
// for commercial or non-commercial use provided the copyright of the author
|
||||
// is preserved in any distributed or derivative work.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
class xmlrpcval
|
||||
{
|
||||
var $me=array();
|
||||
var $mytype=0;
|
||||
|
||||
function xmlrpcval($val=-1, $type='')
|
||||
{
|
||||
//$this->me=array();
|
||||
//$this->mytype=0;
|
||||
if($val!==-1 || $type!='')
|
||||
{
|
||||
if($type=='')
|
||||
{
|
||||
$type='string';
|
||||
}
|
||||
if($GLOBALS['xmlrpcTypes'][$type]==1)
|
||||
{
|
||||
$this->addScalar($val,$type);
|
||||
}
|
||||
elseif($GLOBALS['xmlrpcTypes'][$type]==2)
|
||||
{
|
||||
$this->addArray($val);
|
||||
}
|
||||
elseif($GLOBALS['xmlrpcTypes'][$type]==3)
|
||||
{
|
||||
$this->addStruct($val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addScalar($val, $type='string')
|
||||
{
|
||||
$typeof=@$GLOBALS['xmlrpcTypes'][$type];
|
||||
if($typeof!=1)
|
||||
{
|
||||
error_log("addScalar: not a scalar type ($typeof)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// coerce booleans into correct values
|
||||
// NB: shall we do it for datetime too?
|
||||
if($type == xmlrpcBoolean)
|
||||
{
|
||||
if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
|
||||
{
|
||||
$val=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$val=false;
|
||||
}
|
||||
}
|
||||
|
||||
switch($this->mytype)
|
||||
{
|
||||
case 1:
|
||||
error_log('addScalar: scalar xmlrpcval can have only one value');
|
||||
return 0;
|
||||
case 3:
|
||||
error_log('addScalar: cannot add anonymous scalar to struct xmlrpcval');
|
||||
return 0;
|
||||
case 2:
|
||||
// we're adding a scalar value to an array here
|
||||
//$ar=$this->me['array'];
|
||||
//$ar[]= new xmlrpcval($val, $type);
|
||||
//$this->me['array']=$ar;
|
||||
// Faster (?) avoid all the costly array-copy-by-val done here...
|
||||
$this->me['array'][]=& CreateObject('phpgwapi.xmlrpcval',$val, $type);
|
||||
return 1;
|
||||
default:
|
||||
// a scalar, so set the value and remember we're scalar
|
||||
$this->me[$type]=$val;
|
||||
$this->mytype=$typeof;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
///@todo add some checking for $vals to be an array of xmlrpcvals?
|
||||
function addArray($vals)
|
||||
{
|
||||
if($this->mytype==0)
|
||||
{
|
||||
$this->mytype=$GLOBALS['xmlrpcTypes']['array'];
|
||||
$this->me['array']=$vals;
|
||||
return 1;
|
||||
}
|
||||
elseif($this->mytype==2)
|
||||
{
|
||||
// we're adding to an array here
|
||||
$this->me['array'] = array_merge($this->me['array'], $vals);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('xmlrpcval: already initialized as a [' . $this->kindOf() . ']');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
///@todo add some checking for $vals to be an array?
|
||||
function addStruct($vals)
|
||||
{
|
||||
if($this->mytype==0)
|
||||
{
|
||||
$this->mytype = $GLOBALS['xmlrpcTypes']['struct'];
|
||||
$this->me['struct']=$vals;
|
||||
return 1;
|
||||
}
|
||||
elseif($this->mytype==3)
|
||||
{
|
||||
// we're adding to a struct here
|
||||
$this->me['struct'] = array_merge($this->me['struct'], $vals);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('xmlrpcval: already initialized as a [' . $this->kindOf() . ']');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function dump($ar)
|
||||
{
|
||||
foreach($ar as $key => $val)
|
||||
{
|
||||
echo "$key => $val<br />";
|
||||
if($key == 'array')
|
||||
{
|
||||
while(list($key2, $val2) = each($val))
|
||||
{
|
||||
echo "-- $key2 => $val2<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function kindOf()
|
||||
{
|
||||
switch($this->mytype)
|
||||
{
|
||||
case 3:
|
||||
return 'struct';
|
||||
break;
|
||||
case 2:
|
||||
return 'array';
|
||||
break;
|
||||
case 1:
|
||||
return 'scalar';
|
||||
break;
|
||||
default:
|
||||
return 'undef';
|
||||
}
|
||||
}
|
||||
|
||||
function serializedata($typ, $val)
|
||||
{
|
||||
$rs='';
|
||||
switch(@$GLOBALS['xmlrpcTypes'][$typ])
|
||||
{
|
||||
case 3:
|
||||
// struct
|
||||
$rs.="<struct>\n";
|
||||
foreach($val as $key2 => $val2)
|
||||
{
|
||||
$rs.="<member><name>${key2}</name>\n";
|
||||
$rs.=$this->serializeval($val2);
|
||||
$rs.="</member>\n";
|
||||
}
|
||||
$rs.='</struct>';
|
||||
break;
|
||||
case 2:
|
||||
// array
|
||||
$rs.="<array>\n<data>\n";
|
||||
for($i=0; $i<sizeof($val); $i++)
|
||||
{
|
||||
$rs.=$this->serializeval($val[$i]);
|
||||
}
|
||||
$rs.="</data>\n</array>";
|
||||
break;
|
||||
case 1:
|
||||
switch($typ)
|
||||
{
|
||||
case xmlrpcBase64:
|
||||
$rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
|
||||
break;
|
||||
case xmlrpcBoolean:
|
||||
$rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
|
||||
break;
|
||||
case xmlrpcString:
|
||||
// G. Giunta 2005/2/13: do NOT use htmlentities, since
|
||||
// it will produce named html entities, which are invalid xml
|
||||
$rs.="<${typ}>" . xmlrpc_encode_entities($val). "</${typ}>";
|
||||
// $rs.="<${typ}>" . htmlentities($val). "</${typ}>";
|
||||
break;
|
||||
default:
|
||||
$rs.="<${typ}>${val}</${typ}>";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return $rs;
|
||||
}
|
||||
|
||||
function serialize()
|
||||
{
|
||||
return $this->serializeval($this);
|
||||
}
|
||||
|
||||
function serializeval($o)
|
||||
{
|
||||
// add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
|
||||
//if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
|
||||
//{
|
||||
$ar=$o->me;
|
||||
reset($ar);
|
||||
list($typ, $val) = each($ar);
|
||||
return '<value>' . $this->serializedata($typ, $val) . "</value>\n";
|
||||
//}
|
||||
}
|
||||
|
||||
function structmemexists($m)
|
||||
{
|
||||
return array_key_exists($this->me['struct'][$m]);
|
||||
}
|
||||
|
||||
function structmem($m)
|
||||
{
|
||||
return $this->me['struct'][$m];
|
||||
}
|
||||
|
||||
function structreset()
|
||||
{
|
||||
reset($this->me['struct']);
|
||||
}
|
||||
|
||||
function structeach()
|
||||
{
|
||||
return each($this->me['struct']);
|
||||
}
|
||||
|
||||
function scalarval()
|
||||
{
|
||||
reset($this->me);
|
||||
list(,$b)=each($this->me);
|
||||
return $b;
|
||||
}
|
||||
|
||||
function scalartyp()
|
||||
{
|
||||
reset($this->me);
|
||||
list($a,$b)=each($this->me);
|
||||
if($a == xmlrpcI4)
|
||||
{
|
||||
$a = xmlrpcInt;
|
||||
}
|
||||
return $a;
|
||||
}
|
||||
|
||||
function arraymem($m)
|
||||
{
|
||||
return $this->me['array'][$m];
|
||||
}
|
||||
|
||||
function arraysize()
|
||||
{
|
||||
return count($this->me['array']);
|
||||
}
|
||||
|
||||
function structsize()
|
||||
{
|
||||
return count($this->me['struct']);
|
||||
}
|
||||
|
||||
// DEPRECATED! this code looks like it is very fragile and has not been fixed
|
||||
// for a long long time. Shall we remove it for 2.0?
|
||||
function getval()
|
||||
{
|
||||
// UNSTABLE ?
|
||||
reset($this->me);
|
||||
list($a,$b)=each($this->me);
|
||||
// contributed by I Sofer, 2001-03-24
|
||||
// add support for nested arrays to scalarval
|
||||
// i've created a new method here, so as to
|
||||
// preserve back compatibility
|
||||
|
||||
if(is_array($b))
|
||||
{
|
||||
foreach($b as $id => $cont)
|
||||
{
|
||||
$b[$id] = $cont->scalarval();
|
||||
}
|
||||
}
|
||||
|
||||
// add support for structures directly encoding php objects
|
||||
if(is_object($b))
|
||||
{
|
||||
$t = get_object_vars($b);
|
||||
foreach($t as $id => $cont)
|
||||
{
|
||||
$t[$id] = $cont->scalarval();
|
||||
}
|
||||
|
||||
foreach($t as $id => $cont)
|
||||
{
|
||||
@$b->$id = $cont;
|
||||
}
|
||||
}
|
||||
// end contrib
|
||||
return $b;
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,960 +0,0 @@
|
||||
<?php
|
||||
// by Edd Dumbill (C) 1999-2001
|
||||
// <edd@usefulinc.com>
|
||||
// xmlrpc.inc,v 1.18 2001/07/06 18:23:57 edmundd
|
||||
|
||||
// License is granted to use or modify this software ("XML-RPC for PHP")
|
||||
// for commercial or non-commercial use provided the copyright of the author
|
||||
// is preserved in any distributed or derivative work.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
if (!function_exists('xml_parser_create'))
|
||||
{
|
||||
// Win 32 fix. From: "Leo West" <lwest@imaginet.fr>
|
||||
if($WINDIR)
|
||||
{
|
||||
dl('php3_xml.dll');
|
||||
}
|
||||
else
|
||||
{
|
||||
dl('xml.so');
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['xmlrpc_valid_parents'] = array(
|
||||
'BOOLEAN' => array('VALUE'),
|
||||
'I4' => array('VALUE'),
|
||||
'INT' => array('VALUE'),
|
||||
'STRING' => array('VALUE'),
|
||||
'DOUBLE' => array('VALUE'),
|
||||
'DATETIME.ISO8601' => array('VALUE'),
|
||||
'BASE64' => array('VALUE'),
|
||||
'ARRAY' => array('VALUE'),
|
||||
'STRUCT' => array('VALUE'),
|
||||
'PARAM' => array('PARAMS'),
|
||||
'METHODNAME' => array('METHODCALL'),
|
||||
'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
|
||||
'MEMBER' => array('STRUCT'),
|
||||
'NAME' => array('MEMBER'),
|
||||
'DATA' => array('ARRAY'),
|
||||
'FAULT' => array('METHODRESPONSE'),
|
||||
'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
|
||||
);
|
||||
|
||||
define('xmlrpcI4','i4');
|
||||
define('xmlrpcInt','int');
|
||||
define('xmlrpcBoolean','boolean');
|
||||
define('xmlrpcDouble','double');
|
||||
define('xmlrpcString','string');
|
||||
define('xmlrpcDateTime','dateTime.iso8601');
|
||||
define('xmlrpcBase64','base64');
|
||||
define('xmlrpcArray','array');
|
||||
define('xmlrpcStruct','struct');
|
||||
|
||||
$GLOBALS['xmlrpcTypes'] = array(
|
||||
xmlrpcI4 => 1,
|
||||
xmlrpcInt => 1,
|
||||
xmlrpcBoolean => 1,
|
||||
xmlrpcString => 1,
|
||||
xmlrpcDouble => 1,
|
||||
xmlrpcDateTime => 1,
|
||||
xmlrpcBase64 => 1,
|
||||
xmlrpcArray => 2,
|
||||
xmlrpcStruct => 3
|
||||
);
|
||||
|
||||
$GLOBALS['xmlEntities']=array(
|
||||
'amp' => '&',
|
||||
'quot' => '"',
|
||||
'lt' => '<',
|
||||
'gt' => '>',
|
||||
'apos' => "'"
|
||||
);
|
||||
|
||||
$GLOBALS['xmlrpcerr']['unknown_method']=1;
|
||||
$GLOBALS['xmlrpcstr']['unknown_method']='Unknown method';
|
||||
$GLOBALS['xmlrpcerr']['invalid_return']=2;
|
||||
$GLOBALS['xmlrpcstr']['invalid_return']='Invalid return payload: enable debugging to examine incoming payload';
|
||||
$GLOBALS['xmlrpcerr']['incorrect_params']=3;
|
||||
$GLOBALS['xmlrpcstr']['incorrect_params']='Incorrect parameters passed to method';
|
||||
$GLOBALS['xmlrpcerr']['introspect_unknown']=4;
|
||||
$GLOBALS['xmlrpcstr']['introspect_unknown']="Can't introspect: method unknown";
|
||||
$GLOBALS['xmlrpcerr']['http_error']=5;
|
||||
$GLOBALS['xmlrpcstr']['http_error']="Didn't receive 200 OK from remote server.";
|
||||
$GLOBALS['xmlrpcerr']['no_data']=6;
|
||||
$GLOBALS['xmlrpcstr']['no_data']='No data received from server.';
|
||||
$GLOBALS['xmlrpcerr']['no_ssl']=7;
|
||||
$GLOBALS['xmlrpcstr']['no_ssl']='No SSL support compiled in.';
|
||||
$GLOBALS['xmlrpcerr']['curl_fail']=8;
|
||||
$GLOBALS['xmlrpcstr']['curl_fail']='CURL error';
|
||||
$GLOBALS['xmlrpcerr']['multicall_notstruct'] = 9;
|
||||
$GLOBALS['xmlrpcstr']['multicall_notstruct'] = 'system.multicall expected struct';
|
||||
$GLOBALS['xmlrpcerr']['multicall_nomethod'] = 10;
|
||||
$GLOBALS['xmlrpcstr']['multicall_nomethod'] = 'missing methodName';
|
||||
$GLOBALS['xmlrpcerr']['multicall_notstring'] = 11;
|
||||
$GLOBALS['xmlrpcstr']['multicall_notstring'] = 'methodName is not a string';
|
||||
$GLOBALS['xmlrpcerr']['multicall_recursion'] = 12;
|
||||
$GLOBALS['xmlrpcstr']['multicall_recursion'] = 'recursive system.multicall forbidden';
|
||||
$GLOBALS['xmlrpcerr']['multicall_noparams'] = 13;
|
||||
$GLOBALS['xmlrpcstr']['multicall_noparams'] = 'missing params';
|
||||
$GLOBALS['xmlrpcerr']['multicall_notarray'] = 14;
|
||||
$GLOBALS['xmlrpcstr']['multicall_notarray'] = 'params is not an array';
|
||||
|
||||
$GLOBALS['xmlrpcerr']['invalid_request']=15;
|
||||
$GLOBALS['xmlrpcstr']['invalid_request']='Invalid request payload';
|
||||
$GLOBALS['xmlrpcerr']['no_curl']=16;
|
||||
$GLOBALS['xmlrpcstr']['no_curl']='No CURL support compiled in.';
|
||||
$GLOBALS['xmlrpcerr']['server_error']=17;
|
||||
$GLOBALS['xmlrpcstr']['server_error']='Internal server error';
|
||||
|
||||
$GLOBALS['xmlrpcerr']['no_access'] = 18;
|
||||
$GLOBALS['xmlrpcstr']['no_access'] = 'Access denied';
|
||||
$GLOBALS['xmlrpcerr']['not_existent'] = 19;
|
||||
$GLOBALS['xmlrpcstr']['not_existent'] = 'Entry does not (longer) exist!';
|
||||
|
||||
$GLOBALS['xmlrpcerr']['cannot_decompress']=103;
|
||||
$GLOBALS['xmlrpcstr']['cannot_decompress']='Received from server compressed HTTP and cannot decompress';
|
||||
$GLOBALS['xmlrpcerr']['decompress_fail']=104;
|
||||
$GLOBALS['xmlrpcstr']['decompress_fail']='Received from server invalid compressed HTTP';
|
||||
$GLOBALS['xmlrpcerr']['dechunk_fail']=105;
|
||||
$GLOBALS['xmlrpcstr']['dechunk_fail']='Received from server invalid chunked HTTP';
|
||||
$GLOBALS['xmlrpcerr']['server_cannot_decompress']=106;
|
||||
$GLOBALS['xmlrpcstr']['server_cannot_decompress']='Received from client compressed HTTP request and cannot decompress';
|
||||
$GLOBALS['xmlrpcerr']['server_decompress_fail']=107;
|
||||
$GLOBALS['xmlrpcstr']['server_decompress_fail']='Received from client invalid compressed HTTP request';
|
||||
|
||||
$GLOBALS['xmlrpc_defencoding'] = 'UTF-8';
|
||||
$GLOBALS['xmlrpc_internalencoding']='ISO-8859-1';
|
||||
|
||||
$GLOBALS['xmlrpcName'] = 'XML-RPC for PHP';
|
||||
$GLOBALS['xmlrpcVersion'] = '2.0';
|
||||
|
||||
// let user errors start at 800
|
||||
$GLOBALS['xmlrpcerruser'] = 800;
|
||||
// let XML parse errors start at 100
|
||||
$GLOBALS['xmlrpcerrxml'] = 100;
|
||||
|
||||
// formulate backslashes for escaping regexp
|
||||
$GLOBALS['xmlrpc_backslash'] = chr(92) . chr(92);
|
||||
|
||||
/*!
|
||||
@function xmlrpcfault
|
||||
@abstract Error reporting for XML-RPC
|
||||
@discussion Author: jengo <br>
|
||||
Returns XML-RPC fault and stops this execution of the application. <br>
|
||||
Syntax: void xmlrpcfault(string) <br>
|
||||
Example1: xmlrpcfault('Session could not be verifed'); <br>
|
||||
@param $string Error message to be returned.
|
||||
*/
|
||||
function xmlrpcfault($string)
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',
|
||||
CreateObject('phpgwapi.xmlrpcval'),
|
||||
$GLOBALS['xmlrpcerr']['unknown_method'],
|
||||
$string
|
||||
);
|
||||
$payload = '<?xml version="1.0"?>' . "\n" . $r->serialize();
|
||||
Header('Content-type: text/xml');
|
||||
Header('Content-length: ' . bytes($payload));
|
||||
print $payload;
|
||||
$GLOBALS['egw']->common->phpgw_exit(False);
|
||||
}
|
||||
|
||||
// used to store state during parsing
|
||||
// quick explanation of components:
|
||||
// ac - used to accumulate values
|
||||
// isf - used to indicate a fault
|
||||
// lv - used to indicate "looking for a value": implements
|
||||
// the logic to allow values with no types to be strings
|
||||
// params - used to store parameters in method calls
|
||||
// method - used to store method name
|
||||
// stack - array with genealogy of xml elements names:
|
||||
// used to validate nesting of xmlrpc elements
|
||||
$GLOBALS['_xh'] = null;
|
||||
|
||||
/**
|
||||
* To help correct communication of non-ascii chars inside strings, regardless
|
||||
* of the charset used when sending requests, parsing them, sending responses
|
||||
* and parsing responses, convert all non-ascii chars present in the message
|
||||
* into their equivalent 'charset entity'. Charset entities enumerated this way
|
||||
* are independent of the charset encoding used to transmit them, and all XML
|
||||
* parsers are bound to understand them.
|
||||
*
|
||||
* @author Eugene Pivnev
|
||||
*/
|
||||
function xmlrpc_encode_entities($data)
|
||||
{
|
||||
return htmlspecialchars($data,ENT_QUOTES,$GLOBALS['egw']->translation->system_charset ?
|
||||
$GLOBALS['egw']->translation->system_charset : 'UTF-8');
|
||||
}
|
||||
|
||||
if (!function_exists('htmlspecialchars_decode')) // php < 5.1
|
||||
{
|
||||
function htmlspecialchars_decode($text,$quote_style=ENT_COMPAT)
|
||||
{
|
||||
return strtr($text, array_flip(get_html_translation_table(HTML_SPECIALCHARS,$quote_style)));
|
||||
}
|
||||
}
|
||||
|
||||
function xmlrpc_entity_decode($string)
|
||||
{
|
||||
return htmlspecialchars_decode($data,ENT_QUOTES);
|
||||
}
|
||||
|
||||
function xmlrpc_lookup_entity($ent)
|
||||
{
|
||||
if (isset($GLOBALS['xmlEntities'][strtolower($ent)]))
|
||||
{
|
||||
return $GLOBALS['xmlEntities'][strtolower($ent)];
|
||||
}
|
||||
if (preg_match('/'."^#([0-9]+)$".'/', $ent, $regs))
|
||||
{
|
||||
return chr($regs[1]);
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
|
||||
function xmlrpc_se($parser, $name, $attrs)
|
||||
{
|
||||
// if invalid xmlrpc already detected, skip all processing
|
||||
if ($GLOBALS['_xh'][$parser]['isf'] < 2)
|
||||
{
|
||||
// check for correct element nesting
|
||||
// top level element can only be of 2 types
|
||||
if (count($GLOBALS['_xh'][$parser]['stack']) == 0)
|
||||
{
|
||||
if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['isf'] = 2;
|
||||
$GLOBALS['_xh'][$parser]['isf_reason'] = 'missing top level xmlrpc element';
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// not top level element: see if parent is OK
|
||||
if (!in_array($GLOBALS['_xh'][$parser]['stack'][0], $GLOBALS['xmlrpc_valid_parents'][$name]))
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['isf'] = 2;
|
||||
$GLOBALS['_xh'][$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$GLOBALS['_xh'][$parser]['stack'][0]}";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch($name)
|
||||
{
|
||||
case 'STRUCT':
|
||||
case 'ARRAY':
|
||||
// create an empty array to hold child values, and push it onto appropriate stack
|
||||
$cur_val = array();
|
||||
$cur_val['values'] = array();
|
||||
$cur_val['type'] = $name;
|
||||
@array_unshift($GLOBALS['_xh'][$parser]['valuestack'], $cur_val);
|
||||
break;
|
||||
case 'DATA':
|
||||
case 'METHODCALL':
|
||||
case 'METHODRESPONSE':
|
||||
case 'PARAMS':
|
||||
// valid elements that add little to processing
|
||||
break;
|
||||
case 'METHODNAME':
|
||||
case 'NAME':
|
||||
$GLOBALS['_xh'][$parser]['ac']='';
|
||||
break;
|
||||
case 'FAULT':
|
||||
$GLOBALS['_xh'][$parser]['isf']=1;
|
||||
break;
|
||||
case 'VALUE':
|
||||
$GLOBALS['_xh'][$parser]['vt']='value'; // indicator: no value found yet
|
||||
$GLOBALS['_xh'][$parser]['ac']='';
|
||||
$GLOBALS['_xh'][$parser]['lv']=1;
|
||||
break;
|
||||
case 'I4':
|
||||
case 'INT':
|
||||
case 'STRING':
|
||||
case 'BOOLEAN':
|
||||
case 'DOUBLE':
|
||||
case 'DATETIME.ISO8601':
|
||||
case 'BASE64':
|
||||
if ($GLOBALS['_xh'][$parser]['vt']!='value')
|
||||
{
|
||||
//two data elements inside a value: an error occurred!
|
||||
$GLOBALS['_xh'][$parser]['isf'] = 2;
|
||||
$GLOBALS['_xh'][$parser]['isf_reason'] = "$name element following a {$GLOBALS['_xh'][$parser]['vt']} element inside a single value";
|
||||
return;
|
||||
}
|
||||
|
||||
$GLOBALS['_xh'][$parser]['ac']=''; // reset the accumulator
|
||||
break;
|
||||
case 'MEMBER':
|
||||
$GLOBALS['_xh'][$parser]['valuestack'][0]['name']=''; // set member name to null, in case we do not find in the xml later on
|
||||
//$GLOBALS['_xh'][$parser]['ac']='';
|
||||
// Drop trough intentionally
|
||||
case 'PARAM':
|
||||
// clear value, so we can check later if no value will passed for this param/member
|
||||
$GLOBALS['_xh'][$parser]['value']=null;
|
||||
break;
|
||||
default:
|
||||
/// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!
|
||||
$GLOBALS['_xh'][$parser]['isf'] = 2;
|
||||
$GLOBALS['_xh'][$parser]['isf_reason'] = "found not-xmlrpc xml element $name";
|
||||
break;
|
||||
}
|
||||
|
||||
// Save current element name to stack, to validate nesting
|
||||
@array_unshift($GLOBALS['_xh'][$parser]['stack'], $name);
|
||||
|
||||
if($name!='VALUE')
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['lv']=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function xmlrpc_ee($parser, $name)
|
||||
{
|
||||
if ($GLOBALS['_xh'][$parser]['isf'] < 2)
|
||||
{
|
||||
// push this element name from stack
|
||||
// NB: if XML validates, correct opening/closing is guaranteed and
|
||||
// we do not have to check for $name == $curr_elem.
|
||||
// we also checked for proper nesting at start of elements...
|
||||
$curr_elem = array_shift($GLOBALS['_xh'][$parser]['stack']);
|
||||
|
||||
switch($name)
|
||||
{
|
||||
case 'STRUCT':
|
||||
case 'ARRAY':
|
||||
// fetch out of stack array of values, and promote it to current value
|
||||
$curr_val = array_shift($GLOBALS['_xh'][$parser]['valuestack']);
|
||||
$GLOBALS['_xh'][$parser]['value'] = $curr_val['values'];
|
||||
|
||||
$GLOBALS['_xh'][$parser]['vt']=strtolower($name);
|
||||
break;
|
||||
case 'NAME':
|
||||
$GLOBALS['_xh'][$parser]['valuestack'][0]['name'] = $GLOBALS['_xh'][$parser]['ac'];
|
||||
break;
|
||||
case 'BOOLEAN':
|
||||
case 'I4':
|
||||
case 'INT':
|
||||
case 'STRING':
|
||||
case 'DOUBLE':
|
||||
case 'DATETIME.ISO8601':
|
||||
case 'BASE64':
|
||||
$GLOBALS['_xh'][$parser]['vt']=strtolower($name);
|
||||
if ($name=='STRING')
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['value']=$GLOBALS['_xh'][$parser]['ac'];
|
||||
}
|
||||
elseif ($name=='DATETIME.ISO8601')
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['vt'] = xmlrpcDateTime;
|
||||
$GLOBALS['_xh'][$parser]['value']=$GLOBALS['_xh'][$parser]['ac'];
|
||||
}
|
||||
elseif ($name=='BASE64')
|
||||
{
|
||||
///@todo check for failure of base64 decoding / catch warnings
|
||||
$GLOBALS['_xh'][$parser]['value'] = base64_decode($GLOBALS['_xh'][$parser]['ac']);
|
||||
}
|
||||
elseif ($name=='BOOLEAN')
|
||||
{
|
||||
// special case here: we translate boolean 1 or 0 into PHP
|
||||
// constants true or false
|
||||
// NB: this simple checks helps a lot sanitizing input, ie no
|
||||
// security problems around here
|
||||
if ($GLOBALS['_xh'][$parser]['ac']=='1')
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['value']=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// log if receiveing something strange, even though we set the value to false anyway
|
||||
if ($GLOBALS['_xh'][$parser]['ac']!='0')
|
||||
error_log('XML-RPC: invalid value received in BOOLEAN: '.$GLOBALS['_xh'][$parser]['ac']);
|
||||
$GLOBALS['_xh'][$parser]['value']=false;
|
||||
}
|
||||
}
|
||||
elseif ($name=='DOUBLE')
|
||||
{
|
||||
// we have a DOUBLE
|
||||
// we must check that only 0123456789-.<space> are characters here
|
||||
if (!preg_match('/^[+-]?[eE0123456789 \\t\\.]+$/', $GLOBALS['_xh'][$parser]['ac']))
|
||||
{
|
||||
// TODO: find a better way of throwing an error
|
||||
// than this!
|
||||
error_log('XML-RPC: non numeric value received in DOUBLE: '.$GLOBALS['_xh'][$parser]['ac']);
|
||||
$GLOBALS['_xh'][$parser]['value']='ERROR_NON_NUMERIC_FOUND';
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's ok, add it on
|
||||
$GLOBALS['_xh'][$parser]['value']=(double)$GLOBALS['_xh'][$parser]['ac'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have an I4/INT
|
||||
// we must check that only 0123456789-<space> are characters here
|
||||
if (!preg_match('/^[+-]?[0123456789 \\t]+$/', $GLOBALS['_xh'][$parser]['ac']))
|
||||
{
|
||||
// TODO: find a better way of throwing an error
|
||||
// than this!
|
||||
error_log('XML-RPC: non numeric value received in INT: '.$GLOBALS['_xh'][$parser]['ac']);
|
||||
$GLOBALS['_xh'][$parser]['value']='ERROR_NON_NUMERIC_FOUND';
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's ok, add it on
|
||||
$GLOBALS['_xh'][$parser]['value'] = (int)$GLOBALS['_xh'][$parser]['ac'];
|
||||
}
|
||||
}
|
||||
$GLOBALS['_xh'][$parser]['ac']=''; // is this necessary?
|
||||
$GLOBALS['_xh'][$parser]['lv']=3; // indicate we've found a value
|
||||
break;
|
||||
case 'VALUE':
|
||||
// This if() detects if no scalar was inside <VALUE></VALUE>
|
||||
if ($GLOBALS['_xh'][$parser]['vt'] == 'value')
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['value'] = $GLOBALS['_xh'][$parser]['ac'];
|
||||
$GLOBALS['_xh'][$parser]['vt'] = xmlrpcString;
|
||||
}
|
||||
|
||||
// build the xmlrpc val out of the data received, and substitute it
|
||||
$temp =& CreateObject('phpgwapi.xmlrpcval',$GLOBALS['_xh'][$parser]['value'], $GLOBALS['_xh'][$parser]['vt']);
|
||||
// check if we are inside an array or struct:
|
||||
// if value just built is inside an array, let's move it into array on the stack
|
||||
if (count($GLOBALS['_xh'][$parser]['valuestack']) && $GLOBALS['_xh'][$parser]['valuestack'][0]['type']=='ARRAY')
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['valuestack'][0]['values'][] = $temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['value'] = $temp;
|
||||
}
|
||||
break;
|
||||
case 'MEMBER':
|
||||
$GLOBALS['_xh'][$parser]['ac']=''; // is this necessary?
|
||||
// add to array in the stack the last element built,
|
||||
// unless no VALUE was found
|
||||
if ($GLOBALS['_xh'][$parser]['value'])
|
||||
$GLOBALS['_xh'][$parser]['valuestack'][0]['values'][$GLOBALS['_xh'][$parser]['valuestack'][0]['name']] = $GLOBALS['_xh'][$parser]['value'];
|
||||
else
|
||||
error_log('XML-RPC: missing VALUE inside STRUCT in received xml');
|
||||
break;
|
||||
case 'DATA':
|
||||
$GLOBALS['_xh'][$parser]['ac']=''; // is this necessary?
|
||||
break;
|
||||
case 'PARAM':
|
||||
// add to array of params the current value,
|
||||
// unless no VALUE was found
|
||||
if ($GLOBALS['_xh'][$parser]['value'])
|
||||
$GLOBALS['_xh'][$parser]['params'][]=$GLOBALS['_xh'][$parser]['value'];
|
||||
else
|
||||
error_log('XML-RPC: missing VALUE inside PARAM in received xml');
|
||||
break;
|
||||
case 'METHODNAME':
|
||||
$GLOBALS['_xh'][$parser]['method']=preg_replace('/'."^[\n\r\t ]+".'/', '', $GLOBALS['_xh'][$parser]['ac']);
|
||||
break;
|
||||
case 'PARAMS':
|
||||
case 'FAULT':
|
||||
case 'METHODCALL':
|
||||
case 'METHORESPONSE':
|
||||
break;
|
||||
default:
|
||||
// End of INVALID ELEMENT!
|
||||
// shall we add an assert here for unreachable code???
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function xmlrpc_cd($parser, $data)
|
||||
{
|
||||
//if(preg_match('/'."^[\n\r \t]+$".'/', $data)) return;
|
||||
// print "adding [${data}]\n";
|
||||
|
||||
// skip processing if xml fault already detected
|
||||
if ($GLOBALS['_xh'][$parser]['isf'] < 2)
|
||||
{
|
||||
if($GLOBALS['_xh'][$parser]['lv']!=3)
|
||||
{
|
||||
// "lookforvalue==3" means that we've found an entire value
|
||||
// and should discard any further character data
|
||||
if($GLOBALS['_xh'][$parser]['lv']==1)
|
||||
{
|
||||
// if we've found text and we're just in a <value> then
|
||||
// say we've found a value
|
||||
$GLOBALS['_xh'][$parser]['lv']=2;
|
||||
}
|
||||
if(!@isset($GLOBALS['_xh'][$parser]['ac']))
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['ac'] = '';
|
||||
}
|
||||
$GLOBALS['_xh'][$parser]['ac'].=$data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function xmlrpc_dh($parser, $data)
|
||||
{
|
||||
// skip processing if xml fault already detected
|
||||
if ($GLOBALS['_xh'][$parser]['isf'] < 2)
|
||||
{
|
||||
if(substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')
|
||||
{
|
||||
if($GLOBALS['_xh'][$parser]['lv']==1)
|
||||
{
|
||||
$GLOBALS['_xh'][$parser]['lv']=2;
|
||||
}
|
||||
$GLOBALS['_xh'][$parser]['ac'].=$data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// date helpers
|
||||
function iso8601_encode($timet, $utc=0)
|
||||
{
|
||||
// return an ISO8601 encoded string
|
||||
// really, timezones ought to be supported
|
||||
// but the XML-RPC spec says:
|
||||
//
|
||||
// "Don't assume a timezone. It should be specified by the server in its
|
||||
// documentation what assumptions it makes about timezones."
|
||||
//
|
||||
// these routines always assume localtime unless
|
||||
// $utc is set to 1, in which case UTC is assumed
|
||||
// and an adjustment for locale is made when encoding
|
||||
if (!$utc)
|
||||
{
|
||||
$t=strftime("%Y%m%dT%H:%M:%S", $timet);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(function_exists('gmstrftime'))
|
||||
{
|
||||
// gmstrftime doesn't exist in some versions
|
||||
// of PHP
|
||||
$t = gmstrftime("%Y%m%dT%H:%M:%S", $timet);
|
||||
}
|
||||
else
|
||||
{
|
||||
$t = strftime('%Y%m%dT%H:%M:%S', $timet-date('Z'));
|
||||
}
|
||||
}
|
||||
return $t;
|
||||
}
|
||||
|
||||
function iso8601_decode($idate, $utc=0)
|
||||
{
|
||||
// return a time in the localtime, or UTC
|
||||
$t = 0;
|
||||
if (preg_match('/'."([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})".'/',$idate, $regs))
|
||||
{
|
||||
if ($utc)
|
||||
{
|
||||
$t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
|
||||
}
|
||||
}
|
||||
return $t;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* xmlrpc_decode takes a message in PHP xmlrpc object format and *
|
||||
* tranlates it into native PHP types. *
|
||||
* *
|
||||
* author: Dan Libby (dan@libby.com) *
|
||||
****************************************************************/
|
||||
function phpgw_xmlrpc_decode($xmlrpc_val)
|
||||
{
|
||||
$kind = @$xmlrpc_val->kindOf();
|
||||
|
||||
if($kind == 'scalar')
|
||||
{
|
||||
return $xmlrpc_val->scalarval();
|
||||
}
|
||||
elseif($kind == 'array')
|
||||
{
|
||||
$size = $xmlrpc_val->arraysize();
|
||||
$arr = array();
|
||||
|
||||
for($i = 0; $i < $size; $i++)
|
||||
{
|
||||
$arr[] = phpgw_xmlrpc_decode($xmlrpc_val->arraymem($i));
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
elseif($kind == 'struct')
|
||||
{
|
||||
$xmlrpc_val->structreset();
|
||||
$arr = array();
|
||||
|
||||
while(list($key,$value)=$xmlrpc_val->structeach())
|
||||
{
|
||||
$arr[$key] = phpgw_xmlrpc_decode($value);
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* xmlrpc_encode takes native php types and encodes them into *
|
||||
* xmlrpc PHP object format. *
|
||||
* BUG: All sequential arrays are turned into structs. I don't *
|
||||
* know of a good way to determine if an array is sequential *
|
||||
* only. *
|
||||
* *
|
||||
* feature creep -- could support more types via optional type *
|
||||
* argument. *
|
||||
* *
|
||||
* author: Dan Libby (dan@libby.com) *
|
||||
****************************************************************/
|
||||
function phpgw_xmlrpc_encode($php_val)
|
||||
{
|
||||
$type = gettype($php_val);
|
||||
$xmlrpc_val = CreateObject('phpgwapi.xmlrpcval');
|
||||
|
||||
switch($type)
|
||||
{
|
||||
case 'array':
|
||||
case 'object':
|
||||
$arr = array();
|
||||
while(list($k,$v) = each($php_val))
|
||||
{
|
||||
$arr[$k] = phpgw_xmlrpc_encode($v);
|
||||
}
|
||||
$xmlrpc_val->addStruct($arr);
|
||||
break;
|
||||
case 'integer':
|
||||
$xmlrpc_val->addScalar($php_val, xmlrpcInt);
|
||||
break;
|
||||
case 'double':
|
||||
$xmlrpc_val->addScalar($php_val, xmlrpcDouble);
|
||||
break;
|
||||
case 'string':
|
||||
$xmlrpc_val->addScalar($php_val, xmlrpcString);
|
||||
break;
|
||||
// <G_Giunta_2001-02-29>
|
||||
// Add support for encoding/decoding of booleans, since they are supported in PHP
|
||||
case 'boolean':
|
||||
$xmlrpc_val->addScalar($php_val, xmlrpcBoolean);
|
||||
break;
|
||||
// </G_Giunta_2001-02-29>
|
||||
case 'unknown type':
|
||||
default:
|
||||
$xmlrpc_val = False;
|
||||
break;
|
||||
}
|
||||
return $xmlrpc_val;
|
||||
}
|
||||
|
||||
/* The following functions are the system functions for login, logout, etc.
|
||||
* They are added to the server map at the end of this file.
|
||||
*/
|
||||
|
||||
$GLOBALS['_xmlrpcs_listMethods_sig'] = array(array(xmlrpcArray, xmlrpcString), array(xmlrpcArray));
|
||||
$GLOBALS['_xmlrpcs_listMethods_doc'] = 'This method lists all the methods that the XML-RPC server knows how to dispatch';
|
||||
function _xmlrpcs_listMethods($server, $m)
|
||||
{
|
||||
$v = CreateObject('phpgwapi.xmlrpcval');
|
||||
$dmap = $server->dmap;
|
||||
$outAr = array();
|
||||
for(reset($dmap); list($key, $val) = each($dmap); )
|
||||
{
|
||||
$outAr[] = CreateObject('phpgwapi.xmlrpcval',$key, 'string');
|
||||
}
|
||||
$dmap = $GLOBALS['_xmlrpcs_dmap'];
|
||||
for(reset($dmap); list($key, $val) = each($dmap); )
|
||||
{
|
||||
$outAr[] = CreateObject('phpgwapi.xmlrpcval',$key, 'string');
|
||||
}
|
||||
$v->addArray($outAr);
|
||||
return CreateObject('phpgwapi.xmlrpcresp',$v);
|
||||
}
|
||||
|
||||
$GLOBALS['_xmlrpcs_methodSignature_sig']=array(array(xmlrpcArray, xmlrpcString));
|
||||
$GLOBALS['_xmlrpcs_methodSignature_doc']='Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)';
|
||||
function _xmlrpcs_methodSignature($server, $m)
|
||||
{
|
||||
$methName = $m->getParam(0);
|
||||
$methName = $methName->scalarval();
|
||||
if (preg_match('/'."^system\.".'/', $methName))
|
||||
{
|
||||
$dmap = $GLOBALS['_xmlrpcs_dmap'];
|
||||
$sysCall = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dmap = $server->dmap;
|
||||
$sysCall = 0;
|
||||
}
|
||||
// print "<!-- ${methName} -->\n";
|
||||
if (isset($dmap[$methName]))
|
||||
{
|
||||
if ($dmap[$methName]['signature'])
|
||||
{
|
||||
$sigs = array();
|
||||
$thesigs=$dmap[$methName]['signature'];
|
||||
for($i=0; $i<sizeof($thesigs); $i++)
|
||||
{
|
||||
$cursig = array();
|
||||
$inSig = $thesigs[$i];
|
||||
for($j=0; $j<sizeof($inSig); $j++)
|
||||
{
|
||||
$cursig[] = CreateObject('phpgwapi.xmlrpcval',$inSig[$j], 'string');
|
||||
}
|
||||
$sigs[] = CreateObject('phpgwapi.xmlrpcval',$cursig, 'array');
|
||||
}
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$sigs, 'array'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp', CreateObject('phpgwapi.xmlrpcval','undef', 'string'));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',0,$GLOBALS['xmlrpcerr']['introspect_unknown'],$GLOBALS['xmlrpcstr']['introspect_unknown']);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
$GLOBALS['_xmlrpcs_methodHelp_sig'] = array(array(xmlrpcString, xmlrpcString));
|
||||
$GLOBALS['_xmlrpcs_methodHelp_doc'] = 'Returns help text if defined for the method passed, otherwise returns an empty string';
|
||||
function _xmlrpcs_methodHelp($server, $m)
|
||||
{
|
||||
$methName = $m->getParam(0);
|
||||
$methName = $methName->scalarval();
|
||||
if (preg_match('/'."^system\.".'/', $methName))
|
||||
{
|
||||
$dmap = $GLOBALS['_xmlrpcs_dmap'];
|
||||
$sysCall=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dmap = $server->dmap;
|
||||
$sysCall=0;
|
||||
}
|
||||
// print "<!-- ${methName} -->\n";
|
||||
if (isset($dmap[$methName]))
|
||||
{
|
||||
if ($dmap[$methName]['docstring'])
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp', CreateObject('phpgwapi.xmlrpcval',$dmap[$methName]['docstring']),'string');
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp', CreateObject('phpgwapi.xmlrpcval'), 'string');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$r = CreateObject('phpgwapi.xmlrpcresp',0,$GLOBALS['xmlrpcerr']['introspect_unknown'],$GLOBALS['xmlrpcstr']['introspect_unknown']);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
$GLOBALS['_xmlrpcs_login_sig'] = array(array(xmlrpcStruct,xmlrpcStruct));
|
||||
$GLOBALS['_xmlrpcs_login_doc'] = 'eGroupWare client or server login via XML-RPC';
|
||||
function _xmlrpcs_login($server,$m)
|
||||
{
|
||||
$rdata = $m->getParam(0);
|
||||
$data = $rdata->scalarval();
|
||||
|
||||
if($data['server_name'])
|
||||
{
|
||||
$server_name = $data['server_name']->scalarval();
|
||||
}
|
||||
if($data['domain'])
|
||||
{
|
||||
$domain = $data['domain']->scalarval();
|
||||
}
|
||||
$username = $data['username']->scalarval();
|
||||
$password = $data['password']->scalarval();
|
||||
|
||||
if($server_name)
|
||||
{
|
||||
list($sessionid,$kp3) = $GLOBALS['egw']->session->create($username.'@'.$server_name,$password,"text");
|
||||
}
|
||||
else
|
||||
{
|
||||
if($domain)
|
||||
{
|
||||
$user = $username.'@'.$domain;
|
||||
}
|
||||
else
|
||||
{
|
||||
$user = $username;
|
||||
}
|
||||
$GLOBALS['login'] = $user;
|
||||
|
||||
$sessionid = $GLOBALS['egw']->session->create($user,$password,"text");
|
||||
$kp3 = $GLOBALS['egw']->session->kp3;
|
||||
$domain = $GLOBALS['egw']->session->account_domain;
|
||||
}
|
||||
|
||||
if($sessionid && $kp3)
|
||||
{
|
||||
$rtrn['domain'] = CreateObject('phpgwapi.xmlrpcval',$domain,'string');
|
||||
$rtrn['sessionid'] = CreateObject('phpgwapi.xmlrpcval',$sessionid,'string');
|
||||
$rtrn['kp3'] = CreateObject('phpgwapi.xmlrpcval',$kp3,'string');
|
||||
}
|
||||
else
|
||||
{
|
||||
$rtrn['GOAWAY'] = CreateObject('phpgwapi.xmlrpcval','XOXO','string');
|
||||
}
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$rtrn,'struct'));
|
||||
}
|
||||
|
||||
$GLOBALS['_xmlrpcs_logout_sig'] = array(array(xmlrpcStruct,xmlrpcStruct));
|
||||
$GLOBALS['_xmlrpcs_logout_doc'] = 'eGroupWare client or server logout via XML-RPC';
|
||||
function _xmlrpcs_logout($server,$m)
|
||||
{
|
||||
$rdata = $m->getParam(0);
|
||||
$data = $rdata->scalarval();
|
||||
|
||||
$sessionid = $data['sessionid']->scalarval();
|
||||
$kp3 = $data['kp3']->scalarval();
|
||||
|
||||
$later = $GLOBALS['egw']->session->destroy($sessionid,$kp3);
|
||||
|
||||
if ($later)
|
||||
{
|
||||
$rtrn['GOODBYE'] = CreateObject('phpgwapi.xmlrpcval','XOXO','string');
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This never happens, yet */
|
||||
$rtrn['OOPS'] = CreateObject('phpgwapi.xmlrpcval','WHAT?','string');
|
||||
}
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$rtrn,'struct'));
|
||||
}
|
||||
|
||||
$GLOBALS['_xmlrpcs_phpgw_api_version_sig'] = array(array(xmlrpcString));
|
||||
$GLOBALS['_xmlrpcs_phpgw_api_version_doc'] = 'Returns the eGroupWare API version';
|
||||
function _xmlrpcs_phpgw_api_version($server,$m)
|
||||
{
|
||||
$version = $GLOBALS['egw_info']['server']['versions']['phpgwapi'];
|
||||
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$version,'string'));
|
||||
}
|
||||
|
||||
/*
|
||||
$GLOBALS['_xmlrpcs_listApps_sig'] = array(array(xmlrpcStruct,xmlrpcString));
|
||||
$GLOBALS['_xmlrpcs_listApps_doc'] = 'Returns a list of installed phpgw apps';
|
||||
function _xmlrpcs_listApps($server,$m)
|
||||
{
|
||||
$m->getParam(0);
|
||||
$GLOBALS['egw']->db->query("SELECT * FROM egw_applications WHERE app_enabled<3",__LINE__,__FILE__);
|
||||
if($GLOBALS['egw']->db->num_rows())
|
||||
{
|
||||
while($GLOBALS['egw']->db->next_record())
|
||||
{
|
||||
$name = $GLOBALS['egw']->db->f('app_name');
|
||||
$title = $GLOBALS['egw']->db->f('app_title');
|
||||
$status = $GLOBALS['egw']->db->f('app_enabled');
|
||||
$version= $GLOBALS['egw']->db->f('app_version');
|
||||
$apps[$name] = CreateObject('phpgwapi.xmlrpcval',
|
||||
array(
|
||||
'title' => CreateObject('phpgwapi.xmlrpcval',$title,'string'),
|
||||
'name' => CreateObject('phpgwapi.xmlrpcval',$name,'string'),
|
||||
'status' => CreateObject('phpgwapi.xmlrpcval',$status,'string'),
|
||||
'version'=> CreateObject('phpgwapi.xmlrpcval',$version,'string')
|
||||
),
|
||||
'struct'
|
||||
);
|
||||
}
|
||||
}
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$apps, 'struct'));
|
||||
}
|
||||
*/
|
||||
|
||||
$GLOBALS['_xmlrpcs_egw_time_sig'] = array(array(xmlrpcStruct));
|
||||
$GLOBALS['_xmlrpcs_egw_time_doc'] = 'returns system-time and -timezone and if loged in user-time and timezone';
|
||||
function _xmlrpcs_time($server,$m)
|
||||
{
|
||||
$return = array(
|
||||
'system' => $GLOBALS['server']->date2iso8601(time()),
|
||||
'system_tz_offset' => (int) date('Z'),
|
||||
);
|
||||
if ($GLOBALS['server']->authed)
|
||||
{
|
||||
$tz_offset_s = 3600 * (int) $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
|
||||
$return += array(
|
||||
'user' => $GLOBALS['server']->date2iso8601(time()+$tz_offset_s),
|
||||
'user_tz_offset' => (int) date('Z') + $tz_offset_s,
|
||||
);
|
||||
}
|
||||
return CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
$GLOBALS['server']->build_resp($return,true)
|
||||
);
|
||||
}
|
||||
|
||||
/* Add the system functions to the server map */
|
||||
$GLOBALS['_xmlrpcs_dmap'] = array(
|
||||
'system.listMethods' => array(
|
||||
'function' => '_xmlrpcs_listMethods',
|
||||
'signature' => $GLOBALS['_xmlrpcs_listMethods_sig'],
|
||||
'docstring' => $GLOBALS['_xmlrpcs_listMethods_doc']
|
||||
),
|
||||
'system.methodHelp' => array(
|
||||
'function' => '_xmlrpcs_methodHelp',
|
||||
'signature' => $GLOBALS['_xmlrpcs_methodHelp_sig'],
|
||||
'docstring' => $GLOBALS['_xmlrpcs_methodHelp_doc']
|
||||
),
|
||||
'system.methodSignature' => array(
|
||||
'function' => '_xmlrpcs_methodSignature',
|
||||
'signature' => $GLOBALS['_xmlrpcs_methodSignature_sig'],
|
||||
'docstring' => $GLOBALS['_xmlrpcs_methodSignature_doc']
|
||||
),
|
||||
'system.login' => array(
|
||||
'function' => '_xmlrpcs_login',
|
||||
'signature' => $GLOBALS['_xmlrpcs_login_sig'],
|
||||
'docstring' => $GLOBALS['_xmlrpcs_login_doc']
|
||||
),
|
||||
'system.logout' => array(
|
||||
'function' => '_xmlrpcs_logout',
|
||||
'signature' => $GLOBALS['_xmlrpcs_logout_sig'],
|
||||
'docstring' => $GLOBALS['_xmlrpcs_logout_doc']
|
||||
),
|
||||
'system.phpgw_api_version' => array(
|
||||
'function' => '_xmlrpcs_phpgw_api_version',
|
||||
'signature' => $GLOBALS['_xmlrpcs_phpgw_api_version_sig'],
|
||||
'docstring' => $GLOBALS['_xmlrpcs_phpgw_api_version_doc']
|
||||
),
|
||||
/*
|
||||
'system.listApps' => array(
|
||||
'function' => '_xmlrpcs_listApps',
|
||||
'signature' => $GLOBALS['_xmlrpcs_listApps_sig'],
|
||||
'docstring' => $GLOBALS['_xmlrpcs_listApps_doc']
|
||||
),
|
||||
*/
|
||||
'system.time' => array(
|
||||
'function' => '_xmlrpcs_time',
|
||||
'signature' => $GLOBALS['_xmlrpcs_egw_time_sig'],
|
||||
'docstring' => $GLOBALS['_xmlrpcs_egw_time_doc']
|
||||
)
|
||||
);
|
||||
|
||||
$GLOBALS['_xmlrpc_debuginfo'] = '';
|
||||
function xmlrpc_debugmsg($m)
|
||||
{
|
||||
$GLOBALS['_xmlrpc_debuginfo'] .= $m . "\n";
|
||||
}
|
||||
?>
|
@ -1,629 +0,0 @@
|
||||
<?php
|
||||
/**************************************************************************\
|
||||
* eGroupWare xmlrpc interop functions *
|
||||
* http://www.egroupware.org *
|
||||
* Portions of code from server.php by Edd Dumbill <edd@usefulinc.com> *
|
||||
* part of the xml-rpc for php library *
|
||||
* http://sourceforge.net/projects/phpxmlrpc/ *
|
||||
* Incorporated for egroupware by Miles Lott <milos@groupwhere.org> *
|
||||
* ------------------------------------------------------------------------ *
|
||||
* 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 the *
|
||||
* Free Software Foundation; either version 2 of the License, or (at your *
|
||||
* option) any later version. *
|
||||
\**************************************************************************/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
// a PHP version
|
||||
// of the state-number server
|
||||
// send me an integer and i'll sell you a state
|
||||
|
||||
$stateNames = array(
|
||||
'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California',
|
||||
'Colorado', 'Columbia', 'Connecticut', 'Delaware', 'Florida',
|
||||
'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas',
|
||||
'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan',
|
||||
'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada',
|
||||
'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Carolina',
|
||||
'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island',
|
||||
'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont',
|
||||
'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'
|
||||
);
|
||||
|
||||
$findstate_sig = array(array(xmlrpcString, xmlrpcInt));
|
||||
|
||||
$findstate_doc = 'When passed an integer between 1 and 51 returns the
|
||||
name of a US state, where the integer is the index of that state name
|
||||
in an alphabetic order.';
|
||||
|
||||
function findstate($m)
|
||||
{
|
||||
$err='';
|
||||
// get the first param
|
||||
$sno=$m->getParam(0);
|
||||
// if it's there and the correct type
|
||||
|
||||
if (isset($sno) && ($sno->scalartyp()=='int'))
|
||||
{
|
||||
// extract the value of the state number
|
||||
$snv=$sno->scalarval();
|
||||
// look it up in our array (zero-based)
|
||||
if (isset($GLOBALS['stateNames'][$snv-1]))
|
||||
{
|
||||
$sname=$GLOBALS['stateNames'][$snv-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// not, there so complain
|
||||
$err="I don't have a state for the index '" . $snv . "'";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// parameter mismatch, complain
|
||||
$err='One integer parameter required';
|
||||
}
|
||||
|
||||
// if we generated an error, create an error return response
|
||||
if ($err)
|
||||
{
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval'), $GLOBALS['xmlrpcerruser'], $err);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, we create the right response
|
||||
// with the state name
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$sname));
|
||||
}
|
||||
}
|
||||
|
||||
$addtwo_sig=array(array(xmlrpcInt, xmlrpcInt, xmlrpcInt));
|
||||
$addtwo_doc='Add two integers together and return the result';
|
||||
|
||||
function addtwo($m)
|
||||
{
|
||||
$s=$m->getParam(0);
|
||||
$t=$m->getParam(1);
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$s->scalarval()+$t->scalarval(),'int'));
|
||||
}
|
||||
|
||||
$addtwodouble_sig=array(array(xmlrpcDouble, xmlrpcDouble, xmlrpcDouble));
|
||||
$addtwodouble_doc='Add two doubles together and return the result';
|
||||
|
||||
function addtwodouble($m)
|
||||
{
|
||||
$s=$m->getParam(0);
|
||||
$t=$m->getParam(1);
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$s->scalarval()+$t->scalarval(),'double'));
|
||||
}
|
||||
|
||||
$stringecho_sig=array(array(xmlrpcString, xmlrpcString));
|
||||
$stringecho_doc='Accepts a string parameter, returns the string.';
|
||||
|
||||
function stringecho($m)
|
||||
{
|
||||
// just sends back a string
|
||||
$s=$m->getParam(0);
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$s->scalarval()));
|
||||
}
|
||||
|
||||
$echoback_sig=array(array(xmlrpcString, xmlrpcString));
|
||||
$echoback_doc='Accepts a string parameter, returns the entire incoming payload';
|
||||
|
||||
function echoback($m)
|
||||
{
|
||||
// just sends back a string with what i got
|
||||
// send to me, just escaped, that's all
|
||||
//
|
||||
// $m is an incoming message
|
||||
$s="I got the following message:\n" . $m->serialize();
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$s));
|
||||
}
|
||||
|
||||
$echosixtyfour_sig=array(array(xmlrpcString, xmlrpcBase64));
|
||||
$echosixtyfour_doc='Accepts a base64 parameter and returns it decoded as a string';
|
||||
|
||||
function echosixtyfour($m)
|
||||
{
|
||||
// accepts an encoded value, but sends it back
|
||||
// as a normal string. this is to test base64 encoding
|
||||
// is working as expected
|
||||
$incoming=$m->getParam(0);
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$incoming->scalarval(), 'string'));
|
||||
}
|
||||
|
||||
$bitflipper_sig=array(array(xmlrpcArray, xmlrpcArray));
|
||||
$bitflipper_doc='Accepts an array of booleans, and returns them inverted';
|
||||
|
||||
function bitflipper($m)
|
||||
{
|
||||
$v = $m->getParam(0);
|
||||
$sz = $v->arraysize();
|
||||
$rv = CreateObject('phpgwapi.xmlrpcval',array(), xmlrpcArray);
|
||||
|
||||
for($j=0; $j<$sz; $j++)
|
||||
{
|
||||
$b = $v->arraymem($j);
|
||||
if ($b->scalarval())
|
||||
{
|
||||
$rv->addScalar(False, 'boolean');
|
||||
}
|
||||
else
|
||||
{
|
||||
$rv->addScalar(True, 'boolean');
|
||||
}
|
||||
}
|
||||
return CreateObject('phpgwapi.xmlrpcresp',$rv);
|
||||
}
|
||||
|
||||
// Sorting demo
|
||||
//
|
||||
// send me an array of structs thus:
|
||||
//
|
||||
// Dave 35
|
||||
// Edd 45
|
||||
// Fred 23
|
||||
// Barney 37
|
||||
//
|
||||
// and I'll return it to you in sorted order
|
||||
|
||||
function agesorter_compare($a, $b)
|
||||
{
|
||||
// don't even ask me _why_ these come padded with
|
||||
// hyphens, I couldn't tell you :p
|
||||
$a = str_replace('-', '', $a);
|
||||
$b = str_replace('-', '', $b);
|
||||
|
||||
if ($GLOBALS['agesorter_arr'][$a]==$agesorter[$b])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return ($GLOBALS['agesorter_arr'][$a] > $GLOBALS['agesorter_arr'][$b]) ? -1 : 1;
|
||||
}
|
||||
|
||||
$agesorter_sig=array(array(xmlrpcArray, xmlrpcArray));
|
||||
$agesorter_doc='Send this method an array of [string, int] structs, eg:
|
||||
<PRE>
|
||||
Dave 35
|
||||
Edd 45
|
||||
Fred 23
|
||||
Barney 37
|
||||
</PRE>
|
||||
And the array will be returned with the entries sorted by their numbers.
|
||||
';
|
||||
|
||||
function agesorter($m)
|
||||
{
|
||||
global $s;
|
||||
|
||||
xmlrpc_debugmsg("Entering 'agesorter'");
|
||||
// get the parameter
|
||||
$sno = $m->getParam(0);
|
||||
// error string for [if|when] things go wrong
|
||||
$err = '';
|
||||
// create the output value
|
||||
$v = CreateObject('phpgwapi.xmlrpcval');
|
||||
$agar = array();
|
||||
|
||||
if (isset($sno) && $sno->kindOf()=='array')
|
||||
{
|
||||
$max = $sno->arraysize();
|
||||
// TODO: create debug method to print can work once more
|
||||
// print "<!-- found $max array elements -->\n";
|
||||
for($i=0; $i<$max; $i++)
|
||||
{
|
||||
$rec = $sno->arraymem($i);
|
||||
if ($rec->kindOf()!='struct')
|
||||
{
|
||||
$err = 'Found non-struct in array at element ' . $i;
|
||||
break;
|
||||
}
|
||||
// extract name and age from struct
|
||||
$n = $rec->structmem('name');
|
||||
$a = $rec->structmem('age');
|
||||
// $n and $a are xmlrpcvals,
|
||||
// so get the scalarval from them
|
||||
$agar[$n->scalarval()] = $a->scalarval();
|
||||
}
|
||||
|
||||
$GLOBALS['agesorter_arr'] = $agar;
|
||||
// hack, must make global as uksort() won't
|
||||
// allow us to pass any other auxilliary information
|
||||
uksort($GLOBALS['agesorter_arr'], agesorter_compare);
|
||||
$outAr = array();
|
||||
while (list($key,$val) = each($GLOBALS['agesorter_arr']))
|
||||
{
|
||||
// recreate each struct element
|
||||
$outAr[] = CreateObject('phpgwapi.xmlrpcval',array(
|
||||
'name' => CreateObject('phpgwapi.xmlrpcval',$key),
|
||||
'age' => CreateObject('phpgwapi.xmlrpcval',$val, 'int')
|
||||
),
|
||||
'struct'
|
||||
);
|
||||
}
|
||||
// add this array to the output value
|
||||
$v->addArray($outAr);
|
||||
}
|
||||
else
|
||||
{
|
||||
$err = 'Must be one parameter, an array of structs';
|
||||
}
|
||||
|
||||
if ($err)
|
||||
{
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval'), $GLOBALS['xmlrpcerruser'], $err);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateObject('phpgwapi.xmlrpcresp',$v);
|
||||
}
|
||||
}
|
||||
|
||||
// signature and instructions, place these in the dispatch map
|
||||
|
||||
$mail_send_sig = array(
|
||||
array(
|
||||
xmlrpcBoolean, xmlrpcString, xmlrpcString,
|
||||
xmlrpcString, xmlrpcString, xmlrpcString,
|
||||
xmlrpcString, xmlrpcString
|
||||
)
|
||||
);
|
||||
|
||||
$mail_send_doc = 'mail.send(recipient, subject, text, sender, cc, bcc, mimetype)
|
||||
<BR>recipient, cc, and bcc are strings, comma-separated lists of email addresses, as described above.
|
||||
<BR>subject is a string, the subject of the message.
|
||||
<BR>sender is a string, it\'s the email address of the person sending the message. This string can not be
|
||||
a comma-separated list, it must contain a single email address only.
|
||||
text is a string, it contains the body of the message.
|
||||
<BR>mimetype, a string, is a standard MIME type, for example, text/plain.
|
||||
';
|
||||
|
||||
// WARNING; this functionality depends on the sendmail -t option
|
||||
// it may not work with Windows machines properly; particularly
|
||||
// the Bcc option. Sneak on your friends at your own risk!
|
||||
function mail_send($m)
|
||||
{
|
||||
$err = '';
|
||||
|
||||
$mTo = $m->getParam(0);
|
||||
$mSub = $m->getParam(1);
|
||||
$mBody = $m->getParam(2);
|
||||
$mFrom = $m->getParam(3);
|
||||
$mCc = $m->getParam(4);
|
||||
$mBcc = $m->getParam(5);
|
||||
$mMime = $m->getParam(6);
|
||||
|
||||
if ($mTo->scalarval() == '')
|
||||
{
|
||||
$err = "Error, no 'To' field specified";
|
||||
}
|
||||
if ($mFrom->scalarval() == '')
|
||||
{
|
||||
$err = "Error, no 'From' field specified";
|
||||
}
|
||||
$msghdr = 'From: ' . $mFrom->scalarval() . "\n";
|
||||
$msghdr .= 'To: '. $mTo->scalarval() . "\n";
|
||||
|
||||
if ($mCc->scalarval()!='')
|
||||
{
|
||||
$msghdr .= 'Cc: ' . $mCc->scalarval(). "\n";
|
||||
}
|
||||
if ($mBcc->scalarval()!='')
|
||||
{
|
||||
$msghdr .= 'Bcc: ' . $mBcc->scalarval(). "\n";
|
||||
}
|
||||
if ($mMime->scalarval()!='')
|
||||
{
|
||||
$msghdr .= 'Content-type: ' . $mMime->scalarval() . "\n";
|
||||
}
|
||||
|
||||
$msghdr .= 'X-Mailer: XML-RPC for PHP mailer 1.0';
|
||||
|
||||
if ($err == '')
|
||||
{
|
||||
if (!mail('', $mSub->scalarval(), $mBody->scalarval(), $msghdr))
|
||||
{
|
||||
$err = 'Error, could not send the mail.';
|
||||
}
|
||||
}
|
||||
|
||||
if ($err)
|
||||
{
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval'), $GLOBALS['xmlrpcerruser'], $err);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval','true', xmlrpcBoolean));
|
||||
}
|
||||
}
|
||||
|
||||
$v1_arrayOfStructs_sig = array(array(xmlrpcInt, xmlrpcArray));
|
||||
$v1_arrayOfStructs_doc = 'This handler takes a single parameter, an array of structs, each of which contains at least three elements named moe, larry and curly, all <i4>s. Your handler must add all the struct elements named curly and return the result.';
|
||||
|
||||
function v1_arrayOfStructs($m)
|
||||
{
|
||||
$sno = $m->getParam(0);
|
||||
$numcurly = 0;
|
||||
for($i=0; $i<$sno->arraysize(); $i++)
|
||||
{
|
||||
$str = $sno->arraymem($i);
|
||||
$str->structreset();
|
||||
while(list($key,$val) = $str->structeach())
|
||||
{
|
||||
if ($key == 'curly')
|
||||
{
|
||||
$numcurly += $val->scalarval();
|
||||
}
|
||||
}
|
||||
}
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$numcurly, 'int'));
|
||||
}
|
||||
|
||||
$v1_easyStruct_sig = array(array(xmlrpcInt, xmlrpcStruct));
|
||||
$v1_easyStruct_doc = 'This handler takes a single parameter, a struct, containing at least three elements named moe, larry and curly, all <i4>s. Your handler must add the three numbers and return the result.';
|
||||
|
||||
function v1_easyStruct($m)
|
||||
{
|
||||
$sno = $m->getParam(0);
|
||||
$moe = $sno->structmem('moe');
|
||||
$larry = $sno->structmem('larry');
|
||||
$curly = $sno->structmem('curly');
|
||||
$num = $moe->scalarval() + $larry->scalarval() + $curly->scalarval();
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$num, 'int'));
|
||||
}
|
||||
|
||||
$v1_echoStruct_sig=array(array(xmlrpcStruct, xmlrpcStruct));
|
||||
$v1_echoStruct_doc='This handler takes a single parameter, a struct. Your handler must return the struct.';
|
||||
|
||||
function v1_echoStruct($m)
|
||||
{
|
||||
$sno=$m->getParam(0);
|
||||
return CreateObject('phpgwapi.xmlrpcresp',$sno);
|
||||
}
|
||||
|
||||
$v1_manyTypes_sig = array(
|
||||
array(
|
||||
xmlrpcArray, xmlrpcInt, xmlrpcBoolean,
|
||||
xmlrpcString, xmlrpcDouble, xmlrpcDateTime,
|
||||
xmlrpcBase64
|
||||
)
|
||||
);
|
||||
$v1_manyTypes_doc = 'This handler takes six parameters, and returns an array containing all the parameters.';
|
||||
|
||||
function v1_manyTypes($m)
|
||||
{
|
||||
return CreateObject('phpgwapi.xmlrpcresp',
|
||||
CreateObject('phpgwapi.xmlrpcval',array(
|
||||
$m->getParam(0),
|
||||
$m->getParam(1),
|
||||
$m->getParam(2),
|
||||
$m->getParam(3),
|
||||
$m->getParam(4),
|
||||
$m->getParam(5)
|
||||
),
|
||||
'array'
|
||||
));
|
||||
}
|
||||
|
||||
$v1_moderateSizeArrayCheck_sig = array(array(xmlrpcString, xmlrpcArray));
|
||||
$v1_moderateSizeArrayCheck_doc = 'This handler takes a single parameter, which is an array containing between 100 and 200 elements. Each of the items is a string, your handler must return a string containing the concatenated text of the first and last elements.';
|
||||
|
||||
function v1_moderateSizeArrayCheck($m)
|
||||
{
|
||||
$ar = $m->getParam(0);
|
||||
$sz = $ar->arraysize();
|
||||
$first = $ar->arraymem(0);
|
||||
$last = $ar->arraymem($sz-1);
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$first->scalarval() . $last->scalarval(), "string"));
|
||||
}
|
||||
|
||||
$v1_simpleStructReturn_sig = array(array(xmlrpcStruct, xmlrpcInt));
|
||||
$v1_simpleStructReturn_doc = 'This handler takes one parameter, and returns a struct containing three elements, times10, times100 and times1000, the result of multiplying the number by 10, 100 and 1000.';
|
||||
|
||||
function v1_simpleStructReturn($m)
|
||||
{
|
||||
$sno=$m->getParam(0);
|
||||
$v=$sno->scalarval();
|
||||
return CreateObject('phpgwapi.xmlrpcresp',
|
||||
CreateObject('phpgwapi.xmlrpcval',array(
|
||||
'times10' => CreateObject('phpgwapi.xmlrpcval',$v*10, 'int'),
|
||||
'times100' => CreateObject('phpgwapi.xmlrpcval',$v*100, 'int'),
|
||||
'times1000' => CreateObject('phpgwapi.xmlrpcval',$v*1000, 'int')
|
||||
),
|
||||
'struct'
|
||||
));
|
||||
}
|
||||
|
||||
$v1_nestedStruct_sig = array(array(xmlrpcInt, xmlrpcStruct));
|
||||
$v1_nestedStruct_doc = 'This handler takes a single parameter, a struct, that models a daily calendar. At the top level, there is one struct for each year. Each year is broken down into months, and months into days. Most of the days are empty in the struct you receive, but the entry for April 1, 2000 contains a least three elements named moe, larry and curly, all <i4>s. Your handler must add the three numbers and return the result.';
|
||||
|
||||
function v1_nestedStruct($m)
|
||||
{
|
||||
$sno=$m->getParam(0);
|
||||
$twoK=$sno->structmem('2000');
|
||||
$april=$twoK->structmem('04');
|
||||
$fools=$april->structmem('01');
|
||||
$curly=$fools->structmem('curly');
|
||||
$larry=$fools->structmem('larry');
|
||||
$moe=$fools->structmem('moe');
|
||||
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',
|
||||
$curly->scalarval() + $larry->scalarval() + $moe->scalarval(), 'int'
|
||||
));
|
||||
}
|
||||
|
||||
$v1_countTheEntities_sig=array(array(xmlrpcStruct, xmlrpcString));
|
||||
$v1_countTheEntities_doc='This handler takes a single parameter, a string, that contains any number of predefined entities, namely <, >, & \' and ".<BR>Your handler must return a struct that contains five fields, all numbers: ctLeftAngleBrackets, ctRightAngleBrackets, ctAmpersands, ctApostrophes, ctQuotes.';
|
||||
|
||||
function v1_countTheEntities($m)
|
||||
{
|
||||
$sno=$m->getParam(0);
|
||||
$str=$sno->scalarval();
|
||||
$gt=0; $lt=0; $ap=0; $qu=0; $amp=0;
|
||||
for($i=0; $i<strlen($str); $i++)
|
||||
{
|
||||
$c=substr($str, $i, 1);
|
||||
switch($c)
|
||||
{
|
||||
case '>':
|
||||
$gt++;
|
||||
break;
|
||||
case '<':
|
||||
$lt++;
|
||||
break;
|
||||
case '"':
|
||||
$qu++;
|
||||
break;
|
||||
case "'":
|
||||
$ap++;
|
||||
break;
|
||||
case '&':
|
||||
$amp++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return CreateObject('phpgwapi.xmlrpcresp',
|
||||
CreateObject('phpgwapi.xmlrpcval',array(
|
||||
'ctLeftAngleBrackets' => CreateObject('phpgwapi.xmlrpcval',$lt, 'int'),
|
||||
'ctRightAngleBrackets' => CreateObject('phpgwapi.xmlrpcval',$gt, 'int'),
|
||||
'ctAmpersands' => CreateObject('phpgwapi.xmlrpcval',$amp, 'int'),
|
||||
'ctApostrophes' => CreateObject('phpgwapi.xmlrpcval',$ap, 'int'),
|
||||
'ctQuotes' => CreateObject('phpgwapi.xmlrpcval',$qu, 'int')
|
||||
),
|
||||
'struct'
|
||||
));
|
||||
}
|
||||
|
||||
// trivial interop tests
|
||||
// http://www.xmlrpc.com/stories/storyReader$1636
|
||||
|
||||
$i_echoString_sig=array(array(xmlrpcString, xmlrpcString));
|
||||
$i_echoString_doc='Echoes string.';
|
||||
|
||||
$i_echoStringArray_sig=array(array(xmlrpcArray, xmlrpcArray));
|
||||
$i_echoStringArray_doc='Echoes string array.';
|
||||
|
||||
$i_echoInteger_sig=array(array(xmlrpcInt, xmlrpcInt));
|
||||
$i_echoInteger_doc='Echoes integer.';
|
||||
|
||||
$i_echoIntegerArray_sig=array(array(xmlrpcArray, xmlrpcArray));
|
||||
$i_echoIntegerArray_doc='Echoes integer array.';
|
||||
|
||||
$i_echoFloat_sig=array(array(xmlrpcDouble, xmlrpcDouble));
|
||||
$i_echoFloat_doc='Echoes float.';
|
||||
|
||||
$i_echoFloatArray_sig=array(array(xmlrpcArray, xmlrpcArray));
|
||||
$i_echoFloatArray_doc='Echoes float array.';
|
||||
|
||||
$i_echoStruct_sig=array(array(xmlrpcStruct, xmlrpcStruct));
|
||||
$i_echoStruct_doc='Echoes struct.';
|
||||
|
||||
$i_echoStructArray_sig=array(array(xmlrpcArray, xmlrpcArray));
|
||||
$i_echoStructArray_doc='Echoes struct array.';
|
||||
|
||||
$i_echoValue_doc='Echoes any value back.';
|
||||
|
||||
$i_echoBase64_sig=array(array(xmlrpcBase64, xmlrpcBase64));
|
||||
$i_echoBase64_doc='Echoes base64.';
|
||||
|
||||
$i_echoDate_sig=array(array(xmlrpcDateTime, xmlrpcDateTime));
|
||||
$i_echoDate_doc='Echoes dateTime.';
|
||||
|
||||
function i_echoParam($m)
|
||||
{
|
||||
$s = $m->getParam(0);
|
||||
return CreateObject('phpgwapi.xmlrpcresp',$s);
|
||||
}
|
||||
|
||||
function i_echoString($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoInteger($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoFloat($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoStruct($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoStringArray($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoIntegerArray($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoFloatArray($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoStructArray($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoValue($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoBase64($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
function i_echoDate($m)
|
||||
{
|
||||
return i_echoParam($m);
|
||||
}
|
||||
|
||||
$i_whichToolkit_doc = 'Returns a struct containing the following strings: toolkitDocsUrl, toolkitName, toolkitVersion, toolkitOperatingSystem.';
|
||||
|
||||
function i_whichToolkit($m)
|
||||
{
|
||||
$ret = array(
|
||||
'toolkitDocsUrl' => 'http://xmlrpc.usefulinc.com/php.html',
|
||||
'toolkitName' => $GLOBALS['xmlrpcName'],
|
||||
'toolkitVersion' => $GLOBALS['xmlrpcVersion'],
|
||||
'toolkitOperatingSystem' => $GLOBALS['SERVER_SOFTWARE']
|
||||
);
|
||||
return CreateObject('phpgwapi.xmlrpcresp',phpgw_xmlrpc_encode($ret));
|
||||
}
|
||||
|
||||
$server->add_to_map('examples.getStateName', 'findstate',$findstate_sig,$findstate_doc);
|
||||
$server->add_to_map('examples.sortByAge', 'agesorter',$agesorter_sig,$agesorter_doc);
|
||||
$server->add_to_map('examples.addtwo', 'addtwo',$addtwo_sig,$addtwo_doc);
|
||||
$server->add_to_map('examples.addtwodouble', 'addtwodouble',$addtwodouble_sig,$addtwodouble_doc);
|
||||
$server->add_to_map('examples.stringecho', 'stringecho',$stringecho_sig,$stringecho_doc);
|
||||
$server->add_to_map('examples.echo', 'echoback',$echoback_sig,$echoback_doc);
|
||||
$server->add_to_map('examples.decode64', 'echosixtyfour',$echosixtyfour_sig,$echosixtyfour_doc);
|
||||
$server->add_to_map('examples.invertBooleans', 'bitflipper',$bitflipper_sig,$bitflipper_doc);
|
||||
$server->add_to_map('mail.send', 'mail_send',$mail_send_sig,$mail_send_doc);
|
||||
$server->add_to_map('validator1.arrayOfStructsTest', 'v1_arrayOfStructs',$v1_arrayOfStructs_sig,$v1_arrayOfStructs_doc);
|
||||
$server->add_to_map('validator1.easyStructTest', 'v1_easyStruct',$v1_easyStruct_sig,$v1_easyStruct_doc);
|
||||
$server->add_to_map('validator1.echoStructTest', 'v1_echoStruct',$v1_echoStruct_sig,$v1_echoStruct_doc);
|
||||
$server->add_to_map('validator1.manyTypesTest', 'v1_manyTypes',$v1_manyTypes_sig,$v1_manyTypes_doc);
|
||||
$server->add_to_map('validator1.moderateSizeArrayCheck','v1_moderateSizeArrayCheck',$v1_moderateSizeArrayCheck_sig,$v1_moderateSizeArrayCheck_doc);
|
||||
$server->add_to_map('validator1.simpleStructReturnTest','v1_simpleStructReturn',$v1_simpleStructReturn_sig,$v1_simpleStructReturn_doc);
|
||||
$server->add_to_map('validator1.nestedStructTest', 'v1_nestedStruct',$v1_nestedStruct_sig,$v1_nestedStruct_doc);
|
||||
$server->add_to_map('validator1.countTheEntities', 'v1_countTheEntities',$v1_countTheEntities_sig,$v1_countTheEntities_doc);
|
||||
$server->add_to_map('interopEchoTests.echoString', 'i_echoString',$i_echoString_sig,$i_echoString_doc);
|
||||
$server->add_to_map('interopEchoTests.echoStringArray', 'i_echoStringArray',$i_echoStringArray_sig,$i_echoStringArray_doc);
|
||||
$server->add_to_map('interopEchoTests.echoInteger', 'i_echoInteger',$i_echoInteger_sig,$i_echoInteger_doc);
|
||||
$server->add_to_map('interopEchoTests.echoIntegerArray','i_echoIntegerArray',$i_echoIntegerArray_sig,$i_echoIntegerArray_doc);
|
||||
$server->add_to_map('interopEchoTests.echoFloat', 'i_echoFloat',$i_echoFloat_sig,$i_echoFloat_doc);
|
||||
$server->add_to_map('interopEchoTests.echoFloatArray', 'i_echoFloatArray',$i_echoFloatArray_sig,$i_echoFloatArray_doc);
|
||||
$server->add_to_map('interopEchoTests.echoStruct', 'i_echoStruct',$i_echoStruct_sig,$i_echoStruct_doc);
|
||||
$server->add_to_map('interopEchoTests.echoStructArray', 'i_echoStructArray',$i_echoStructArray_sig,$i_echoStructArray_doc);
|
||||
$server->add_to_map('interopEchoTests.echoValue', 'i_echoValue','',$i_echoValue_doc);
|
||||
$server->add_to_map('interopEchoTests.echoBase64', 'i_echoBase64',$i_echoBase64_sig,$i_echoBase64_doc);
|
||||
$server->add_to_map('interopEchoTests.echoDate', 'i_echoDate',$i_echoDate_sig,$i_echoDate_doc);
|
||||
$server->add_to_map('interopEchoTests.whichToolkit', 'i_whichToolkit','',$i_whichToolkit_doc);
|
||||
|
||||
// that should do all we need!
|
||||
?>
|
@ -1,102 +0,0 @@
|
||||
<?php
|
||||
/**************************************************************************\
|
||||
* eGroupWare - XML-RPC Test App *
|
||||
* http://www.egroupware.org *
|
||||
* -------------------------------------------- *
|
||||
* 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 the *
|
||||
* Free Software Foundation; either version 2 of the License, or (at your *
|
||||
* option) any later version. *
|
||||
\**************************************************************************/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
$phpgw_info = array();
|
||||
$GLOBALS['phpgw_info']['flags'] = array(
|
||||
'noheader' => True,
|
||||
'nonavbar' => True,
|
||||
'currentapp' => 'home',
|
||||
'noapi' => True
|
||||
);
|
||||
include('./inc/functions.inc.php');
|
||||
include(PHPGW_SERVER_ROOT . 'phpgwapi/inc/xml_functions.inc.php');
|
||||
|
||||
/* Check header and authentication */
|
||||
if (!$GLOBALS['phpgw_setup']->auth('Config'))
|
||||
{
|
||||
Header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
// Does not return unless user is authorized
|
||||
|
||||
$tpl_root = $GLOBALS['phpgw_setup']->html->setup_tpl_dir('setup');
|
||||
$setup_tpl = CreateObject('phpgwapi.Template',$tpl_root);
|
||||
$setup_tpl->set_file(array(
|
||||
'T_head' => 'head.tpl',
|
||||
'T_footer' => 'footer.tpl'
|
||||
));
|
||||
$setup_tpl->set_block('T_footer','footer','footer');
|
||||
|
||||
$host = 'us.egroupware.org';
|
||||
$path = '/cvsdemo/xmlrpc.php';
|
||||
|
||||
$GLOBALS['phpgw_setup']->html->show_header(lang('Application List'),True);
|
||||
|
||||
/* Login as demo */
|
||||
$login = CreateObject(
|
||||
'phpgwapi.xmlrpcmsg',
|
||||
'system.login',
|
||||
array(
|
||||
CreateObject(
|
||||
'phpgwapi.xmlrpcval',
|
||||
array(
|
||||
'domain' => CreateObject('phpgwapi.xmlrpcval','default','string'),
|
||||
'username' => CreateObject('phpgwapi.xmlrpcval','demo','string'),
|
||||
'password' => CreateObject('phpgwapi.xmlrpcval','guest','string')
|
||||
),
|
||||
'struct'
|
||||
)
|
||||
)
|
||||
);
|
||||
echo '<pre>' . htmlentities($login->serialize()) . "</pre>\n";
|
||||
|
||||
$c = CreateObject('phpgwapi.xmlrpc_client',$path,$host,80);
|
||||
$c->setDebug(1);
|
||||
$r = $c->send($login);
|
||||
$v = $r->value();
|
||||
$result = xmlrpc_decode($v);
|
||||
|
||||
/* Get applist */
|
||||
$f = CreateObject('phpgwapi.xmlrpcmsg','system.listApps','');
|
||||
echo '<pre>' . htmlentities($f->serialize()) . "</pre>\n";
|
||||
|
||||
$c = CreateObject('phpgwapi.xmlrpc_client',$path,$host,80);
|
||||
$c->setDebug(1);
|
||||
$c->username = $result['sessionid'];
|
||||
$c->password = $result['kp3'];
|
||||
$r = $c->send($f);
|
||||
|
||||
/* Logout */
|
||||
$logout = CreateObject(
|
||||
'phpgwapi.xmlrpcmsg',
|
||||
'system.logout',
|
||||
array(
|
||||
CreateObject(
|
||||
'phpgwapi.xmlrpcval',
|
||||
array(
|
||||
'sessionid' => CreateObject('phpgwapi.xmlrpcval',$result['sessionid'],'string'),
|
||||
'kp3' => CreateObject('phpgwapi.xmlrpcval',$result['kp3'],'string')
|
||||
),
|
||||
'struct'
|
||||
)
|
||||
)
|
||||
);
|
||||
echo '<pre>' . htmlentities($logout->serialize()) . "</pre>\n";
|
||||
|
||||
$c = CreateObject('phpgwapi.xmlrpc_client',$path,$host,80);
|
||||
$c->setDebug(1);
|
||||
$r = $c->send($logout);
|
||||
$v = $r->value();
|
||||
|
||||
$GLOBALS['phpgw_setup']->html->show_footer();
|
||||
?>
|
95
soap.php
95
soap.php
@ -1,95 +0,0 @@
|
||||
<?php
|
||||
/**************************************************************************\
|
||||
* eGroupWare - SOAP Server *
|
||||
* http://www.egroupware.org *
|
||||
* Written by Miles Lott <milos@groupwhere.org> *
|
||||
* -------------------------------------------- *
|
||||
* 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 the *
|
||||
* Free Software Foundation; either version 2 of the License, or (at your *
|
||||
* option) any later version. *
|
||||
\**************************************************************************/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
$GLOBALS['egw_info'] = array(
|
||||
'flags' => array(
|
||||
'disable_Template_class' => True,
|
||||
'currentapp' => 'login',
|
||||
'noheader' => True,
|
||||
'disable_Template_class' => True
|
||||
)
|
||||
);
|
||||
include('./header.inc.php');
|
||||
|
||||
include_once(EGW_API_INC . '/xml_functions.inc.php'); // not sure that's neccessary, but I have no way to test
|
||||
include_once(EGW_API_INC . '/soap_functions.inc.php');
|
||||
|
||||
$GLOBALS['server'] = CreateObject('phpgwapi.soap_server');
|
||||
/* _debug_array($GLOBALS['server']);exit; */
|
||||
/* include(EGW_API_INC . '/soaplib.soapinterop.php'); */
|
||||
|
||||
if (!$GLOBALS['egw_info']['server']['soap_enabled'])
|
||||
{
|
||||
$GLOBALS['server']->make_fault(9999,'soap service is not enabled in the eGroupWare system configuration');
|
||||
$GLOBALS['server']->service($GLOBALS['server']->fault());
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Note: this command only available natively in Apache (Netscape/iPlanet/SunONE in php >= 4.3.3) */
|
||||
if(!function_exists('getallheaders'))
|
||||
{
|
||||
function getallheaders()
|
||||
{
|
||||
settype($headers,'array');
|
||||
foreach($_SERVER as $h => $v)
|
||||
{
|
||||
if(preg_match('/HTTP_(.+)/',$h,$hp))
|
||||
{
|
||||
$headers[$hp[1]] = $v;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
$headers = getallheaders();
|
||||
|
||||
if(strpos($headers['Authorization'],'Basic') !== false)
|
||||
{
|
||||
$tmp = $headers['Authorization'];
|
||||
$tmp = str_replace(' ','',$tmp);
|
||||
$tmp = str_replace('Basic','',$tmp);
|
||||
$auth = base64_decode(trim($tmp));
|
||||
list($sessionid,$kp3) = explode(':',$auth);
|
||||
|
||||
if($GLOBALS['egw']->session->verify($sessionid,$kp3))
|
||||
{
|
||||
$GLOBALS['server']->authed = True;
|
||||
}
|
||||
elseif($GLOBALS['egw']->session->verify_server($sessionid,$kp3))
|
||||
{
|
||||
$GLOBALS['server']->authed = True;
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['server']->add_to_map(
|
||||
'system_login',
|
||||
array('soapstruct'),
|
||||
array('soapstruct')
|
||||
);
|
||||
$GLOBALS['server']->add_to_map(
|
||||
'system_logout',
|
||||
array('soapstruct'),
|
||||
array('soapstruct')
|
||||
);
|
||||
|
||||
if(function_exists('system_listapps'))
|
||||
{
|
||||
$GLOBALS['server']->add_to_map(
|
||||
'system_listApps',
|
||||
array(),
|
||||
array('soapstruct')
|
||||
);
|
||||
}
|
||||
|
||||
$GLOBALS['server']->service($HTTP_RAW_POST_DATA);
|
90
xmlrpc.php
90
xmlrpc.php
@ -1,90 +0,0 @@
|
||||
<?php
|
||||
/**************************************************************************\
|
||||
* eGroupWare xmlrpc server *
|
||||
* http://www.egroupware.org *
|
||||
* This file written by Miles Lott <milos@groupwhere.org> *
|
||||
* -------------------------------------------- *
|
||||
* 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 the *
|
||||
* Free Software Foundation; either version 2 of the License, or (at your *
|
||||
* option) any later version. *
|
||||
\**************************************************************************/
|
||||
|
||||
/* $Id$ */
|
||||
/* $Source$ */
|
||||
/*list($usec, $sec) = explode(" ", microtime());
|
||||
$GLOBALS['concisus']['script_start'] = ((float)$usec + (float)$sec);*/
|
||||
|
||||
$GLOBALS['egw_info'] = array(
|
||||
'flags' => array(
|
||||
'currentapp' => 'login',
|
||||
'noheader' => True,
|
||||
'disable_Template_class' => True
|
||||
)
|
||||
);
|
||||
include('./header.inc.php');
|
||||
|
||||
include_once(EGW_API_INC . '/xml_functions.inc.php');
|
||||
include_once(EGW_API_INC . '/soap_functions.inc.php'); // not sure that's neccessary, but I have no way to test
|
||||
|
||||
//viniciuscb: a secure way to know if we're in a xmlrpc call...
|
||||
$GLOBALS['egw_info']['server']['xmlrpc'] = true;
|
||||
|
||||
$server = CreateObject('phpgwapi.xmlrpc_server');
|
||||
|
||||
/* uncomment here if you want to show all of the testing functions for compatibility */
|
||||
//include(EGW_API_INC . '/xmlrpc.interop.php');
|
||||
|
||||
if (!$GLOBALS['egw_info']['server']['xmlrpc_enabled'])
|
||||
{
|
||||
$server->xmlrpc_error(9999,'xmlrpc service is not enabled in the eGroupWare system configuration');
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Note: this command only available natively in Apache (Netscape/iPlanet/SunONE in php >= 4.3.3) */
|
||||
if(!function_exists('getallheaders'))
|
||||
{
|
||||
function getallheaders()
|
||||
{
|
||||
settype($headers,'array');
|
||||
foreach($_SERVER as $h => $v)
|
||||
{
|
||||
if(preg_match('/HTTP_(.+)/',$h,$hp))
|
||||
{
|
||||
$headers[$hp[1]] = $v;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
$headers = getallheaders();
|
||||
|
||||
//print_r($headers);
|
||||
$isodate = $headers['isoDate'] ? $headers['isoDate'] : $headers['isodate'];
|
||||
$isodate = ($isodate == 'simple') ? True : False;
|
||||
$server->setSimpleDate($isodate);
|
||||
$auth_header = $headers['Authorization'] ? $headers['Authorization'] : $headers['authorization'];
|
||||
|
||||
if(preg_match('/Basic *([^ ]*)/i',$auth_header,$auth))
|
||||
{
|
||||
list($sessionid,$kp3) = explode(':',base64_decode($auth[1]));
|
||||
//echo "auth='$auth[1]', sessionid='$sessionid', kp3='$kp3'\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sessionid = get_var('sessionid',array('COOKIE','GET'));
|
||||
$kp3 = get_var('kp3',array('COOKIE','GET'));
|
||||
}
|
||||
$server->authed = $GLOBALS['egw']->session->verify($sessionid,$kp3);
|
||||
|
||||
if (!$server->authed and isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW']))
|
||||
{
|
||||
$authed = $GLOBALS['egw']->session->create($login.'@'.$domain, $_SERVER['PHP_AUTH_PW'], 'text');
|
||||
|
||||
if ($authed)
|
||||
{
|
||||
$server->authed = true;
|
||||
}
|
||||
}
|
||||
|
||||
$server->service($_SERVER['HTTP_RAW_POST_DATA']);
|
Loading…
Reference in New Issue
Block a user