1 #define _POSIX_C_SOURCE 200809L
11 #include "../src/meshlink-tiny.h"
13 static void log_message(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) {
16 static const char *levelstr[] = {
17 [MESHLINK_DEBUG] = "\x1b[34mDEBUG",
18 [MESHLINK_INFO] = "\x1b[32mINFO",
19 [MESHLINK_WARNING] = "\x1b[33mWARNING",
20 [MESHLINK_ERROR] = "\x1b[31mERROR",
21 [MESHLINK_CRITICAL] = "\x1b[31mCRITICAL",
24 fprintf(stderr, "%s:\x1b[0m %s\n", levelstr[level], text);
27 static void receive(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len) {
30 const char *msg = data;
32 if(!len || msg[len - 1]) {
33 fprintf(stderr, "Received invalid data from %s\n", source->name);
37 printf("%s says: %s\n", source->name, msg);
40 static void node_status(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
44 printf("%s joined.\n", node->name);
46 printf("%s left.\n", node->name);
50 static void parse_command(meshlink_handle_t *mesh, char *buf) {
51 char *arg = strchr(buf, ' ');
57 if(!strcasecmp(buf, "join")) {
59 fprintf(stderr, "/join requires an argument!\n");
65 if(!meshlink_join(mesh, arg)) {
66 fprintf(stderr, "Could not join using invitation: %s\n", meshlink_strerror(meshlink_errno));
68 fprintf(stderr, "Invitation accepted!\n");
71 if(!meshlink_start(mesh)) {
72 fprintf(stderr, "Could not restart MeshLink: %s\n", meshlink_strerror(meshlink_errno));
75 } else if(!strcasecmp(buf, "quit")) {
78 } else if(!strcasecmp(buf, "help")) {
80 "<name>: <message> Send a message to the given node.\n"
81 " Subsequent messages don't need the <name>: prefix.\n"
82 "/join <invitation> Join an existing mesh using an invitation.\n"
83 "/kick <name> Blacklist the given node.\n"
84 "/who [<name>] List all nodes or show information about the given node.\n"
85 "/quit Exit this program.\n"
88 fprintf(stderr, "Unknown command '/%s'\n", buf);
92 static void parse_input(meshlink_handle_t *mesh, char *buf) {
93 static meshlink_node_t *destination;
104 if(len && buf[len - 1] == '\n') {
108 if(len && buf[len - 1] == '\r') {
112 // Ignore empty lines.
118 // Commands start with '/'
121 parse_command(mesh, buf + 1);
125 // Lines in the form "name: message..." set the destination node.
128 char *colon = strchr(buf, ':');
138 destination = meshlink_get_node(mesh, buf);
141 fprintf(stderr, "Error looking up '%s': %s\n", buf, meshlink_strerror(meshlink_errno));
147 fprintf(stderr, "Who are you talking to? Write 'name: message...'\n");
151 if(!meshlink_send(mesh, destination, msg, strlen(msg) + 1)) {
152 fprintf(stderr, "Could not send message to '%s': %s\n", destination->name, meshlink_strerror(meshlink_errno));
156 printf("Message sent to '%s'.\n", destination->name);
159 static char *flatten(const char *filename) {
160 char *result = strdup(filename);
163 for(char *c = result; *c; c++) {
172 static bool load_cb(meshlink_handle_t *mesh, const char *key, void *data, size_t *len) {
173 fprintf(stderr, "load_cb(%s, %s, %p, %zu)\n", mesh->name, key, data, *len);
174 FILE *f = fopen(flatten(key), "r");
176 fread(data, 1, *len, f);
177 fseek(f, 0, SEEK_END);
183 static bool store_cb(meshlink_handle_t *mesh, const char *key, const void *data, size_t len) {
184 fprintf(stderr, "store_cb(%s, %s, %p, %zu)\n", mesh->name, key, data, len);
185 FILE *f = fopen(flatten(key), "w");
187 assert(fwrite(data, len, 1, f) == 1);
192 static bool ls_cb(meshlink_handle_t *mesh, meshlink_ls_entry_cb_t entry_cb) {
193 fprintf(stderr, "ls_cb()");
194 DIR *dir = opendir(".");
197 while((ent = readdir(dir))) {
198 if(ent->d_name[0] != '.') {
199 entry_cb(mesh, ent->d_name, 0);
208 int main(int argc, char *argv[]) {
209 const char *confbase = ".chat";
210 const char *nick = NULL;
221 assert(mkdir(confbase, 0700) == 0);
222 assert(chdir(confbase) == 0);
224 meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_message);
225 meshlink_open_params_t *params = meshlink_open_params_init(confbase, nick, "chat", DEV_CLASS_STATIONARY);
226 //assert(meshlink_open_params_set_storage_key(params, "12345", 5));
227 assert(meshlink_open_params_set_storage_callbacks(params, load_cb, store_cb, ls_cb));
228 meshlink_handle_t *mesh = meshlink_open_ex(params);
229 meshlink_open_params_free(params);
232 fprintf(stderr, "Could not open MeshLink: %s\n", meshlink_strerror(meshlink_errno));
236 meshlink_set_receive_cb(mesh, receive);
237 meshlink_set_node_status_cb(mesh, node_status);
238 meshlink_set_log_cb(mesh, MESHLINK_INFO, log_message);
240 if(!meshlink_start(mesh)) {
241 fprintf(stderr, "Could not start MeshLink: %s\n", meshlink_strerror(meshlink_errno));
245 printf("Chat started.\nType /help for a list of commands.\n");
247 while(fgets(buf, sizeof(buf), stdin)) {
248 parse_input(mesh, buf);
251 printf("Chat stopping.\n");
254 meshlink_close(mesh);