mqtt.c 16.9 KB
Newer Older
alexandre burton's avatar
alexandre burton committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include "/usr/local/include/mosquitto.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "ext.h"
#include "ext_obex.h"

typedef struct _mqtt {
    t_object p_ob;
    void *p_status_outlet;
    void *p_main_outlet;
    
    struct mosquitto *mosq;     // instance of mosquitto client
alexandre burton's avatar
alexandre burton committed
16
    
alexandre burton's avatar
alexandre burton committed
17
18
    int a_state;                // MQTT connection state
    
alexandre burton's avatar
alexandre burton committed
19
20
21
22
    long a_port;               // MQTT Broker port
    char a_clean;              // Clean session
    char a_verbose;            // verbose chatter in Max windows
    char a_autoconnect;        // auto-connect on object instanciation
alexandre burton's avatar
alexandre burton committed
23
    t_symbol *a_user;           // MQTT username
alexandre burton's avatar
alexandre burton committed
24
25
    t_symbol *a_host;           // MQTT host
    t_symbol *a_password;;      // MQTT password
alexandre burton's avatar
alexandre burton committed
26
    t_symbol *a_id;             // Client ID
27
    
alexandre burton's avatar
alexandre burton committed
28
29
    char payload[1000];           // reusable memory for received payload

alexandre burton's avatar
alexandre burton committed
30
31
32
33
34
35
36
37
38
39
40
41
} t_mqtt;

#define MQTT_DEFAULT_PORT 1883
static long MOSQUITTO_CLIENT_ID = 0;

// download & compile static mosquitto lib (did not fight TLS/https; disabled in cmake)
// /usr/bin/codesign --force --sign 0EFF62FA1517300CC579B619A634293E5A5E7193 --timestamp=none/usr/bin/codesign --force --sign 0EFF62FA1517300CC579B619A634293E5A5E7193 --timestamp=none /Users/brtn/Downloads/max-sdk-8.0.3/externals/mqtt.mxo/Contents/Frameworks/libmosquitto_static.a
// add to max project

