2010-07-27 17:04:11

by Marcel Mol

[permalink] [raw]
Subject: [PATCH] IrMC sync server support

A reasonable working IrMC SYNC server (only full phonebook sync support)
Support for cal and note by just returning nothing.
---
Makefile.am | 3 +
plugins/irmc.c | 488 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/main.c | 12 ++-
src/obex.h | 1 +
4 files changed, 502 insertions(+), 2 deletions(-)
create mode 100644 plugins/irmc.c

diff --git a/Makefile.am b/Makefile.am
index 73e2f28..ce8c675 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -58,6 +58,9 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
builtin_modules += syncevolution
builtin_sources += plugins/syncevolution.c

+builtin_modules += irmc
+builtin_sources += plugins/irmc.c plugins/phonebook.h
+
builtin_nodist += plugins/phonebook.c

libexec_PROGRAMS += src/obexd
diff --git a/plugins/irmc.c b/plugins/irmc.c
new file mode 100644
index 0000000..96fd807
--- /dev/null
+++ b/plugins/irmc.c
@@ -0,0 +1,488 @@
+/*
+ *
+ * OBEX IrMC Sync Server
+ *
+ * Copyright (C) 2010 Marcel Mol <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <openobex/obex.h>
+#include <openobex/obex_const.h>
+
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "service.h"
+#include "phonebook.h"
+#include "mimetype.h"
+#include "filesystem.h"
+#include "dbus.h"
+
+#define IRMC_CHANNEL 17
+
+#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
+<record> \
+ <attribute id=\"0x0001\"> \
+ <sequence> \
+ <uuid value=\"0x1104\"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0004\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x0100\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0003\"/> \
+ <uint8 value=\"%u\" name=\"channel\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0008\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0009\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x1104\"/> \
+ <uint16 value=\"0x0100\" name=\"version\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0100\"> \
+ <text value=\"%s\" name=\"name\"/> \
+ </attribute> \
+ \
+ <attribute id=\"0x0301\"> \
+ <sequence> \
+ <uint8 value=\"0x01\"/> \
+ </sequence> \
+ </attribute> \
+</record>"
+
+
+struct aparam_header {
+ uint8_t tag;
+ uint8_t len;
+ uint8_t val[0];
+} __attribute__ ((packed));
+
+#define DIDLEN 18
+struct irmc_session {
+ struct obex_session *os;
+ struct apparam_field *params;
+ uint16_t entries;
+ GString *buffer;
+ char sn[DIDLEN];
+ char did[DIDLEN];
+ char manu[DIDLEN];
+ char model[DIDLEN];
+};
+
+#define IRMC_TARGET_SIZE 9
+
+static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
+ 0x49, 0x52, 0x4d, 0x43, 0x2d, 0x53, 0x59, 0x4e, 0x43 };
+
+static void phonebook_size_result(const char *buffer, size_t bufsize,
+ int vcards, int missed, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+
+ DBG("vcards %d", vcards);
+
+ irmc->params->maxlistcount = vcards;
+}
+
+static void query_result(const char *buffer, size_t bufsize, int vcards,
+ int missed, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+ const char *s;
+ char *t;
+
+ DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
+
+ // first create an empty 'owner' vcard
+ t = "BEGIN:VCARD\r\n"
+ "VERSION:2.1\r\n"
+ "N:\r\n"
+ "TEL:\r\n"
+ "X-IRMX-LUID:0\r\n"
+ "END:VCARDi\r\n";
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new_len(t, strlen(t));
+ else
+ irmc->buffer = g_string_append_len(irmc->buffer, t, strlen(t));
+
+ // loop around buffer and add X-IRMC-LUID attribs
+ s = buffer;
+ while ((t = strstr(s, "UID:")) != NULL) {
+ // add upto UID: into buffer
+ irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+ // add UID: line into buffer
+ // Not sure if UID is still needed if X-IRMC-LUID is there
+ s = t;
+ t = strstr(s, "\r\n");
+ t += 2;
+ irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+ // add X-IRMC-LUID with same number as UID
+ irmc->buffer = g_string_append_len(irmc->buffer,
+ "X-IRMC-LUID:", 12);
+ s += 4; // point to uid number
+ irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+ s = t;
+ }
+ // add remaining bit of buffer
+ irmc->buffer = g_string_append_len(irmc->buffer, s,
+ bufsize - (s-buffer));
+
+ obex_object_set_io_flags(irmc, G_IO_IN, 0);
+}
+
+static void *irmc_connect(struct obex_session *os, int *err)
+{
+ struct irmc_session *irmc;
+ struct apparam_field *param;
+
+ DBG("");
+
+ manager_register_session(os);
+
+ irmc = g_new0(struct irmc_session, 1);
+ irmc->os = os;
+
+ /*
+ * ideally get capabilities info here and use that to define
+ * IrMC DID and SN etc parameters.
+ * For now lets used hostname and some 'random' value
+ */
+ gethostname(irmc->did, DIDLEN);
+ strncpy(irmc->sn, "12345", DIDLEN);
+ strncpy(irmc->manu, "obex", DIDLEN);
+ strncpy(irmc->model, "mymodel", DIDLEN);
+
+ /*
+ * we need to know the number of contact/cal/nt entries
+ * somewhere so why not do it now.
+ */
+ param = g_new0(struct apparam_field, 1);
+ param->maxlistcount = 0; // to count the number of vcards...
+ param->filter = 0x200085; // UID TEL N VERSION
+ irmc->params = param;
+ phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
+ irmc);
+
+ if (err)
+ *err = 0;
+
+ return irmc;
+}
+
+static int irmc_get(struct obex_session *os, obex_object_t *obj,
+ gboolean *stream, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+ const char *type = obex_get_type(os);
+ const char *name = obex_get_name(os);
+ char *path;
+ int ret;
+
+ DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
+
+ path = g_strdup(name);
+ *stream = TRUE;
+
+ ret = obex_get_stream_start(os, path);
+
+ g_free(path);
+
+ return ret;
+}
+
+static void irmc_disconnect(struct obex_session *os, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+
+ DBG("");
+
+ manager_unregister_session(os);
+
+ if (irmc->params) {
+ if (irmc->params->searchval)
+ g_free(irmc->params->searchval);
+ g_free(irmc->params);
+ }
+ if (irmc->buffer) {
+ string_free(irmc->buffer);
+ irmc->buffer = NULL;
+ }
+
+ g_free(irmc);
+}
+
+static int irmc_chkput(struct obex_session *os, void *user_data)
+{
+ DBG("");
+ /* Reject all PUTs */
+ return -EBADR;
+}
+
+static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
+{
+ char mybuf[1024];
+
+ sprintf(mybuf, "MANU:%s\r\n"
+ "MOD:%s\r\n"
+ "SN:%s\r\n"
+ "PB-TYPE-TX:VCARD2.1\r\n",
+ irmc->manu, irmc->model, irmc->sn);
+
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new(mybuf);
+ else
+ irmc->buffer = g_string_append(irmc->buffer, mybuf);
+
+ return irmc;
+}
+
+static void *irmc_open_pb(const char *name,
+ struct irmc_session *irmc, int *err)
+{
+ char mybuf[1024];
+ int ret;
+
+ if (!g_strcmp0(name, ".vcf")) {
+ // how can we tell if the vcard count call already finished?
+ ret = phonebook_pull("telecom/pb.vcf", irmc->params,
+ query_result, irmc);
+ if (ret < 0) {
+ DBG("phonebook_pull failed...");
+ goto fail;
+ }
+ return irmc;
+ }
+
+ if (!g_strcmp0(name, "/info.log")) {
+ sprintf(mybuf, "Total-Records:%d\r\n"
+ "Maximum-Records:%d\r\n"
+ "DID:%s\r\n",
+ irmc->params->maxlistcount,
+ irmc->params->maxlistcount, irmc->did);
+ }
+ else if (!strncmp(name, "/luid/", 6)) {
+ name += 6;
+ if (!g_strcmp0(name, "cc.log"))
+ sprintf(mybuf, "%d\r\n", irmc->params->maxlistcount);
+ else {
+ int l = strlen(name);
+ /* FIXME
+ * reply the same to any *.log so we hopefully force a
+ * full phonebook dump.
+ * Is IEL:2 ok?
+ */
+ if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
+ DBG("changelog request, force whole book");
+ sprintf(mybuf, "SN:%s\r\n"
+ "IEL:2\r\n"
+ "DID:%s\r\n"
+ "Total-Records:%d\r\n"
+ "Maximum-Records:%d\r\n"
+ "*\r\n",
+ irmc->sn, irmc->did,
+ irmc->params->maxlistcount,
+ irmc->params->maxlistcount);
+ }
+ else {
+ ret = -EBADR;
+ goto fail;
+ }
+ }
+ }
+ else {
+ ret = -EBADR;
+ goto fail;
+ }
+
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new(mybuf);
+ else
+ irmc->buffer = g_string_append(irmc->buffer, mybuf);
+
+ return irmc;
+
+fail:
+ if (err)
+ *err = ret;
+
+ return NULL;
+}
+
+static void *irmc_open_cal(const char *name,
+ struct irmc_session *irmc, int *err)
+{
+ // no suport yet. Just return an empty buffer
+ //cal.vcs
+ DBG("unsupported, returning empty buffer");
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new("");
+ else
+ irmc->buffer = g_string_append(irmc->buffer, "");
+
+ return irmc;
+}
+
+static void *irmc_open_nt(const char *name,
+ struct irmc_session *irmc, int *err)
+{
+ // no suport yet. Just return an empty buffer
+ //nt.vnt
+ DBG("unsupported, returning empty buffer");
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new("");
+ else
+ irmc->buffer = g_string_append(irmc->buffer, "");
+
+ return irmc;
+}
+
+static void *irmc_open(const char *name, int oflag, mode_t mode,
+ void *context, size_t *size, int *err)
+{
+ struct irmc_session *irmc = context;
+ int ret;
+ const char *p;
+
+ DBG("name %s context %p", name, context);
+ if (oflag != O_RDONLY) {
+ ret = -EPERM;
+ goto fail;
+ }
+ if (strncmp(name, "telecom/", 8) != NULL) {
+ ret = -EBADR;
+ goto fail;
+ }
+
+ p = name + 8;
+ if (!g_strcmp0(p, "devinfo.txt"))
+ return irmc_open_devinfo(irmc, err);
+ else if (!strncmp(p, "pb", 2))
+ return irmc_open_pb(p+2, irmc, err);
+ else if (!strncmp(p, "cal", 3))
+ return irmc_open_cal(p+3, irmc, err);
+ else if (!strncmp(p, "nt", 2))
+ return irmc_open_nt(p+2, irmc, err);
+
+fail:
+ if (err)
+ *err = ret;
+
+ return NULL;
+}
+
+static int irmc_close(void *object)
+{
+ struct irmc_session *irmc = object;
+
+ DBG("");
+ if (irmc->buffer) {
+ string_free(irmc->buffer);
+ irmc->buffer = NULL;
+ }
+
+ return 0;
+}
+
+static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi)
+{
+ struct irmc_session *irmc = object;
+ int len;
+
+ DBG("buffer %p count %d", irmc->buffer, count);
+ if (!irmc->buffer)
+ return -EAGAIN;
+
+ *hi = OBEX_HDR_BODY;
+ len = string_read(irmc->buffer, buf, count);
+ DBG("returning %d bytes", len);
+ return len;
+}
+
+static struct obex_mime_type_driver irmc_driver = {
+ .target = IRMC_TARGET,
+ .target_size = IRMC_TARGET_SIZE,
+ .open = irmc_open,
+ .close = irmc_close,
+ .read = irmc_read,
+};
+
+static struct obex_service_driver irmc = {
+ .name = "IRMC Sync server",
+ .service = OBEX_IRMC,
+ .channel = IRMC_CHANNEL,
+ .record = IRMC_RECORD,
+ .target = IRMC_TARGET,
+ .target_size = IRMC_TARGET_SIZE,
+ .connect = irmc_connect,
+ .get = irmc_get,
+ .disconnect = irmc_disconnect,
+ .chkput = irmc_chkput
+};
+
+static int irmc_init(void)
+{
+ int err;
+
+ DBG("");
+ err = phonebook_init();
+ if (err < 0)
+ return err;
+
+ err = obex_mime_type_driver_register(&irmc_driver);
+ if (err < 0)
+ return err;
+
+ return obex_service_driver_register(&irmc);
+}
+
+static void irmc_exit(void)
+{
+ DBG("");
+ obex_service_driver_unregister(&irmc);
+ obex_mime_type_driver_unregister(&irmc_driver);
+ phonebook_exit();
+}
+
+OBEX_PLUGIN_DEFINE(irmc, irmc_init, irmc_exit)
diff --git a/src/main.c b/src/main.c
index 649acf9..96523a6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -83,6 +83,7 @@ static gboolean option_pbap = FALSE;
static gboolean option_pcsuite = FALSE;
static gboolean option_symlinks = FALSE;
static gboolean option_syncevolution = FALSE;
+static gboolean option_irmc = FALSE;

static gboolean parse_debug(const char *key, const char *value,
gpointer user_data, GError **error)
@@ -122,6 +123,8 @@ static GOptionEntry options[] = {
"Enable PC Suite Services server" },
{ "syncevolution", 'e', 0, G_OPTION_ARG_NONE, &option_syncevolution,
"Enable OBEX server for SyncEvolution" },
+ { "irmc", 'i', 0, G_OPTION_ARG_NONE, &option_irmc,
+ "Enable IrMCSync server" },
{ NULL },
};

@@ -208,9 +211,10 @@ int main(int argc, char *argv[])

