Closed Bug 978288 Opened 10 years ago Closed 10 years ago

Convert a B2G contact into a VCARD

Categories

(Firefox OS Graveyard :: FxA, defect)

x86_64
Linux
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: francois, Assigned: jedp)

References

Details

Attachments

(1 file, 11 obsolete files)

398 bytes, text/html
Details
Using the B2G contact API, extract a contact and then convert it to a VCARD stored somewhere (SD card?).
Attachment #8385867 - Attachment is obsolete: true
Refactoring
Attachment #8385926 - Attachment is obsolete: true
Line folding and unfolding
More tests
Attachment #8386191 - Attachment is obsolete: true
Realistic full contact test
Empty contact test (missing data for all fields)
Fixed empty line formatting
Attachment #8386233 - Attachment is obsolete: true
Status: NEW → ASSIGNED
Added mochitest using mozContact API, converting mozContact to VCard
Attachment #8386444 - Attachment is obsolete: true
This time having actually exported the patch first.  :facepalm:
Attachment #8387291 - Attachment is obsolete: true
Attachment #8387294 - Attachment is obsolete: true
It seems the date entries in a mozContact are already converted to an ISO string, and are not returned as Date objects, contrary to the documentation. Updated the code to handle either case, so this will now convert mozContact data captured on FirefoxOS to VCard 1.4.
Attachment #8387311 - Attachment is obsolete: true
Comment on attachment 8388535 [details] [diff] [review]
Convert mozContact to VCard (wip)

Evert, hi,

Can you tell me whether the VCard at line 384 of test_modules_contactsVcard.js has any errors in it?  Thanks!
j
Attachment #8388535 - Flags: feedback?(evert)
I think I need to move all this code into gaia.  Sniff.  I'm going to miss javascript 1.8.
Comment on attachment 8388535 [details] [diff] [review]
Convert mozContact to VCard (wip)

Review of attachment 8388535 [details] [diff] [review]:
-----------------------------------------------------------------

::: services/fxaccounts/modules/VCard.js
@@ +83,5 @@
> +  this.params = [];
> +  this.value = "";
> +  return this;
> +}
> +Line.prototype = {

I think what you call a line here, is typically called a 'Property'.

@@ +103,5 @@
> +  },
> +
> +  param: function(name, value) {
> +    if (value) {
> +      this.params.push(name + "=" + value);

This may not be an issue just yet.. but property parameters must be escaped. If you only use simple property parameters (e.g. alphabetic only), you're not running into any issues, but you can probably imagine that as soon as a parameter contains a ; or a newline, you're running into issues.

@@ +114,5 @@
> +    // string, but type of email and others is list.
> +
> +    // XXX do we need to add quotes around type values when there is more than
> +    // one value, as Perreault does in his example vcard?  I don't see this in
> +    // the spec anywhere...

Don't.. this was specified in errata and considered a Really Bad Idea™.

@@ +305,5 @@
> +    let maybeDate = this.mozContact.bday;
> +    return new Line("BDAY")
> +      .val((typeof maybeDate == "string") ?
> +            maybeDate :
> +            new Date(+maybeDate).toISOString());

It may be wise to not encode the time, and just do the date.

Note that the year component may not always exist in vcards, but this is only relevant if you're decoding vcards.

@@ +386,5 @@
> +        (x) => {
> +          return new Line("TEL")
> +            .type(x.type)
> +            .pref(x.pref)
> +            .param("CARRIER", x.carrier)

Is this non-standard? Perhaps this should be X-MOZ prefixed. We can also X-SABRE- prefix this and add it to our registry for proprietary extensions.

@@ +459,5 @@
> +      }
> +    );
> +  },
> +
> +  // XXX PROID? what to do?

Some examples for inspiration:

PRODID:-//Sabre//Sabre VObject 3.2.0//EN
PRODID:-//Ximian//NONSGML Evolution Calendar//EN
PRODID:-//Apple Inc.//Mac OS X 10.9//EN
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN

@@ +478,5 @@
> +            maybeDate :
> +            new Date(+maybeDate).toISOString());
> +  },
> +
> +  // SOUND? Are you kidding me?

Used for ringtones and such :)

@@ +528,5 @@
> +  get CATEGORIES() {
> +    let categories = this.mozContact.categories || [];
> +    return new Line("CATEGORIES").textList(categories);
> +  },
> +};