void mqtt_change_state(t_mqtt *x, int state) {
    switch (state) {
        case 1:
42
            if (x->a_verbose) object_post((t_object *)x,"<%s> connection up",x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
43
44
45
            x->a_state =1;
            break;
        default:
46
            if (x->a_verbose) object_warn((t_object *)x,"<%s> connecction down",x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
47
48
49
50
51
            x->a_state =0;
    }
    outlet_int(x->p_status_outlet, x->a_state);
}

52
void mosquitto_publish_callback(struct mosquitto *mosq, void *obj, int mid)
alexandre burton's avatar
alexandre burton committed
53
54
{
    t_mqtt * x = obj;
55
    if (x->a_verbose) object_post((t_object *)x,"<%s> published topic id#%05i",x->a_id->s_name,mid);
alexandre burton's avatar
alexandre burton committed
56
57
}

58
void mosquitto_connect_callback(struct mosquitto *mosq, void *obj, int result)
alexandre burton's avatar
alexandre burton committed
59
60
61
62
63
64
65
{
    t_mqtt * x = obj;
    switch (result) {
        case 0:
            mqtt_change_state(x, 1);
            break;
        default:
66
            object_warn((t_object *)x,"<%s> Connection Refused, [%s]", x->a_id->s_name, mosquitto_reason_string(result));
alexandre burton's avatar
alexandre burton committed
67
68
69
70
71
            mqtt_change_state(x, 0);
            mosquitto_disconnect(mosq);
    }
}

72
void mosquitto_disconnect_callback(struct mosquitto *mosq, void *obj, int result)
alexandre burton's avatar
alexandre burton committed
73
74
75
{
    t_mqtt * x = obj;
    if (result ==0) {
76
        if (x->a_verbose) object_post((t_object *)x,"<%s> disconnected as requested",x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
77
    } else {
78
        object_warn((t_object *)x,"<%s> unexpectedly disconnected from broker",x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
79
80
81
82
    }
    mqtt_change_state(x, 0);
}

83
void mosquitto_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
alexandre burton's avatar
alexandre burton committed
84
85
86
{
    t_mqtt * x = obj;
    t_atom a[1];
87
88
    
    // asssumes something that fits in a max symbol -- should check for cues or magic numbers and generates json dicts, jitter matrices, or vectors of audio
alexandre burton's avatar
alexandre burton committed
89
90
91
92
    atom_setsym(a+0, gensym((char*) message->payload));
    outlet_anything(x->p_main_outlet, gensym(message->topic), 1,a);
}

alexandre burton's avatar
alexandre burton committed
93
// methods
94
void mqtt_assist_method(t_mqtt *x, void *b, long m, long a, char *s);
alexandre burton's avatar
alexandre burton committed
95
96
97
98
99
100
void mqtt_subscribe_method(t_mqtt *x, t_symbol *topic);
void mqtt_unsubscribe_method(t_mqtt *x, t_symbol *topic);
void mqtt_publish_method(t_mqtt *x, t_symbol *s, long argc, t_atom *argv);
void mqtt_connect_method(t_mqtt *x, t_symbol *s, long argc, t_atom *argv);
void mqtt_loop_method(t_mqtt *x);

alexandre burton's avatar
alexandre burton committed
101
102
// attribute setters
void mqtt_set_clean(t_mqtt *x, void *attr, long argc, t_atom *argv);
alexandre burton's avatar
alexandre burton committed
103
void mqtt_set_id(t_mqtt *x, void *attr, long argc, t_atom *argv);
alexandre burton's avatar
alexandre burton committed
104
105
106
107
108
void mqtt_set_user(t_mqtt *x, void *attr, long argc, t_atom *argv);
void mqtt_set_port(t_mqtt *x, void *attr, long argc, t_atom *argv);
void mqtt_set_password(t_mqtt *x, void *attr, long argc, t_atom *argv);
void mqtt_set_host(t_mqtt *x, void *attr, long argc, t_atom *argv);
void mqtt_set_autoconnect(t_mqtt *x, void *attr, long argc, t_atom *argv);
alexandre burton's avatar
alexandre burton committed
109

110
// lifecycle
alexandre burton's avatar
alexandre burton committed
111
void *mqtt_new(t_symbol *s, long argc, t_atom *argv);
112
113
void mqtt_free(t_mqtt *x);
void mosquitto_free_client(t_mqtt *x);
alexandre burton's avatar
alexandre burton committed
114

115
void actually_connect(t_mqtt *x);
alexandre burton's avatar
alexandre burton committed
116
117
118
119
120
121
122
123
124

t_class *mqtt_class;

void ext_main(void *r)
{
    t_class *c;
    
    c = class_new("mqtt", (method)mqtt_new, (method)mqtt_free, sizeof(t_mqtt), 0L, A_GIMME, 0);
    
125
126
//    class_addmethod(c, (method)mqtt_loop_method,        "bang",       0);
    class_addmethod(c, (method)mqtt_assist_method,      "assist",     A_CANT, 0);
alexandre burton's avatar
alexandre burton committed
127
128
129
130
131
    class_addmethod(c, (method)mqtt_subscribe_method,   "subscribe",  A_DEFSYM, 0);
    class_addmethod(c, (method)mqtt_unsubscribe_method, "unsubscribe",A_DEFSYM, 0);
    class_addmethod(c, (method)mqtt_publish_method,     "publish",    A_GIMME, 0);
    class_addmethod(c, (method)mqtt_connect_method,     "connect",    A_GIMME, 0);
    
alexandre burton's avatar
alexandre burton committed
132
133
134
    CLASS_ATTR_SYM(c,         "id",           0, t_mqtt, a_id);
    CLASS_ATTR_ACCESSORS(c,   "id",           NULL, mqtt_set_id);
    
135
    CLASS_ATTR_CHAR(c,        "clean",        0, t_mqtt, a_clean);
alexandre burton's avatar
alexandre burton committed
136
137
138
139
140
    CLASS_ATTR_STYLE_LABEL(c, "clean",        0, "onoff", "Clean Session");
    CLASS_ATTR_ACCESSORS(c,   "clean",        NULL, mqtt_set_clean);
    
    CLASS_ATTR_CHAR(c,        "verbose",      0, t_mqtt, a_verbose);
    CLASS_ATTR_STYLE_LABEL(c, "verbose",      0, "onoff", "Verbose");
141
    
alexandre burton's avatar
alexandre burton committed
142
143
144
    CLASS_ATTR_CHAR(c,        "autoconnect",  0, t_mqtt, a_autoconnect);
    CLASS_ATTR_STYLE_LABEL(c, "autoconnect",  0, "onoff", "Auto-connect");
    CLASS_ATTR_ACCESSORS(c,   "autoconnect",  NULL, mqtt_set_autoconnect);
145
    
alexandre burton's avatar
alexandre burton committed
146
147
    CLASS_ATTR_SYM(c,         "user",         0, t_mqtt, a_user);
    CLASS_ATTR_ACCESSORS(c,   "user",         NULL, mqtt_set_user);
alexandre burton's avatar
alexandre burton committed
148
    
alexandre burton's avatar
alexandre burton committed
149
150
151
152
153
154
155
156
    CLASS_ATTR_SYM(c,         "password",     0, t_mqtt, a_password);
    CLASS_ATTR_ACCESSORS(c,   "password",     NULL, mqtt_set_password);
    
    CLASS_ATTR_SYM(c,         "host",         0, t_mqtt, a_host);
    CLASS_ATTR_ACCESSORS(c,   "host",         NULL, mqtt_set_host);
    
    CLASS_ATTR_LONG(c,        "port",         0, t_mqtt, a_port);
    CLASS_ATTR_ACCESSORS(c,   "port",         NULL, mqtt_set_port);
157
    
alexandre burton's avatar
alexandre burton committed
158
159
160
161
    class_register(CLASS_BOX, c);
    mqtt_class = c;
    
    post("MQTT Client for Max ©2021 https://gitlab.artificiel.org/max/mqtt",0);
162
163
    
    int res = mosquitto_lib_init();
alexandre burton's avatar
alexandre burton committed
164
    if (res==MOSQ_ERR_SUCCESS) {
165
166
        int x,y,z;
        mosquitto_lib_version(&x,&y,&z);
alexandre burton's avatar
alexandre burton committed
167
        post("Mosquitto MQTT Library %i.%i.%i initialized.",x ,y ,z);
alexandre burton's avatar
alexandre burton committed
168
    } else {
169
        error("Mosquitto MQTT Library did not correctly initialize!",0);
alexandre burton's avatar
alexandre burton committed
170
171
172
173
174
175
176
177
178
179
180
181
182
    }
}

void mqtt_set_id(t_mqtt *x, void *attr, long argc, t_atom *argv)
{
    if (atom_getsym(argv)->s_name != x->a_id->s_name) {
        x->a_id = atom_getsym(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with id %s", x->a_id->s_name);
        }
    }
}

alexandre burton's avatar
alexandre burton committed
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
void mqtt_set_user(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getsym(argv)->s_name != x->a_user->s_name) {
        x->a_user = atom_getsym(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with user %s", x->a_user->s_name);
        }
    }
}

void mqtt_set_port(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getlong(argv) != x->a_port) {
        x->a_port = atom_getlong(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with port %i", x->a_port);
        }
    }
}

void mqtt_set_password(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getsym(argv)->s_name != x->a_password->s_name) {
        x->a_password = atom_getsym(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with passwoord %s", x->a_password->s_name);
        }
    }
}

void mqtt_set_host(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getsym(argv)->s_name != x->a_host->s_name) {
        x->a_host = atom_getsym(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with host %s", x->a_host->s_name);
        }
    }
}

