#pragma once #include #include #include // This is a fairly low-level client library for the tomsg protocol. No state // is kept; the API just allows for sending commands and receiving responses // and push messages from the server. // Use tomsg_connect() to connect, then wait for messages by poll(2)'ing on the // file descriptor returned by tomsg_poll_fd(). To send a command, use // functions like tomsg_register(), tomsg_send(), etc. struct tomsg_client; enum tomsg_retval { // Successful result TOMSG_OK = 0, // Error codes TOMSG_ERR_CONNECT, // Server refused connection TOMSG_ERR_CLOSED, // Server connection unexpectedly closed TOMSG_ERR_VERSION, // Server protocol version incompatible TOMSG_ERR_TRANSPORT, // Error in the underlying SSH transport TOMSG_ERR_SPACE, // Argument contained space or LF, while it could not TOMSG_ERR_AGAIN, // (tomsg_next_event) no events for now, poll(2) and try again TOMSG_ERR_PARSE, // (tomsg_next_event) could not parse line from server, line ignored TOMSG_ERR_MEMORY, // Error allocating memory }; // Should return 'true' if the key is trusted, 'false' otherwise. The hash is // sha256 in byte form, not yet encoded in hexadecimal or similar. The // 'userdata' pointer comes from the 'tomsg_connect' invocation. typedef bool (*tomsg_hostkey_checker_t)( const unsigned char *hash, size_t length, void *userdata); // Convenience function to convert a hash to a human-readable form. Returns a // reference to an internal static buffer. const char* tomsg_print_hash(const unsigned char *hash, size_t length); // Returns reference to internal static buffer. const char* tomsg_strerror(enum tomsg_retval code); // If successful, stores a new connection structure in 'client' and returns // TOMSG_OK. On error, stores NULL in 'client' and returns an error code. enum tomsg_retval tomsg_connect( const char *hostname, int port, tomsg_hostkey_checker_t checker, void *userdata, // for checker struct tomsg_client **client // output ); // Close the connection. This also frees the client structure. Note that even // in case of an error, you must still call this function to prevent a memory // leak. void tomsg_close(struct tomsg_client *client); // Returns a file descriptor that can be listened for read-ready events (using // e.g. select(2) or poll(2)). Whenever it becomes ready for reading, you // should call tomsg_next_event(). If the connection was already closed // internally due to an error, returns -1. int tomsg_poll_fd(const struct tomsg_client *client); enum tomsg_event_type { // Data in union fields indicated (but check 'error' first) TOMSG_EV_REGISTER, // login TOMSG_EV_LOGIN, // login TOMSG_EV_LOGOUT, // - TOMSG_EV_LIST_ROOMS, // list_rooms TOMSG_EV_LIST_MEMBERS, // list_members TOMSG_EV_CREATE_ROOM, // create_room TOMSG_EV_INVITE, // join TOMSG_EV_SEND, // send TOMSG_EV_HISTORY, // history TOMSG_EV_PING, // - TOMSG_EV_IS_ONLINE, // is_online TOMSG_EV_USER_ACTIVE, // user_active TOMSG_EV_PUSH_ONLINE, // is_online TOMSG_EV_PUSH_MESSAGE, // push_message TOMSG_EV_PUSH_INVITE, // push_invite TOMSG_EV_PUSH_JOIN, // join }; struct history_message { char *username; int64_t timestamp; int64_t msgid; char *message; }; struct tomsg_event { enum tomsg_event_type type; // If the server returned an error, 'error' is non-NULL; otherwise it is // NULL, and the union fields describe the server's response. // Actually, if 'error' is non-NULL, the union fields that can be // filled with request data will already be filled. char *error; union { struct { char *username; } login; struct { int64_t count; char **rooms; } list_rooms; struct { char *room_name; int64_t count; char **members; } list_members; struct { char *room_name; } create_room; struct { char *room_name; char *username; } join; struct { int64_t tag; // the tag of the send request, returned by tomsg_send() int64_t msgid; } send; struct { char *room_name; int64_t count; struct history_message *messages; } history; struct { char *username; int64_t online_count; } is_online; struct { bool active; } user_active; struct { char *room_name; struct history_message message; } push_message; struct { char *room_name; char *inviter; } push_invite; }; }; // Free the fields in the event structure corresponding to the event type set. // The structure memory may be re-used for a different event afterwards. Note // that, despite the name, the fields are not actually set to NULL -- they // couldn't be, since the structure is passed by value (to indicate ownership // transfer). void tomsg_event_nullify(struct tomsg_event event); // Will return TOMSG_ERR_AGAIN if no events are available at present. In that // case, use poll(2) on the file descriptor from tomsg_poll_fd(). // NOTE: when calling this function, you must call it as long as it gives // TOMSG_OK, because there might be multiple messages in one batch. enum tomsg_retval tomsg_next_event( struct tomsg_client *client, struct tomsg_event *event // output ); // Send a register command to the server. enum tomsg_retval tomsg_register( struct tomsg_client *client, const char *username, const char *password ); // Send a login command to the server. enum tomsg_retval tomsg_login( struct tomsg_client *client, const char *username, const char *password ); // Send a logout command to the server. enum tomsg_retval tomsg_logout(struct tomsg_client *client); // Send a list_rooms command to the server. enum tomsg_retval tomsg_list_rooms(struct tomsg_client *client); // Send a list_members command to the server. enum tomsg_retval tomsg_list_members(struct tomsg_client *client, const char *room_name); // Send a create_room command to the server. enum tomsg_retval tomsg_create_room(struct tomsg_client *client); // Send an invite command to the server. enum tomsg_retval tomsg_invite( struct tomsg_client *client, const char *room_name, const char *username); // Send a send command to the server. // If 'tag' is not NULL, will write the message request tag to the referenced // location. This tag will also be given in the TOMSG_EV_SEND response, so that // the response can be linked to the original message. enum tomsg_retval tomsg_send( struct tomsg_client *client, const char *room_name, const char *message, int64_t *tag // output ); // Send a history command to the server. // Pass -1 to 'before_msgid' to return the latest 'count' instead messages // before that id. enum tomsg_retval tomsg_history( struct tomsg_client *client, const char *room_name, int64_t count, int64_t before_msgid); // Send a ping command to the server. enum tomsg_retval tomsg_ping(struct tomsg_client *client); // Send an is_online command to the server. enum tomsg_retval tomsg_is_online(struct tomsg_client *client, const char *username); // Send a user_active command to the server. enum tomsg_retval tomsg_user_active(struct tomsg_client *client, bool active);