if (option_opp == FALSE && option_ftp == FALSE &&
option_pbap == FALSE &&
- option_syncevolution == FALSE) {
+ option_syncevolution == FALSE &&
+ option_irmc == FALSE) {
fprintf(stderr, "No server selected (use either "
- "--opp, --ftp, --pbap or --syncevolution)\n");
+ "--opp, --ftp, --pbap --syncevolution or --irmc)\n");
exit(EXIT_FAILURE);
}

@@ -270,6 +274,10 @@ int main(int argc, char *argv[])
obex_server_init(OBEX_SYNCEVOLUTION, NULL, TRUE, FALSE,
FALSE, NULL);

+ if (option_irmc == TRUE)
+ obex_server_init(OBEX_IRMC, NULL, TRUE, FALSE, FALSE,
+ option_capability);
+
if (!root_folder_setup(option_root, option_root_setup)) {
error("Unable to setup root folder %s", option_root);
exit(EXIT_FAILURE);
diff --git a/src/obex.h b/src/obex.h
index 9424b6b..cfe9159 100644
--- a/src/obex.h
+++ b/src/obex.h
@@ -35,6 +35,7 @@
#define OBEX_PBAP (1 << 4)
#define OBEX_PCSUITE (1 << 5)
#define OBEX_SYNCEVOLUTION (1 << 6)
+#define OBEX_IRMC (1 << 7)

#define TARGET_SIZE 16

--
1.7.2



2010-08-19 15:02:10

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

Hi,

On Thu, Aug 19, 2010, Luiz Augusto von Dentz wrote:
> We decided to use 14, also Johan pushed a complete list of bluez
> assigned number to:
>
> http://git.kernel.org/?p=bluetooth/bluez.git;a=commitdiff;h=fbeff4fd303b43fa7f6c27e95fb6f023e80720a9;hp=0627552640140e1d986d36bb4770ccc4b3206b03
>
> Could you please update your changes to use 14? Also there seems to be
> some white spaces that doesn't follow our code styling, could you
> please fix those?

Since Luiz didn't send an update here about the status I'll do it to
avoid duplicate work at your end. Luiz went ahead and did the cleanups
himself (and I added a few more on top of that) and the resulting patch
is now pushed upstream. Btw, it'd proabably be a good idea for you to
hang out on the #obexd channel on freenode since that's where many of
these quick interactions and decisions seem to be happening now days.

Johan

2010-08-19 10:53:21

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

Hi Marcel,

On Tue, Aug 17, 2010 at 11:48 AM, Marcel J.E. Mol <[email protected]> wrote:
> Ok, then 17 is just fine for IrMC then. I posted a 3th version at the end=
of
> last week. Are there any new comments I have to take care of? Or can it =
=A0be
> considere for inclusion in the main tree now?
>
>
> On the other hand, if the channel 'varies' it might be better to let the
> plugin manager select a channel number for each service instead of alloca=
ting
> a fixed one in the specific plugin code.
>
> What did you found about channel 11 then? On my nokia 7710 channel 11 is =
used for
> "OBEX File Transfer" (serivce 0x1106).

We decided to use 14, also Johan pushed a complete list of bluez
assigned number to:

http://git.kernel.org/?p=3Dbluetooth/bluez.git;a=3Dcommitdiff;h=3Dfbeff4fd3=
03b43fa7f6c27e95fb6f023e80720a9;hp=3D0627552640140e1d986d36bb4770ccc4b3206b=
03

Could you please update your changes to use 14? Also there seems to be
some white spaces that doesn't follow our code styling, could you
please fix those?

--=20
Luiz Augusto von Dentz
Computer Engineer

2010-08-17 08:48:50

by Marcel Mol

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

Hi,

On Mon, Aug 16, 2010 at 10:47:08PM +0300, Luiz Augusto von Dentz wrote:
> Hi,
>
> On Mon, Aug 16, 2010 at 8:22 PM, Marcel J.E. Mol <[email protected]> wrote:
> > On Thu, Aug 12, 2010 at 07:41:39AM -0400, Marcel Holtmann wrote:
> >> Hi Marcel,
> >>
> >> > A reasonable working IrMC SYNC server (only full phonebook sync support)
> >> > Support for cal and note by just returning nothing.
> >> > ---
> >> >  Makefile.am    |    3 +
> >> >  plugins/irmc.c |  488 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >> >  src/main.c     |   12 ++-
> >> >  src/obex.h     |    1 +
> >> >  4 files changed, 502 insertions(+), 2 deletions(-)
> >> >  create mode 100644 plugins/irmc.c
> >> >
> >> > diff --git a/Makefile.am b/Makefile.am
> >> > index 73e2f28..ce8c675 100644
> >> > --- a/Makefile.am
> >> > +++ b/Makefile.am
> >> > @@ -58,6 +58,9 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
> >> >  builtin_modules += syncevolution
> >> >  builtin_sources += plugins/syncevolution.c
> >> >
> >> > +builtin_modules += irmc
> >> > +builtin_sources += plugins/irmc.c plugins/phonebook.h
> >> > +
> >> >  builtin_nodist += plugins/phonebook.c
> >> >
> >> >  libexec_PROGRAMS += src/obexd
> >> > diff --git a/plugins/irmc.c b/plugins/irmc.c
> >> > new file mode 100644
> >> > index 0000000..96fd807
> >> > --- /dev/null
> >> > +++ b/plugins/irmc.c
> >> > @@ -0,0 +1,488 @@
> >> > +/*
> >> > + *
> >> > + *  OBEX IrMC Sync Server
> >> > ...
> >> > +#include "dbus.h"
> >> > +
> >> > +#define IRMC_CHANNEL       17
> >>
> >> we did have a list of defined RFCOMM channels for various protocols, but
> >> just don't remember where it is.
> >>
> >> Johan, we should put that into the doc/ directory actually. Can you dig
> >> up that list and commit it as text file.
> >>
> >
> > Any news on this one? Is 17 the correct channel for IrMC?
>
> I just took a look in the spec, it just say that the channel 'varies',
> which is not very revealing and it does not suggest anything. The only
> record that I found was using channel 11 which apparently we are not
> using too.

Ok, then 17 is just fine for IrMC then. I posted a 3th version at the end of
last week. Are there any new comments I have to take care of? Or can it be
considere for inclusion in the main tree now?


On the other hand, if the channel 'varies' it might be better to let the
plugin manager select a channel number for each service instead of allocating
a fixed one in the specific plugin code.

What did you found about channel 11 then? On my nokia 7710 channel 11 is used for
"OBEX File Transfer" (serivce 0x1106).

-Marcel
--
======-------- Marcel J.E. Mol MESA Consulting B.V.
=======--------- ph. +31-(0)6-54724868 P.O. Box 112
=======--------- [email protected] 2630 AC Nootdorp
__==== http://www.mesa.nl ---____U_n_i_x______I_n_t_e_r_n_e_t____ The Netherlands ____
They couldn't think of a number, Linux user 1148 -- counter.li.org
so they gave me a name! -- Rupert Hine -- http://www.ruperthine.com

2010-08-16 19:47:08

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

Hi,

On Mon, Aug 16, 2010 at 8:22 PM, Marcel J.E. Mol <[email protected]> wrote:
> On Thu, Aug 12, 2010 at 07:41:39AM -0400, Marcel Holtmann wrote:
>> Hi Marcel,
>>
>> > A reasonable working IrMC SYNC server (only full phonebook sync suppor=
t)
>> > Support for cal and note by just returning nothing.
>> > ---
>> > =A0Makefile.am =A0 =A0| =A0 =A03 +
>> > =A0plugins/irmc.c | =A0488 +++++++++++++++++++++++++++++++++++++++++++=
+++++++++++++
>> > =A0src/main.c =A0 =A0 | =A0 12 ++-
>> > =A0src/obex.h =A0 =A0 | =A0 =A01 +
>> > =A04 files changed, 502 insertions(+), 2 deletions(-)
>> > =A0create mode 100644 plugins/irmc.c
>> >
>> > diff --git a/Makefile.am b/Makefile.am
>> > index 73e2f28..ce8c675 100644
>> > --- a/Makefile.am
>> > +++ b/Makefile.am
>> > @@ -58,6 +58,9 @@ builtin_sources +=3D plugins/pbap.c plugins/phoneboo=
k.h \
>> > =A0builtin_modules +=3D syncevolution
>> > =A0builtin_sources +=3D plugins/syncevolution.c
>> >
>> > +builtin_modules +=3D irmc
>> > +builtin_sources +=3D plugins/irmc.c plugins/phonebook.h
>> > +
>> > =A0builtin_nodist +=3D plugins/phonebook.c
>> >
>> > =A0libexec_PROGRAMS +=3D src/obexd
>> > diff --git a/plugins/irmc.c b/plugins/irmc.c
>> > new file mode 100644
>> > index 0000000..96fd807
>> > --- /dev/null
>> > +++ b/plugins/irmc.c
>> > @@ -0,0 +1,488 @@
>> > +/*
>> > + *
>> > + * =A0OBEX IrMC Sync Server
>> > ...
>> > +#include "dbus.h"
>> > +
>> > +#define IRMC_CHANNEL =A0 =A0 =A0 17
>>
>> we did have a list of defined RFCOMM channels for various protocols, but
>> just don't remember where it is.
>>
>> Johan, we should put that into the doc/ directory actually. Can you dig
>> up that list and commit it as text file.
>>
>
> Any news on this one? Is 17 the correct channel for IrMC?

I just took a look in the spec, it just say that the channel 'varies',
which is not very revealing and it does not suggest anything. The only
record that I found was using channel 11 which apparently we are not
using too.


--=20
Luiz Augusto von Dentz
Computer Engineer

2010-08-16 17:22:38

by Marcel Mol

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

On Thu, Aug 12, 2010 at 07:41:39AM -0400, Marcel Holtmann wrote:
> Hi Marcel,
>
> > A reasonable working IrMC SYNC server (only full phonebook sync support)
> > Support for cal and note by just returning nothing.
> > ---
> > Makefile.am | 3 +
> > plugins/irmc.c | 488 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > src/main.c | 12 ++-
> > src/obex.h | 1 +
> > 4 files changed, 502 insertions(+), 2 deletions(-)
> > create mode 100644 plugins/irmc.c
> >
> > diff --git a/Makefile.am b/Makefile.am
> > index 73e2f28..ce8c675 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -58,6 +58,9 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
> > builtin_modules += syncevolution
> > builtin_sources += plugins/syncevolution.c
> >
> > +builtin_modules += irmc
> > +builtin_sources += plugins/irmc.c plugins/phonebook.h
> > +
> > builtin_nodist += plugins/phonebook.c
> >
> > libexec_PROGRAMS += src/obexd
> > diff --git a/plugins/irmc.c b/plugins/irmc.c
> > new file mode 100644
> > index 0000000..96fd807
> > --- /dev/null
> > +++ b/plugins/irmc.c
> > @@ -0,0 +1,488 @@
> > +/*
> > + *
> > + * OBEX IrMC Sync Server
> > ...
> > +#include "dbus.h"
> > +
> > +#define IRMC_CHANNEL 17
>
> we did have a list of defined RFCOMM channels for various protocols, but
> just don't remember where it is.
>
> Johan, we should put that into the doc/ directory actually. Can you dig
> up that list and commit it as text file.
>

Any news on this one? Is 17 the correct channel for IrMC?

-Marcel
--
======-------- Marcel J.E. Mol MESA Consulting B.V.
=======--------- ph. +31-(0)6-54724868 P.O. Box 112
=======--------- [email protected] 2630 AC Nootdorp
__==== http://www.mesa.nl ---____U_n_i_x______I_n_t_e_r_n_e_t____ The Netherlands ____
They couldn't think of a number, Linux user 1148 -- counter.li.org
so they gave me a name! -- Rupert Hine -- http://www.ruperthine.com

2010-08-12 15:39:35

by Marcel Mol

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

On Thu, Aug 12, 2010 at 04:57:03PM +0200, Luiz Augusto von Dentz wrote:
> Hi Marcel,
>
> On Thu, Aug 12, 2010 at 3:12 PM, Marcel J.E. Mol <[email protected]> wrote:
> > abstracting it made de irmc_open() more clean (e.g. no buffer fills in
> > irmc_open()) and more readable in my opinion.
> > The specs for devinfo.txt contain many more attributes but the currrent
> > set seems to be enough. In future this may need to be extended and
> > supporting scripts may be needed for getting the info. The current
> > values are actually not correct I think as the will be the same for any
> > device now... (hence the hint for using x-obex/capabilities in
> > irmc_connect().)
>
> It doesn't look like we can use x-obex/capabilities for this
> devinfo.txt, afaik they are not the same thing, thats why I suggested
> open it as any regular file so the platforms has some way to customize
> it. Executing scripts is always tricky since you have to depend on
> async io to suspend the request while the script is running and resume
> when finished. Of course if there is no file called devinfo.txt then
> we can think about a default value, what does the spec says in this
> regard, is devinfo.txt mandatory? If not then we can just fail as we
> do for x-obex/capabilities when not set.

I don;t know how diffenent capbilities is from the things devinfo.txt
needs. On the n900 the capabilities script seems to provide what is needed
for devinfo.txt so I was lead by that...

I'm not suere how mandatory devinfo.txt is. My carkit did ask for it but
when I returned some data to it it never asked again... It probably will
when I remove my phones configuration from the carkit.

I never checked the specs again for it as it all seems to work fine with
the code as it is now. It also works for other n900 owners so i did not
bother any more.

I think the code seems to be in a reasonable state to be usefull now so
that is why I released it here. There is probably lots of extra work to be
done to be fully specs complient. But by releasing it other people can jump
in and improve...

Thanks,

-Marcel
--
======-------- Marcel J.E. Mol MESA Consulting B.V.
=======--------- ph. +31-(0)6-54724868 P.O. Box 112
=======--------- [email protected] 2630 AC Nootdorp
__==== http://www.mesa.nl ---____U_n_i_x______I_n_t_e_r_n_e_t____ The Netherlands ____
They couldn't think of a number, Linux user 1148 -- counter.li.org
so they gave me a name! -- Rupert Hine -- http://www.ruperthine.com

2010-08-12 14:57:03

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

Hi Marcel,

On Thu, Aug 12, 2010 at 3:12 PM, Marcel J.E. Mol <[email protected]> wrote:
> abstracting it made de irmc_open() more clean (e.g. no buffer fills in
> irmc_open()) and more readable in my opinion.
> The specs for devinfo.txt contain many more attributes but the currrent
> set seems to be enough. In future this may need to be extended and
> supporting scripts may be needed for getting the info. The current
> values are actually not correct I think as the will be the same for any
> device now... (hence the hint for using x-obex/capabilities in
> irmc_connect().)

It doesn't look like we can use x-obex/capabilities for this
devinfo.txt, afaik they are not the same thing, thats why I suggested
open it as any regular file so the platforms has some way to customize
it. Executing scripts is always tricky since you have to depend on
async io to suspend the request while the script is running and resume
when finished. Of course if there is no file called devinfo.txt then
we can think about a default value, what does the spec says in this
regard, is devinfo.txt mandatory? If not then we can just fail as we
do for x-obex/capabilities when not set.

--
Luiz Augusto von Dentz
Computer Engineer

2010-08-12 14:56:43

by Marcel Mol

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

On Thu, Aug 12, 2010 at 07:41:39AM -0400, Marcel Holtmann wrote:
> Hi Marcel,
>
> > A reasonable working IrMC SYNC server (only full phonebook sync support)
> > Support for cal and note by just returning nothing.
> > ---
> > Makefile.am | 3 +
> > plugins/irmc.c | 488 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > src/main.c | 12 ++-
> > src/obex.h | 1 +
> > 4 files changed, 502 insertions(+), 2 deletions(-)
> > create mode 100644 plugins/irmc.c
> >
> > diff --git a/Makefile.am b/Makefile.am
> > index 73e2f28..ce8c675 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -58,6 +58,9 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
> > builtin_modules += syncevolution
> > builtin_sources += plugins/syncevolution.c
> >
> > +builtin_modules += irmc
> > +builtin_sources += plugins/irmc.c plugins/phonebook.h
> > +
> > builtin_nodist += plugins/phonebook.c
> >
> > libexec_PROGRAMS += src/obexd
> > diff --git a/plugins/irmc.c b/plugins/irmc.c
> > new file mode 100644
> > index 0000000..96fd807
> > --- /dev/null
> > +++ b/plugins/irmc.c
> > @@ -0,0 +1,488 @@
> > +/*
> > + *
> > + * OBEX IrMC Sync Server
> > + *
> > + * Copyright (C) 2010 Marcel Mol <[email protected]>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> > + *
> > + */
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include <config.h>
> > +#endif
> > +
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <errno.h>
> > +#include <glib.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <arpa/inet.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +#include <openobex/obex.h>
> > +#include <openobex/obex_const.h>
> > +
> > +#include "plugin.h"
> > +#include "log.h"
> > +#include "obex.h"
> > +#include "service.h"
> > +#include "phonebook.h"
> > +#include "mimetype.h"
> > +#include "filesystem.h"
> > +#include "dbus.h"
> > +
> > +#define IRMC_CHANNEL 17
>
> we did have a list of defined RFCOMM channels for various protocols, but
> just don't remember where it is.
>
> Johan, we should put that into the doc/ directory actually. Can you dig
> up that list and commit it as text file.
>
> > +
> > +#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
> > +<record> \
> > + <attribute id=\"0x0001\"> \
> > + <sequence> \
> > + <uuid value=\"0x1104\"/> \
> > + </sequence> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0004\"> \
> > + <sequence> \
> > + <sequence> \
> > + <uuid value=\"0x0100\"/> \
> > + </sequence> \
> > + <sequence> \
> > + <uuid value=\"0x0003\"/> \
> > + <uint8 value=\"%u\" name=\"channel\"/> \
> > + </sequence> \
> > + <sequence> \
> > + <uuid value=\"0x0008\"/> \
> > + </sequence> \
> > + </sequence> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0009\"> \
> > + <sequence> \
> > + <sequence> \
> > + <uuid value=\"0x1104\"/> \
> > + <uint16 value=\"0x0100\" name=\"version\"/> \
> > + </sequence> \
> > + </sequence> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0100\"> \
> > + <text value=\"%s\" name=\"name\"/> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0301\"> \
> > + <sequence> \
> > + <uint8 value=\"0x01\"/> \
> > + </sequence> \
> > + </attribute> \
> > +</record>"
> > +
> > +
> > +struct aparam_header {
> > + uint8_t tag;
> > + uint8_t len;
> > + uint8_t val[0];
> > +} __attribute__ ((packed));
> > +
> > +#define DIDLEN 18
> > +struct irmc_session {
> > + struct obex_session *os;
> > + struct apparam_field *params;
> > + uint16_t entries;
> > + GString *buffer;
> > + char sn[DIDLEN];
> > + char did[DIDLEN];
> > + char manu[DIDLEN];
> > + char model[DIDLEN];
> > +};
>
> What is DIDLEN.

Just to have a symbolic name for the max length of the char strings in
the irmc_session struct.
All strings may need a different max length, but for now a single value
suffices. (see also the comment in irmc_connect())

>
> > +
> > +#define IRMC_TARGET_SIZE 9
> > +
> > +static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
> > + 0x49, 0x52, 0x4d, 0x43, 0x2d, 0x53, 0x59, 0x4e, 0x43 };
> > +
> > +static void phonebook_size_result(const char *buffer, size_t bufsize,
> > + int vcards, int missed, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > +
> > + DBG("vcards %d", vcards);
> > +
> > + irmc->params->maxlistcount = vcards;
> > +}
> > +
> > +static void query_result(const char *buffer, size_t bufsize, int vcards,
> > + int missed, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > + const char *s;
> > + char *t;
> > +
> > + DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
> > +
> > + // first create an empty 'owner' vcard
>
> As Luiz already mentioned, please use /* */ style comments.

Fine

>
> > + t = "BEGIN:VCARD\r\n"
> > + "VERSION:2.1\r\n"
> > + "N:\r\n"
> > + "TEL:\r\n"
> > + "X-IRMX-LUID:0\r\n"
> > + "END:VCARDi\r\n";

> You really wanna use const char *t here. And I would even prefer if you
> make that one static and global.

Ok will do.

> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new_len(t, strlen(t));
> > + else
> > + irmc->buffer = g_string_append_len(irmc->buffer, t, strlen(t));
>
> Why the string_append_len. Just append it it.

Don't know :). Will change it.

>
> > + // loop around buffer and add X-IRMC-LUID attribs
> > + s = buffer;
> > + while ((t = strstr(s, "UID:")) != NULL) {
> > + // add upto UID: into buffer
> > + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > + // add UID: line into buffer
> > + // Not sure if UID is still needed if X-IRMC-LUID is there
> > + s = t;
> > + t = strstr(s, "\r\n");
> > + t += 2;
> > + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > + // add X-IRMC-LUID with same number as UID
> > + irmc->buffer = g_string_append_len(irmc->buffer,
> > + "X-IRMC-LUID:", 12);
> > + s += 4; // point to uid number
> > + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > + s = t;
> > + }
> > + // add remaining bit of buffer
> > + irmc->buffer = g_string_append_len(irmc->buffer, s,
> > + bufsize - (s-buffer));
> > +
> > + obex_object_set_io_flags(irmc, G_IO_IN, 0);
> > +}
> > +
> > +static void *irmc_connect(struct obex_session *os, int *err)
> > +{
> > + struct irmc_session *irmc;
> > + struct apparam_field *param;
> > +
> > + DBG("");
> > +
> > + manager_register_session(os);
> > +
> > + irmc = g_new0(struct irmc_session, 1);
> > + irmc->os = os;
> > +
> > + /*
> > + * ideally get capabilities info here and use that to define
> > + * IrMC DID and SN etc parameters.
> > + * For now lets used hostname and some 'random' value
> > + */
> > + gethostname(irmc->did, DIDLEN);
> > + strncpy(irmc->sn, "12345", DIDLEN);
> > + strncpy(irmc->manu, "obex", DIDLEN);
> > + strncpy(irmc->model, "mymodel", DIDLEN);
> > +
> > + /*
> > + * we need to know the number of contact/cal/nt entries
> > + * somewhere so why not do it now.
> > + */
> > + param = g_new0(struct apparam_field, 1);
> > + param->maxlistcount = 0; // to count the number of vcards...
> > + param->filter = 0x200085; // UID TEL N VERSION
> > + irmc->params = param;
> > + phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
> > + irmc);
> > +
> > + if (err)
> > + *err = 0;
> > +
> > + return irmc;
> > +}
> > +
> > +static int irmc_get(struct obex_session *os, obex_object_t *obj,
> > + gboolean *stream, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > + const char *type = obex_get_type(os);
> > + const char *name = obex_get_name(os);
> > + char *path;
> > + int ret;
> > +
> > + DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
> > +
> > + path = g_strdup(name);
> > + *stream = TRUE;
> > +
> > + ret = obex_get_stream_start(os, path);
> > +
> > + g_free(path);
> > +
> > + return ret;
> > +}
> > +
> > +static void irmc_disconnect(struct obex_session *os, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > +
> > + DBG("");
> > +
> > + manager_unregister_session(os);
> > +
> > + if (irmc->params) {
> > + if (irmc->params->searchval)
> > + g_free(irmc->params->searchval);
> > + g_free(irmc->params);
> > + }
> > + if (irmc->buffer) {
> > + string_free(irmc->buffer);
> > + irmc->buffer = NULL;
> > + }
> > +
> > + g_free(irmc);
> > +}
> > +
> > +static int irmc_chkput(struct obex_session *os, void *user_data)
> > +{
> > + DBG("");
> > + /* Reject all PUTs */
> > + return -EBADR;
> > +}
> > +
> > +static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
> > +{
> > + char mybuf[1024];
> > +
> > + sprintf(mybuf, "MANU:%s\r\n"
> > + "MOD:%s\r\n"
> > + "SN:%s\r\n"
> > + "PB-TYPE-TX:VCARD2.1\r\n",
> > + irmc->manu, irmc->model, irmc->sn);
> > +
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new(mybuf);
> > + else
> > + irmc->buffer = g_string_append(irmc->buffer, mybuf);
>
> We have something that is called g_string_append_printf(). Use that one
> and not allocate a buf up-front.

thanks, was not aware of this.

>
> > +
> > + return irmc;
> > +}
> > +
> > +static void *irmc_open_pb(const char *name,
> > + struct irmc_session *irmc, int *err)
> > +{
> > + char mybuf[1024];
> > + int ret;
> > +
> > + if (!g_strcmp0(name, ".vcf")) {
> > + // how can we tell if the vcard count call already finished?
> > + ret = phonebook_pull("telecom/pb.vcf", irmc->params,
> > + query_result, irmc);
> > + if (ret < 0) {
> > + DBG("phonebook_pull failed...");
> > + goto fail;
> > + }
> > + return irmc;
> > + }
> > +
> > + if (!g_strcmp0(name, "/info.log")) {
> > + sprintf(mybuf, "Total-Records:%d\r\n"
> > + "Maximum-Records:%d\r\n"
> > + "DID:%s\r\n",
> > + irmc->params->maxlistcount,
> > + irmc->params->maxlistcount, irmc->did);
> > + }
>
> Same here. A GLib _printf() function is way better usage.

Ok wil look into that. This one may need some more thinking to make in nice and clean

>
> > + else if (!strncmp(name, "/luid/", 6)) {
> > + name += 6;
> > + if (!g_strcmp0(name, "cc.log"))
> > + sprintf(mybuf, "%d\r\n", irmc->params->maxlistcount);
> > + else {
> > + int l = strlen(name);
> > + /* FIXME
> > + * reply the same to any *.log so we hopefully force a
> > + * full phonebook dump.
> > + * Is IEL:2 ok?
> > + */
> > + if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
> > + DBG("changelog request, force whole book");
> > + sprintf(mybuf, "SN:%s\r\n"
> > + "IEL:2\r\n"
> > + "DID:%s\r\n"
> > + "Total-Records:%d\r\n"
> > + "Maximum-Records:%d\r\n"
> > + "*\r\n",
> > + irmc->sn, irmc->did,
> > + irmc->params->maxlistcount,
> > + irmc->params->maxlistcount);
> > + }
> > + else {
> > + ret = -EBADR;
> > + goto fail;
> > + }
> > + }
> > + }
> > + else {
> > + ret = -EBADR;
> > + goto fail;
> > + }
> > +
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new(mybuf);
> > + else
> > + irmc->buffer = g_string_append(irmc->buffer, mybuf);
> > +
> > + return irmc;
> > +
> > +fail:
> > + if (err)
> > + *err = ret;
> > +
> > + return NULL;
> > +}
> > +
> > +static void *irmc_open_cal(const char *name,
> > + struct irmc_session *irmc, int *err)
> > +{
> > + // no suport yet. Just return an empty buffer
> > + //cal.vcs
> > + DBG("unsupported, returning empty buffer");
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new("");
> > + else
> > + irmc->buffer = g_string_append(irmc->buffer, "");
> > +
> > + return irmc;
>
> Empty buffer is empty buffer. Just return it.

Well, an empty buffer it is. irmc->buffer may not be NULL after as that
will be seen as 'no data available yet'.

>
> > +}
> > +
> > +static void *irmc_open_nt(const char *name,
> > + struct irmc_session *irmc, int *err)
> > +{
> > + // no suport yet. Just return an empty buffer
> > + //nt.vnt
> > + DBG("unsupported, returning empty buffer");
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new("");
> > + else
> > + irmc->buffer = g_string_append(irmc->buffer, "");
> > +
> > + return irmc;
>
> Same here.
>
> > +}
> > +
> > +static void *irmc_open(const char *name, int oflag, mode_t mode,
> > + void *context, size_t *size, int *err)
> > +{
> > + struct irmc_session *irmc = context;
> > + int ret;
> > + const char *p;
> > +
> > + DBG("name %s context %p", name, context);
> > + if (oflag != O_RDONLY) {
> > + ret = -EPERM;
> > + goto fail;
> > + }
> > + if (strncmp(name, "telecom/", 8) != NULL) {
> > + ret = -EBADR;
> > + goto fail;
> > + }
> > +
> > + p = name + 8;
> > + if (!g_strcmp0(p, "devinfo.txt"))
> > + return irmc_open_devinfo(irmc, err);
> > + else if (!strncmp(p, "pb", 2))
> > + return irmc_open_pb(p+2, irmc, err);
> > + else if (!strncmp(p, "cal", 3))
> > + return irmc_open_cal(p+3, irmc, err);
> > + else if (!strncmp(p, "nt", 2))
> > + return irmc_open_nt(p+2, irmc, err);
> > +
> > +fail:
> > + if (err)
> > + *err = ret;
> > +
> > + return NULL;
> > +}
> > +
> > +static int irmc_close(void *object)
> > +{
> > + struct irmc_session *irmc = object;
> > +
> > + DBG("");
> > + if (irmc->buffer) {
> > + string_free(irmc->buffer);
> > + irmc->buffer = NULL;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi)
> > +{
> > + struct irmc_session *irmc = object;
> > + int len;
> > +
> > + DBG("buffer %p count %d", irmc->buffer, count);
> > + if (!irmc->buffer)
> > + return -EAGAIN;
> > +
> > + *hi = OBEX_HDR_BODY;
> > + len = string_read(irmc->buffer, buf, count);
> > + DBG("returning %d bytes", len);
> > + return len;
> > +}
> > +
> > +static struct obex_mime_type_driver irmc_driver = {
> > + .target = IRMC_TARGET,
> > + .target_size = IRMC_TARGET_SIZE,
> > + .open = irmc_open,
> > + .close = irmc_close,
> > + .read = irmc_read,
> > +};
> > +
> > +static struct obex_service_driver irmc = {
> > + .name = "IRMC Sync server",
> > + .service = OBEX_IRMC,
> > + .channel = IRMC_CHANNEL,
> > + .record = IRMC_RECORD,
> > + .target = IRMC_TARGET,
> > + .target_size = IRMC_TARGET_SIZE,
> > + .connect = irmc_connect,
> > + .get = irmc_get,
> > + .disconnect = irmc_disconnect,
> > + .chkput = irmc_chkput
> > +};
> > +
> > +static int irmc_init(void)
> > +{
> > + int err;
> > +
> > + DBG("");
> > + err = phonebook_init();
> > + if (err < 0)
> > + return err;
> > +
> > + err = obex_mime_type_driver_register(&irmc_driver);
> > + if (err < 0)
> > + return err;
>
> Don't you need to phonebook_exit() here?
>
> > +
> > + return obex_service_driver_register(&irmc);
> > +}
>
> Also what happens if this one fails. You do need to clean up.

Oops, should have seen this when it was fixsed for pbap.

>
> > +
> > +static void irmc_exit(void)
> > +{
> > + DBG("");
> > + obex_service_driver_unregister(&irmc);
> > + obex_mime_type_driver_unregister(&irmc_driver);
> > + phonebook_exit();
> > +}
> > +
> > +OBEX_PLUGIN_DEFINE(irmc, irmc_init, irmc_exit)
> > diff --git a/src/main.c b/src/main.c
> > index 649acf9..96523a6 100644
> > --- a/src/main.c
> > +++ b/src/main.c
> > @@ -83,6 +83,7 @@ static gboolean option_pbap = FALSE;
> > static gboolean option_pcsuite = FALSE;
> > static gboolean option_symlinks = FALSE;
> > static gboolean option_syncevolution = FALSE;
> > +static gboolean option_irmc = FALSE;
> >
> > static gboolean parse_debug(const char *key, const char *value,
> > gpointer user_data, GError **error)
> > @@ -122,6 +123,8 @@ static GOptionEntry options[] = {
> > "Enable PC Suite Services server" },
> > { "syncevolution", 'e', 0, G_OPTION_ARG_NONE, &option_syncevolution,
> > "Enable OBEX server for SyncEvolution" },
> > + { "irmc", 'i', 0, G_OPTION_ARG_NONE, &option_irmc,
> > + "Enable IrMCSync server" },
> > { NULL },
> > };
>
> Just put irmc before syncevolution. Like nicer ;)