void mqtt_set_autoconnect(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    x->a_autoconnect = atom_getlong(argv);
    if (x->a_state == 0 && x->a_autoconnect == 1) {
        post("TO IMPLEMENT: should connect when autoconnect is turned on",0);
    }
}

void mqtt_set_clean(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getlong(argv) != x->a_clean) {
        x->a_clean = atom_getlong(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with cleaniness %i", x->a_clean);
        }
    }
}

alexandre burton's avatar
alexandre burton committed
235
void mqtt_connect_method(t_mqtt *x, t_symbol *s, long argc, t_atom *argv) {
alexandre burton's avatar
alexandre burton committed
236
    if ((argc < 0 && argc > 4) || argc ==3) {
237
         object_error((t_object *)x,"connect requires 0, 1, 2 or 4 arguments: (host (port (username password)))");
alexandre burton's avatar
alexandre burton committed
238
    } else {
alexandre burton's avatar
alexandre burton committed
239
        if (argv>0) {
alexandre burton's avatar
alexandre burton committed
240
            
alexandre burton's avatar
alexandre burton committed
241
242
243
            if (argv[0].a_type==A_SYM) {
                
                //mosquitto_reinitialise(x->mosq, x->clientid, false, x);
alexandre burton's avatar
alexandre burton committed
244
                
alexandre burton's avatar
alexandre burton committed
245
246
247
248
249
250
251
252
253
                //                char host[100];
                //                int port = MQTT_DEFAULT_PORT;
                //                sprintf(host, "%s", argv[0].a_w.w_sym->s_name);
                //
                x->a_host = argv[0].a_w.w_sym;
                
                if (argc > 1) {
                    if (argv[1].a_type==A_LONG) {
                        x->a_port = argv[1].a_w.w_long;
alexandre burton's avatar
alexandre burton committed
254
                    } else {
255
                        object_error((t_object *)x,"connect port (arg#2) must be int -- using %i", x->a_port);
alexandre burton's avatar
alexandre burton committed
256
257
258
259
260
261
262
                    }
                    
                    if (argc ==4) {
                        if (argv[2].a_type==A_SYM && argv[3].a_type==A_SYM) {
                            x->a_password = gensym(argv[3].a_w.w_sym->s_name);
                            x->a_user = argv[2].a_w.w_sym;
                        } else {
263
                            object_error((t_object *)x,"connect username & password (arg#2-3) must be symbols");
alexandre burton's avatar
alexandre burton committed
264
                        }
alexandre burton's avatar
alexandre burton committed
265
266
267
                    }
                }
            }
alexandre burton's avatar
alexandre burton committed
268
        }
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
        actually_connect(x);
    }
}

