
/*
  Meanwhile - Unofficial Lotus Sametime Community Client Library
  Copyright (C) 2004  Christopher (siege) O'Brien
  
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) 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
  Library General Public License for more details.
  
  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef _MW_MESSAGE_H
#define _MW_MESSAGE_H


#include <glib/glist.h>
#include "mw_common.h"


#ifdef __cplusplus
extern "C" {
#endif


/** Cast a pointer to a message subtype (eg, mwMsgHandshake,
    mwMsgAdmin) into a pointer to a mwMessage */
#define MW_MESSAGE(msg) (&msg->head)


/** Indicates the type of a message. */
enum mwMessageType {
  mwMessage_HANDSHAKE         = 0x0000,  /**< mwMsgHandshake */
  mwMessage_HANDSHAKE_ACK     = 0x8000,  /**< mwMsgHandshakeAck */
  mwMessage_LOGIN             = 0x0001,  /**< mwMsgLogin */
  mwMessage_LOGIN_ACK         = 0x8001,  /**< mwMsgLoginAck */
  mwMessage_LOGIN_REDIRECT    = 0x0018,  /**< mwMsgLoginRedirect */
  mwMessage_LOGIN_CONTINUE    = 0x0016,  /**< mwMsgLoginContinue */

  mwMessage_CHANNEL_CREATE    = 0x0002,  /**< mwMsgChannelCreate */
  mwMessage_CHANNEL_DESTROY   = 0x0003,  /**< mwMsgChannelDestroy */
  mwMessage_CHANNEL_SEND      = 0x0004,  /**< mwMsgChannelSend */
  mwMessage_CHANNEL_ACCEPT    = 0x0006,  /**< mwMsgChannelAccept */

  mwMessage_SET_USER_STATUS   = 0x0009,  /**< mwMsgSetUserStatus */
  mwMessage_SET_PRIVACY_LIST  = 0x000b,  /**< mwMsgSetPrivacyList */
  mwMessage_SENSE_SERVICE     = 0x0011,  /**< mwMsgSenseService */
  mwMessage_ADMIN             = 0x0019,  /**< mwMsgAdmin */
  mwMessage_ANNOUNCE          = 0x0022,  /**< mwMsgAnnounce */
};


enum mwMessageOption {
  mwMessageOption_ENCRYPT      = 0x4000,  /**< message data is encrypted */
  mwMessageOption_HAS_ATTRIBS  = 0x8000,  /**< message has attributes */
};


/** @see mwMessageOption */
#define MW_MESSAGE_HAS_OPTION(msg, opt) \
  ((msg)->options & (opt))


struct mwMessage {
  guint16 type;     /**< @see mwMessageType */
  guint16 options;  /**< @see mwMessageOption */
  guint32 channel;  /**< ID of channel message is intended for */
  struct mwOpaque attribs;  /**< optional message attributes */
};



/** Allocate and initialize a new message of the specified type */
struct mwMessage *mwMessage_new(enum mwMessageType type);


/** build a message from its representation */
struct mwMessage *mwMessage_get(struct mwGetBuffer *b);


void mwMessage_put(struct mwPutBuffer *b, struct mwMessage *msg);


void mwMessage_free(struct mwMessage *msg);


/* 8.4 Messages */
/* 8.4.1 Basic Community Messages */
/* 8.4.1.1 Handshake */

struct mwMsgHandshake {
  struct mwMessage head;
  guint16 major;          /**< client's major version number */
  guint16 minor;          /**< client's minor version number */
  guint32 srvrcalc_addr;  /**< 0.0.0.0 */
  guint16 login_type;     /**< @see mwLoginType */
  guint32 loclcalc_addr;  /**< local public IP */
  guint16 unknown_a;      /**< normally 0x0100 */
  guint32 unknown_b;      /**< normally 0x00000000 */
  char *local_host;       /**< name of client host */
};


/* 8.4.1.2 HandshakeAck */

struct mwMsgHandshakeAck {
  struct mwMessage head;
  guint16 major;          /**< server's major version number */
  guint16 minor;          /**< server's minor version number */
  guint32 srvrcalc_addr;  /**< server-calculated address */
  guint32 magic;          /**< four bytes of something */
  struct mwOpaque data;   /**< server's DH public key for auth */
};


/* 8.3.7 Authentication Types */

enum mwAuthType {
  mwAuthType_PLAIN    = 0x0000,
  mwAuthType_TOKEN    = 0x0001,
  mwAuthType_ENCRYPT  = 0x0002, /**< @todo remove for 1.0 */
  mwAuthType_RC2_40   = 0x0002,
  mwAuthType_RC2_128  = 0x0004,
};