Agree :)

> >
> > @@ -208,9 +211,10 @@ int main(int argc, char *argv[])
> >
> > if (option_opp == FALSE && option_ftp == FALSE &&
> > option_pbap == FALSE &&
> > - option_syncevolution == FALSE) {
> > + option_syncevolution == FALSE &&
> > + option_irmc == FALSE) {
> > fprintf(stderr, "No server selected (use either "
> > - "--opp, --ftp, --pbap or --syncevolution)\n");
> > + "--opp, --ftp, --pbap --syncevolution or --irmc)\n");
> > exit(EXIT_FAILURE);
> > }
>
> Same here. Leave syncevolution at the end.
>
> >
> > @@ -270,6 +274,10 @@ int main(int argc, char *argv[])
> > obex_server_init(OBEX_SYNCEVOLUTION, NULL, TRUE, FALSE,
> > FALSE, NULL);
> >
> > + if (option_irmc == TRUE)
> > + obex_server_init(OBEX_IRMC, NULL, TRUE, FALSE, FALSE,
> > + option_capability);
> > +
>
> And here again.
>
> > if (!root_folder_setup(option_root, option_root_setup)) {
> > error("Unable to setup root folder %s", option_root);
> > exit(EXIT_FAILURE);
> > diff --git a/src/obex.h b/src/obex.h
> > index 9424b6b..cfe9159 100644
> > --- a/src/obex.h
> > +++ b/src/obex.h
> > @@ -35,6 +35,7 @@
> > #define OBEX_PBAP (1 << 4)
> > #define OBEX_PCSUITE (1 << 5)
> > #define OBEX_SYNCEVOLUTION (1 << 6)
> > +#define OBEX_IRMC (1 << 7)
> >
>
> And here as well. Just use 1 << 6 for IRMC and move SYNCEVO to 1 << 7.
>
> > #define TARGET_SIZE 16
> >
>
> Regards
>
> Marcel
>

thanks for your comments Marcel

-Marcel
--
======-------- Marcel J.E. Mol MESA Consulting B.V.
=======--------- ph. +31-(0)6-54724868 P.O. Box 112
=======--------- [email protected] 2630 AC Nootdorp
__==== http://www.mesa.nl ---____U_n_i_x______I_n_t_e_r_n_e_t____ The Netherlands ____
They couldn't think of a number, Linux user 1148 -- counter.li.org
so they gave me a name! -- Rupert Hine -- http://www.ruperthine.com

2010-08-12 14:56:30

by Marcel Mol

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

On Thu, Aug 12, 2010 at 02:16:30PM +0300, Luiz Augusto von Dentz wrote:
> Hi Marcel,
>
> On Tue, Jul 27, 2010 at 8:04 PM, Marcel Mol <[email protected]> wrote:
> > A reasonable working IrMC SYNC server (only full phonebook sync support)
> > Support for cal and note by just returning nothing.
> > ---
> >  Makefile.am    |    3 +
> >  plugins/irmc.c |  488 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  src/main.c     |   12 ++-
> >  src/obex.h     |    1 +
> >  4 files changed, 502 insertions(+), 2 deletions(-)
> >  create mode 100644 plugins/irmc.c
> >
> > diff --git a/Makefile.am b/Makefile.am
> > index 73e2f28..ce8c675 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -58,6 +58,9 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
> >  builtin_modules += syncevolution
> >  builtin_sources += plugins/syncevolution.c
> >
> > +builtin_modules += irmc
> > +builtin_sources += plugins/irmc.c plugins/phonebook.h
> > +
> >  builtin_nodist += plugins/phonebook.c
> >
> >  libexec_PROGRAMS += src/obexd
> > diff --git a/plugins/irmc.c b/plugins/irmc.c
> > new file mode 100644
> > index 0000000..96fd807
> > --- /dev/null
> > +++ b/plugins/irmc.c
> > @@ -0,0 +1,488 @@
> > +/*
> > + *
> > + *  OBEX IrMC Sync Server
> > + *
> > + *  Copyright (C) 2010  Marcel Mol <[email protected]>
> > + *
> > + *  This program is free software; you can redistribute it and/or modify
> > + *  it under the terms of the GNU General Public License as published by
> > + *  the Free Software Foundation; either version 2 of the License, or
> > + *  (at your option) any later version.
> > + *
> > + *  This program is distributed in the hope that it will be useful,
> > + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + *  GNU General Public License for more details.
> > + *
> > + *  You should have received a copy of the GNU General Public License
> > + *  along with this program; if not, write to the Free Software
> > + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> > + *
> > + */
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include <config.h>
> > +#endif
> > +
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <errno.h>
> > +#include <glib.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <arpa/inet.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +#include <openobex/obex.h>
> > +#include <openobex/obex_const.h>
> > +
> > +#include "plugin.h"
> > +#include "log.h"
> > +#include "obex.h"
> > +#include "service.h"
> > +#include "phonebook.h"
> > +#include "mimetype.h"
> > +#include "filesystem.h"
> > +#include "dbus.h"
> > +
> > +#define IRMC_CHANNEL   17
> > +
> > +#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>       \
> > +<record>                                                               \
> > +  <attribute id=\"0x0001\">                                            \
> > +    <sequence>                                                         \
> > +      <uuid value=\"0x1104\"/>                                         \
> > +    </sequence>                                                                \
> > +  </attribute>                                                         \
> > +                                                                       \
> > +  <attribute id=\"0x0004\">                                            \
> > +    <sequence>                                                         \
> > +      <sequence>                                                       \
> > +        <uuid value=\"0x0100\"/>                                       \
> > +      </sequence>                                                      \
> > +      <sequence>                                                       \
> > +        <uuid value=\"0x0003\"/>                                       \
> > +        <uint8 value=\"%u\" name=\"channel\"/>                         \
> > +      </sequence>                                                      \
> > +      <sequence>                                                       \
> > +        <uuid value=\"0x0008\"/>                                       \
> > +      </sequence>                                                      \
> > +    </sequence>                                                                \
> > +  </attribute>                                                         \
> > +                                                                       \
> > +  <attribute id=\"0x0009\">                                            \
> > +    <sequence>                                                         \
> > +      <sequence>                                                       \
> > +        <uuid value=\"0x1104\"/>                                       \
> > +        <uint16 value=\"0x0100\" name=\"version\"/>                    \
> > +      </sequence>                                                      \
> > +    </sequence>                                                                \
> > +  </attribute>                                                         \
> > +                                                                       \
> > +  <attribute id=\"0x0100\">                                            \
> > +    <text value=\"%s\" name=\"name\"/>                                 \
> > +  </attribute>                                                         \
> > +                                                                       \
> > +  <attribute id=\"0x0301\">                                            \
> > +    <sequence>                                                         \
> > +      <uint8 value=\"0x01\"/>                                          \
> > +    </sequence>                                                                \
> > +  </attribute>                                                         \
> > +</record>"
> > +
> > +
> > +struct aparam_header {
> > +       uint8_t tag;
> > +       uint8_t len;
> > +       uint8_t val[0];
> > +} __attribute__ ((packed));
> > +
> > +#define DIDLEN 18
> > +struct irmc_session {
> > +       struct obex_session *os;
> > +       struct apparam_field *params;
> > +       uint16_t entries;
> > +       GString *buffer;
> > +       char sn[DIDLEN];
> > +       char did[DIDLEN];
> > +       char manu[DIDLEN];
> > +       char model[DIDLEN];
> > +};
> > +
> > +#define IRMC_TARGET_SIZE 9
> > +
> > +static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
> > +                       0x49, 0x52, 0x4d, 0x43,  0x2d, 0x53, 0x59, 0x4e, 0x43 };
> > +
> > +static void phonebook_size_result(const char *buffer, size_t bufsize,
> > +                               int vcards, int missed, void *user_data)
> > +{
> > +       struct irmc_session *irmc = user_data;
> > +
> > +       DBG("vcards %d", vcards);
> > +
> > +       irmc->params->maxlistcount = vcards;
> > +}
> > +
> > +static void query_result(const char *buffer, size_t bufsize, int vcards,
> > +                                       int missed, void *user_data)
> > +{
> > +       struct irmc_session *irmc = user_data;
> > +       const char *s;
> > +       char *t;
> > +
> > +       DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
> > +
> > +       // first create an empty 'owner' vcard
> > +       t = "BEGIN:VCARD\r\n"
> > +               "VERSION:2.1\r\n"
> > +               "N:\r\n"
> > +               "TEL:\r\n"
> > +               "X-IRMX-LUID:0\r\n"
> > +               "END:VCARDi\r\n";
> > +       if (!irmc->buffer)
> > +               irmc->buffer = g_string_new_len(t, strlen(t));
> > +       else
> > +               irmc->buffer = g_string_append_len(irmc->buffer, t, strlen(t));
> > +
> > +       // loop around buffer and add X-IRMC-LUID attribs
> > +       s = buffer;
> > +       while ((t = strstr(s, "UID:")) != NULL) {
> > +               // add upto UID: into buffer
> > +               irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > +               // add UID: line into buffer
> > +               // Not sure if UID is still needed if X-IRMC-LUID is there
> > +               s = t;
> > +               t = strstr(s, "\r\n");
> > +               t += 2;
> > +               irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > +               // add X-IRMC-LUID with same number as UID
> > +               irmc->buffer = g_string_append_len(irmc->buffer,
> > +                                                       "X-IRMC-LUID:", 12);
> > +               s += 4; // point to uid number
> > +               irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > +               s = t;
> > +       }
> > +       // add remaining bit of buffer
> > +       irmc->buffer = g_string_append_len(irmc->buffer, s,
> > +                                                       bufsize - (s-buffer));
> > +
> > +       obex_object_set_io_flags(irmc, G_IO_IN, 0);
> > +}
> > +
> > +static void *irmc_connect(struct obex_session *os, int *err)
> > +{
> > +       struct irmc_session *irmc;
> > +       struct apparam_field *param;
> > +
> > +       DBG("");
> > +
> > +       manager_register_session(os);
> > +
> > +       irmc = g_new0(struct irmc_session, 1);
> > +       irmc->os = os;
> > +
> > +       /*
> > +        * ideally get capabilities info here and use that to define
> > +        * IrMC DID and SN etc parameters.
> > +        * For now lets used hostname and some 'random' value
> > +        */
> > +       gethostname(irmc->did, DIDLEN);
> > +       strncpy(irmc->sn, "12345", DIDLEN);
> > +       strncpy(irmc->manu, "obex", DIDLEN);
> > +       strncpy(irmc->model, "mymodel", DIDLEN);
> > +
> > +       /*
> > +         *  we need to know the number of contact/cal/nt entries
> > +         *  somewhere so why not do it now.
> > +         */
> > +       param = g_new0(struct apparam_field, 1);
> > +       param->maxlistcount = 0; // to count the number of vcards...
> > +       param->filter = 0x200085; // UID TEL N VERSION
> > +       irmc->params = param;
> > +       phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
> > +                                                                       irmc);
> > +
> > +       if (err)
> > +               *err = 0;
> > +
> > +       return irmc;
> > +}
> > +
> > +static int irmc_get(struct obex_session *os, obex_object_t *obj,
> > +               gboolean *stream, void *user_data)
> > +{
> > +       struct irmc_session *irmc = user_data;
> > +       const char *type = obex_get_type(os);
> > +       const char *name = obex_get_name(os);
> > +       char *path;
> > +       int ret;
> > +
> > +       DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
> > +
> > +       path = g_strdup(name);
> > +       *stream = TRUE;
> > +
> > +       ret = obex_get_stream_start(os, path);
> > +
> > +       g_free(path);
> > +
> > +       return ret;
> > +}
> > +
> > +static void irmc_disconnect(struct obex_session *os, void *user_data)
> > +{
> > +       struct irmc_session *irmc = user_data;
> > +
> > +       DBG("");
> > +
> > +       manager_unregister_session(os);
> > +
> > +        if (irmc->params) {
> > +                if (irmc->params->searchval)
> > +                       g_free(irmc->params->searchval);
> > +                g_free(irmc->params);
> > +        }
> > +       if (irmc->buffer) {
> > +               string_free(irmc->buffer);
> > +               irmc->buffer = NULL;
> > +       }
> > +
> > +       g_free(irmc);
> > +}
> > +
> > +static int irmc_chkput(struct obex_session *os, void *user_data)
> > +{
> > +       DBG("");
> > +       /* Reject all PUTs */
> > +       return -EBADR;
> > +}
> > +
> > +static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
> > +{
> > +       char mybuf[1024];
> > +
> > +       sprintf(mybuf, "MANU:%s\r\n"
> > +                       "MOD:%s\r\n"
> > +                       "SN:%s\r\n"
> > +                       "PB-TYPE-TX:VCARD2.1\r\n",
> > +                       irmc->manu, irmc->model, irmc->sn);
> > +
> > +       if (!irmc->buffer)
> > +               irmc->buffer = g_string_new(mybuf);
> > +       else
> > +               irmc->buffer = g_string_append(irmc->buffer, mybuf);
> > +
> > +       return irmc;
> > +}
> > +
> > +static void *irmc_open_pb(const char *name,
> > +                struct irmc_session *irmc, int *err)
> > +{
> > +       char mybuf[1024];
> > +       int ret;
> > +
> > +       if (!g_strcmp0(name, ".vcf")) {
> > +               // how can we tell if the vcard count call already finished?
> > +               ret = phonebook_pull("telecom/pb.vcf", irmc->params,
> > +                                                       query_result, irmc);
> > +               if (ret < 0) {
> > +                       DBG("phonebook_pull failed...");
> > +                       goto fail;
> > +               }
> > +               return irmc;
> > +       }
> > +
> > +       if (!g_strcmp0(name, "/info.log")) {
> > +               sprintf(mybuf, "Total-Records:%d\r\n"
> > +                               "Maximum-Records:%d\r\n"
> > +                               "DID:%s\r\n",
> > +                               irmc->params->maxlistcount,
> > +                               irmc->params->maxlistcount, irmc->did);
> > +       }
> > +       else if (!strncmp(name, "/luid/", 6)) {
> > +               name += 6;
> > +               if (!g_strcmp0(name, "cc.log"))
> > +                       sprintf(mybuf, "%d\r\n", irmc->params->maxlistcount);
> > +               else {
> > +                       int l = strlen(name);
> > +                       /* FIXME
> > +                        * reply the same to any *.log so we hopefully force a
> > +                        * full phonebook dump.
> > +                        * Is IEL:2 ok?
> > +                        */
> > +                       if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
> > +                               DBG("changelog request, force whole book");
> > +                               sprintf(mybuf, "SN:%s\r\n"
> > +                                               "IEL:2\r\n"
> > +                                               "DID:%s\r\n"
> > +                                               "Total-Records:%d\r\n"
> > +                                               "Maximum-Records:%d\r\n"
> > +                                               "*\r\n",
> > +                                       irmc->sn, irmc->did,
> > +                                       irmc->params->maxlistcount,
> > +                                       irmc->params->maxlistcount);
> > +                       }
> > +                       else {
> > +                               ret = -EBADR;
> > +                               goto fail;
> > +                       }
> > +               }
> > +       }
> > +       else {
> > +               ret = -EBADR;
> > +               goto fail;
> > +       }
> > +
> > +       if (!irmc->buffer)
> > +               irmc->buffer = g_string_new(mybuf);
> > +       else
> > +               irmc->buffer = g_string_append(irmc->buffer, mybuf);
> > +
> > +       return irmc;
> > +
> > +fail:
> > +       if (err)
> > +               *err = ret;
> > +
> > +       return NULL;
> > +}
> > +
> > +static void *irmc_open_cal(const char *name,
> > +                struct irmc_session *irmc, int *err)
> > +{
> > +       // no suport yet. Just return an empty buffer
> > +       //cal.vcs
> > +       DBG("unsupported, returning empty buffer");
> > +       if (!irmc->buffer)
> > +               irmc->buffer = g_string_new("");
> > +       else
> > +               irmc->buffer = g_string_append(irmc->buffer, "");
> > +
> > +       return irmc;
> > +}
> > +
> > +static void *irmc_open_nt(const char *name,
> > +                struct irmc_session *irmc, int *err)
> > +{
> > +       // no suport yet. Just return an empty buffer
> > +       //nt.vnt
> > +       DBG("unsupported, returning empty buffer");
> > +       if (!irmc->buffer)
> > +               irmc->buffer = g_string_new("");
> > +       else
> > +               irmc->buffer = g_string_append(irmc->buffer, "");
> > +
> > +       return irmc;
> > +}
> > +
> > +static void *irmc_open(const char *name, int oflag, mode_t mode,
> > +               void *context, size_t *size, int *err)
> > +{
> > +       struct irmc_session *irmc = context;
> > +       int ret;
> > +       const char *p;
> > +
> > +       DBG("name %s context %p", name, context);
> > +       if (oflag != O_RDONLY) {
> > +               ret = -EPERM;
> > +               goto fail;
> > +       }
> > +       if (strncmp(name, "telecom/", 8) != NULL) {
> > +               ret = -EBADR;
> > +               goto fail;
> > +       }
> > +
> > +       p = name + 8;
> > +       if (!g_strcmp0(p, "devinfo.txt"))
> > +               return irmc_open_devinfo(irmc, err);
> > +       else if (!strncmp(p, "pb", 2))
> > +               return irmc_open_pb(p+2, irmc, err);
> > +       else if (!strncmp(p, "cal", 3))
> > +               return irmc_open_cal(p+3, irmc, err);
> > +       else if (!strncmp(p, "nt", 2))
> > +               return irmc_open_nt(p+2, irmc, err);
> > +
> > +fail:
> > +       if (err)
> > +               *err = ret;
> > +
> > +       return NULL;
> > +}
> > +
> > +static int irmc_close(void *object)
> > +{
> > +       struct irmc_session *irmc = object;
> > +
> > +       DBG("");
> > +       if (irmc->buffer) {
> > +               string_free(irmc->buffer);
> > +               irmc->buffer = NULL;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi)
> > +{
> > +       struct irmc_session *irmc = object;
> > +        int len;
> > +
> > +       DBG("buffer %p count %d", irmc->buffer, count);
> > +       if (!irmc->buffer)
> > +                return -EAGAIN;
> > +
> > +        *hi = OBEX_HDR_BODY;
> > +       len = string_read(irmc->buffer, buf, count);
> > +       DBG("returning %d bytes", len);
> > +       return len;
> > +}
> > +
> > +static struct obex_mime_type_driver irmc_driver = {
> > +       .target = IRMC_TARGET,
> > +       .target_size = IRMC_TARGET_SIZE,
> > +       .open = irmc_open,
> > +       .close = irmc_close,
> > +       .read = irmc_read,
> > +};
> > +
> > +static struct obex_service_driver irmc = {
> > +       .name = "IRMC Sync server",
> > +       .service = OBEX_IRMC,
> > +       .channel = IRMC_CHANNEL,
> > +       .record = IRMC_RECORD,
> > +       .target = IRMC_TARGET,
> > +       .target_size = IRMC_TARGET_SIZE,
> > +       .connect = irmc_connect,
> > +       .get = irmc_get,
> > +       .disconnect = irmc_disconnect,
> > +       .chkput = irmc_chkput
> > +};
> > +
> > +static int irmc_init(void)
> > +{
> > +       int err;
> > +
> > +       DBG("");
> > +       err = phonebook_init();
> > +       if (err < 0)
> > +               return err;
> > +
> > +       err = obex_mime_type_driver_register(&irmc_driver);
> > +       if (err < 0)
> > +               return err;
> > +
> > +       return obex_service_driver_register(&irmc);
> > +}
> > +
> > +static void irmc_exit(void)
> > +{
> > +       DBG("");
> > +       obex_service_driver_unregister(&irmc);
> > +       obex_mime_type_driver_unregister(&irmc_driver);
> > +       phonebook_exit();
> > +}
> > +
> > +OBEX_PLUGIN_DEFINE(irmc, irmc_init, irmc_exit)
> > diff --git a/src/main.c b/src/main.c
> > index 649acf9..96523a6 100644
> > --- a/src/main.c
> > +++ b/src/main.c
> > @@ -83,6 +83,7 @@ static gboolean option_pbap = FALSE;
> >  static gboolean option_pcsuite = FALSE;
> >  static gboolean option_symlinks = FALSE;
> >  static gboolean option_syncevolution = FALSE;
> > +static gboolean option_irmc = FALSE;
> >
> >  static gboolean parse_debug(const char *key, const char *value,
> >                                gpointer user_data, GError **error)
> > @@ -122,6 +123,8 @@ static GOptionEntry options[] = {
> >                                "Enable PC Suite Services server" },
> >        { "syncevolution", 'e', 0, G_OPTION_ARG_NONE, &option_syncevolution,
> >                                "Enable OBEX server for SyncEvolution" },
> > +       { "irmc", 'i', 0, G_OPTION_ARG_NONE, &option_irmc,
> > +                               "Enable IrMCSync server" },
> >        { NULL },
> >  };
> >
> > @@ -208,9 +211,10 @@ int main(int argc, char *argv[])
> >
> >        if (option_opp == FALSE && option_ftp == FALSE &&
> >                                option_pbap == FALSE &&
> > -                               option_syncevolution == FALSE) {
> > +                               option_syncevolution == FALSE &&
> > +                               option_irmc == FALSE) {
> >                fprintf(stderr, "No server selected (use either "
> > -                               "--opp, --ftp, --pbap or --syncevolution)\n");
> > +                               "--opp, --ftp, --pbap --syncevolution or --irmc)\n");
> >                exit(EXIT_FAILURE);
> >        }
> >
> > @@ -270,6 +274,10 @@ int main(int argc, char *argv[])
> >                obex_server_init(OBEX_SYNCEVOLUTION, NULL, TRUE, FALSE,
> >                                                        FALSE, NULL);
> >
> > +       if (option_irmc == TRUE)
> > +               obex_server_init(OBEX_IRMC, NULL, TRUE, FALSE, FALSE,
> > +                               option_capability);
> > +
> >        if (!root_folder_setup(option_root, option_root_setup)) {
> >                error("Unable to setup root folder %s", option_root);
> >                exit(EXIT_FAILURE);
> > diff --git a/src/obex.h b/src/obex.h
> > index 9424b6b..cfe9159 100644
> > --- a/src/obex.h
> > +++ b/src/obex.h
> > @@ -35,6 +35,7 @@
> >  #define OBEX_PBAP      (1 << 4)
> >  #define OBEX_PCSUITE   (1 << 5)
> >  #define OBEX_SYNCEVOLUTION     (1 << 6)
> > +#define OBEX_IRMC      (1 << 7)
> >
> >  #define TARGET_SIZE 16
> >
> > --
> > 1.7.2
>
> Looks pretty good, but you need to fix those c++ comments (//) please
> use /*,

Fine. will do.

> also the you don't necessary need to abstract the file
> devinfo.txt so platform can just write their own stuff there, if that
> is not sufficient than we can thing of supporting scripts like we do
> with x-obex/capability but I don't think we really need it since the
> device info should be static, right?

abstracting it made de irmc_open() more clean (e.g. no buffer fills in
irmc_open()) and more readable in my opinion.
The specs for devinfo.txt contain many more attributes but the currrent
set seems to be enough. In future this may need to be extended and
supporting scripts may be needed for getting the info. The current
values are actually not correct I think as the will be the same for any
device now... (hence the hint for using x-obex/capabilities in
irmc_connect().)

2010-08-12 11:41:39

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

Hi Marcel,

> A reasonable working IrMC SYNC server (only full phonebook sync support)
> Support for cal and note by just returning nothing.
> ---
> Makefile.am | 3 +
> plugins/irmc.c | 488 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> src/main.c | 12 ++-
> src/obex.h | 1 +
> 4 files changed, 502 insertions(+), 2 deletions(-)
> create mode 100644 plugins/irmc.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 73e2f28..ce8c675 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -58,6 +58,9 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
> builtin_modules += syncevolution
> builtin_sources += plugins/syncevolution.c
>
> +builtin_modules += irmc
> +builtin_sources += plugins/irmc.c plugins/phonebook.h
> +
> builtin_nodist += plugins/phonebook.c
>
> libexec_PROGRAMS += src/obexd
> diff --git a/plugins/irmc.c b/plugins/irmc.c
> new file mode 100644
> index 0000000..96fd807
> --- /dev/null
> +++ b/plugins/irmc.c
> @@ -0,0 +1,488 @@
> +/*
> + *
> + * OBEX IrMC Sync Server
> + *
> + * Copyright (C) 2010 Marcel Mol <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <glib.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <arpa/inet.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +#include <openobex/obex.h>
> +#include <openobex/obex_const.h>
> +
> +#include "plugin.h"
> +#include "log.h"
> +#include "obex.h"
> +#include "service.h"
> +#include "phonebook.h"
> +#include "mimetype.h"
> +#include "filesystem.h"
> +#include "dbus.h"
> +
> +#define IRMC_CHANNEL 17

we did have a list of defined RFCOMM channels for various protocols, but
just don't remember where it is.

Johan, we should put that into the doc/ directory actually. Can you dig
up that list and commit it as text file.

> +
> +#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
> +<record> \
> + <attribute id=\"0x0001\"> \
> + <sequence> \
> + <uuid value=\"0x1104\"/> \
> + </sequence> \
> + </attribute> \
> + \
> + <attribute id=\"0x0004\"> \
> + <sequence> \
> + <sequence> \
> + <uuid value=\"0x0100\"/> \
> + </sequence> \
> + <sequence> \
> + <uuid value=\"0x0003\"/> \
> + <uint8 value=\"%u\" name=\"channel\"/> \
> + </sequence> \
> + <sequence> \
> + <uuid value=\"0x0008\"/> \
> + </sequence> \
> + </sequence> \
> + </attribute> \
> + \
> + <attribute id=\"0x0009\"> \
> + <sequence> \
> + <sequence> \
> + <uuid value=\"0x1104\"/> \
> + <uint16 value=\"0x0100\" name=\"version\"/> \
> + </sequence> \
> + </sequence> \
> + </attribute> \
> + \
> + <attribute id=\"0x0100\"> \
> + <text value=\"%s\" name=\"name\"/> \
> + </attribute> \
> + \
> + <attribute id=\"0x0301\"> \
> + <sequence> \
> + <uint8 value=\"0x01\"/> \
> + </sequence> \
> + </attribute> \
> +</record>"
> +
> +
> +struct aparam_header {
> + uint8_t tag;
> + uint8_t len;
> + uint8_t val[0];
> +} __attribute__ ((packed));
> +
> +#define DIDLEN 18
> +struct irmc_session {
> + struct obex_session *os;
> + struct apparam_field *params;
> + uint16_t entries;
> + GString *buffer;
> + char sn[DIDLEN];
> + char did[DIDLEN];
> + char manu[DIDLEN];
> + char model[DIDLEN];
> +};

What is DIDLEN.

> +
> +#define IRMC_TARGET_SIZE 9
> +
> +static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
> + 0x49, 0x52, 0x4d, 0x43, 0x2d, 0x53, 0x59, 0x4e, 0x43 };
> +
> +static void phonebook_size_result(const char *buffer, size_t bufsize,
> + int vcards, int missed, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> +
> + DBG("vcards %d", vcards);
> +
> + irmc->params->maxlistcount = vcards;
> +}
> +
> +static void query_result(const char *buffer, size_t bufsize, int vcards,
> + int missed, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> + const char *s;
> + char *t;
> +
> + DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
> +
> + // first create an empty 'owner' vcard

As Luiz already mentioned, please use /* */ style comments.

> + t = "BEGIN:VCARD\r\n"
> + "VERSION:2.1\r\n"
> + "N:\r\n"
> + "TEL:\r\n"
> + "X-IRMX-LUID:0\r\n"
> + "END:VCARDi\r\n";

You really wanna use const char *t here. And I would even prefer if you
make that one static and global.

> + if (!irmc->buffer)
> + irmc->buffer = g_string_new_len(t, strlen(t));
> + else
> + irmc->buffer = g_string_append_len(irmc->buffer, t, strlen(t));

Why the string_append_len. Just append it it.

> + // loop around buffer and add X-IRMC-LUID attribs
> + s = buffer;
> + while ((t = strstr(s, "UID:")) != NULL) {
> + // add upto UID: into buffer
> + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + // add UID: line into buffer
> + // Not sure if UID is still needed if X-IRMC-LUID is there
> + s = t;
> + t = strstr(s, "\r\n");
> + t += 2;
> + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + // add X-IRMC-LUID with same number as UID
> + irmc->buffer = g_string_append_len(irmc->buffer,
> + "X-IRMC-LUID:", 12);
> + s += 4; // point to uid number
> + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + s = t;
> + }
> + // add remaining bit of buffer
> + irmc->buffer = g_string_append_len(irmc->buffer, s,
> + bufsize - (s-buffer));
> +
> + obex_object_set_io_flags(irmc, G_IO_IN, 0);
> +}
> +
> +static void *irmc_connect(struct obex_session *os, int *err)
> +{
> + struct irmc_session *irmc;
> + struct apparam_field *param;
> +
> + DBG("");
> +
> + manager_register_session(os);
> +
> + irmc = g_new0(struct irmc_session, 1);
> + irmc->os = os;
> +
> + /*
> + * ideally get capabilities info here and use that to define
> + * IrMC DID and SN etc parameters.
> + * For now lets used hostname and some 'random' value
> + */
> + gethostname(irmc->did, DIDLEN);
> + strncpy(irmc->sn, "12345", DIDLEN);
> + strncpy(irmc->manu, "obex", DIDLEN);
> + strncpy(irmc->model, "mymodel", DIDLEN);
> +
> + /*
> + * we need to know the number of contact/cal/nt entries
> + * somewhere so why not do it now.
> + */
> + param = g_new0(struct apparam_field, 1);
> + param->maxlistcount = 0; // to count the number of vcards...
> + param->filter = 0x200085; // UID TEL N VERSION
> + irmc->params = param;
> + phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
> + irmc);
> +
> + if (err)
> + *err = 0;
> +
> + return irmc;
> +}
> +
> +static int irmc_get(struct obex_session *os, obex_object_t *obj,
> + gboolean *stream, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> + const char *type = obex_get_type(os);
> + const char *name = obex_get_name(os);
> + char *path;
> + int ret;
> +
> + DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
> +
> + path = g_strdup(name);
> + *stream = TRUE;
> +
> + ret = obex_get_stream_start(os, path);
> +
> + g_free(path);
> +
> + return ret;
> +}
> +
> +static void irmc_disconnect(struct obex_session *os, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> +
> + DBG("");
> +
> + manager_unregister_session(os);
> +
> + if (irmc->params) {
> + if (irmc->params->searchval)
> + g_free(irmc->params->searchval);
> + g_free(irmc->params);
> + }
> + if (irmc->buffer) {
> + string_free(irmc->buffer);
> + irmc->buffer = NULL;
> + }
> +
> + g_free(irmc);
> +}
> +
> +static int irmc_chkput(struct obex_session *os, void *user_data)
> +{
> + DBG("");
> + /* Reject all PUTs */
> + return -EBADR;
> +}
> +
> +static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
> +{
> + char mybuf[1024];
> +
> + sprintf(mybuf, "MANU:%s\r\n"
> + "MOD:%s\r\n"
> + "SN:%s\r\n"
> + "PB-TYPE-TX:VCARD2.1\r\n",
> + irmc->manu, irmc->model, irmc->sn);
> +
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new(mybuf);
> + else
> + irmc->buffer = g_string_append(irmc->buffer, mybuf);

We have something that is called g_string_append_printf(). Use that one
and not allocate a buf up-front.

> +
> + return irmc;
> +}
> +
> +static void *irmc_open_pb(const char *name,
> + struct irmc_session *irmc, int *err)
> +{
> + char mybuf[1024];
> + int ret;
> +
> + if (!g_strcmp0(name, ".vcf")) {
> + // how can we tell if the vcard count call already finished?
> + ret = phonebook_pull("telecom/pb.vcf", irmc->params,
> + query_result, irmc);
> + if (ret < 0) {
> + DBG("phonebook_pull failed...");
> + goto fail;
> + }
> + return irmc;
> + }
> +
> + if (!g_strcmp0(name, "/info.log")) {
> + sprintf(mybuf, "Total-Records:%d\r\n"
> + "Maximum-Records:%d\r\n"
> + "DID:%s\r\n",
> + irmc->params->maxlistcount,
> + irmc->params->maxlistcount, irmc->did);
> + }

Same here. A GLib _printf() function is way better usage.

> + else if (!strncmp(name, "/luid/", 6)) {
> + name += 6;
> + if (!g_strcmp0(name, "cc.log"))
> + sprintf(mybuf, "%d\r\n", irmc->params->maxlistcount);
> + else {
> + int l = strlen(name);
> + /* FIXME
> + * reply the same to any *.log so we hopefully force a
> + * full phonebook dump.
> + * Is IEL:2 ok?
> + */
> + if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
> + DBG("changelog request, force whole book");
> + sprintf(mybuf, "SN:%s\r\n"
> + "IEL:2\r\n"
> + "DID:%s\r\n"
> + "Total-Records:%d\r\n"
> + "Maximum-Records:%d\r\n"
> + "*\r\n",
> + irmc->sn, irmc->did,
> + irmc->params->maxlistcount,
> + irmc->params->maxlistcount);
> + }
> + else {
> + ret = -EBADR;
> + goto fail;
> + }
> + }
> + }
> + else {
> + ret = -EBADR;
> + goto fail;
> + }
> +
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new(mybuf);
> + else
> + irmc->buffer = g_string_append(irmc->buffer, mybuf);
> +
> + return irmc;
> +
> +fail:
> + if (err)
> + *err = ret;
> +
> + return NULL;
> +}
> +
> +static void *irmc_open_cal(const char *name,
> + struct irmc_session *irmc, int *err)
> +{
> + // no suport yet. Just return an empty buffer
> + //cal.vcs
> + DBG("unsupported, returning empty buffer");
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new("");
> + else
> + irmc->buffer = g_string_append(irmc->buffer, "");
> +
> + return irmc;

Empty buffer is empty buffer. Just return it.

> +}
> +
> +static void *irmc_open_nt(const char *name,
> + struct irmc_session *irmc, int *err)
> +{
> + // no suport yet. Just return an empty buffer
> + //nt.vnt
> + DBG("unsupported, returning empty buffer");
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new("");
> + else
> + irmc->buffer = g_string_append(irmc->buffer, "");
> +
> + return irmc;

Same here.

> +}
> +
> +static void *irmc_open(const char *name, int oflag, mode_t mode,
> + void *context, size_t *size, int *err)
> +{
> + struct irmc_session *irmc = context;
> + int ret;
> + const char *p;
> +
> + DBG("name %s context %p", name, context);
> + if (oflag != O_RDONLY) {
> + ret = -EPERM;
> + goto fail;
> + }
> + if (strncmp(name, "telecom/", 8) != NULL) {
> + ret = -EBADR;
> + goto fail;
> + }
> +
> + p = name + 8;
> + if (!g_strcmp0(p, "devinfo.txt"))
> + return irmc_open_devinfo(irmc, err);
> + else if (!strncmp(p, "pb", 2))
> + return irmc_open_pb(p+2, irmc, err);
> + else if (!strncmp(p, "cal", 3))
> + return irmc_open_cal(p+3, irmc, err);
> + else if (!strncmp(p, "nt", 2))
> + return irmc_open_nt(p+2, irmc, err);
> +
> +fail:
> + if (err)
> + *err = ret;
> +
> + return NULL;
> +}
> +
> +static int irmc_close(void *object)
> +{
> + struct irmc_session *irmc = object;
> +
> + DBG("");
> + if (irmc->buffer) {
> + string_free(irmc->buffer);
> + irmc->buffer = NULL;
> + }
> +
> + return 0;
> +}
> +
> +static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi)
> +{
> + struct irmc_session *irmc = object;
> + int len;
> +
> + DBG("buffer %p count %d", irmc->buffer, count);
> + if (!irmc->buffer)
> + return -EAGAIN;
> +
> + *hi = OBEX_HDR_BODY;
> + len = string_read(irmc->buffer, buf, count);
> + DBG("returning %d bytes", len);
> + return len;
> +}
> +
> +static struct obex_mime_type_driver irmc_driver = {
> + .target = IRMC_TARGET,
> + .target_size = IRMC_TARGET_SIZE,
> + .open = irmc_open,
> + .close = irmc_close,
> + .read = irmc_read,
> +};
> +
> +static struct obex_service_driver irmc = {
> + .name = "IRMC Sync server",
> + .service = OBEX_IRMC,
> + .channel = IRMC_CHANNEL,
> + .record = IRMC_RECORD,
> + .target = IRMC_TARGET,
> + .target_size = IRMC_TARGET_SIZE,
> + .connect = irmc_connect,
> + .get = irmc_get,
> + .disconnect = irmc_disconnect,
> + .chkput = irmc_chkput
> +};
> +
> +static int irmc_init(void)
> +{
> + int err;
> +
> + DBG("");
> + err = phonebook_init();
> + if (err < 0)
> + return err;
> +
> + err = obex_mime_type_driver_register(&irmc_driver);
> + if (err < 0)
> + return err;

Don't you need to phonebook_exit() here?

> +
> + return obex_service_driver_register(&irmc);
> +}

