Each request must have a "x-magicsmoke-request=..." header. The actual request data is sent as POST-data. Except for the serverinfo and startsession requests all requests must also carry a "x-magicsmoke-session" header.
x-magicsmoke-request | The request that is to be executed by the server. This header is mandatory for all requests. |
x-magicsmoke-session | The session ID of this connection. This header is mandatory for all requests except serverinfo and startsession. |
x-magicsmoke-status | The status of the request execution. See table below for details |
Possible status codes are:
(missing) | If the whole header is missing or contains an unknown value, this should be treated as if it contained "Error" (see below). |
Ok | The request went ok and the actual data comes as response body. |
Error | Some unspecified error occured. The response body might contain some detailed human readable information. |
NonPost | The HTTP method was not POST. The body is a simple HTML page explaining to the user that browsers are not meant to use this page. |
Unauthenticated | The session ID does not exist, authentication failed or the session expired. |
NotAllowed | The user does not have the right to execute this transaction. |
InvalidRequest | The request was not understood. There was probably a mismatch in client and server version. |
SyntaxError | There was a syntactical error in the request data. Some details might follow in the response body. |
The server replies with an XML document that contains the most important information:
<Info> <ServerVersion proto="protocol-version">server-version-number</ServerVersion> <AuthAlgorithm>hash-algo</AuthAlgorithm> </Info>The proto argument of the ServerVersion tag returns the protocol version, which is used by the client to check whether it is compatible with the server. It consists of two blocks of four hex-digits each, separated by a space. The first block is the lowest protocol version understood by the server, while the second block contains the current protocol version implemented by the server.
The server version number in the ServerVersion tags text is a the software version itself. The hash-algorithm values are described below in the authentication protocol section.
The protocol version described in this document is 0000.
md5, sha1, sha256 | use the hash algorithm directly, the returned value is calculated by first concatenating challenge and password/hostkey and then hashing it |
hmac-* | use the same algorithm in HMAC mode with the challenge as data and the password/hostkey as key |
<SessionStart> <ID>session-id-string</ID> <HostChallenge>host-challenge-string</HostChallenge> <UserChallenge>user-challenge-string</UserChallenge> <Timeout>seconds-till-session-timeout</Timeout> </SessionStart>The challenge strings are derived from some internal function and the clock. By no means they are meant to be secure against all kinds of attack. The challenge-response-protocol is only supposed to avoid sending the passwords in plain text over the wire.
The timeout of the temporary session is usually 5 minutes (300s).
The client sends its authentication data as XML:
<SessionAuth> <HostName>host-name</HostName> <HostAuth>host-authentication-data</HostAuth> <UserName>user-name</UserName> <UserAuth>user-authentication-data</UserAuth> </SessionAuth>The authentication data is calculated using the hash-function mandated by the server. The HostAuth item is calculated using the HostChallenge and the hosts key. The UserAuth item is calculated using the UserChallenge and the users password. Both *Auth values are hexadecimal-encoded.
The status is "Ok" or "Unauthenticated" - in the latter case the session ID is deleted and the client needs to start with a startsession request again if it wants to retry. If the request succeeds, the result body contains two numeric items (separated by a newline) that state the new session timeout and the current time as a Unix timestamp (seconds sice epoch - 1Jan1970, 00:00 UTC).
A result of "Unauthenticated" can have multiple reasons: the timeout of the temporary session expired before the request was received, the authentication of the user failed, the user is not allowed to connect from this or an anonymous host, or the authentication of the host failed and the user is not allowed to connect from an anonymous host.
This request always yields an "Ok" status response regardless of whether the session ID was still valid or not.
Each role corresponds to a function that can be called and executed remotely through the machine interface. Roles beginning with "_" are reserved keywords that can alter the behaviour of other roles and must not be used to name functions.
Special rights are:
_admin | The user is an administrator and can automatically execute everything. |
<EventList> <Event id="0" start="1190543432" sold="11" capacity="20" reserved="2">blechsalat</Event> <Event id="1" start="1191419769" sold="11" capacity="20" reserved="2">stringsalat</Event> </EventList>Each event is encapsulated in an Event tag. The events have no specific order. The id attribute contains the internal ID of the event that can be used to reference it in other requests. The start attribute contains the start time of the event as Unix timestamp. The text of the Event tag contains the title of the event.
There are 3 optional attributes: capacity contains the maximum number of seats for this event, sold the number of tickets that have been sold and reserved the number of tickets that have been reserved.
<EventData> <Event id="0" start="1190543432" end="1190543532" capacity="25" defaultprice="1177" cancelled="false"> <Title>blechsalat</Title> <Artist>Broken Blech</Artist> <Description>a lot of text containing encoded <b>HTML</b> tags</Description> <Room>Invisible Library</Room> <CancelReason>a damned good one</CancelReason> </Event> <Event id="1" start="1191419769" ...> ... </Event> </EventData>Attributes and tags:
id | the ID of the event |
start | the start time as Unix timestamp |
end | the end time as Unix timestamp |
capacity | how many tickets may be sold for this event |
defaultprice | the default price for tickets as integer in cent (or penny or ...) |
cancelled | optional: "true" or "false" -- shows whether the event is cancelled, default is "false" |
Title | the title of the event |
Artist | the artist appearing |
Description | a description for the web page, may contain HTML |
Room | the room it is happening in (the room must exist in the list of available rooms) |
CancelReason | optional: if the event is cancelled, the reason for it (human readable) |
<Event id="0" ....> <Title>.... </Event>Attributes and tags are the same as for the geteventdata response. Except that the id attribute may contain the value "new" to create a new event, a negative integer is not allowed.
The response contains the ID of the new/changed event if the status is "Ok". In the case of failure the status will be "Error" and an optional reason for the failure may be in the body.
The request must not change the cancellation status of an event - the attribute "cancelled" is ignored and the element "CancelReason" may be ignored if it violates the current status.
<EventSummary event="eventID" reserved="numbeOfCurrentlyReservedTickets" cancelled="numberOfCurrentlyCancelledTickets" totaltickets="numberOfUsableTickets" totalmoney="totalIncomeOfEventInCent" > <Tickets price="priceCategoryInCent" bought="numberOfUsableTicketsInThisCategory" used="numberOfUsedTickets" unused="numberOfUnusedTickets" /> <Comment customerid="customerID" customer="customers Name" orderid="orderID">comment</Comment> <Orders>space separated IDs of all orders for this event</Orders> </EventSummary>
<GetRooms detail="basic"> <Room>ID of room</Room> ... </GetRooms>The detail attribute may be "basic" or "full". If no <Room> tags are present all rooms are returned.
The response data looks like:
<RoomData> <Room capacity="24"> <ID>Room ID</ID> <Description>some encoded HTML text that describes the room</Description> </Room> ... </RoomData>The capacity attribute tells how many persons fit into the room. The ID tag contains the ID or Name of the room, the optional Description tag contains a description of the room - it is only present if full detail has been requested.
<RoomData> <Room capacity="24"> <ID>Room ID</ID> <Description>some encoded HTML text that describes the room</Description> </Room> ... </RoomData>The response simply contains the status "Ok" or "Error".
<Users> <User name="loginname">Description of User</User> ... </Users>
The adduser call can be used to create new user accounts. Initially the new user will have no ACL and no host settings.
Both calls use this structure for the request:
<Users> <User name="loginname" passwd="initial password">Description of User</User> ... </Users>The passwd attribute is optional.
The adduser call also uses it for the response, leaving out any user name that already existed or does not conform to the syntax requirements.
The response is empty or optionally contains an error message.
<SetMyPasswd oldpwd="old password" newpwd="new password"\>The response is empty. Only the status counts.
<SetPasswd user="user name" newpwd="new password"\>The response is empty. Only the status counts.
<ACL user="username"> <Role name="rolename" set="1|0"/> ... </ACL>All setable roles must be listed, so that the client can use these for displaying in a dialog.
Any role listed in the request is changed accordingly, non-existant roles are ignored, roles not listed are left unchanged.
<Hosts user="username"> <Host name="hostname" set="1|0"/> ... </Hosts>All setable hosts must be listed, so that the client can use these for displaying in a dialog.
Any host listed in the request is changed accordingly, non-existant hosts are ignored, hosts not listed are left unchanged.
<Hosts> <Host name="hostname">hostkey</Host> ... </Hosts>FIXME: currently these transactions do not return any feedback about success. The sethost transaction silently ignores hosts that do not exist.
FIXME: special hosts (beginning with "_") return errors. Non-existing hosts are silently ignored.
<CustomerList> <Customer id="integer ID" name="full name"/> ... </CustomerList>
<Customer id="integer ID" name="full name" mail="login-mail-for-webinterface"> <Address> address info</Address> <Contact> contact information</Contact> <Comment> system internal comment</Comment> </Customer>The "mail" attribute is optional - it is only reported for customers that have a web-interface account.
If customers are merged, the following rules are executed:
<Order id="orderid" customer="customerid" seller="sellerid" ordertime="timestamp" senttime="timestamp" totalprice="amountInCent" paid="amountInCent" status="orderstate"> <Ticket event="eventid" id="ticketid" price="priceInCent" status="ticketstate" /> <Voucher id="voucherid" price="priceInCent" value="remainingValueInCent" used="0|1" status=""/> <Shipping price="priceInCent" type="shippingtypeID">Shipping Comment</Shipping> <DeliveryAddress>deliver address</DeliveryAddress> <Comment>comment...</Comment> </Order>
Item | Description | Occurrence |
Order | Container for one single order or sale | 1 |
id | ID of the order, if already known. | 0-1 |
customer | ID of the customer. Mandatory. | 1 |
seller | Login of the seller. Automatically filled in. | 0-1 |
ordertime | Time of the order. Automatically filled in. | 0-1 |
senttime | Time at which the order was shipped. Automatically filled in. | 0-1 |
totalprice | Total accumulated price of the order. Automatically filled in. | 0-1 |
paid | Amount that has already been paid. Automatically filled in. | 0-1 |
status | Current status of the order. Automatically filled in. See table below. | 0-1 |
Ticket(*) | data about a single ticket bought in this order | 0-unlimited |
id | ID of the ticket | 1 |
event | ID of the event this ticket refers to. | 1 |
price | Price of the ticket | 1 |
status | Status of the ticket (see below) | 1 |
Voucher(*) | data about a single voucher bought in this order, vouchers that are used to pay for an order are not stored | 0-unlimited |
id | ID of the voucher | 1 |
price | Price of the voucher (adds to price of the order) | 1 |
value | Value (in cent) of the voucher (does not add to the order, but refers to how much the voucher is worth) | 1 |
status | only in validation responses: result of the validation | 0-1 |
used | Flag whether the voucher has been used to pay for anything (assumed as 0 if not present) | 0-1 |
Shipping | information about the kind of shipping used and how much it costs; if text is used it is a copy of the text from the shipping table information - it cannot be changed here | 0-1 |
price | Price of the shipping option | 1 |
type | shipping type ID | 1 |
DeliveryAddress | the address to send the stuff to, if not present or empty the address of the customer is used | 0-1 |
Comment | comment entered into the order by customer or seller | 0-1 |
If items that are not expected are filled in in a message, they will be ignored.
Order status:
Status | Description |
placed | The order has been placed, nothing has been sent or paid yet. |
sent | The order has been shipped. |
reserved | The order has been reserved. This means the tickets are blocked, but it cannot be paid or shipped. |
cancelled | The user cancelled an unshipped and unpaid order. |
closed | The order is final and cannot be altered. (State maybe not needed.) |
Status | Description |
bought(1) | The ticket is valid; whether it is paid for depends on the order status. |
refund(2) | The ticket has been or needs to be refunded; eg. after the event or order was cancelled. |
used(1) | The ticket has been used. |
reserved | The ticket is reserved. This state is currently not used. |
The create* transactions fail with an error if a ticket cannot be reserved or if a voucher value is invalid. The checkorder transaction uses special state values to signify failure. It sets the price of a voucher to the nearest legal voucher value if the value is not allowed.
The request is an order object without most fields filled in, the response is a copy of that object with all relevant fields filled in:
Element | Attributes in Request | Attributes in Response |
Order | customer | id(1), customer, seller(3), ordertime(1,4), totalprice(5), paid(1), status(6), senttime(2,4) |
Ticket | event, price(7) | event, id(1), price, status(6) |
Voucher | value, price(7) | value, price, id(1), status(11) |
Shipping | type(8), price(9) | type(10), price, [text](10) |
DeliveryAddress | [text] | [text] |
Comment | [text] | [text] |
Order status for checks:
State | Description |
ok(1) | the order can be executed as is |
saleonly(2) | the order can only be continued as a sale, not as an open order |
orderonly(2) | the order can only be continued as an open order, not as a sale; this state also shows that there is a problem with the configuration |
fail | the order contains failed items |
State | Description |
ok(1) | the order can be executed as is |
saleonly(2) | the order can only be continued as a sale, not as an open order |
orderonly(2) | the order can only be continued as an open order, not as a sale; this state also shows that there is a problem with the configuration |
toolate | the order is not possible any more |
exhausted | there are no more tickets for this event |
cancelled | the event has been cancelled, no order is possible |
invalid | the event does not exist in the database |
State | Description |
[empty] | the order can be executed as is |
invalidvalue | the user is not allowed to use this value for the voucher |
invalidprice | for this user the price must equal the value (or be ommitted) |
<OrderList> <Order id="orderid" customer="customerid" status="orderstatus" totalprice="amountDueInCent" paid="amountPaidInCent"/> ... </OrderList>(this is a small subset of the full order object)
The request contains the order ID, the response is empty or contains an error message.
Use the cancelorder transaction (see above) to cancel a reservation.
The getordersbyevents transaction can be used to return all orders that contain tickets for a specific event. The request is a space separated list of event IDs, the response has the format of the getorderlist response.
<OrderComment orderid="id">comment text...</OrderComment>The response body is empty or optionally contains an error message.
<OrderChangeShipping orderid="orderId" type="newShippingType" price="newPriceInCent"/>If type is not present, the price is taken from the new shipping type. If type is not present, it is not changed. If type is empty it is reset to none (NULL) in the Database. If a price other than 0 is used, the type in the database must be present (!= NULL).
The response contains the updated order object or just an error message.
<ShippingOption type="shippingOptionID" price="priceInCent" web="0|1" anyUser="0|1"> Text that describes the option </ShippingOption>If the type attribute is missing the server creates a new option. Otherwise it changes an existing one. The web attribute tells whether the option is available to customers using the web interface. The anyUser attribute tells whether the option can be used by anyone who can create an order/sale (=1) or only by users with the "_anyshipping" privilege (=0).
The response contains the new shipping option id or contains an error message.
The deleteshipping transaction can be used to delete a shipping option. The request contains just the ID of the option, the response is empty.
<ShippingList> <ShippingOption type="shippingOptionID" price="priceInCent" web="0|1" anyUser="0|1"> Text that describes the option </ShippingOption> ... ... </ShippingList>
<Ticket id="ticketid" status="ticketstate" order="orderid" event="eventid" price="priceincent" orderpaystate="status of the order" />The attribute orderid may be <0 if the ticket is not attached to an order.
Attribute | Description |
status | can be any of reserved, bought, used, refund, error (see getorder above for details) |
orderpaystate | the payment status of the order, it can be "none" if the order is invalid or the ticket is not attached to one, "ok" if the order has been paid correctly, "cancelled" if the order was cancelled, "needpayment" if the order is not fully paid yet, or "needrefund" if too much has been paid |
Only tickets that have status "bought" and whose order have payment status "ok" or "needrefund" can be used. The transaction fails for all other tickets.
On success the response contains the amount that remains on the voucher on the first line and the now current amount that has been paid for the order on the second line. On error the response contains an error message.
For this transaction to succeed the voucher must not have been used. The price and the value will be reset to zero. If the voucher is already cancelled the transaction will report success.
This transaction simulates buying nothing for a lot of money: it sets the voucher to used and resets the remaining value to zero. The voucher will still have a price that needs to be paid and it cannot be returned/reimbursed afterwards.
Only privileged users should be able to do this (if anybody at all).
Base names of templates are restricted to the regular expression ^[a-z0-9_]+$ and are case-insensitive. They may have an extension (legal values: "od[ts]t", "xtt") and a variant ID (at the moment numeric, but may match "^[a-z0-9_]+$").
Below "file name" refers to the complete concatenation of base name, extension, and variant: basename.extension[,variant]
<TList> <Template name="filename" hash="md5-hash">Description text</Template> ... </TList>The Hash is caculated at the server side and can be used to find out whether the template has been changed. It does not necessarily need to be MD5 or any other specific algorithm, it can be any kind of ASCII string that shows changes (hence the client must remember the string if it wants to use it).
The settemplatedescription transaction sets a new description for a template. The first line of the request contains the filename, the remainder the description.
The machine interface only provides for the retrieval of the backup file. Restoration is done via admin.php.
The backup transaction is used to retrieve a backup file. It does not have any parameters. The response is in the special backup format:
startbackup backupversion 0 dbversion 00.02 table exampletab value stringcolumn str TWFnaWNTbW9rZVZlcnNpb24= value intcolumn int 1 value boolcolumn bool 1 value anothercolumn NULL NULL insert endofbackupThe format is command oriented: each line is a specific command that can be interpreted by the restore processor:
Command | Description |
startbackup | marks the begin of a backup file |
backupversion | defines the format version (integer version number) of this backup file - this only shows which commands are valid, not what content can be transferred |
dbversion | version of the database scheme this data is taken from |
table | marks the start of a new table, has the (scheme-)name of the table as parameter, deletes the current dataset buffer |
value | adds a value to the current dataset buffer, parameters are the column name, encoding format and value |
insert | pushes the current dataset buffer into the current table, then empties the dataset buffer |
endofbackup | marks the end of the backup file, the processor should stop here |
Table cell values are encoded according to the content in the source database. The target database must decode the values according to the format used in the backup file and then escape the value as appropriate for the target database (irrespective of the just decoded source format).
The following encoding formats are currently known:
Format | Description |
NULL | a NULL value, the actual value in the backup file does not matter, the target value is NULL |
int | integer, the value must be converted into an integer number |
bool | boolean, the value "1" means true, the value "0" means false, everything else is an error and should be interpreted as NULL |
str | string or blob, the content is base64 encoded - if it is a string the result of base64 decoding is in UTF-8 encoding |