/* 8.4.1.3 Login */

struct mwMsgLogin {
  struct mwMessage head;
  guint16 login_type;         /**< @see mwLoginType */
  char *name;                 /**< user identification */
  guint16 auth_type;          /**< @see mwAuthType */
  struct mwOpaque auth_data;  /**< authentication data */
};


/* 8.4.1.4 LoginAck */

struct mwMsgLoginAck {
  struct mwMessage head;
  struct mwLoginInfo login;
  struct mwPrivacyInfo privacy;
  struct mwUserStatus status;
};


/* 8.4.1.5 LoginCont */

struct mwMsgLoginContinue {
  struct mwMessage head;
};


/* 8.4.1.6 AuthPassed */

struct mwMsgLoginRedirect {
  struct mwMessage head;
  char *host;
  char *server_id;
};


/* 8.4.1.7 CreateCnl */

/** an offer of encryption items */
struct mwEncryptOffer {
  guint16 mode;   /**< encryption mode */
  GList *items;   /**< list of mwEncryptItem offered */
  guint16 extra;  /**< encryption mode again? */
  gboolean flag;  /**< unknown flag */
};


struct mwMsgChannelCreate {
  struct mwMessage head;
  guint32 reserved;         /**< unknown reserved data */
  guint32 channel;          /**< intended ID for new channel */
  struct mwIdBlock target;  /**< User ID. for service use */
  guint32 service;          /**< ID for the target service */
  guint32 proto_type;       /**< protocol type for the service */
  guint32 proto_ver;        /**< protocol version for the service */
  guint32 options;          /**< options */
  struct mwOpaque addtl;    /**< service-specific additional data */
  gboolean creator_flag;    /**< indicate presence of creator information */
  struct mwLoginInfo creator;
  struct mwEncryptOffer encrypt;
};


/* 8.4.1.8 AcceptCnl */

/** a selected encryption item from those offered */
struct mwEncryptAccept {
  guint16 mode;                /**< encryption mode */
  struct mwEncryptItem *item;  /**< chosen mwEncryptItem (optional) */
  guint16 extra;               /**< encryption mode again? */
  gboolean flag;               /**< unknown flag */
};


struct mwMsgChannelAccept {
  struct mwMessage head;
  guint32 service;         /**< ID for the channel's service */
  guint32 proto_type;      /**< protocol type for the service */
  guint32 proto_ver;       /**< protocol version for the service */
  struct mwOpaque addtl;   /**< service-specific additional data */
  gboolean acceptor_flag;  /**< indicate presence of acceptor information */
  struct mwLoginInfo acceptor;
  struct mwEncryptAccept encrypt;
};


/* 8.4.1.9 SendOnCnl */

struct mwMsgChannelSend {
  struct mwMessage head;

  /** message type. each service defines its own send types. Type IDs
      are only necessarily unique within a given service. */
  guint16 type;

  /** protocol data to be interpreted by the handling service */
  struct mwOpaque data;
};


/* 8.4.1.10 DestroyCnl */

struct mwMsgChannelDestroy {
  struct mwMessage head;
  guint32 reason;        /**< reason for closing the channel. */
  struct mwOpaque data;  /**< additional information */
};


/* 8.4.1.11 SetUserStatus */

struct mwMsgSetUserStatus {
  struct mwMessage head;
  struct mwUserStatus status;
};


/* 8.4.1.12 SetPrivacyList */

struct mwMsgSetPrivacyList {
  struct mwMessage head;
  struct mwPrivacyInfo privacy;
};


/* Sense Service */

/** Sent to the server to request the presense of a service by its
    ID. Sent to the client to indicate the presense of such a
    service */
struct mwMsgSenseService {
  struct mwMessage head;
  guint32 service;
};


/* Admin */

/** An administrative broadcast message */
struct mwMsgAdmin {
  struct mwMessage head;
  char *text;
};


/* Announce */

/** An announcement between users */
struct mwMsgAnnounce {
  struct mwMessage head;
  gboolean sender_present;    /**< indicates presence of sender data */
  struct mwLoginInfo sender;  /**< who sent the announcement */
  guint16 unknown_a;          /**< unknown A. Usually 0x00 */
  gboolean may_reply;         /**< replies allowed */
  char *text;                 /**< text of message */

  /** list of (char *) indicating recipients. Recipient users are in
      the format "@U username" and recipient NAB groups are in the
      format "@G groupname" */
  GList *recipients;
};


#ifdef __cplusplus
}
#endif


#endif /* _MW_MESSAGE_H */