void actually_connect(t_mqtt *x) {

    if (strlen(x->a_host->s_name)) {
        
        if (x->mosq != NULL) {
            mosquitto_free_client(x);
        }
        
        x->mosq = mosquitto_new(x->a_id->s_name, false, x); // pass this object into mosquitto for callbacks
        if (x->a_verbose) object_post((t_object *)x,"instance for cliend id <%s> created",x->a_id->s_name);
        
        mosquitto_disconnect_callback_set(x->mosq, mosquitto_disconnect_callback);
        mosquitto_connect_callback_set(x->mosq, mosquitto_connect_callback);
        mosquitto_message_callback_set(x->mosq, mosquitto_message_callback);
        mosquitto_publish_callback_set(x->mosq, mosquitto_publish_callback);
        mosquitto_user_data_set(x->mosq, x);
        
        if (strlen(x->a_user->s_name) && strlen(x->a_password->s_name)) {
            mosquitto_username_pw_set(x->mosq, x->a_user->s_name, x->a_password->s_name);
            if (x->a_verbose) object_post((t_object *)x,"<%s> attempting connection to %s:%s@%s:%i",
                                          x->a_id->s_name, x->a_user->s_name, x->a_password->s_name, x->a_host->s_name, x->a_port);
alexandre burton's avatar
alexandre burton committed
294
        } else {
295
296
            if (x->a_verbose) object_post((t_object *)x,"<%s> attempting connection to %s:%i",
                                          x->a_id->s_name, x->a_host->s_name, x->a_port);
alexandre burton's avatar
alexandre burton committed
297
        }
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
        
        
        int res= mosquitto_connect(x->mosq, x->a_host->s_name, x->a_port, 60);
        
        int rloop;
        switch (res) {
            case MOSQ_ERR_SUCCESS:
                rloop = mosquitto_loop_start(x->mosq);
                switch (rloop) {
                    case MOSQ_ERR_SUCCESS:
                        if (x->a_verbose) object_post((t_object *)x,"<%s> started event thread",x->a_id->s_name);
                        break;
                    default:
                        object_error((t_object *)x,"<%s> could not start thread [%02i]:%s", x->a_id->s_name, rloop, mosquitto_reason_string(rloop));
                }
                break;
            default:
                object_error((t_object *)x,"<%s> could not connect [%02i]:%s", x->a_id->s_name, res,mosquitto_reason_string(res));
        }
    } else {
        object_error((t_object *)x,"need to set host prior to connect");
alexandre burton's avatar
alexandre burton committed
319
320
321
    }
}