Here's our full list of standard vcard properties, in case you missed one:

        // vCard 2.1 properties and up
        'N'       => 'Sabre\\VObject\\Property\\Text',
        'FN'      => 'Sabre\\VObject\\Property\\FlatText',
        'PHOTO'   => 'Sabre\\VObject\\Property\\Binary', // Todo: we should add a class for Binary values.
        'BDAY'    => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
        'ADR'     => 'Sabre\\VObject\\Property\\Text',
        'LABEL'   => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
        'TEL'     => 'Sabre\\VObject\\Property\\FlatText',
        'EMAIL'   => 'Sabre\\VObject\\Property\\FlatText',
        'MAILER'  => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
        'GEO'     => 'Sabre\\VObject\\Property\\FlatText',
        'GEO'     => 'Sabre\\VObject\\Property\\FlatText',
        'TITLE'   => 'Sabre\\VObject\\Property\\FlatText',
        'ROLE'    => 'Sabre\\VObject\\Property\\FlatText',
        'LOGO'    => 'Sabre\\VObject\\Property\\Binary',
        // 'AGENT'   => 'Sabre\\VObject\\Property\\',      // Todo: is an embedded vCard. Probably rare, so
                                 // not supported at the moment
        'ORG'     => 'Sabre\\VObject\\Property\\Text',
        'NOTE'    => 'Sabre\\VObject\\Property\\FlatText',
        'REV'     => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
        'SOUND'   => 'Sabre\\VObject\\Property\\FlatText',
        'URL'     => 'Sabre\\VObject\\Property\\Uri',
        'UID'     => 'Sabre\\VObject\\Property\\FlatText',
        'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
        'KEY'     => 'Sabre\\VObject\\Property\\FlatText',
        'TZ'      => 'Sabre\\VObject\\Property\\Text',

        // vCard 3.0 properties
        'CATEGORIES'  => 'Sabre\\VObject\\Property\\Text',
        'SORT-STRING' => 'Sabre\\VObject\\Property\\FlatText',
        'PRODID'      => 'Sabre\\VObject\\Property\\FlatText',
        'NICKNAME'    => 'Sabre\\VObject\\Property\\Text',
        'CLASS'       => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0

        // rfc2739 properties
        'FBURL'        => 'Sabre\\VObject\\Property\\Uri',
        'CAPURI'       => 'Sabre\\VObject\\Property\\Uri',
        'CALURI'       => 'Sabre\\VObject\\Property\\Uri',

        // rfc4770 properties
        'IMPP'         => 'Sabre\\VObject\\Property\\Uri',

        // vCard 4.0 properties
        'XML'          => 'Sabre\\VObject\\Property\\FlatText',
        'ANNIVERSARY'  => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
        'CLIENTPIDMAP' => 'Sabre\\VObject\\Property\\Text',
        'LANG'         => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
        'GENDER'       => 'Sabre\\VObject\\Property\\Text',
        'KIND'         => 'Sabre\\VObject\\Property\\FlatText',

        // rfc6474 properties
        'BIRTHPLACE'    => 'Sabre\\VObject\\Property\\FlatText',
        'DEATHPLACE'    => 'Sabre\\VObject\\Property\\FlatText',
        'DEATHDATE'     => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',

        // rfc6715 properties
        'EXPERTISE'     => 'Sabre\\VObject\\Property\\FlatText',
        'HOBBY'         => 'Sabre\\VObject\\Property\\FlatText',
        'INTEREST'      => 'Sabre\\VObject\\Property\\FlatText',
        'ORG-DIRECTORY' => 'Sabre\\VObject\\Property\\FlatText',

::: services/fxaccounts/tests/mochitest/test_modules_contactsVcard.html
@@ +43,5 @@
> +    "VERSION:4.0" + CRLF +
> +    "FN:Kevin Phillips-Bong" + CRLF +
> +    "N:Phillips-Bong;Kevin;;Sir;" + CRLF +
> +    "NICKNAME:Sir Kev" + CRLF +
> +    "BDAY:1927-04-01T08:00:00.000Z" + CRLF +

Our validator says:

$ ./bin/vobject validate test2.vcf
sabre/vobject 3.2.0
vCard: 4.0
  The supplied value (1927-04-01T08:00:00.000Z) is not a correct DATE-AND-OR-TIME property

