You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/protocols/groupwise/libgroupwise/coreprotocol.h

204 lines
7.9 KiB

/*
Kopete Groupwise Protocol
coreprotocol.h- the core GroupWise protocol
Copyright (c) 2004 SUSE Linux AG http://www.suse.com
Based on Iris, Copyright (C) 2003 Justin Karneges
Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
*************************************************************************
* *
* 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 of the License, or (at your option) any later version. *
* *
*************************************************************************
*/
#ifndef GW_CORE_PROTOCOL_H
#define GW_CORE_PROTOCOL_H
#include <tqcstring.h>
#include <tqobject.h>
#include <tqptrlist.h>
#include "gwfield.h"
class EventProtocol;
class ResponseProtocol;
class Request;
class Transfer;
/**
* This class handles transforming data between structured high level messages and encoded bytes that are sent
* and received over the network.
*
* 0) FIELD ARRAYS
* ---------------
* This is relevant to both input and output handling.
* Requests (out) and Responses (in) are messages containing, after a HTTP header, a series of 'Fields'.
* A message may contain a flat series of Fields, or each Field may mark the start of a nested array of more Fields.
* In this case the Field's value is the length of the following nested array.
* The length of the top level Field series is not given. The message ends when there are no more Fields expected as part of a nested array,
* and is marked by a terminator.
* The encoding used for Fields differs for Requests and Responses, and is described below.
*
* 1) INPUT
* --------
* The input functionality is a finite state machine that processes the stream of data from the GroupWise server.
* Since the server may arbitrarily truncate or run together protocol level messages, we buffer the incoming data stream,
* parsing it into individual messages that are removed from the buffer and passed back to the ClientStream, which propagates
* them to higher layers.
*
* Incoming data may be in either of two formats; a Response or an Event.
* All binary data is Little Endian on the network.
*
* 1.1) INPUT MESSAGE 'SPECIES'
*
* 1.1.1) Events
*
* Events are independently occuring notifications generated by the server or by the activity of other users.
* Events are represented on the wire in binary format:
*
* BYTE 1
* 0 8 6....
* AAAABBBBCCCCCCCCC....DDDDDDDD.....
* AAAA is a UINT32 giving the type of event
* BBBB is a UINT32 giving the length of the event source,
* CCCC... is the event source, a UTF8 encoded string, which is observed to be zero terminated
* DDDD... is event dependent binary data, which frequently consists of the conference the event relates to,
* conference flags describing the logging, chat security and closed status, and message data.
*
* As the DDDD portion is irregularly structured, it must be processed knowing the semantics of the event type.
* See the @ref EventProtocol documentation.
*
* Event message data is always a UINT32 giving the message length, then a message in RTF format.
* The message length may be zero.
*
* 1.1.2) Responses
* Responses are the server's response to client Requests. Each Request generates one Response. Requests and Responses are regularly structured
* and can be parsed/generated without any knowledge of their content.
* Responses consist of text/line oriented standard HTTP headers, followed by a binary payload. The payload is a series of Fields as described above,
* and the terminator following the last field is a null (0x0) byte.
*
* TODO: Add Field structure format: type, tag, method, flags, and value. see ResponseProtocol::readFields() for reference if this is incomplete.
*
* 1.3) INPUT PROCESSING IMPLEMENTATION
* CoreProtocol input handling operates on an event driven basis. It starts processing when it receives data via @ref addIncomingData(),
* and emits @ref incomingData() as each complete message is parsed in off the wire.
* Each call to addIncomingData() may result in zero or more incomingData() signals
*
* 2) REQUESTS
* -----------
* The output functionality is an encoding function that transforms outgoing Requests into the wire request format
* - a HTTP POST made up of the request operation type as the path, followed by a series of (repeated) variables that form the arguments.
* Order of the arguments is significant!
* Argument values are URL-encoded with spaces encoded as + rather than %20.
* The terminator used is a CRLF pair ("\r\n").
* HTTP headers are only used in a login operation, where they contain a Host: hostname:port line.
* Headers are separated from the arguments by a blank line (only CRLF) as usual.
*
* 3) USER MESSAGE BODY TEXT REPRESENTATION
* -----------------------------------
* Message text sent by users (found in both Requests and Events) is generally formatted as Rich Text Format.
* Text portions of the RTF may be be encoded in
* any of three ways -
* ascii text,
* latin1 as hexadecimal,
* escaped unicode code points (encoded/escaped as \uUNICODEVALUE?, with or without a space between the end of the unicode value and the ? )
* Outgoing messages may contain rich text, and additionally the plain text encoded as UTF8, but this plain payload is apparently ignored by the server
*
*/
class CoreProtocol : public TQObject
{
TQ_OBJECT
public:
enum State { NeedMore, Available, NoData };
CoreProtocol();
virtual ~CoreProtocol();
/**
* Debug output
*/
static void debug(const TQString &str);
/**
* Reset the protocol, clear buffers
*/
void reset();
/**
* Accept data from the network, and buffer it into a useful message
* @param incomingBytes Raw data in wire format.
*/
void addIncomingData( const TQByteArray& incomingBytes );
/**
* @return the incoming transfer or 0 if none is available.
*/
Transfer* incomingTransfer();
/**
* Convert a request into an outgoing transfer
* emits @ref outgoingData() with each part of the transfer
*/
void outgoingTransfer( Request* outgoing );
/**
* Get the state of the protocol
*/
int state();
signals:
/**
* Emitted as the core protocol converts fields to wire ready data
*/
void outgoingData( const TQByteArray& );
/**
* Emitted when there is incoming data, parsed into a Transfer
*/
void incomingData();
protected slots:
/**
* Just a debug method to test emitting to the socket, atm - should go to the ClientStream
*/
void slotOutgoingData( const TQCString & );
protected:
/**
* Check that there is data to read, and set the protocol's state if there isn't any.
*/
bool okToProceed();
/**
* Convert incoming wire data into a Transfer object and queue it
* @return number of bytes from the input that were parsed into a Transfer
*/
int wireToTransfer( const TQByteArray& wire );
/**
* Convert fields to a wire representation. Emits outgoingData as each field is written.
* Calls itself recursively to process nested fields, hence
* @param depth Current depth of recursion. Don't use this parameter yourself!
*/
void fieldsToWire( Field::FieldList fields, int depth = 0 );
/**
* encodes a method number (usually supplied as a #defined symbol) to a char
*/
TQChar encode_method( TQ_UINT8 method );
private:
TQByteArray m_in; // buffer containing unprocessed bytes we received
TQDataStream* m_din; // contains the packet currently being parsed
int m_error;
Transfer* m_inTransfer; // the transfer that is being received
int m_state; // represents the protocol's overall state
EventProtocol* m_eventProtocol;
ResponseProtocol * m_responseProtocol;
};
#endif