322
323
324
325

//void mqtt_loop_method(t_mqtt * x) {
    //int res = mosquitto_loop(x->mosq, -1, 1);
//}
alexandre burton's avatar
alexandre burton committed
326
327
328
329
330
331
332
333

void mqtt_publish_method(t_mqtt *x, t_symbol *s, long argc, t_atom *argv) {
    t_symbol topic;
    
    long qos = 0;
    bool retain = false;
    
    if (argc < 2 || argc > 4) {
334
         object_error((t_object *)x,"publish requires 2, 3 or 4 arguments: topic payload (qos (retain))");
alexandre burton's avatar
alexandre burton committed
335
336
337
338
339
    } else {
        if (argv[0].a_type==A_SYM) {
            topic = *argv[0].a_w.w_sym;
            
            if (argv[1].a_type==A_LONG) {
alexandre burton's avatar
alexandre burton committed
340
                sprintf(x->payload, "%lli", argv[1].a_w.w_long);
alexandre burton's avatar
alexandre burton committed
341
            } else if (argv[1].a_type==A_FLOAT) {
alexandre burton's avatar
alexandre burton committed
342
                sprintf(x->payload, "%f", argv[1].a_w.w_float);
alexandre burton's avatar
alexandre burton committed
343
            } else if (argv[1].a_type==A_SYM) {
alexandre burton's avatar
alexandre burton committed
344
                sprintf(x->payload, "%s", argv[1].a_w.w_sym->s_name);
alexandre burton's avatar
alexandre burton committed
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
            }
            
            if (argc>2) {
                if (argv[2].a_type==A_LONG) {
                    long q = argv[2].a_w.w_long;
                    if (q <0) q = 0;
                    if (q > 2) q = 2;
                    qos = q;
                }
                if (argc==4) {
                    if (argv[4].a_type==A_LONG) {
                        long q = argv[2].a_w.w_long;
                        if (q <0) q = 0;
                        if (q > 1) q = 1;
                        retain = q;
                    }
                }
            }
            
alexandre burton's avatar
alexandre burton committed
364
            int res = mosquitto_publish(x->mosq, NULL, topic.s_name, strlen(x->payload), x->payload, qos,  retain);
alexandre burton's avatar
alexandre burton committed
365
366
            switch (res) {
                case MOSQ_ERR_SUCCESS: /* silent success */
367
                    if (x->a_verbose) object_post((t_object *)x,"<%s> published %s with %s",x->a_id->s_name, topic.s_name, x->payload);
alexandre burton's avatar
alexandre burton committed
368
369
                    break;
                default:
370
                     object_error((t_object *)x,"<%s> can't publish %s [%s]", x->a_id->s_name, topic, mosquitto_reason_string(res));
alexandre burton's avatar
alexandre burton committed
371
372
            }
        } else {
373
             object_error((t_object *)x,"publish topic (arg#1) must be string");
alexandre burton's avatar
alexandre burton committed
374
375
376
377
378
379
380
381
        }
    }
}

void mqtt_subscribe_method(t_mqtt *x, t_symbol * topic) {
    int sres = mosquitto_subscribe(x->mosq, NULL, topic->s_name, 0);
    switch (sres) {
        case MOSQ_ERR_SUCCESS:
382
            if (x->a_verbose) object_post((t_object *)x,"<%s> susbscribed %s", x->a_id->s_name, topic->s_name);
alexandre burton's avatar
alexandre burton committed
383
384
            break;
        default:
385
            object_error((t_object *)x,"subscribe <%s> failed [%02i: %s]", x->a_id->s_name, sres, mosquitto_reason_string(sres));
alexandre burton's avatar
alexandre burton committed
386
387
388
389
390
391
392
    }
}

void mqtt_unsubscribe_method(t_mqtt *x, t_symbol * topic) {
    int sres = mosquitto_unsubscribe(x->mosq, NULL, topic->s_name);
    switch (sres) {
        case MOSQ_ERR_SUCCESS:
393
            if (x->a_verbose) object_post((t_object *)x,"<%s> unsusbscribed %s", x->a_id->s_name, topic->s_name);
alexandre burton's avatar
alexandre burton committed
394
395
            break;
        default:
396
             object_error((t_object *)x,"unsubscribe <%s> failed [%s]]", x->a_id->s_name, mosquitto_reason_string(sres));
alexandre burton's avatar
alexandre burton committed
397
398
399
    }
}

alexandre burton's avatar
alexandre burton committed
400
void *mqtt_new(t_symbol *s, long argc, t_atom *argv)
alexandre burton's avatar
alexandre burton committed
401
402
403
{
    t_mqtt *x;
    x = (t_mqtt *)object_alloc(mqtt_class);
404
    
alexandre burton's avatar
alexandre burton committed
405
406
407
408
    char hostname[100];
    char random_id[100];
    hostname[99] = '\0';
    gethostname(hostname, 1023);
alexandre burton's avatar
alexandre burton committed
409
410
    snprintf(random_id, 99, "%s-%03ld", hostname, MOSQUITTO_CLIENT_ID++);
    
411

alexandre burton's avatar
alexandre burton committed
412
413
    x->a_id = gensym(random_id);
    x->a_verbose = 0;
alexandre burton's avatar
alexandre burton committed
414
415
416
417
418
419
420
    x->a_clean = 0;
    x->a_autoconnect = 0;
    x->a_port = 1883;
    x->a_host = gensym("");
    x->a_user = gensym("");
    x->a_password = gensym("");
    
alexandre burton's avatar
alexandre burton committed
421
    attr_args_process(x, argc, argv);
422
    
alexandre burton's avatar
alexandre burton committed
423
424
    x->p_status_outlet  = outlet_new(x, NULL);
    x->p_main_outlet = outlet_new(x, NULL);
425
    
426
427
428
429
    if  (x->a_autoconnect) {
        actually_connect(x);
    }
    
alexandre burton's avatar
alexandre burton committed
430
431
432
    return(x);
}

433
void mqtt_assist_method(t_mqtt *x, void *b, long m, long a, char *s) // 4 final arguments are always the same for the assistance method
alexandre burton's avatar
alexandre burton committed
434
435
{
    if (m == ASSIST_OUTLET)
alexandre burton's avatar
alexandre burton committed
436
437
438
439
440
441
442
443
        switch (a) {
            case 0:
                sprintf(s,"topic and payload (2 symbols list)");
                break;
            case 1:
                sprintf(s,"connection status (0 or 1)");
                break;
        }
alexandre burton's avatar
alexandre burton committed
444
445
446
    else {
        switch (a) {
            case 0:
alexandre burton's avatar
alexandre burton committed
447
                sprintf(s,"all messages go here");
alexandre burton's avatar
alexandre burton committed
448
449
450
451
452
453
454
                break;
            case 1:
                sprintf(s,"Inlet %ld: Right Operand (Added to Left)", a);
                break;
        }
    }
}
455
456
457
458
459
460
461
462
463
464
465
466

void mosquitto_free_client(t_mqtt *x) {
    if (x->a_verbose) object_post((t_object *)x,"freeing underlying client <%s>", x->a_id->s_name);
    mosquitto_disconnect(x->mosq);
    mosquitto_loop_stop(x->mosq, true);
    mosquitto_destroy(x->mosq);
}

void mqtt_free(t_mqtt *x)
{
    mosquitto_free_client(x);
}