::: services/fxaccounts/tests/xpcshell/test_modules_contactsVcard.js
@@ +178,5 @@
> +      carrier: "AfricanSwallow",
> +      value: "0845 748 4950",
> +    },
> +    {
> +      type: ["shed"],

Non-standard

@@ +228,5 @@
> +  ];
> +
> +  let contact = {impp: [
> +    {
> +      type: ["guards"],

Non-standard? X-Prefix
(In reply to Evert Pot from comment #12)
> Comment on attachment 8388535 [details] [diff] [review]
> Convert mozContact to VCard (wip)
> 
> Review of attachment 8388535 [details] [diff] [review]:
> -----------------------------------------------------------------

Evert, thank you for this thorough review.  This was very helpful.

> ::: services/fxaccounts/modules/VCard.js
> @@ +83,5 @@
> > +  this.params = [];
> > +  this.value = "";
> > +  return this;
> > +}
> > +Line.prototype = {
> 
> I think what you call a line here, is typically called a 'Property'.

Thanks.  Fixed.

> @@ +103,5 @@
> > +  },
> > +
> > +  param: function(name, value) {
> > +    if (value) {
> > +      this.params.push(name + "=" + value);
> 
> This may not be an issue just yet.. but property parameters must be escaped.
> If you only use simple property parameters (e.g. alphabetic only), you're
> not running into any issues, but you can probably imagine that as soon as a
> parameter contains a ; or a newline, you're running into issues.

Ah - good point.  Fixed and tests added.

> @@ +114,5 @@
> > +    // string, but type of email and others is list.
> > +
> > +    // XXX do we need to add quotes around type values when there is more than
> > +    // one value, as Perreault does in his example vcard?  I don't see this in
> > +    // the spec anywhere...
> 
> Don't.. this was specified in errata and considered a Really Bad Idea™.

Heh.  Ok :)

> @@ +305,5 @@
> > +    let maybeDate = this.mozContact.bday;
> > +    return new Line("BDAY")
> > +      .val((typeof maybeDate == "string") ?
> > +            maybeDate :
> > +            new Date(+maybeDate).toISOString());
> 
> It may be wise to not encode the time, and just do the date.
> 
> Note that the year component may not always exist in vcards, but this is
> only relevant if you're decoding vcards.

Yes, for decoding I see that we can get a variety of interesting values.  For decoding, I've updated this to always output something of the form YYYY-MM-DD.

> @@ +386,5 @@
> > +        (x) => {
> > +          return new Line("TEL")
> > +            .type(x.type)
> > +            .pref(x.pref)
> > +            .param("CARRIER", x.carrier)
> 
> Is this non-standard? Perhaps this should be X-MOZ prefixed. We can also
> X-SABRE- prefix this and add it to our registry for proprietary extensions.

Ok, I've prefixed it with X-MOZ-.  We can look into these further if necessary.

> @@ +459,5 @@
> > +      }
> > +    );
> > +  },
> > +
> > +  // XXX PROID? what to do?
> 
> Some examples for inspiration:
> 
> PRODID:-//Sabre//Sabre VObject 3.2.0//EN
> PRODID:-//Ximian//NONSGML Evolution Calendar//EN
> PRODID:-//Apple Inc.//Mac OS X 10.9//EN
> PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN

Cool.  I've just invented one for now.  We can figure out the right formalization later.

> @@ +478,5 @@
> > +            maybeDate :
> > +            new Date(+maybeDate).toISOString());
> > +  },
> > +
> > +  // SOUND? Are you kidding me?
> 
> Used for ringtones and such :)

I know.  I still think it's crazy :)  I'll try to figure out how to encode these properly.

> @@ +528,5 @@
> > +  get CATEGORIES() {
> > +    let categories = this.mozContact.categories || [];
> > +    return new Line("CATEGORIES").textList(categories);
> > +  },
> > +};
> 
> Here's our full list of standard vcard properties, in case you missed one:
> 
>         // vCard 2.1 properties and up
>         // ...

Yes the list is huge compared to what mozContact supports at the moment.  I think for our present project, since the device stores things as mozContacts, I'm just going to have to stay with them for now, meaning I won't be able to produce all these awesome fields.  In the future, maybe we can move to vcard being the on-device standard for mozContacts storage.

> ::: services/fxaccounts/tests/mochitest/test_modules_contactsVcard.html
> @@ +43,5 @@
> > +    "VERSION:4.0" + CRLF +
> > +    "FN:Kevin Phillips-Bong" + CRLF +
> > +    "N:Phillips-Bong;Kevin;;Sir;" + CRLF +
> > +    "NICKNAME:Sir Kev" + CRLF +
> > +    "BDAY:1927-04-01T08:00:00.000Z" + CRLF +
> 
> Our validator says:
> 
> $ ./bin/vobject validate test2.vcf
> sabre/vobject 3.2.0
> vCard: 4.0
>   The supplied value (1927-04-01T08:00:00.000Z) is not a correct
> DATE-AND-OR-TIME property

Ah so this is the bday simply wanting to be "1927-04-01"?  Hopefully I've fixed this correctly.