Also what happens if this one fails. You do need to clean up.

> +
> +static void irmc_exit(void)
> +{
> + DBG("");
> + obex_service_driver_unregister(&irmc);
> + obex_mime_type_driver_unregister(&irmc_driver);
> + phonebook_exit();
> +}
> +
> +OBEX_PLUGIN_DEFINE(irmc, irmc_init, irmc_exit)
> diff --git a/src/main.c b/src/main.c
> index 649acf9..96523a6 100644
> --- a/src/main.c
> +++ b/src/main.c
> @@ -83,6 +83,7 @@ static gboolean option_pbap = FALSE;
> static gboolean option_pcsuite = FALSE;
> static gboolean option_symlinks = FALSE;
> static gboolean option_syncevolution = FALSE;
> +static gboolean option_irmc = FALSE;
>
> static gboolean parse_debug(const char *key, const char *value,
> gpointer user_data, GError **error)
> @@ -122,6 +123,8 @@ static GOptionEntry options[] = {
> "Enable PC Suite Services server" },
> { "syncevolution", 'e', 0, G_OPTION_ARG_NONE, &option_syncevolution,
> "Enable OBEX server for SyncEvolution" },
> + { "irmc", 'i', 0, G_OPTION_ARG_NONE, &option_irmc,
> + "Enable IrMCSync server" },
> { NULL },
> };

Just put irmc before syncevolution. Like nicer ;)

>
> @@ -208,9 +211,10 @@ int main(int argc, char *argv[])
>
> if (option_opp == FALSE && option_ftp == FALSE &&
> option_pbap == FALSE &&
> - option_syncevolution == FALSE) {
> + option_syncevolution == FALSE &&
> + option_irmc == FALSE) {
> fprintf(stderr, "No server selected (use either "
> - "--opp, --ftp, --pbap or --syncevolution)\n");
> + "--opp, --ftp, --pbap --syncevolution or --irmc)\n");
> exit(EXIT_FAILURE);
> }

Same here. Leave syncevolution at the end.

>
> @@ -270,6 +274,10 @@ int main(int argc, char *argv[])
> obex_server_init(OBEX_SYNCEVOLUTION, NULL, TRUE, FALSE,
> FALSE, NULL);
>
> + if (option_irmc == TRUE)
> + obex_server_init(OBEX_IRMC, NULL, TRUE, FALSE, FALSE,
> + option_capability);
> +

And here again.

> if (!root_folder_setup(option_root, option_root_setup)) {
> error("Unable to setup root folder %s", option_root);
> exit(EXIT_FAILURE);
> diff --git a/src/obex.h b/src/obex.h
> index 9424b6b..cfe9159 100644
> --- a/src/obex.h
> +++ b/src/obex.h
> @@ -35,6 +35,7 @@
> #define OBEX_PBAP (1 << 4)
> #define OBEX_PCSUITE (1 << 5)
> #define OBEX_SYNCEVOLUTION (1 << 6)
> +#define OBEX_IRMC (1 << 7)
>

And here as well. Just use 1 << 6 for IRMC and move SYNCEVO to 1 << 7.

> #define TARGET_SIZE 16
>

Regards

Marcel



2010-08-12 11:16:30

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH] IrMC sync server support

