1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
// 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);
|