> ::: services/fxaccounts/tests/xpcshell/test_modules_contactsVcard.js
> @@ +178,5 @@
> > +      carrier: "AfricanSwallow",
> > +      value: "0845 748 4950",
> > +    },
> > +    {
> > +      type: ["shed"],
> 
> Non-standard

Oh so you can't just invent those, eh?

I'll stick to the list at https://tools.ietf.org/html/rfc6350#page-34

> @@ +228,5 @@
> > +  ];
> > +
> > +  let contact = {impp: [
> > +    {
> > +      type: ["guards"],
> 
> Non-standard? X-Prefix

Ah ok.  mozContact supports a type for these. I'll add an X-MOZ- prefix.

So helpful.  Thanks, Evert!
Addresses evert's feedback from Comment 12
Attachment #8388535 - Attachment is obsolete: true
Attachment #8388535 - Flags: feedback?(evert)
The way you escape parameters is wrong.

It's a bit weird, here's a sample how it's supposed to work:

https://github.com/fruux/sabre-vobject/blob/master/lib/Sabre/VObject/Parameter.php#L283

The summary:

1. A parameter can have multiple values. They can be encoded in two different ways:
   a. PARAM=value1;PARAM=value2
   b. PARAM=value1,value2
2. A parameter may be surrounded by double-quotes, and this is required if the value contains special characters.
3. Multiple values surrounded by double-quotes should be encoded as such:
   a. PARAM="value1";PARAM="value2";
   b. PARAM="value1","value2"
4. Even though this syntax appears in the vcard 4 spec, you must not do this:
   a. PARAM="value1,value2";
5. We have a simply blacklist of characters that will trigger the serializer to switch to double-quote escaping: ; : \n and ^ ,
6. vCard 4 does not define a way to do escaping in double-quotes in parameters. So just based on the vcard 4 rfc, it would simply not be possible to embed newlines or literal ".
7. This was extended by http://tools.ietf.org/html/rfc6868, which introduces the caret as an escape character

Note that if you also want to export vcard 2.1, things are different again, but lets not go there ;)
Oh crazy!  Thanks for straightening me out.  I had no idea about the caret escape.
Starting to move this to https://github.com/jedp/gaia/tree/contacts-backup

I haven't got the tests working there yet.  Once tests are working, including tests for Comment 15, I'll replace the attachment on this bug with a pointer to diff.
btw for those who may be wondering, no, the PR linked from comment 17 is *not* a proposal for an architecture as well.  I'm just trying to get things rolling (system app, main thread) to unblock UX and integration with external carddav services.  After that, refactoring into a suitable architecture can commence.
I forgot to mention that gaia unit tests are in there, too, now.
Attached file gaia branch for contacts backup (obsolete) —
Link to gaia branch
Attachment #8393028 - Attachment is obsolete: true
Link to gaia branch with functional redirect
Attachment #8395464 - Attachment is obsolete: true
Hi, ferjm, yes, I'm aware of those!  I actually started off in gecko land, hence the duplication and not starting with the shared lib right away.  I'm looking forward to merging our work into the shared lib.  I think we have some good additional functionality here (more fields, proper quoting and escaping) as well as more tests.  I'll check in with Gabriel as I go.
Hi folks,

Sergi, cced in this bug has been doing a lot of work around our implementation for VCARD, including the weird problems that we had to face, like versioning (yes, we started with protocol 4, and needed to downgrade to 3 cause android compatibility).

Sure he is an amazing source of information ;)

Cheers,
F.
If this means I get to work with Sergi again, I couldn't be happier!  Sergi, let's talk on IRC so I can let you know what we're up to here and make sure we're working in the same direction.
Hi Jed, I am currently pretty busy moving our vCard export from 4.0 to 3.0, so this comes a bit out of the blue :) Some questions about your work though:

- What vCard format are you planning to export? A quick look shows that you are following the RFC for 4.0, is that so?
- Do you think that we can integrate add this extra functionality you mention to the existing implementation?
- As I understand your patch is only about exporting, not importing. Is that correct?

Nice talking to you again!
Sergi!  Hi, sorry this is out of the blue.  The beginnings of my participation in this were on bug 859306 comment 34.  That discussion sort of fizzled in the bug.  I did some follow-up emails with some of the other folks on the bug, but I regret I did not end up connecting with you.  (I followed leads from bug 859306 comment 38.)

So let's talk more, but here's a summary of where we are in respect to your questions:

- vcard format: we would like to export 4.0, yes.  I will investigate whether 3.0 is ok.  It sounds from comment 25 that there are issues with android, so maybe we want to make that downgrade.  In the end, though, perhaps we'll have a way to export either 3.0 or 4.0?

- extra functionality should absolutely be integratable in the existing implementation, except for some of the quoting and escaping fanciness of vcard 4.0, which appears to be at odd with 3.0 (or at worst, underspecified).

- exporting, not importing.  Correct.  At this point, we're only looking at backup solutions.

So glad to be connected with you again!
Working sufficiently well for our prototype
Status: ASSIGNED → RESOLVED
Closed: 10 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: