1/* $Id$ */
2
3/***
4  This file is part of avahi.
5
6  avahi is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Lesser General Public License as
8  published by the Free Software Foundation; either version 2.1 of the
9  License, or (at your option) any later version.
10
11  avahi is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14  Public License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with avahi; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  USA.
20***/
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29
30#include <dbus/dbus.h>
31
32#include <avahi-client/client.h>
33#include <avahi-common/dbus.h>
34#include <avahi-common/llist.h>
35#include <avahi-common/error.h>
36#include <avahi-common/malloc.h>
37
38#include "client.h"
39#include "internal.h"
40
41void avahi_entry_group_set_state(AvahiEntryGroup *group, AvahiEntryGroupState state) {
42    assert(group);
43
44    if (group->state_valid && group->state == state)
45        return;
46
47    group->state = state;
48    group->state_valid = 1;
49
50    if (group->callback)
51        group->callback(group, state, group->userdata);
52}
53
54static int retrieve_state(AvahiEntryGroup *group) {
55    DBusMessage *message = NULL, *reply = NULL;
56    DBusError error;
57    int r = AVAHI_OK;
58    int32_t state;
59    AvahiClient *client;
60
61    dbus_error_init(&error);
62
63    assert(group);
64    client = group->client;
65
66    if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState"))) {
67        r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
68        goto fail;
69    }
70
71    if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
72        dbus_error_is_set (&error)) {
73        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
74        goto fail;
75    }
76
77    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID) ||
78        dbus_error_is_set (&error)) {
79        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
80        goto fail;
81    }
82
83    dbus_message_unref(message);
84    dbus_message_unref(reply);
85
86    return state;
87
88fail:
89    if (dbus_error_is_set(&error)) {
90        r = avahi_client_set_dbus_error(client, &error);
91        dbus_error_free(&error);
92    }
93
94    if (message)
95        dbus_message_unref(message);
96
97    if (reply)
98        dbus_message_unref(reply);
99
100    return r;
101}
102
103AvahiEntryGroup* avahi_entry_group_new (AvahiClient *client, AvahiEntryGroupCallback callback, void *userdata) {
104    AvahiEntryGroup *group = NULL;
105    DBusMessage *message = NULL, *reply = NULL;
106    DBusError error;
107    char *path;
108    int state;
109
110    assert(client);
111
112    dbus_error_init (&error);
113
114    if (!avahi_client_is_connected(client)) {
115        avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
116        goto fail;
117    }
118
119    if (!(group = avahi_new(AvahiEntryGroup, 1))) {
120        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
121        goto fail;
122    }
123
124    group->client = client;
125    group->callback = callback;
126    group->userdata = userdata;
127    group->state_valid = 0;
128    group->path = NULL;
129    AVAHI_LLIST_PREPEND(AvahiEntryGroup, groups, client->groups, group);
130
131    if (!(message = dbus_message_new_method_call(
132              AVAHI_DBUS_NAME,
133              AVAHI_DBUS_PATH_SERVER,
134              AVAHI_DBUS_INTERFACE_SERVER,
135              "EntryGroupNew"))) {
136        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
137        goto fail;
138    }
139
140    if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
141        dbus_error_is_set (&error)) {
142        avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
143        goto fail;
144    }
145
146    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
147        dbus_error_is_set (&error)) {
148        avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
149        goto fail;
150    }
151
152    if (!(group->path = avahi_strdup (path))) {
153
154        /* FIXME: We don't remove the object on the server side */
155
156        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
157        goto fail;
158    }
159
160    if ((state = retrieve_state(group)) < 0) {
161        avahi_client_set_errno(client, state);
162        goto fail;
163    }
164
165    avahi_entry_group_set_state(group, (AvahiEntryGroupState) state);
166
167    dbus_message_unref(message);
168    dbus_message_unref(reply);
169
170    return group;
171
172fail:
173    if (dbus_error_is_set(&error)) {
174        avahi_client_set_dbus_error(client, &error);
175        dbus_error_free(&error);
176    }
177
178    if (group)
179        avahi_entry_group_free(group);
180
181    if (message)
182        dbus_message_unref(message);
183
184    if (reply)
185        dbus_message_unref(reply);
186
187    return NULL;
188}
189
190static int entry_group_simple_method_call(AvahiEntryGroup *group, const char *method) {
191    DBusMessage *message = NULL, *reply = NULL;
192    DBusError error;
193    int r = AVAHI_OK;
194    AvahiClient *client;
195
196    dbus_error_init(&error);
197
198    assert(group);
199    client = group->client;
200
201    if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, method))) {
202        r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
203        goto fail;
204    }
205
206    if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
207        dbus_error_is_set (&error)) {
208        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
209        goto fail;
210    }
211
212    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
213        dbus_error_is_set (&error)) {
214        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
215        goto fail;
216    }
217
218    dbus_message_unref(message);
219    dbus_message_unref(reply);
220
221    return AVAHI_OK;
222
223fail:
224    if (dbus_error_is_set(&error)) {
225        r = avahi_client_set_dbus_error(client, &error);
226        dbus_error_free(&error);
227    }
228
229    if (message)
230        dbus_message_unref(message);
231
232    if (reply)
233        dbus_message_unref(reply);
234
235    return r;
236}
237
238int avahi_entry_group_free(AvahiEntryGroup *group) {
239    AvahiClient *client = group->client;
240    int r = AVAHI_OK;
241
242    assert(group);
243
244    if (group->path && avahi_client_is_connected(client))
245        r = entry_group_simple_method_call(group, "Free");
246
247    AVAHI_LLIST_REMOVE(AvahiEntryGroup, groups, client->groups, group);
248
249    avahi_free(group->path);
250    avahi_free(group);
251
252    return r;
253}
254
255int avahi_entry_group_commit(AvahiEntryGroup *group) {
256    int ret;
257    assert(group);
258
259    if (!group->path || !avahi_client_is_connected(group->client))
260        return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
261
262    if ((ret = entry_group_simple_method_call(group, "Commit")) < 0)
263        return ret;
264
265    group->state_valid = 0;
266    return ret;
267}
268
269int avahi_entry_group_reset(AvahiEntryGroup *group) {
270    int ret;
271    assert(group);
272
273    if (!group->path || !avahi_client_is_connected(group->client))
274        return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
275
276    if ((ret = entry_group_simple_method_call(group, "Reset")) < 0)
277        return ret;
278
279    group->state_valid = 0;
280    return ret;
281}
282
283int avahi_entry_group_get_state (AvahiEntryGroup *group) {
284    assert (group);
285
286    if (group->state_valid)
287        return group->state;
288
289    return retrieve_state(group);
290}
291
292AvahiClient* avahi_entry_group_get_client (AvahiEntryGroup *group) {
293    assert(group);
294
295    return group->client;
296}
297
298int avahi_entry_group_is_empty (AvahiEntryGroup *group) {
299    DBusMessage *message = NULL, *reply = NULL;
300    DBusError error;
301    int r = AVAHI_OK;
302    int b;
303    AvahiClient *client;
304
305    assert(group);
306    client = group->client;
307
308    if (!group->path || !avahi_client_is_connected(group->client))
309        return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
310
311    dbus_error_init(&error);
312
313    if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty"))) {
314        r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
315        goto fail;
316    }
317
318    if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
319        dbus_error_is_set (&error)) {
320        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
321        goto fail;
322    }
323
324    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID) ||
325        dbus_error_is_set (&error)) {
326        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
327        goto fail;
328    }
329
330    dbus_message_unref(message);
331    dbus_message_unref(reply);
332
333    return !!b;
334
335fail:
336    if (dbus_error_is_set(&error)) {
337        r = avahi_client_set_dbus_error(client, &error);
338        dbus_error_free(&error);
339    }
340
341    if (message)
342        dbus_message_unref(message);
343
344    if (reply)
345        dbus_message_unref(reply);
346
347    return r;
348}
349
350static int append_rdata(DBusMessage *message, const void *rdata, size_t size) {
351    DBusMessageIter iter, sub;
352
353    assert(message);
354
355    dbus_message_iter_init_append(message, &iter);
356
357    if (!(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &sub)) ||
358        !(dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &rdata, size)) ||
359        !(dbus_message_iter_close_container(&iter, &sub)))
360        return -1;
361
362    return 0;
363}
364
365static int append_string_list(DBusMessage *message, AvahiStringList *txt) {
366    DBusMessageIter iter, sub;
367    int r = -1;
368    AvahiStringList *p;
369
370    assert(message);
371
372    dbus_message_iter_init_append(message, &iter);
373
374    /* Reverse the string list, so that we can pass it in-order to the server */
375    txt = avahi_string_list_reverse(txt);
376
377    if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "ay", &sub))
378        goto fail;
379
380    /* Assemble the AvahiStringList into an Array of Array of Bytes to send over dbus */
381    for (p = txt; p != NULL; p = p->next) {
382        DBusMessageIter sub2;
383        const uint8_t *data = p->text;
384
385        if (!(dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2)) ||
386            !(dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size)) ||
387            !(dbus_message_iter_close_container(&sub, &sub2)))
388            goto fail;
389    }
390
391    if (!dbus_message_iter_close_container(&iter, &sub))
392        goto fail;
393
394    r = 0;
395
396fail:
397
398    /* Reverse the string list to the original state */
399    txt = avahi_string_list_reverse(txt);
400
401    return r;
402}
403
404int avahi_entry_group_add_service_strlst(
405    AvahiEntryGroup *group,
406    AvahiIfIndex interface,
407    AvahiProtocol protocol,
408    AvahiPublishFlags flags,
409    const char *name,
410    const char *type,
411    const char *domain,
412    const char *host,
413    uint16_t port,
414    AvahiStringList *txt) {
415
416    DBusMessage *message = NULL, *reply = NULL;
417    int r = AVAHI_OK;
418    DBusError error;
419    AvahiClient *client;
420    int32_t i_interface, i_protocol;
421    uint32_t u_flags;
422
423    assert(group);
424    assert(name);
425    assert(type);
426
427    client = group->client;
428
429    if (!group->path || !avahi_client_is_connected(group->client))
430        return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
431
432    if (!domain)
433        domain = "";
434
435    if (!host)
436        host = "";
437
438    dbus_error_init(&error);
439
440    if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService"))) {
441        r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
442        goto fail;
443    }
444
445    i_interface = (int32_t) interface;
446    i_protocol = (int32_t) protocol;
447    u_flags = (uint32_t) flags;
448
449    if (!dbus_message_append_args(
450            message,
451            DBUS_TYPE_INT32, &i_interface,
452            DBUS_TYPE_INT32, &i_protocol,
453            DBUS_TYPE_UINT32, &u_flags,
454            DBUS_TYPE_STRING, &name,
455            DBUS_TYPE_STRING, &type,
456            DBUS_TYPE_STRING, &domain,
457            DBUS_TYPE_STRING, &host,
458            DBUS_TYPE_UINT16, &port,
459            DBUS_TYPE_INVALID) ||
460        append_string_list(message, txt) < 0) {
461        r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
462        goto fail;
463    }
464
465    if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
466        dbus_error_is_set (&error)) {
467        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
468        goto fail;
469    }
470
471    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
472        dbus_error_is_set (&error)) {
473        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
474        goto fail;
475    }
476
477    dbus_message_unref(message);
478    dbus_message_unref(reply);
479
480    return AVAHI_OK;
481
482fail:
483
484    if (dbus_error_is_set(&error)) {
485        r = avahi_client_set_dbus_error(client, &error);
486        dbus_error_free(&error);
487    }
488
489    if (message)
490        dbus_message_unref(message);
491
492    if (reply)
493        dbus_message_unref(reply);
494
495    return r;
496}
497
498int avahi_entry_group_add_service(
499    AvahiEntryGroup *group,
500    AvahiIfIndex interface,
501    AvahiProtocol protocol,
502    AvahiPublishFlags flags,
503    const char *name,
504    const char *type,
505    const char *domain,
506    const char *host,
507    uint16_t port,
508    ...) {
509
510    va_list va;
511    int r;
512    AvahiStringList *txt;
513
514    assert(group);
515
516    va_start(va, port);
517    txt = avahi_string_list_new_va(va);
518    r = avahi_entry_group_add_service_strlst(group, interface, protocol, flags, name, type, domain, host, port, txt);
519    avahi_string_list_free(txt);
520    va_end(va);
521    return r;
522}
523
524int avahi_entry_group_add_service_subtype(
525    AvahiEntryGroup *group,
526    AvahiIfIndex interface,
527    AvahiProtocol protocol,
528    AvahiPublishFlags flags,
529    const char *name,
530    const char *type,
531    const char *domain,
532    const char *subtype) {
533
534    DBusMessage *message = NULL, *reply = NULL;
535    int r = AVAHI_OK;
536    DBusError error;
537    AvahiClient *client;
538    int32_t i_interface, i_protocol;
539    uint32_t u_flags;
540
541    assert(group);
542    assert(name);
543    assert(type);
544    assert(subtype);
545
546    client = group->client;
547
548    if (!group->path || !avahi_client_is_connected(group->client))
549        return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
550
551    if (!domain)
552        domain = "";
553
554    dbus_error_init(&error);
555
556    if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddServiceSubtype"))) {
557        r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
558        goto fail;
559    }
560
561    i_interface = (int32_t) interface;
562    i_protocol = (int32_t) protocol;
563    u_flags = (uint32_t) flags;
564
565    if (!dbus_message_append_args(
566            message,
567            DBUS_TYPE_INT32, &i_interface,
568            DBUS_TYPE_INT32, &i_protocol,
569            DBUS_TYPE_UINT32, &u_flags,
570            DBUS_TYPE_STRING, &name,
571            DBUS_TYPE_STRING, &type,
572            DBUS_TYPE_STRING, &domain,
573            DBUS_TYPE_STRING, &subtype,
574            DBUS_TYPE_INVALID)) {
575        r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
576        goto fail;
577    }
578
579    if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
580        dbus_error_is_set (&error)) {
581        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
582        goto fail;
583    }
584
585    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
586        dbus_error_is_set (&error)) {
587        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
588        goto fail;
589    }
590
591    dbus_message_unref(message);
592    dbus_message_unref(reply);
593
594    return AVAHI_OK;
595
596fail:
597
598    if (dbus_error_is_set(&error)) {
599        r = avahi_client_set_dbus_error(client, &error);
600        dbus_error_free(&error);
601    }
602
603    if (message)
604        dbus_message_unref(message);
605
606    if (reply)
607        dbus_message_unref(reply);
608
609    return r;
610
611}
612
613int avahi_entry_group_update_service_txt(
614    AvahiEntryGroup *group,
615    AvahiIfIndex interface,
616    AvahiProtocol protocol,
617    AvahiPublishFlags flags,
618    const char *name,
619    const char *type,
620    const char *domain,
621    ...) {
622
623    va_list va;
624    int r;
625    AvahiStringList *txt;
626
627    va_start(va, domain);
628    txt = avahi_string_list_new_va(va);
629    r = avahi_entry_group_update_service_txt_strlst(group, interface, protocol, flags, name, type, domain, txt);
630    avahi_string_list_free(txt);
631    va_end(va);
632    return r;
633}
634
635int avahi_entry_group_update_service_txt_strlst(
636    AvahiEntryGroup *group,
637    AvahiIfIndex interface,
638    AvahiProtocol protocol,
639    AvahiPublishFlags flags,
640    const char *name,
641    const char *type,
642    const char *domain,
643    AvahiStringList *txt) {
644
645    DBusMessage *message = NULL, *reply = NULL;
646    int r = AVAHI_OK;
647    DBusError error;
648    AvahiClient *client;
649    int32_t i_interface, i_protocol;
650    uint32_t u_flags;
651
652    assert(group);
653    assert(name);
654    assert(type);
655
656    client = group->client;
657
658    if (!group->path || !avahi_client_is_connected(group->client))
659        return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
660
661    if (!domain)
662        domain = "";
663
664    dbus_error_init(&error);
665
666    if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "UpdateServiceTxt"))) {
667        r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
668        goto fail;
669    }
670
671    i_interface = (int32_t) interface;
672    i_protocol = (int32_t) protocol;
673    u_flags = (uint32_t) flags;
674
675    if (!dbus_message_append_args(
676            message,
677            DBUS_TYPE_INT32, &i_interface,
678            DBUS_TYPE_INT32, &i_protocol,
679            DBUS_TYPE_UINT32, &u_flags,
680            DBUS_TYPE_STRING, &name,
681            DBUS_TYPE_STRING, &type,
682            DBUS_TYPE_STRING, &domain,
683            DBUS_TYPE_INVALID) ||
684        append_string_list(message, txt) < 0) {
685        r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
686        goto fail;
687    }
688
689    if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
690        dbus_error_is_set (&error)) {
691        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
692        goto fail;
693    }
694
695    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
696        dbus_error_is_set (&error)) {
697        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
698        goto fail;
699    }
700
701    dbus_message_unref(message);
702    dbus_message_unref(reply);
703
704    return AVAHI_OK;
705
706fail:
707
708    if (dbus_error_is_set(&error)) {
709        r = avahi_client_set_dbus_error(client, &error);
710        dbus_error_free(&error);
711    }
712
713    if (message)
714        dbus_message_unref(message);
715
716    if (reply)
717        dbus_message_unref(reply);
718
719    return r;
720}
721
722/** Add a host/address pair */
723int avahi_entry_group_add_address(
724    AvahiEntryGroup *group,
725    AvahiIfIndex interface,
726    AvahiProtocol protocol,
727    AvahiPublishFlags flags,
728    const char *name,
729    const AvahiAddress *a) {
730
731    DBusMessage *message = NULL, *reply = NULL;
732    int r = AVAHI_OK;
733    DBusError error;
734    AvahiClient *client;
735    int32_t i_interface, i_protocol;
736    uint32_t u_flags;
737    char s_address[AVAHI_ADDRESS_STR_MAX];
738    char *p_address = s_address;
739
740    assert(name);
741
742    client = group->client;
743
744    if (!group->path || !avahi_client_is_connected(group->client))
745        return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
746
747    dbus_error_init(&error);
748
749    if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress"))) {
750        r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
751        goto fail;
752    }
753
754    i_interface = (int32_t) interface;
755    i_protocol = (int32_t) protocol;
756    u_flags = (uint32_t) flags;
757
758    if (!avahi_address_snprint (s_address, sizeof (s_address), a))
759    {
760        r = avahi_client_set_errno(client, AVAHI_ERR_INVALID_ADDRESS);
761        goto fail;
762    }
763
764    if (!dbus_message_append_args(
765            message,
766            DBUS_TYPE_INT32, &i_interface,
767            DBUS_TYPE_INT32, &i_protocol,
768            DBUS_TYPE_UINT32, &u_flags,
769            DBUS_TYPE_STRING, &name,
770            DBUS_TYPE_STRING, &p_address,
771            DBUS_TYPE_INVALID)) {
772        r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
773        goto fail;
774    }
775
776    if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
777        dbus_error_is_set (&error)) {
778        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
779        goto fail;
780    }
781
782    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
783        dbus_error_is_set (&error)) {
784        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
785        goto fail;
786    }
787
788    dbus_message_unref(message);
789    dbus_message_unref(reply);
790
791    return AVAHI_OK;
792
793fail:
794
795    if (dbus_error_is_set(&error)) {
796        r = avahi_client_set_dbus_error(client, &error);
797        dbus_error_free(&error);
798    }
799
800    if (message)
801        dbus_message_unref(message);
802
803    if (reply)
804        dbus_message_unref(reply);
805
806    return r;
807}
808
809/** Add an arbitrary record */
810int avahi_entry_group_add_record(
811    AvahiEntryGroup *group,
812    AvahiIfIndex interface,
813    AvahiProtocol protocol,
814    AvahiPublishFlags flags,
815    const char *name,
816    uint16_t clazz,
817    uint16_t type,
818    uint32_t ttl,
819    const void *rdata,
820    size_t size) {
821
822    DBusMessage *message = NULL, *reply = NULL;
823    int r = AVAHI_OK;
824    DBusError error;
825    AvahiClient *client;
826    int32_t i_interface, i_protocol;
827    uint32_t u_flags;
828
829    assert(name);
830
831    client = group->client;
832
833    if (!group->path || !avahi_client_is_connected(group->client))
834        return avahi_client_set_errno(group->client, AVAHI_ERR_BAD_STATE);
835
836    dbus_error_init(&error);
837
838    if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, group->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddRecord"))) {
839        r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
840        goto fail;
841    }
842
843    i_interface = (int32_t) interface;
844    i_protocol = (int32_t) protocol;
845    u_flags = (uint32_t) flags;
846
847    if (!dbus_message_append_args(
848            message,
849            DBUS_TYPE_INT32, &i_interface,
850            DBUS_TYPE_INT32, &i_protocol,
851            DBUS_TYPE_UINT32, &u_flags,
852            DBUS_TYPE_STRING, &name,
853            DBUS_TYPE_UINT16, &clazz,
854            DBUS_TYPE_UINT16, &type,
855            DBUS_TYPE_UINT32, &ttl,
856            DBUS_TYPE_INVALID) || append_rdata(message, rdata, size) < 0) {
857        r = avahi_client_set_errno(group->client, AVAHI_ERR_NO_MEMORY);
858        goto fail;
859    }
860
861    if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
862        dbus_error_is_set (&error)) {
863        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
864        goto fail;
865    }
866
867    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
868        dbus_error_is_set (&error)) {
869        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
870        goto fail;
871    }
872
873    dbus_message_unref(message);
874    dbus_message_unref(reply);
875
876    return AVAHI_OK;
877
878fail:
879
880    if (dbus_error_is_set(&error)) {
881        r = avahi_client_set_dbus_error(client, &error);
882        dbus_error_free(&error);
883    }
884
885    if (message)
886        dbus_message_unref(message);
887
888    if (reply)
889        dbus_message_unref(reply);
890
891    return r;
892}
893