Hi Marcel,

On Tue, Jul 27, 2010 at 8:04 PM, Marcel Mol <[email protected]> wrote:
> A reasonable working IrMC SYNC server (only full phonebook sync support)
> Support for cal and note by just returning nothing.
> ---
> ?Makefile.am ? ?| ? ?3 +
> ?plugins/irmc.c | ?488 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ?src/main.c ? ? | ? 12 ++-
> ?src/obex.h ? ? | ? ?1 +
> ?4 files changed, 502 insertions(+), 2 deletions(-)
> ?create mode 100644 plugins/irmc.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 73e2f28..ce8c675 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -58,6 +58,9 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
> ?builtin_modules += syncevolution
> ?builtin_sources += plugins/syncevolution.c
>
> +builtin_modules += irmc
> +builtin_sources += plugins/irmc.c plugins/phonebook.h
> +
> ?builtin_nodist += plugins/phonebook.c
>
> ?libexec_PROGRAMS += src/obexd
> diff --git a/plugins/irmc.c b/plugins/irmc.c
> new file mode 100644
> index 0000000..96fd807
> --- /dev/null
> +++ b/plugins/irmc.c
> @@ -0,0 +1,488 @@
> +/*
> + *
> + * ?OBEX IrMC Sync Server
> + *
> + * ?Copyright (C) 2010 ?Marcel Mol <[email protected]>
> + *
> + * ?This program is free software; you can redistribute it and/or modify
> + * ?it under the terms of the GNU General Public License as published by
> + * ?the Free Software Foundation; either version 2 of the License, or
> + * ?(at your option) any later version.
> + *
> + * ?This program is distributed in the hope that it will be useful,
> + * ?but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * ?MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * ?GNU General Public License for more details.
> + *
> + * ?You should have received a copy of the GNU General Public License
> + * ?along with this program; if not, write to the Free Software
> + * ?Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ?02110-1301 ?USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <glib.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <arpa/inet.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +#include <openobex/obex.h>
> +#include <openobex/obex_const.h>
> +
> +#include "plugin.h"
> +#include "log.h"
> +#include "obex.h"
> +#include "service.h"
> +#include "phonebook.h"
> +#include "mimetype.h"
> +#include "filesystem.h"
> +#include "dbus.h"
> +
> +#define IRMC_CHANNEL ? 17
> +
> +#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> ? ? ? \
> +<record> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ?<attribute id=\"0x0001\"> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?<sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ?<uuid value=\"0x1104\"/> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?</sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ?</attribute> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ?<attribute id=\"0x0004\"> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?<sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ?<sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ?<uuid value=\"0x0100\"/> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ?</sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ? ?<sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ?<uuid value=\"0x0003\"/> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ?<uint8 value=\"%u\" name=\"channel\"/> ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ?</sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ? ?<sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ?<uuid value=\"0x0008\"/> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ?</sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?</sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ?</attribute> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ?<attribute id=\"0x0009\"> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?<sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ?<sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ?<uuid value=\"0x1104\"/> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ?<uint16 value=\"0x0100\" name=\"version\"/> ? ? ? ? ? ? ? ? ? ?\
> + ? ? ?</sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?</sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ?</attribute> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ?<attribute id=\"0x0100\"> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?<text value=\"%s\" name=\"name\"/> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ?</attribute> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ?<attribute id=\"0x0301\"> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?<sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ?<uint8 value=\"0x01\"/> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?</sequence> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ?</attribute> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> +</record>"
> +
> +
> +struct aparam_header {
> + ? ? ? uint8_t tag;
> + ? ? ? uint8_t len;
> + ? ? ? uint8_t val[0];
> +} __attribute__ ((packed));
> +
> +#define DIDLEN 18
> +struct irmc_session {
> + ? ? ? struct obex_session *os;
> + ? ? ? struct apparam_field *params;
> + ? ? ? uint16_t entries;
> + ? ? ? GString *buffer;
> + ? ? ? char sn[DIDLEN];
> + ? ? ? char did[DIDLEN];
> + ? ? ? char manu[DIDLEN];
> + ? ? ? char model[DIDLEN];
> +};
> +
> +#define IRMC_TARGET_SIZE 9
> +
> +static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
> + ? ? ? ? ? ? ? ? ? ? ? 0x49, 0x52, 0x4d, 0x43, ?0x2d, 0x53, 0x59, 0x4e, 0x43 };
> +
> +static void phonebook_size_result(const char *buffer, size_t bufsize,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int vcards, int missed, void *user_data)
> +{
> + ? ? ? struct irmc_session *irmc = user_data;
> +
> + ? ? ? DBG("vcards %d", vcards);
> +
> + ? ? ? irmc->params->maxlistcount = vcards;
> +}
> +
> +static void query_result(const char *buffer, size_t bufsize, int vcards,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int missed, void *user_data)
> +{
> + ? ? ? struct irmc_session *irmc = user_data;
> + ? ? ? const char *s;
> + ? ? ? char *t;
> +
> + ? ? ? DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
> +
> + ? ? ? // first create an empty 'owner' vcard
> + ? ? ? t = "BEGIN:VCARD\r\n"
> + ? ? ? ? ? ? ? "VERSION:2.1\r\n"
> + ? ? ? ? ? ? ? "N:\r\n"
> + ? ? ? ? ? ? ? "TEL:\r\n"
> + ? ? ? ? ? ? ? "X-IRMX-LUID:0\r\n"
> + ? ? ? ? ? ? ? "END:VCARDi\r\n";
> + ? ? ? if (!irmc->buffer)
> + ? ? ? ? ? ? ? irmc->buffer = g_string_new_len(t, strlen(t));
> + ? ? ? else
> + ? ? ? ? ? ? ? irmc->buffer = g_string_append_len(irmc->buffer, t, strlen(t));
> +
> + ? ? ? // loop around buffer and add X-IRMC-LUID attribs
> + ? ? ? s = buffer;
> + ? ? ? while ((t = strstr(s, "UID:")) != NULL) {
> + ? ? ? ? ? ? ? // add upto UID: into buffer
> + ? ? ? ? ? ? ? irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + ? ? ? ? ? ? ? // add UID: line into buffer
> + ? ? ? ? ? ? ? // Not sure if UID is still needed if X-IRMC-LUID is there
> + ? ? ? ? ? ? ? s = t;
> + ? ? ? ? ? ? ? t = strstr(s, "\r\n");
> + ? ? ? ? ? ? ? t += 2;
> + ? ? ? ? ? ? ? irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + ? ? ? ? ? ? ? // add X-IRMC-LUID with same number as UID
> + ? ? ? ? ? ? ? irmc->buffer = g_string_append_len(irmc->buffer,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "X-IRMC-LUID:", 12);
> + ? ? ? ? ? ? ? s += 4; // point to uid number
> + ? ? ? ? ? ? ? irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + ? ? ? ? ? ? ? s = t;
> + ? ? ? }
> + ? ? ? // add remaining bit of buffer
> + ? ? ? irmc->buffer = g_string_append_len(irmc->buffer, s,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bufsize - (s-buffer));
> +
> + ? ? ? obex_object_set_io_flags(irmc, G_IO_IN, 0);
> +}
> +
> +static void *irmc_connect(struct obex_session *os, int *err)
> +{
> + ? ? ? struct irmc_session *irmc;
> + ? ? ? struct apparam_field *param;
> +
> + ? ? ? DBG("");
> +
> + ? ? ? manager_register_session(os);
> +
> + ? ? ? irmc = g_new0(struct irmc_session, 1);
> + ? ? ? irmc->os = os;
> +
> + ? ? ? /*
> + ? ? ? ?* ideally get capabilities info here and use that to define
> + ? ? ? ?* IrMC DID and SN etc parameters.
> + ? ? ? ?* For now lets used hostname and some 'random' value
> + ? ? ? ?*/
> + ? ? ? gethostname(irmc->did, DIDLEN);
> + ? ? ? strncpy(irmc->sn, "12345", DIDLEN);
> + ? ? ? strncpy(irmc->manu, "obex", DIDLEN);
> + ? ? ? strncpy(irmc->model, "mymodel", DIDLEN);
> +
> + ? ? ? /*
> + ? ? ? ? * ?we need to know the number of contact/cal/nt entries
> + ? ? ? ? * ?somewhere so why not do it now.
> + ? ? ? ? */
> + ? ? ? param = g_new0(struct apparam_field, 1);
> + ? ? ? param->maxlistcount = 0; // to count the number of vcards...
> + ? ? ? param->filter = 0x200085; // UID TEL N VERSION
> + ? ? ? irmc->params = param;
> + ? ? ? phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? irmc);
> +
> + ? ? ? if (err)
> + ? ? ? ? ? ? ? *err = 0;
> +
> + ? ? ? return irmc;
> +}
> +
> +static int irmc_get(struct obex_session *os, obex_object_t *obj,
> + ? ? ? ? ? ? ? gboolean *stream, void *user_data)
> +{
> + ? ? ? struct irmc_session *irmc = user_data;
> + ? ? ? const char *type = obex_get_type(os);
> + ? ? ? const char *name = obex_get_name(os);
> + ? ? ? char *path;
> + ? ? ? int ret;
> +
> + ? ? ? DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
> +
> + ? ? ? path = g_strdup(name);
> + ? ? ? *stream = TRUE;
> +
> + ? ? ? ret = obex_get_stream_start(os, path);
> +
> + ? ? ? g_free(path);
> +
> + ? ? ? return ret;
> +}
> +
> +static void irmc_disconnect(struct obex_session *os, void *user_data)
> +{
> + ? ? ? struct irmc_session *irmc = user_data;
> +
> + ? ? ? DBG("");
> +
> + ? ? ? manager_unregister_session(os);
> +
> + ? ? ? ?if (irmc->params) {
> + ? ? ? ? ? ? ? ?if (irmc->params->searchval)
> + ? ? ? ? ? ? ? ? ? ? ? g_free(irmc->params->searchval);
> + ? ? ? ? ? ? ? ?g_free(irmc->params);
> + ? ? ? ?}
> + ? ? ? if (irmc->buffer) {
> + ? ? ? ? ? ? ? string_free(irmc->buffer);
> + ? ? ? ? ? ? ? irmc->buffer = NULL;
> + ? ? ? }
> +
> + ? ? ? g_free(irmc);
> +}
> +
> +static int irmc_chkput(struct obex_session *os, void *user_data)
> +{
> + ? ? ? DBG("");
> + ? ? ? /* Reject all PUTs */
> + ? ? ? return -EBADR;
> +}
> +
> +static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
> +{
> + ? ? ? char mybuf[1024];
> +
> + ? ? ? sprintf(mybuf, "MANU:%s\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? "MOD:%s\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? "SN:%s\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? "PB-TYPE-TX:VCARD2.1\r\n",
> + ? ? ? ? ? ? ? ? ? ? ? irmc->manu, irmc->model, irmc->sn);
> +
> + ? ? ? if (!irmc->buffer)
> + ? ? ? ? ? ? ? irmc->buffer = g_string_new(mybuf);
> + ? ? ? else
> + ? ? ? ? ? ? ? irmc->buffer = g_string_append(irmc->buffer, mybuf);
> +
> + ? ? ? return irmc;
> +}
> +
> +static void *irmc_open_pb(const char *name,
> + ? ? ? ? ? ? ? ?struct irmc_session *irmc, int *err)
> +{
> + ? ? ? char mybuf[1024];
> + ? ? ? int ret;
> +
> + ? ? ? if (!g_strcmp0(name, ".vcf")) {
> + ? ? ? ? ? ? ? // how can we tell if the vcard count call already finished?
> + ? ? ? ? ? ? ? ret = phonebook_pull("telecom/pb.vcf", irmc->params,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? query_result, irmc);
> + ? ? ? ? ? ? ? if (ret < 0) {
> + ? ? ? ? ? ? ? ? ? ? ? DBG("phonebook_pull failed...");
> + ? ? ? ? ? ? ? ? ? ? ? goto fail;
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? return irmc;
> + ? ? ? }
> +
> + ? ? ? if (!g_strcmp0(name, "/info.log")) {
> + ? ? ? ? ? ? ? sprintf(mybuf, "Total-Records:%d\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Maximum-Records:%d\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "DID:%s\r\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? irmc->params->maxlistcount,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? irmc->params->maxlistcount, irmc->did);
> + ? ? ? }
> + ? ? ? else if (!strncmp(name, "/luid/", 6)) {
> + ? ? ? ? ? ? ? name += 6;
> + ? ? ? ? ? ? ? if (!g_strcmp0(name, "cc.log"))
> + ? ? ? ? ? ? ? ? ? ? ? sprintf(mybuf, "%d\r\n", irmc->params->maxlistcount);
> + ? ? ? ? ? ? ? else {
> + ? ? ? ? ? ? ? ? ? ? ? int l = strlen(name);
> + ? ? ? ? ? ? ? ? ? ? ? /* FIXME
> + ? ? ? ? ? ? ? ? ? ? ? ?* reply the same to any *.log so we hopefully force a
> + ? ? ? ? ? ? ? ? ? ? ? ?* full phonebook dump.
> + ? ? ? ? ? ? ? ? ? ? ? ?* Is IEL:2 ok?
> + ? ? ? ? ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? ? ? ? ? if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DBG("changelog request, force whole book");
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sprintf(mybuf, "SN:%s\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "IEL:2\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "DID:%s\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Total-Records:%d\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Maximum-Records:%d\r\n"
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "*\r\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? irmc->sn, irmc->did,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? irmc->params->maxlistcount,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? irmc->params->maxlistcount);
> + ? ? ? ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? ? ? ? ? else {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret = -EBADR;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goto fail;
> + ? ? ? ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> + ? ? ? else {
> + ? ? ? ? ? ? ? ret = -EBADR;
> + ? ? ? ? ? ? ? goto fail;
> + ? ? ? }
> +
> + ? ? ? if (!irmc->buffer)
> + ? ? ? ? ? ? ? irmc->buffer = g_string_new(mybuf);
> + ? ? ? else
> + ? ? ? ? ? ? ? irmc->buffer = g_string_append(irmc->buffer, mybuf);
> +
> + ? ? ? return irmc;
> +
> +fail:
> + ? ? ? if (err)
> + ? ? ? ? ? ? ? *err = ret;
> +
> + ? ? ? return NULL;
> +}
> +
> +static void *irmc_open_cal(const char *name,
> + ? ? ? ? ? ? ? ?struct irmc_session *irmc, int *err)
> +{
> + ? ? ? // no suport yet. Just return an empty buffer
> + ? ? ? //cal.vcs
> + ? ? ? DBG("unsupported, returning empty buffer");
> + ? ? ? if (!irmc->buffer)
> + ? ? ? ? ? ? ? irmc->buffer = g_string_new("");
> + ? ? ? else
> + ? ? ? ? ? ? ? irmc->buffer = g_string_append(irmc->buffer, "");
> +
> + ? ? ? return irmc;
> +}
> +
> +static void *irmc_open_nt(const char *name,
> + ? ? ? ? ? ? ? ?struct irmc_session *irmc, int *err)
> +{
> + ? ? ? // no suport yet. Just return an empty buffer
> + ? ? ? //nt.vnt
> + ? ? ? DBG("unsupported, returning empty buffer");
> + ? ? ? if (!irmc->buffer)
> + ? ? ? ? ? ? ? irmc->buffer = g_string_new("");
> + ? ? ? else
> + ? ? ? ? ? ? ? irmc->buffer = g_string_append(irmc->buffer, "");
> +
> + ? ? ? return irmc;
> +}
> +
> +static void *irmc_open(const char *name, int oflag, mode_t mode,
> + ? ? ? ? ? ? ? void *context, size_t *size, int *err)
> +{
> + ? ? ? struct irmc_session *irmc = context;
> + ? ? ? int ret;
> + ? ? ? const char *p;
> +
> + ? ? ? DBG("name %s context %p", name, context);
> + ? ? ? if (oflag != O_RDONLY) {
> + ? ? ? ? ? ? ? ret = -EPERM;
> + ? ? ? ? ? ? ? goto fail;
> + ? ? ? }
> + ? ? ? if (strncmp(name, "telecom/", 8) != NULL) {
> + ? ? ? ? ? ? ? ret = -EBADR;
> + ? ? ? ? ? ? ? goto fail;
> + ? ? ? }
> +
> + ? ? ? p = name + 8;
> + ? ? ? if (!g_strcmp0(p, "devinfo.txt"))
> + ? ? ? ? ? ? ? return irmc_open_devinfo(irmc, err);
> + ? ? ? else if (!strncmp(p, "pb", 2))
> + ? ? ? ? ? ? ? return irmc_open_pb(p+2, irmc, err);
> + ? ? ? else if (!strncmp(p, "cal", 3))
> + ? ? ? ? ? ? ? return irmc_open_cal(p+3, irmc, err);
> + ? ? ? else if (!strncmp(p, "nt", 2))
> + ? ? ? ? ? ? ? return irmc_open_nt(p+2, irmc, err);
> +
> +fail:
> + ? ? ? if (err)
> + ? ? ? ? ? ? ? *err = ret;
> +
> + ? ? ? return NULL;
> +}
> +
> +static int irmc_close(void *object)
> +{
> + ? ? ? struct irmc_session *irmc = object;
> +
> + ? ? ? DBG("");
> + ? ? ? if (irmc->buffer) {
> + ? ? ? ? ? ? ? string_free(irmc->buffer);
> + ? ? ? ? ? ? ? irmc->buffer = NULL;
> + ? ? ? }
> +
> + ? ? ? return 0;
> +}
> +
> +static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi)
> +{
> + ? ? ? struct irmc_session *irmc = object;
> + ? ? ? ?int len;
> +
> + ? ? ? DBG("buffer %p count %d", irmc->buffer, count);
> + ? ? ? if (!irmc->buffer)
> + ? ? ? ? ? ? ? ?return -EAGAIN;
> +
> + ? ? ? ?*hi = OBEX_HDR_BODY;
> + ? ? ? len = string_read(irmc->buffer, buf, count);
> + ? ? ? DBG("returning %d bytes", len);
> + ? ? ? return len;
> +}
> +
> +static struct obex_mime_type_driver irmc_driver = {
> + ? ? ? .target = IRMC_TARGET,
> + ? ? ? .target_size = IRMC_TARGET_SIZE,
> + ? ? ? .open = irmc_open,
> + ? ? ? .close = irmc_close,
> + ? ? ? .read = irmc_read,
> +};
> +
> +static struct obex_service_driver irmc = {
> + ? ? ? .name = "IRMC Sync server",
> + ? ? ? .service = OBEX_IRMC,
> + ? ? ? .channel = IRMC_CHANNEL,
> + ? ? ? .record = IRMC_RECORD,
> + ? ? ? .target = IRMC_TARGET,
> + ? ? ? .target_size = IRMC_TARGET_SIZE,
> + ? ? ? .connect = irmc_connect,
> + ? ? ? .get = irmc_get,
> + ? ? ? .disconnect = irmc_disconnect,
> + ? ? ? .chkput = irmc_chkput
> +};
> +
> +static int irmc_init(void)
> +{
> + ? ? ? int err;
> +
> + ? ? ? DBG("");
> + ? ? ? err = phonebook_init();
> + ? ? ? if (err < 0)
> + ? ? ? ? ? ? ? return err;
> +
> + ? ? ? err = obex_mime_type_driver_register(&irmc_driver);
> + ? ? ? if (err < 0)
> + ? ? ? ? ? ? ? return err;
> +
> + ? ? ? return obex_service_driver_register(&irmc);
> +}
> +
> +static void irmc_exit(void)
> +{
> + ? ? ? DBG("");
> + ? ? ? obex_service_driver_unregister(&irmc);
> + ? ? ? obex_mime_type_driver_unregister(&irmc_driver);
> + ? ? ? phonebook_exit();
> +}
> +
> +OBEX_PLUGIN_DEFINE(irmc, irmc_init, irmc_exit)
> diff --git a/src/main.c b/src/main.c
> index 649acf9..96523a6 100644
> --- a/src/main.c
> +++ b/src/main.c
> @@ -83,6 +83,7 @@ static gboolean option_pbap = FALSE;
> ?static gboolean option_pcsuite = FALSE;
> ?static gboolean option_symlinks = FALSE;
> ?static gboolean option_syncevolution = FALSE;
> +static gboolean option_irmc = FALSE;
>
> ?static gboolean parse_debug(const char *key, const char *value,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?gpointer user_data, GError **error)
> @@ -122,6 +123,8 @@ static GOptionEntry options[] = {
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"Enable PC Suite Services server" },
> ? ? ? ?{ "syncevolution", 'e', 0, G_OPTION_ARG_NONE, &option_syncevolution,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"Enable OBEX server for SyncEvolution" },
> + ? ? ? { "irmc", 'i', 0, G_OPTION_ARG_NONE, &option_irmc,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Enable IrMCSync server" },
> ? ? ? ?{ NULL },
> ?};
>
> @@ -208,9 +211,10 @@ int main(int argc, char *argv[])
>
> ? ? ? ?if (option_opp == FALSE && option_ftp == FALSE &&
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?option_pbap == FALSE &&
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? option_syncevolution == FALSE) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? option_syncevolution == FALSE &&
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? option_irmc == FALSE) {
> ? ? ? ? ? ? ? ?fprintf(stderr, "No server selected (use either "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "--opp, --ftp, --pbap or --syncevolution)\n");
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "--opp, --ftp, --pbap --syncevolution or --irmc)\n");
> ? ? ? ? ? ? ? ?exit(EXIT_FAILURE);
> ? ? ? ?}
>
> @@ -270,6 +274,10 @@ int main(int argc, char *argv[])
> ? ? ? ? ? ? ? ?obex_server_init(OBEX_SYNCEVOLUTION, NULL, TRUE, FALSE,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FALSE, NULL);
>
> + ? ? ? if (option_irmc == TRUE)
> + ? ? ? ? ? ? ? obex_server_init(OBEX_IRMC, NULL, TRUE, FALSE, FALSE,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? option_capability);
> +
> ? ? ? ?if (!root_folder_setup(option_root, option_root_setup)) {
> ? ? ? ? ? ? ? ?error("Unable to setup root folder %s", option_root);
> ? ? ? ? ? ? ? ?exit(EXIT_FAILURE);
> diff --git a/src/obex.h b/src/obex.h
> index 9424b6b..cfe9159 100644
> --- a/src/obex.h
> +++ b/src/obex.h
> @@ -35,6 +35,7 @@
> ?#define OBEX_PBAP ? ? ?(1 << 4)
> ?#define OBEX_PCSUITE ? (1 << 5)
> ?#define OBEX_SYNCEVOLUTION ? ? (1 << 6)
> +#define OBEX_IRMC ? ? ?(1 << 7)
>
> ?#define TARGET_SIZE 16
>
> --
> 1.7.2

Looks pretty good, but you need to fix those c++ comments (//) please
use /*, also the you don't necessary need to abstract the file
devinfo.txt so platform can just write their own stuff there, if that
is not sufficient than we can thing of supporting scripts like we do
with x-obex/capability but I don't think we really need it since the
device info should be static, right?


--
Luiz Augusto von Dentz
Computer Engineer