diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-03-25 09:45:30 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-03-25 09:45:30 +0000 |
commit | df15a2e6ece1afa76425fd1186710afd567ff321 (patch) | |
tree | 95fd075ee5d60b2637949a64958aab1ab9f1e567 | |
parent | f27bd6cdf16f258d0ad76ab5222cc74c64796a11 (diff) | |
parent | 766510d2ae84cd04a770626a76029447bc4cdf66 (diff) |
Merge branch 'master' into next
72 files changed, 5729 insertions, 1706 deletions
@@ -155,8 +155,9 @@ Then use gdb as normal. To run a single test: make -C tests/<dir> check TESTS=<test name> -To run a single test with debugging output: - make -C tests/<dir> check TESTS=<test name> CHECK_VERBOSE=1 +Thanks to automake’s parallel test harness, the output from all tests is logged +automatically to <test name>.log, so no additional options need to be provided +to force verbose output. If a test needs to be run through Valgrind for memory debugging, use: make -C tests/<dir> check TESTS=<test name> FOLKS_TEST_VALGRIND=1 @@ -14,11 +14,15 @@ Bugs fixed: • Bug 723054 - edsf-persona.vala:1666.21-1666.79: error: Reference transfer not supported for this expression • Bug 723540 — standalone-individuals test failing with master + • Bug 724339 — vala.m4: don't keep generated files in git + • Bug 724809 — Fail to unset contact favorite + • Bug 722892 — Linking personas on Dummy backend does not work API changes: • Add Individual.display_name • Add StructuredName.to_string_with_format() • Add libfolks-dummy.la and all its symbols + • Add IndividualAggregator.backend_store Overview of changes from libfolks 0.9.5 to libfolks 0.9.6 ========================================================= @@ -1,19 +1,6 @@ #!/bin/sh set -e -if test -n "$AUTOMAKE"; then - : # don't override an explicit user request -elif automake-1.11 --version >/dev/null 2>/dev/null && \ - aclocal-1.11 --version >/dev/null 2>/dev/null; then - # If we have automake-1.11, use it. This is the oldest version (=> least - # likely to introduce undeclared dependencies) that will give us - # --enable-silent-rules support. - AUTOMAKE=automake-1.11 - export AUTOMAKE - ACLOCAL=aclocal-1.11 - export ACLOCAL -fi - autoreconf -i -f intltoolize --force --copy --automake diff --git a/backends/bluez/Makefile.am b/backends/bluez/Makefile.am index 9cae3823..f644687a 100644 --- a/backends/bluez/Makefile.am +++ b/backends/bluez/Makefile.am @@ -7,6 +7,7 @@ backend_LTLIBRARIES = bluez.la bluez_la_VALAFLAGS = \ $(backend_valaflags) \ --pkg libebook-1.2 \ + --pkg folks-generics \ $(NULL) bluez_la_SOURCES = \ diff --git a/backends/bluez/bluez-backend-factory.vala b/backends/bluez/bluez-backend-factory.vala index 061db6fa..22ef9a51 100644 --- a/backends/bluez/bluez-backend-factory.vala +++ b/backends/bluez/bluez-backend-factory.vala @@ -26,48 +26,25 @@ */ using Folks; -using Folks.Backends.BlueZ; - -private BackendFactory _backend_factory = null; /** * The backend module entry point. * - * @param backend_store the {@link BackendStore} to use in this factory. - * + * @backend_store a store to add the BlueZ backends to * @since 0.9.6 */ public void module_init (BackendStore backend_store) { - _backend_factory = new BackendFactory (backend_store); + backend_store.add_backend (new Folks.Backends.BlueZ.Backend ()); } /** * The backend module exit point. * - * @param backend_store the {@link BackendStore} to use in this factory. - * + * @param backend_store the store to remove the backends from * @since 0.9.6 */ public void module_finalize (BackendStore backend_store) { - _backend_factory = null; -} - -/** - * A backend factory to create a single {@link Backend}. - * - * @since 0.9.6 - */ -public class Folks.Backends.BlueZ.BackendFactory : Object -{ - /** - * {@inheritDoc} - * - * @since 0.9.6 - */ - public BackendFactory (BackendStore backend_store) - { - backend_store.add_backend (new Backend ()); - } + /* FIXME: No way to remove backends from the store. */ } diff --git a/backends/bluez/bluez-backend.vala b/backends/bluez/bluez-backend.vala index 9032c435..72f7243f 100644 --- a/backends/bluez/bluez-backend.vala +++ b/backends/bluez/bluez-backend.vala @@ -170,7 +170,7 @@ public class Folks.Backends.BlueZ.Backend : Folks.Backend if (!this._persona_stores.has_key (store.id)) return; - this._remove_persona_store ((!) _store); + this._remove_persona_store ((!) _store, true, true); } /** @@ -376,6 +376,10 @@ public class Folks.Backends.BlueZ.Backend : Folks.Backend PersonaStore store = new BlueZ.PersonaStore (device, path, this._obex_client); + /* Set the initial properties. */ + store.set_is_trusted (device.trusted); + store.set_alias (device.alias); + this._watched_devices[path] = store; this._persona_stores.set (store.id, store); @@ -384,7 +388,8 @@ public class Folks.Backends.BlueZ.Backend : Folks.Backend this.notify_property ("persona-stores"); } - private void _remove_persona_store (PersonaStore store) + private void _remove_persona_store (PersonaStore store, + bool remove_from_persona_stores, bool remove_from_watched_devices) { store.removed.disconnect (this._persona_store_removed_cb); @@ -394,8 +399,10 @@ public class Folks.Backends.BlueZ.Backend : Folks.Backend this.persona_store_removed (store); - this._persona_stores.unset (store.id); - this._watched_devices.unset (store.object_path); + if (remove_from_persona_stores == true) + this._persona_stores.unset (store.id); + if (remove_from_watched_devices == true) + this._watched_devices.unset (store.object_path); this.notify_property ("persona-stores"); } @@ -514,7 +521,7 @@ public class Folks.Backends.BlueZ.Backend : Folks.Backend if (this._watched_devices.unset (path, out store) == true) { debug ("Device ‘%s’ removed", path); - this._remove_persona_store (store); + this._remove_persona_store (store, true, false); } } @@ -679,11 +686,13 @@ public class Folks.Backends.BlueZ.Backend : Folks.Backend this.freeze_notify (); - foreach (var persona_store in this._persona_stores.values) - this._remove_persona_store (persona_store); + var iter = this._persona_stores.map_iterator (); + while (iter.next () == true) + { + this._remove_persona_store (iter.get_value (), false, true); + iter.unset (); + } - this._watched_devices.clear (); - this._persona_stores.clear (); this.notify_property ("persona-stores"); this._is_quiescent = false; @@ -702,6 +711,6 @@ public class Folks.Backends.BlueZ.Backend : Folks.Backend private void _persona_store_removed_cb (Folks.PersonaStore store) { - this._remove_persona_store ((BlueZ.PersonaStore) store); + this._remove_persona_store ((BlueZ.PersonaStore) store, true, true); } } diff --git a/backends/bluez/bluez-persona-store.vala b/backends/bluez/bluez-persona-store.vala index 6ff9f27c..73262187 100644 --- a/backends/bluez/bluez-persona-store.vala +++ b/backends/bluez/bluez-persona-store.vala @@ -198,6 +198,8 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore */ public new string display_name { + /* FIXME: Folks.display_name should be abstract, and this should be + * override. */ get { return this._display_name; } construct { this._display_name = value; } } @@ -274,6 +276,8 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore var removed_personas = new HashSet<Persona> (); var photos_up_to_date = this._photos_up_to_date; + debug ("Parsing contacts from file ‘%s’.", file.get_path ()); + /* Start with all personas being marked as removed, and then eliminate the * ones which are found in the vCard. */ removed_personas.add_all (this._personas.values); @@ -284,6 +288,7 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore uint i = 0; string? line = null; StringBuilder vcard = new StringBuilder (); + var vcard_without_photo = new StringBuilder (); /* For each vCard in the file create or update a Persona. */ while ((line = yield dis.read_line_async ()) != null) @@ -294,6 +299,13 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore vcard.append (line); vcard.append_c ('\n'); + + if (!line.has_prefix ("PHOTO:") && !line.has_prefix ("PHOTO;")) + { + vcard_without_photo.append (line); + vcard_without_photo.append_c ('\n'); + } + if (line.strip () == "END:VCARD") { var card = new E.VCard.from_string (vcard.str); @@ -311,7 +323,12 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore * checksum of the vCard data itself. This means that whenever * a contact’s properties change in the vCard its IID will * change and hence the persona will be removed and re-added, - * but without stable UIDs this is unavoidable. */ + * but without stable UIDs this is unavoidable. + * + * Note that the checksum is always calculated from the vCard + * data *without* the photo. This hopefully ensures that IIDs + * from queries which do and do not include photos will + * match. */ var attribute = card.get_attribute ("UID"); if (attribute != null) { @@ -323,7 +340,7 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore /* Fallback. */ iid = Checksum.compute_for_string (ChecksumType.SHA1, - vcard.str); + vcard_without_photo.str); iid_is_checksum = true; } @@ -338,10 +355,11 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore else { /* If the IID is a checksum and we found the persona in - * the store, that means their properties havent’t + * the store, that means their properties haven’t * changed, so as an optimisation, don’t bother updating * the Persona from the vCard in that case. */ - if (iid_is_checksum == false) + if (iid_is_checksum == false || + vcard_without_photo.len != vcard.len) { /* Note: This updates persona’s state, which could be * left updated if we later throw an error. */ @@ -355,6 +373,7 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore i++; vcard.erase (); + vcard_without_photo.erase (); } } } @@ -369,6 +388,10 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore /* Now that all the I/O is done and no more errors can be thrown, update * the store’s internal state. */ + debug ("Finished parsing personas; now updating store state with %u " + + "added personas and %u removed personas.", added_personas.size, + removed_personas.size); + foreach (var p in added_personas) this._personas.set (p.iid, p); foreach (var p in removed_personas) @@ -516,6 +539,10 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore } catch (IOError ie) { + /* Ignore errors from closing or cancelling. */ + if (ie is IOError.CLOSED || ie is IOError.CANCELLED) + return; + warning ("Couldn’t remove OBEX session ‘%s’: %s", session_path, ie.message); } @@ -568,6 +595,10 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore ulong signal_id; ulong cancellable_id = 0; + /* Find the initial status, if it’s already been set. Otherwise it’ll + * be null. */ + transfer_status = transfer.status; + /* Set up the cancellable. */ if (cancellable != null) { @@ -624,11 +655,24 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore /* Process the results: either success or error. */ if (transfer_status == "complete") { - string filename = transfer.filename; - var file = File.new_for_path (filename); + string? filename = transfer.filename; + if (filename == null) + { + /* The Filename property is optional, so bail if it’s not + * available for whatever reason. */ + throw new PersonaStoreError.STORE_OFFLINE ( + /* Translators: the first parameter is the name of the + * failed transfer, and the second is a Bluetooth device + * alias. */ + _("Error during transfer of the address book ‘%s’ from " + + "Bluetooth device ‘%s’."), + transfer.name, this._display_name); + } + + var file = File.new_for_path ((!) filename); debug ("vCard’s filename for device ‘%s’ (%s): %s", - this._display_name, this.id, filename); + this._display_name, this.id, (!) filename); yield this._update_contacts_from_file (file); } @@ -759,9 +803,12 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore phonebook_filter.insert ("Format", "Vcard30"); if (download_photos == true) { - /* Download only the photo (and UID, if available). */ + /* Download everything including the photo. */ phonebook_filter.insert ("Fields", - new Variant.strv ({ "UID", "PHOTO" })); + new Variant.strv ({ + "UID", "N", "FN", "NICKNAME", "TEL", "URL", "EMAIL", + "PHOTO" + })); } else { @@ -890,7 +937,8 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore PersonaStore._MAX_CONSECUTIVE_FAILURES) return; - /* Calculate the timeout. */ + /* Calculate the timeout (in milliseconds). If no divisor is applied, the + * timeout should always be a whole number of seconds. */ var timeout = uint.min (PersonaStore._TIMEOUT_MIN + (uint) Math.pow (PersonaStore._TIMEOUT_BASE, @@ -898,9 +946,23 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore PersonaStore._TIMEOUT_MAX); this._update_contacts_n++; + timeout *= 1000; /* convert from seconds to milliseconds */ + + /* Allow the timeout to be tweaked for testing. */ + var divisor_str = + Environment.get_variable ("FOLKS_BLUEZ_TIMEOUT_DIVISOR"); + if (divisor_str != null) + { + uint64 divisor; + if (uint64.try_parse (divisor_str, out divisor) == true) + timeout /= (uint) divisor; + } + /* Schedule the update. */ - this._update_contacts_id = Timeout.add_seconds (timeout, () => + SourceFunc fn = () => { + debug ("Scheduled update firing for BlueZ store ‘%s’.", this.id); + /* Acknowledge the source has fired. */ this._update_contacts_id = 0; @@ -916,13 +978,33 @@ public class Folks.Backends.BlueZ.PersonaStore : Folks.PersonaStore if (e4 is IOError.CANCELLED) return; - warning ("Error updating persona store from BlueZ: %s", - e4.message); + /* Don't warn about offline stores. */ + if (e4 is PersonaStoreError.STORE_OFFLINE) + { + debug ("Not updating persona store from BlueZ due to " + + "store being offline: %s", e4.message); + } + else + { + warning ("Error updating persona store from BlueZ: %s", + e4.message); + } } }); return false; - }); + }; + + if (timeout % 1000 == 0) + { + this._update_contacts_id = + Timeout.add_seconds (timeout / 1000, (owned) fn); + } + else + { + this._update_contacts_id = + Timeout.add (timeout, (owned) fn); + } } /** diff --git a/backends/bluez/bluez-persona.vala b/backends/bluez/bluez-persona.vala index b93eb469..ac6e2d5c 100644 --- a/backends/bluez/bluez-persona.vala +++ b/backends/bluez/bluez-persona.vala @@ -41,17 +41,6 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, PhoneDetails, UrlDetails { - private StructuredName? _structured_name = null; - private string _full_name = ""; - private string _nickname = ""; - private Set<UrlFieldDetails>? _urls = null; - private Set<UrlFieldDetails>? _urls_ro = null; - private LoadableIcon? _avatar = null; - private HashSet<PhoneFieldDetails> _phone_numbers; - private Set<PhoneFieldDetails> _phone_numbers_ro; - private HashSet<EmailFieldDetails> _email_addresses; - private Set<EmailFieldDetails> _email_addresses_ro; - private const string[] _linkable_properties = { "phone-numbers", @@ -69,6 +58,9 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, get { return BlueZ.Persona._linkable_properties; } } + private SmallSet<UrlFieldDetails>? _urls = null; + private Set<UrlFieldDetails> _urls_ro; + /** * {@inheritDoc} * @@ -81,6 +73,8 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, set { this.change_urls.begin (value); } /* not writeable */ } + private LoadableIcon? _avatar = null; + /** * {@inheritDoc} * @@ -103,6 +97,9 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, get { return BlueZ.Persona._writeable_properties; } } + private SmallSet<PhoneFieldDetails>? _phone_numbers = null; + private Set<PhoneFieldDetails> _phone_numbers_ro; + /** * {@inheritDoc} * @@ -115,6 +112,8 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, set { this.change_phone_numbers.begin (value); } /* not writeable */ } + private StructuredName? _structured_name = null; + /** * {@inheritDoc} * @@ -127,6 +126,8 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, set { this.change_structured_name.begin (value); } /* not writeable */ } + private string _full_name = ""; + /** * {@inheritDoc} * @@ -139,6 +140,8 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, set { this.change_full_name.begin (value); } /* not writeable */ } + private string _nickname = ""; + /** * {@inheritDoc} * @@ -151,6 +154,9 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, set { this.change_nickname.begin (value); } /* not writeable */ } + private SmallSet<EmailFieldDetails>? _email_addresses = null; + private Set<EmailFieldDetails> _email_addresses_ro; + /** * {@inheritDoc} * @@ -197,16 +203,35 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, { debug ("Adding BlueZ Persona '%s' (IID '%s')", this.uid, this.iid); - this._phone_numbers = new HashSet<PhoneFieldDetails> (); + this._phone_numbers = new SmallSet<PhoneFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); this._phone_numbers_ro = this._phone_numbers.read_only_view; - - this._email_addresses = new HashSet<EmailFieldDetails> (); + this._email_addresses = new SmallSet<EmailFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); this._email_addresses_ro = this._email_addresses.read_only_view; - - this._urls = new HashSet<UrlFieldDetails> (); + this._urls = new SmallSet<UrlFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); this._urls_ro = this._urls.read_only_view; } + private void _update_params (AbstractFieldDetails details, + E.VCardAttribute attr) + { + foreach (unowned E.VCardAttributeParam param in attr.get_params ()) + { + /* EVCard handles parameter names and values entirely + * case-insensitively, so we’ll do the same. */ + foreach (unowned string param_value in param.get_values ()) + { + details.add_parameter (param.get_name ().down (), + param_value.down ()); + } + } + } + /** * Update the Persona’s properties from a vCard. * @@ -222,69 +247,136 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, { var properties_changed = false; - this.freeze_notify (); + /* Somewhere to store the new property values. */ + var new_phone_numbers = new SmallSet<PhoneFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); + var new_uris = new SmallSet<UrlFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); + var new_email_addresses = new SmallSet<EmailFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); + BytesIcon? new_avatar = null; + var new_full_name = ""; + var new_nickname = ""; + StructuredName? new_structured_name = null; - /* Phone numbers. */ - var attribute = card.get_attribute ("TEL"); - var new_phone_numbers = new HashSet<PhoneFieldDetails> (); + /* Parse the attributes by iterating over the vCard’s attribute list once + * only. Convenience functions like E.VCard.get_attribute() cause multiple + * iterations over the list. */ + unowned GLib.List<unowned E.VCardAttribute> attrs = + card.get_attributes (); - if (attribute != null) + foreach (var attr in attrs) { - unowned GLib.List<unowned StringBuilder> vals = - attribute.get_values_decoded (); - foreach (unowned StringBuilder v in vals) - new_phone_numbers.add (new PhoneFieldDetails (v.str)); - } + unowned string attr_name = attr.get_name (); - if (!Folks.Internal.equal_sets<PhoneFieldDetails> (this._phone_numbers, - new_phone_numbers)) - { - this._phone_numbers = new_phone_numbers; - this._phone_numbers_ro = new_phone_numbers.read_only_view; - this.notify_property ("phone-numbers"); - properties_changed = true; - } + if (attr_name == "TEL") + { + var val = attr.get_value (); + if (val == null || (!) val == "") + continue; - /* Full name. */ - attribute = card.get_attribute ("FN"); - var new_full_name = ""; + var new_field_details = new PhoneFieldDetails ((!) val); + this._update_params (new_field_details, attr); + new_phone_numbers.add (new_field_details); + } + else if (attr_name == "URL") + { + var val = attr.get_value (); + if (val == null || (!) val == "") + continue; - if (attribute != null) - new_full_name = attribute.get_value_decoded ().str; + var new_field_details = new UrlFieldDetails ((!) val); + this._update_params (new_field_details, attr); + new_uris.add (new_field_details); + } + else if (attr_name == "EMAIL") + { + var val = attr.get_value (); + if (val == null || (!) val == "") + continue; - if (this._full_name != new_full_name) - { - this._full_name = new_full_name; - this.notify_property ("full-name"); - properties_changed = true; + var new_field_details = new EmailFieldDetails ((!) val); + this._update_params (new_field_details, attr); + new_email_addresses.add (new_field_details); + } + else if (attr_name == "PHOTO") + { + var encoded_data = (string) attr.get_value ().data; + var bytes = new Bytes (Base64.decode (encoded_data)); + new_avatar = new BytesIcon (bytes); + } + else if (attr_name == "FN") + new_full_name = attr.get_value (); + else if (attr_name == "NICKNAME") + new_nickname = attr.get_value (); + else if (attr_name == "N") + { + unowned GLib.List<unowned string> values = attr.get_values (); + unowned string? family_name = null, given_name = null, + additional_names = null, prefixes = null, suffixes = null; + + if (values != null) + { + family_name = values.data; + values = values.next; + } + if (values != null) + { + given_name = values.data; + values = values.next; + } + if (values != null) + { + additional_names = values.data; + values = values.next; + } + if (values != null) + { + prefixes = values.data; + values = values.next; + } + if (values != null) + { + suffixes = values.data; + values = values.next; + } + + if (suffixes == null || values != null) + { + debug ("Expected 5 components in N attribute of vCard, " + + "but got %s.", (suffixes == null) ? "fewer" : "more"); + } + + new_structured_name = + new StructuredName (family_name, given_name, additional_names, + prefixes, suffixes); + } + else if (attr_name != "VERSION" && attr_name != "UID") + { + /* Unknown attribute. */ + warning ("Unknown attribute ‘%s’ in vCard for persona %s.", + attr_name, this.uid); + } } - /* Nickname. */ - attribute = card.get_attribute ("NICKNAME"); - var new_nickname = ""; - - if (attribute != null) - new_nickname = attribute.get_value_decoded ().str; + /* Now test the new property values to see if they’ve changed; if so, emit + * property change notifications. */ + this.freeze_notify (); - if (this._nickname != new_nickname) + /* Phone numbers. */ + if (!Folks.Internal.equal_sets<PhoneFieldDetails> (this._phone_numbers, + new_phone_numbers)) { - this._nickname = new_nickname; - this.notify_property ("nickname"); + this._phone_numbers = new_phone_numbers; + this._phone_numbers_ro = new_phone_numbers.read_only_view; + this.notify_property ("phone-numbers"); properties_changed = true; } /* URIs. */ - attribute = card.get_attribute ("URL"); - var new_uris = new HashSet<UrlFieldDetails> (); - - if (attribute != null) - { - unowned GLib.List<unowned StringBuilder> vals = - attribute.get_values_decoded (); - foreach (unowned StringBuilder v in vals) - new_uris.add (new UrlFieldDetails (v.str)); - } - if (!Folks.Internal.equal_sets<UrlFieldDetails> (this._urls, new_uris)) { this._urls = new_uris; @@ -293,56 +385,7 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, properties_changed = true; } - /* Structured name. */ - attribute = card.get_attribute ("N"); - StructuredName? new_structured_name = null; - - if (attribute != null) - { - string[] components = { "", "", "", "", "" }; - unowned GLib.List<unowned StringBuilder> values = - attribute.get_values_decoded (); - - uint i = 0; - foreach (unowned StringBuilder b in values) - { - if (i >= components.length) - break; - - components[i++] = b.str; - } - - this._structured_name = new StructuredName (components[0], - components[1], components[2], components[3], components[4]); - - if (i != 5) - { - debug ("Expected 5 components in N value of vCard, but got %u.", - i); - } - } - - if ((new_structured_name == null) != (this._structured_name == null) || - (new_structured_name != null && this._structured_name != null && - !new_structured_name.equal (this._structured_name))) - { - this._structured_name = new_structured_name; - this.notify_property ("structured-name"); - properties_changed = true; - } - /* E-mail addresses. */ - attribute = card.get_attribute ("EMAIL"); - var new_email_addresses = new HashSet<EmailFieldDetails> (); - - if (attribute != null) - { - unowned GLib.List<unowned StringBuilder> vals = - attribute.get_values_decoded (); - foreach (unowned StringBuilder v in vals) - new_email_addresses.add (new EmailFieldDetails (v.str)); - } - if (!Folks.Internal.equal_sets<EmailFieldDetails> (this._email_addresses, new_email_addresses)) { @@ -353,16 +396,6 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, } /* Photo. */ - attribute = card.get_attribute ("PHOTO"); - BytesIcon? new_avatar = null; - - if (attribute != null) - { - var encoded_data = (string) attribute.get_value ().data; - var bytes = new Bytes (Base64.decode (encoded_data)); - new_avatar = new BytesIcon (bytes); - } - if ((new_avatar == null) != (this._avatar == null) || (new_avatar != null && this._avatar != null && !new_avatar.equal (this._avatar))) @@ -372,6 +405,32 @@ public class Folks.Backends.BlueZ.Persona : Folks.Persona, properties_changed = true; } + /* Full name. */ + if (this._full_name != new_full_name) + { + this._full_name = new_full_name; + this.notify_property ("full-name"); + properties_changed = true; + } + + /* Nickname. */ + if (this._nickname != new_nickname) + { + this._nickname = new_nickname; + this.notify_property ("nickname"); + properties_changed = true; + } + + /* Structured name. */ + if ((new_structured_name == null) != (this._structured_name == null) || + (new_structured_name != null && this._structured_name != null && + !new_structured_name.equal (this._structured_name))) + { + this._structured_name = new_structured_name; + this.notify_property ("structured-name"); + properties_changed = true; + } + this.thaw_notify (); return properties_changed; diff --git a/backends/dummy/lib/dummy-full-persona.vala b/backends/dummy/lib/dummy-full-persona.vala index 8330abb6..f998664a 100644 --- a/backends/dummy/lib/dummy-full-persona.vala +++ b/backends/dummy/lib/dummy-full-persona.vala @@ -72,6 +72,16 @@ public class FolksDummy.FullPersona : FolksDummy.Persona, PostalAddressDetails, WebServiceDetails { + private const string[] _default_linkable_properties = + { + "im-addresses", + "email-addresses", + "local-ids", + "web-service-addresses", + null /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=682698 */ + }; + + /** * Create a new ‘full’ persona. * @@ -88,7 +98,8 @@ public class FolksDummy.FullPersona : FolksDummy.Persona, * @since UNRELEASED */ public FullPersona (PersonaStore store, string contact_id, - bool is_user = false, string[] linkable_properties = {}) + bool is_user = false, + string[] linkable_properties = {}) { base (store, contact_id, is_user, linkable_properties); } @@ -104,6 +115,8 @@ public class FolksDummy.FullPersona : FolksDummy.Persona, this._groups_ro = this._groups.read_only_view; this._roles_ro = this._roles.read_only_view; this._anti_links_ro = this._anti_links.read_only_view; + this.update_linkable_properties ( + FullPersona._default_linkable_properties); } private HashMultiMap<string, WebServiceFieldDetails> _web_service_addresses = diff --git a/backends/dummy/lib/dummy-persona.vala b/backends/dummy/lib/dummy-persona.vala index a0d8cbdb..56679d20 100644 --- a/backends/dummy/lib/dummy-persona.vala +++ b/backends/dummy/lib/dummy-persona.vala @@ -96,8 +96,8 @@ public class FolksDummy.Persona : Folks.Persona * * @since UNRELEASED */ - public Persona (PersonaStore store, string contact_id, bool is_user = false, - string[] linkable_properties = {}) + public Persona (PersonaStore store, string contact_id, + bool is_user = false, string[] linkable_properties = {}) { var uid = Folks.Persona.build_uid (BACKEND_NAME, store.id, contact_id); var iid = store.id + ":" + contact_id; @@ -234,6 +234,32 @@ public class FolksDummy.Persona : Folks.Persona } /** + * Update the persona’s set of linkable properties. + * + * Update the {@link Folks.Persona.linkable_properties} property to contain + * the given ``linkable_properties``. + * + * @param linkable_properties new set of linkable property names, in lower + * case, hyphenated form + * @since UNRELEASED + */ + public void update_linkable_properties (string[] linkable_properties) + { + var new_linkable_properties = new SmallSet<string> (); + new_linkable_properties.add_all_array (linkable_properties); + + var old_linkable_properties = new SmallSet<string> (); + old_linkable_properties.add_all_array (this._linkable_properties); + + if (!Folks.Internal.equal_sets<string> (old_linkable_properties, + new_linkable_properties)) + { + this._linkable_properties = linkable_properties; + this.notify_property ("linkable-properties"); + } + } + + /** * Delay between property changes and notifications. * * This sets an optional delay between client code requesting a property diff --git a/backends/eds/eds-backend.vala b/backends/eds/eds-backend.vala index 90855f2d..7bdb1a57 100644 --- a/backends/eds/eds-backend.vala +++ b/backends/eds/eds-backend.vala @@ -133,11 +133,11 @@ public class Folks.Backends.Eds.Backend : Folks.Backend } } - var iter = this._persona_stores.values.iterator (); + var iter = this._persona_stores.map_iterator (); while (iter.next ()) { - var store = iter.get (); + var store = iter.get_value (); if (!storeids.contains (store.id)) { @@ -249,10 +249,10 @@ public class Folks.Backends.Eds.Backend : Folks.Backend this._prepare_pending = true; this.freeze_notify (); - var iter = this._persona_stores.values.iterator (); + var iter = this._persona_stores.map_iterator (); while (iter.next ()) - this._remove_address_book (iter.get (), true, iter); + this._remove_address_book (iter.get_value (), true, iter); this._ab_sources.source_added.disconnect (this._ab_source_list_changed_cb); this._ab_sources.source_enabled.disconnect (this._ab_source_list_changed_cb); @@ -345,14 +345,14 @@ public class Folks.Backends.Eds.Backend : Folks.Backend private void _remove_address_book (Folks.PersonaStore store, bool notify = true, - Iterator<Folks.PersonaStore>? iter = null) + MapIterator<string, Folks.PersonaStore>? iter = null) { debug ("Removing address book '%s'.", store.id); if (iter != null) { - assert (store == iter.get ()); - iter.remove (); + assert (store == iter.get_value ()); + iter.unset (); } else { diff --git a/backends/eds/lib/edsf-persona-store.vala b/backends/eds/lib/edsf-persona-store.vala index 0c6b9c15..1fc3425a 100644 --- a/backends/eds/lib/edsf-persona-store.vala +++ b/backends/eds/lib/edsf-persona-store.vala @@ -313,8 +313,9 @@ public class Edsf.PersonaStore : Folks.PersonaStore public PersonaStore.with_source_registry (E.SourceRegistry r, E.Source s) { string eds_uid = s.get_uid (); + string eds_name = s.get_display_name (); Object (id: eds_uid, - display_name: eds_uid, + display_name: eds_name, source: s); this._source_registry = r; @@ -366,7 +367,8 @@ public class Edsf.PersonaStore : Folks.PersonaStore } catch (GLib.Error e) { - GLib.warning ("~PersonaStore: %s\n", e.message); + if (!(e is IOError.CLOSED)) + GLib.warning ("~PersonaStore: %s\n", e.message); } } @@ -1227,6 +1229,16 @@ public class Edsf.PersonaStore : Folks.PersonaStore * if _addressbook is null. */ assert (this._addressbook != null); + var debug_obj = Debug.dup (); + if (debug_obj.debug_output_enabled == true) + { + debug ("Committing modified property ‘%s’ to persona %p (UID: %s).", + property_name, persona, persona.uid); + + debug ("Modified vCard: %s", + persona.contact.to_string (E.VCardFormat.@30)); + } + var contact = persona.contact; ulong signal_id = 0; @@ -1272,10 +1284,15 @@ public class Edsf.PersonaStore : Folks.PersonaStore * they can only be modified from the main loop. */ if (received_notification == false) { + debug ("Yielding."); has_yielded = true; yield; } + debug ("Finished: received_notification = %s, has_yielded = %s", + received_notification ? "yes" : "no", + has_yielded ? "yes" : "no"); + /* If we hit the timeout instead of the property notification, throw * an error. */ if (received_notification == false) @@ -1309,11 +1326,7 @@ public class Edsf.PersonaStore : Folks.PersonaStore private void _remove_attribute (E.Contact contact, string attr_name) { - unowned VCardAttribute? attr = contact.get_attribute (attr_name); - if (attr != null) - { - contact.remove_attribute ((!) attr); - } + contact.remove_attributes (null, attr_name); } internal async void _set_avatar (Edsf.Persona persona, LoadableIcon? avatar) @@ -2048,14 +2061,14 @@ public class Edsf.PersonaStore : Folks.PersonaStore private void _set_contact_system_groups (E.Contact contact, Set<string> system_groups) { + var group_ids_str = "X-GOOGLE-SYSTEM-GROUP-IDS"; var vcard = (E.VCard) contact; - unowned E.VCardAttribute? prev_attr = - vcard.get_attribute ("X-GOOGLE-SYSTEM-GROUP-IDS"); + unowned E.VCardAttribute? prev_attr = vcard.get_attribute (group_ids_str); if (prev_attr != null) - contact.remove_attribute (prev_attr); + contact.remove_attributes (null, group_ids_str); - E.VCardAttribute new_attr = new E.VCardAttribute ("", "X-GOOGLE-SYSTEM-GROUP-IDS"); + E.VCardAttribute new_attr = new E.VCardAttribute ("", group_ids_str); foreach (var group in system_groups) { if (group == null || group == "") diff --git a/backends/eds/lib/edsf-persona.vala b/backends/eds/lib/edsf-persona.vala index 7a076f18..1dd3c896 100644 --- a/backends/eds/lib/edsf-persona.vala +++ b/backends/eds/lib/edsf-persona.vala @@ -119,7 +119,7 @@ public class Edsf.Persona : Folks.Persona, * and the value ‘TRUE’. This allows clients to detect such fields * and (for example) ignore them in the UI. * - * Since: UNRELEASED + * @since UNRELEASED */ public static const string folks_field_attribute_name = "X-FOLKS-FIELD"; @@ -1007,7 +1007,6 @@ public class Edsf.Persona : Folks.Persona, new HashMultiMap<string, WebServiceFieldDetails> ( null, null, AbstractFieldDetails<string>.hash_static, AbstractFieldDetails<string>.equal_static); - this._email_addresses_ro = this._email_addresses.read_only_view; this._groups = new SmallSet<string> (); this._groups_ro = this._groups.read_only_view; this._roles = new SmallSet<RoleFieldDetails> ( diff --git a/backends/tracker/lib/trf-persona-store.vala b/backends/tracker/lib/trf-persona-store.vala index 5d5613ec..dc570d0a 100644 --- a/backends/tracker/lib/trf-persona-store.vala +++ b/backends/tracker/lib/trf-persona-store.vala @@ -1134,8 +1134,13 @@ public class Trf.PersonaStore : Folks.PersonaStore } catch (GLib.IOError e1) { - warning ("Could not connect to D-Bus service: %s", - e1.message); + /* Ignore errors from the bus disappearing. */ + if (!(e1 is IOError.CLOSED)) + { + warning ("Could not connect to D-Bus service: %s", + e1.message); + } + this.removed (); throw new PersonaStoreError.INVALID_ARGUMENT (e1.message); } @@ -1,7 +1,6 @@ # taken from gstreamer # gdb any given test by running make test.gdb %.gdb: % - CHECK_VERBOSE=1 \ $(TESTS_ENVIRONMENT) \ $(LIBTOOL) --mode=execute \ gdb $* diff --git a/configure.ac b/configure.ac index b25d40ba..03bd4b11 100644 --- a/configure.ac +++ b/configure.ac @@ -79,7 +79,7 @@ AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_SRCDIR([configure.ac]) -AM_INIT_AUTOMAKE([1.11 dist-xz no-define +AM_INIT_AUTOMAKE([1.12 dist-xz no-define no-dist-gzip tar-ustar -Wno-portability color-tests parallel-tests]) AM_MAINTAINER_MODE([enable]) @@ -339,8 +339,29 @@ AS_IF([test x$enable_ofono_backend = xyes], [ AS_IF([test x$enable_bluez_backend = xyes], [ PKG_CHECK_MODULES([EBOOK], [libebook-1.2 >= $EBOOK_REQUIRED]) + + # Dependencies for the BlueZ tests + PKG_CHECK_MODULES([GLIB_2_39_2], [glib-2.0 >= 2.39.2], + [have_glib_2_39_2=yes], [have_glib_2_39_2=no]) + AM_PATH_PYTHON([3.0], [have_python=yes], [have_python=no]) + + AC_MSG_CHECKING([for python-dbusmock]) + AS_IF([! $PYTHON -c 'import dbusmock' > /dev/null 2>&1], + [have_dbusmock=no], [have_dbusmock=yes]) + AC_MSG_RESULT([$have_dbusmock]) + + AM_PROG_VALAC([0.22.0.45-383d-dirty], + [have_valac_0_22_2=yes], [have_valac_0_22_2=no]) ]) +# The BlueZ tests are conditional on several bleeding-edge dependencies. +# FIXME: Remove this once things have stabilised a bit. +AM_CONDITIONAL([HAVE_BLUEZ_TESTS], + [test "x$have_glib_2_39_2" = "xyes" -a \ + "x$have_python" = "xyes" -a \ + "x$have_dbusmock" = "xyes" -a \ + "x$have_valac_0_22_2" = "xyes"]) + # # Vala building options -- allows tarball builds without installing Vala # @@ -754,6 +775,7 @@ AC_CONFIG_FILES([ docs/Makefile po/Makefile.in tests/Makefile + tests/bluez/Makefile tests/data/Makefile tests/eds/Makefile tests/folks/Makefile @@ -764,6 +786,7 @@ AC_CONFIG_FILES([ tests/tracker/Makefile tests/lib/Makefile tests/lib/folks-test-uninstalled.pc + tests/lib/bluez/Makefile tests/lib/eds/Makefile tests/lib/dummy/Makefile tests/lib/key-file/Makefile diff --git a/docs/Makefile.am b/docs/Makefile.am index 205aca03..3092fee8 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -126,6 +126,7 @@ folks_dummy_doc_deps = \ gee-0.8 \ folks \ folks-internal \ + folks-generics \ $(NULL) valadoc_flags_folks_dummy = \ $(valadoc_flags) \ diff --git a/folks/anti-linkable.vala b/folks/anti-linkable.vala index 93a82c79..0c3657e6 100644 --- a/folks/anti-linkable.vala +++ b/folks/anti-linkable.vala @@ -45,6 +45,9 @@ public interface Folks.AntiLinkable : Folks.Persona * {@link Persona} instance) are permitted, as personas may appear and * disappear over time. * + * The special UID ``*`` is used as a wildcard to mark the persona as globally + * anti-linked. See {@link AntiLinkable.has_global_anti_link}. + * * It is expected, but not guaranteed, that anti-links made between personas * will be reciprocal. That is, if persona A lists persona B's UID in its * {@link AntiLinkable.anti_links} set, persona B will typically also list @@ -93,7 +96,8 @@ public interface Folks.AntiLinkable : Folks.Persona */ public bool has_anti_link_with_persona (Persona other_persona) { - return (other_persona.uid in this.anti_links); + return (this.has_global_anti_link ()) || + (other_persona.uid in this.anti_links); } /** @@ -137,6 +141,9 @@ public interface Folks.AntiLinkable : Folks.Persona * The UIDs of all personas in ``other_personas`` will be removed from this * persona's anti-links set and the changes propagated to backends. * + * If the global anti-link is set, this will not have any effect until the + * global anti-link is removed. + * * This method is safe to call multiple times concurrently (e.g. begin one * asynchronous call, then begin another before the first has finished). * @@ -156,6 +163,67 @@ public interface Folks.AntiLinkable : Folks.Persona yield this.change_anti_links (new_anti_links); } + + /** + * Prevent persona from being linked with any other personas + * + * This function will add a wildcard ``*`` to the set of anti-links, which will + * prevent the persona from being linked with any other personas. + * + * To make the persona linkable again you need to remove the global anti-link + * + * This method is safe to call multiple times concurrently (e.g. begin one + * asynchronous call, then begin another before the first has finished). + * + * @throws PropertyError if setting the anti-links failed + * @since UNRELEASED + */ + public async void add_global_anti_link() + throws PropertyError + { + if (!this.has_global_anti_link()) + { + var new_anti_links = SmallSet.copy (this.anti_links); + new_anti_links.add ("*"); + yield this.change_anti_links (new_anti_links); + } + } + + /** + * Allow persona to be linked with other personas + * + * This function removes the wildcard ``*`` from the set of anti-links, allowing + * the persona to be linked again. + * + * This method is safe to call multiple times concurrently (e.g. begin one + * asynchronous call, then begin another before the first has finished). + * + * @throws PropertyError if setting the anti-links failed + * @since UNRELEASED + */ + public async void remove_global_anti_link() + throws PropertyError + { + if (this.has_global_anti_link()) + { + var new_anti_links = SmallSet.copy (this.anti_links); + new_anti_links.remove ("*"); + yield this.change_anti_links (new_anti_links); + } + } + + /** + * Check if the persona has a global anti link. + * + * If the persona has global anti link this means that the persona can not be + * linked with any other persona. + * + * @since UNRELEASED + */ + public bool has_global_anti_link() + { + return (this.anti_links.contains ("*")); + } } /* vim: filetype=vala textwidth=80 tabstop=2 expandtab: */ diff --git a/folks/backend-store.vala b/folks/backend-store.vala index 4af4d20f..e2ec2877 100644 --- a/folks/backend-store.vala +++ b/folks/backend-store.vala @@ -158,6 +158,16 @@ public class Folks.BackendStore : Object { ~BackendStore () { + /* Unprepare all existing backends. */ + var iter = this._prepared_backends.map_iterator (); + while (iter.next () == true) + { + var backend = iter.get_value (); + backend.unprepare.begin (); + } + + this._prepared_backends.clear (); + /* Finalize all the loaded modules that have finalize functions */ foreach (var module in this._modules.values) { @@ -169,6 +179,8 @@ public class Folks.BackendStore : Object { } } + this._modules.clear (); + /* Disconnect from the debug handler */ this._debug.print_status.disconnect (this._debug_print_status); diff --git a/folks/individual-aggregator.vala b/folks/individual-aggregator.vala index 18151455..06d0f3da 100644 --- a/folks/individual-aggregator.vala +++ b/folks/individual-aggregator.vala @@ -217,6 +217,17 @@ public class Folks.IndividualAggregator : Object get { return this._primary_store; } } + /** + * The backend store providing the persona stores for this aggregator. + * + * @since UNRELEASED + */ + public BackendStore backend_store + { + get { return this._backend_store; } + construct { this._backend_store = value; } + } + private Map<string, Individual> _individuals; private Map<string, Individual> _individuals_ro; @@ -376,8 +387,7 @@ public class Folks.IndividualAggregator : Object replacement = "IndividualAggregator.dup")] public IndividualAggregator () { - Object (); - this._backend_store = BackendStore.dup (); + Object (backend_store: BackendStore.dup ()); } /** @@ -437,8 +447,7 @@ public class Folks.IndividualAggregator : Object replacement = "IndividualAggregator.dup_with_backend_store")] public IndividualAggregator.with_backend_store (BackendStore store) { - Object (); - this._backend_store = store; + Object (backend_store: store); } construct @@ -504,8 +513,6 @@ public class Folks.IndividualAggregator : Object this._linking_enabled = (disable_linking == null || disable_linking == "no" || disable_linking == "0"); - this._backend_store = BackendStore.dup (); - debug ("Constructing IndividualAggregator %p", this); } diff --git a/m4/vala.m4 b/m4/vala.m4 deleted file mode 100644 index 37359488..00000000 --- a/m4/vala.m4 +++ /dev/null @@ -1,70 +0,0 @@ -dnl vala.m4 -dnl -dnl Copyright 2010 Marc-Andre Lureau -dnl -dnl This library is free software; you can redistribute it and/or -dnl modify it under the terms of the GNU Lesser General Public -dnl License as published by the Free Software Foundation; either -dnl version 2.1 of the License, or (at your option) any later version. -dnl -dnl This library is distributed in the hope that it will be useful, -dnl but WITHOUT ANY WARRANTY; without even the implied warranty of -dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -dnl Lesser General Public License for more details. -dnl -dnl You should have received a copy of the GNU Lesser General Public -dnl License along with this library; if not, write to the Free Software -dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -# _VALA_CHECK_COMPILE_WITH_ARGS(ARGS, [ACTION-IF-TRUE], -# [ACTION-IF-FALSE]) -# -------------------------------------- -# Check that Vala compile with ARGS. -# -AC_DEFUN([_VALA_CHECK_COMPILE_WITH_ARGS], -[AC_REQUIRE([AM_PROG_VALAC])[]dnl - - cat <<_ACEOF >conftest.vala -void main(){} -_ACEOF - - AS_IF([vala_error=`$VALAC $1 -q -o conftest$ac_exeext conftest.vala 2>&1`], - [$2], [$3]) -]) - -])# _VALA_CHECK_COMPILE_WITH_ARGS - -# VALA_CHECK_PACKAGES(PKGS, [ACTION-IF-FOUND], -# [ACTION-IF-NOT-FOUND]) -# -------------------------------------- -# Check that PKGS Vala bindings are installed and usable. -# -AC_DEFUN([VALA_CHECK_PACKAGES], -[ - ac_save_ifs="$IFS"; unset IFS - for vala_pkg in $(echo "$1"); do - vala_pkgs="$vala_pkgs --pkg $vala_pkg" - vala_bindings="$vala_bindings $vala_pkg" - done - IFS="$ac_save_ifs" - AC_MSG_CHECKING([for $vala_bindings vala bindings]) - _VALA_CHECK_COMPILE_WITH_ARGS([$vala_pkgs], - [vala_pkg_exists=yes], - [vala_pkg_exists=no]) - -AS_IF([test x${vala_pkg_exists} = xno],[ - ifelse([$3], , [AC_MSG_ERROR([]dnl -[Package requirements were not met: $1 - -$vala_error - -Consider adjusting the XDG_DATA_DIRS environment variable if you -installed bindings in a non-standard prefix. -])], - [AC_MSG_RESULT([no]) -$3])],[ - AC_MSG_RESULT([yes]) - ifelse([$2], , :, [$2])[]dnl -]) - -])# VALA_CHECK_PACKAGES @@ -1,7 +1,9 @@ # Danish translation for folks. -# Copyright (C) 2012 The Free Software Foundation +# Copyright (C) 2012, 2014 The Free Software Foundation # This file is distributed under the same license as the folks package. +# # Kenneth Nielsen <k.nielsen81@gmail.com>, 2012. +# Ask Hjorth Larsen <asklarsen@gmail.com>, 2014. # # persona -> persona # store i "persona store" -> kilde @@ -13,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: folks master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-17 08:26+0100\n" -"PO-Revision-Date: 2013-03-16 16:30+0100\n" -"Last-Translator: Kenneth Nielsen <k.nielsen81@gmail.com>\n" +"POT-Creation-Date: 2014-03-20 21:06+0100\n" +"PO-Revision-Date: 2014-03-16 01:09+0100\n" +"Last-Translator: Ask Hjorth Larsen <asklarsen@gmail.com>\n" "Language-Team: Danish <dansk@dansk-gruppen.dk>\n" "Language: da\n" "MIME-Version: 1.0\n" @@ -23,6 +25,85 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: ../backends/bluez/bluez-backend.vala:600 +msgid "" +"No BlueZ 5 object manager running, so the BlueZ backend will be inactive. " +"Either your BlueZ installation is too old (only version 5 is supported) or " +"the service can’t be started." +msgstr "" +"Der kører ikke nogen BlueZ 5-objekthåndtering, så BlueZ-motoren vil være " +"inaktiv. Enten er din BlueZ-installation for gammel (kun version 5 " +"understøttes), eller tjenesten kan ikke startes." + +#: ../backends/bluez/bluez-backend.vala:613 +msgid "" +"Error connecting to OBEX transfer daemon over D-Bus. Ensure BlueZ and obexd " +"are installed." +msgstr "" +"Fejl ved forbindelse til OBEX-overførselsdæmon over D-Bus. Sikr dig at BlueZ " +"og obexd er installeret." + +#. Translators: the parameter is an error message. +#: ../backends/bluez/bluez-persona-store.vala:385 +#, c-format +msgid "Error reading the transferred address book file: %s" +msgstr "Fejl ved læsning af den overførte adressebogsfil: %s" + +#. Translators: the first parameter is the name of the +#. * failed transfer, and the second is a Bluetooth device +#. * alias. +#: ../backends/bluez/bluez-persona-store.vala:667 +#, fuzzy, c-format +msgid "Error during transfer of the address book ‘%s’ from " +msgstr "" +"Fejl under overførsel af adressebogen \"%s\" fra Bluetooth-enheden \"%s\"." + +#. Translators: the first parameter is the name of the failed +#. * transfer, and the second is a Bluetooth device alias. +#: ../backends/bluez/bluez-persona-store.vala:689 +#, c-format +msgid "" +"Error during transfer of the address book ‘%s’ from Bluetooth device ‘%s’." +msgstr "" +"Fejl under overførsel af adressebogen \"%s\" fra Bluetooth-enheden \"%s\"." + +#: ../backends/bluez/bluez-persona-store.vala:782 +#, c-format +msgid "" +"Permission to access the address book on Bluetooth device ‘%s’ was denied by " +"the user." +msgstr "" +"Adgangstilladelse til adressebogen på Bluetooth-enheden \"%s\" blev nægtet " +"af brugeren." + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:789 +#, c-format +msgid "An OBEX address book transfer from device ‘%s’ could not be started: %s" +msgstr "" +"En OBEX-overførsel af adressebog fra enheden \"%s\" kunne ikke startes: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:829 +#, c-format +msgid "The OBEX address book transfer from device ‘%s’ failed: %s" +msgstr "OBEX-overførslen af adressebog fra enheden \"%s\" mislykkedes: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:846 +#, c-format +msgid "" +"Error during transfer of the address book from Bluetooth device ‘%s’: %s" +msgstr "Fejl under overførsel af adressebogen fra Bluetooth-enheden \"%s\": %s" + +#: ../backends/bluez/bluez-persona-store.vala:1064 +#, c-format +msgid "Bluetooth device ‘%s’ disappeared during address book transfer." +msgstr "Bluetooth-enheden \"%s\" forsvandt under overførsel af adressebog." + # Jeg har lavet en fejlrapport for at få dem til at acceptere at alle strenge bør kunne have en oversættelse #. The timeout after which we consider a property change to have failed if we #. * haven't received a property change notification for it. @@ -38,7 +119,7 @@ msgstr "Starred in Android" #. Translators: the first parameter is an address book #. * URI and the second is a persona UID. -#: ../backends/eds/lib/edsf-persona-store.vala:671 +#: ../backends/eds/lib/edsf-persona-store.vala:674 #, c-format msgid "Address book ‘%s’ is offline, so contact ‘%s’ cannot be removed." msgstr "" @@ -46,61 +127,61 @@ msgstr "" #. Translators: the first parameter is an address book #. * URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:677 +#: ../backends/eds/lib/edsf-persona-store.vala:680 #, c-format msgid "Permission denied to remove contact ‘%s’: %s" msgstr "Nægtet tilladelse til at fjerne kontakt \"%s\": %s" #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:682 +#: ../backends/eds/lib/edsf-persona-store.vala:685 #, c-format msgid "Removing contacts isn't supported by this persona store: %s" msgstr "At fjerne kontakter er ikke understøttet af denne personakilde: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:711 +#: ../backends/eds/lib/edsf-persona-store.vala:714 #, c-format msgid "Can't remove contact ‘%s’: %s" msgstr "Kan ikke fjerne \"%s\": %s" #. Translators: the parameter is an address book #. * URI. -#: ../backends/eds/lib/edsf-persona-store.vala:801 -#: ../backends/eds/lib/edsf-persona-store.vala:992 +#: ../backends/eds/lib/edsf-persona-store.vala:803 +#: ../backends/eds/lib/edsf-persona-store.vala:994 #, c-format msgid "Address book ‘%s’ is offline." msgstr "Adressebogen \"%s\" er offline." #. Translators: the first parameter is an address #. * book URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:806 -#: ../backends/eds/lib/edsf-persona-store.vala:997 +#: ../backends/eds/lib/edsf-persona-store.vala:808 +#: ../backends/eds/lib/edsf-persona-store.vala:999 #, c-format msgid "Permission denied to open address book ‘%s’: %s" msgstr "Nægtet tilladelse til at åbne adressebogen \"%s\": %s" #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:839 +#: ../backends/eds/lib/edsf-persona-store.vala:841 #, c-format msgid "Couldn't open address book ‘%s’: %s" msgstr "Kunne ikke åbne adressebogen \"%s\": %s" #. Translators: the parameteter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:905 -#: ../backends/eds/lib/edsf-persona-store.vala:935 +#: ../backends/eds/lib/edsf-persona-store.vala:907 +#: ../backends/eds/lib/edsf-persona-store.vala:937 #, c-format msgid "Couldn't get address book capabilities: %s" msgstr "Kunne ikke hente adressebogsevner: %s" #. Translators: the parameter is an address book URI. -#: ../backends/eds/lib/edsf-persona-store.vala:951 +#: ../backends/eds/lib/edsf-persona-store.vala:953 #, c-format msgid "Couldn't get view for address book ‘%s’." msgstr "Kunne ikke hente visning for adressebogen \"%s\"." #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1030 +#: ../backends/eds/lib/edsf-persona-store.vala:1032 #, c-format msgid "Couldn't get view for address book ‘%s’: %s" msgstr "Kunne ikke hente visning for adressebogen \"%s\": %s" @@ -108,119 +189,119 @@ msgstr "Kunne ikke hente visning for adressebogen \"%s\": %s" #. Translators: the parameter is the name of a property on a #. * contact, formatted in the normal GObject style (e.g. #. * lowercase with hyphens to separate words). -#: ../backends/eds/lib/edsf-persona-store.vala:1390 +#: ../backends/eds/lib/edsf-persona-store.vala:1304 #, c-format msgid "Changing the ‘%s’ property failed due to reaching the timeout." msgstr "Ændring af \"%s\"-egenskaben mislykkedes på grund af tidsudløb." -#: ../backends/eds/lib/edsf-persona-store.vala:1428 +#: ../backends/eds/lib/edsf-persona-store.vala:1338 #: ../folks/avatar-details.vala:63 msgid "Avatar is not writeable on this contact." msgstr "Profilbillede kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1449 +#: ../backends/eds/lib/edsf-persona-store.vala:1359 #: ../folks/web-service-details.vala:123 msgid "Web service addresses are not writeable on this contact." msgstr "Webtjenesteadresse kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1485 +#: ../backends/eds/lib/edsf-persona-store.vala:1395 #: ../folks/url-details.vala:152 msgid "URLs are not writeable on this contact." msgstr "URL'er kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1566 +#: ../backends/eds/lib/edsf-persona-store.vala:1476 #: ../folks/local-id-details.vala:64 msgid "Local IDs are not writeable on this contact." msgstr "Lokale id'er kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1595 +#: ../backends/eds/lib/edsf-persona-store.vala:1505 msgid "The contact cannot be marked as favourite." msgstr "Kontakten kan ikke markeres som favorit." #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1667 +#: ../backends/eds/lib/edsf-persona-store.vala:1577 #, c-format msgid "Can't update avatar: %s" msgstr "Kan ikke opdatere profilbillede: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:1678 +#: ../backends/eds/lib/edsf-persona-store.vala:1588 #: ../folks/email-details.vala:120 msgid "E-mail addresses are not writeable on this contact." msgstr "E-mail-adresse kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1696 -#: ../folks/phone-details.vala:224 +#: ../backends/eds/lib/edsf-persona-store.vala:1606 +#: ../folks/phone-details.vala:255 msgid "Phone numbers are not writeable on this contact." msgstr "Telefonnumre kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1714 +#: ../backends/eds/lib/edsf-persona-store.vala:1624 #: ../folks/postal-address-details.vala:361 msgid "Postal addresses are not writeable on this contact." msgstr "Postadresser kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1785 -#: ../folks/name-details.vala:283 +#: ../backends/eds/lib/edsf-persona-store.vala:1695 +#: ../folks/name-details.vala:454 msgid "Full name is not writeable on this contact." msgstr "Fulde navn kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1807 -#: ../folks/name-details.vala:321 +#: ../backends/eds/lib/edsf-persona-store.vala:1717 +#: ../folks/name-details.vala:492 msgid "Nickname is not writeable on this contact." msgstr "Kaldenavn kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1829 +#: ../backends/eds/lib/edsf-persona-store.vala:1739 #: ../folks/note-details.vala:138 msgid "Notes are not writeable on this contact." msgstr "Noter kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1861 +#: ../backends/eds/lib/edsf-persona-store.vala:1771 #: ../folks/birthday-details.vala:62 msgid "Birthday is not writeable on this contact." msgstr "Fødselsdag kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:1905 +#: ../backends/eds/lib/edsf-persona-store.vala:1815 #: ../folks/role-details.vala:279 msgid "Roles are not writeable on this contact." msgstr "Roller kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:2006 -#: ../folks/name-details.vala:246 +#: ../backends/eds/lib/edsf-persona-store.vala:1916 +#: ../folks/name-details.vala:417 msgid "Structured name is not writeable on this contact." msgstr "Struktureret navn kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:2045 +#: ../backends/eds/lib/edsf-persona-store.vala:1955 #: ../folks/im-details.vala:136 msgid "IM addresses are not writeable on this contact." msgstr "IM-adresser kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:2095 +#: ../backends/eds/lib/edsf-persona-store.vala:2005 #: ../folks/group-details.vala:174 msgid "Groups are not writeable on this contact." msgstr "Grupper kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:2110 +#: ../backends/eds/lib/edsf-persona-store.vala:2020 msgid "My Contacts is only available for Google Contacts" msgstr "Mine kontakter er kun tilgængelige for Google-kontakter" -#: ../backends/eds/lib/edsf-persona-store.vala:2181 +#: ../backends/eds/lib/edsf-persona-store.vala:2091 #: ../folks/gender-details.vala:79 msgid "Gender is not writeable on this contact." msgstr "Køn kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:2219 -#: ../folks/anti-linkable.vala:81 +#: ../backends/eds/lib/edsf-persona-store.vala:2129 +#: ../folks/anti-linkable.vala:84 msgid "Anti-links are not writeable on this contact." msgstr "Anti-henvisninger kan ikke skrives til denne kontakt." -#: ../backends/eds/lib/edsf-persona-store.vala:2262 -#: ../folks/location-details.vala:129 +#: ../backends/eds/lib/edsf-persona-store.vala:2172 +#: ../folks/location-details.vala:135 msgid "Location is not writeable on this contact." msgstr "Placering er skrivebeskyttet for denne kontakt." #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2439 +#: ../backends/eds/lib/edsf-persona-store.vala:2485 #, c-format msgid "Property ‘%s’ is not writeable: %s" msgstr "Egenskaben \"%s\" er ikke skrivbar: %s" @@ -228,42 +309,42 @@ msgstr "Egenskaben \"%s\" er ikke skrivbar: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2448 +#: ../backends/eds/lib/edsf-persona-store.vala:2494 #, c-format msgid "Invalid value for property ‘%s’: %s" msgstr "Ugyldig værdi for egenskaben \"%s\": %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:2474 +#: ../backends/eds/lib/edsf-persona-store.vala:2520 #, c-format msgid "Unknown error setting property ‘%s’: %s" msgstr "Ukendt fejl ved indstilling af egenskaben \"%s\": %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:233 +#: ../backends/key-file/kf-persona-store.vala:234 #, c-format msgid "The relationship key file '%s' could not be loaded: %s" msgstr "Forholdsnøglefilen \"%s\" kunne ikke indlæses: %s" #. Translators: the first parameter is a path, and the #. * second is an error message. -#: ../backends/key-file/kf-persona-store.vala:255 +#: ../backends/key-file/kf-persona-store.vala:256 #, c-format msgid "The relationship key file directory '%s' could not be created: %s" msgstr "Kataloget \"%s\" til forholdsnøglefilen kunne ikke blive oprettet: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:279 +#: ../backends/key-file/kf-persona-store.vala:280 #, c-format msgid "The relationship key file '%s' could not be created: %s" msgstr "Forholdsnøglefilen \"%s\" kunne ikke blive oprettet: %s" #. Translators: the first parameter is a filename, the second is #. * an error message. -#: ../backends/key-file/kf-persona-store.vala:470 +#: ../backends/key-file/kf-persona-store.vala:471 #, c-format msgid "Could not write updated key file '%s': %s" msgstr "Kunne ikke skrive opdateret nøglefil \"%s\": %s" @@ -273,13 +354,13 @@ msgstr "Kunne ikke skrive opdateret nøglefil \"%s\": %s" #. * an IM address (e.g. “foo@jabber.org”), the second is #. * the name of a protocol (e.g. “jabber”) and the third is #. * an error message. -#: ../backends/key-file/kf-persona.vala:172 +#: ../backends/key-file/kf-persona.vala:174 #, c-format msgid "Invalid IM address ‘%s’ for protocol ‘%s’: %s" msgstr "Ugyldig IM-adresse \"%s\" for protokol \"%s\": %s" #. Translators: the parameter is an error message. -#: ../backends/key-file/kf-persona.vala:430 +#: ../backends/key-file/kf-persona.vala:432 #, c-format msgid "Couldn't load data from key file: %s" msgstr "Kunne ikke indlæse data fra nøglefil: %s" @@ -304,30 +385,27 @@ msgstr "Ingen kontaktevner fundet." msgid "Error opening contacts view." msgstr "Fejl ved åbning af kontaktvisningen." -#. Translators: the first parameter is the display name for -#. * the Telepathy account, and the second is an error -#. * message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:814 -#, c-format +#: ../backends/ofono/ofono-backend.vala:196 msgid "" -"Failed to determine whether we can set aliases on Telepathy account '%s': %s" +"No oFono object manager running, so the oFono backend will be inactive. " +"Either oFono isn’t installed or the service can’t be started." msgstr "" -"Kunne ikke finde ud af om vi kan indstille aliasser på Telepathy-kontoen \"%s" -"\": %s" +"Der kører ikke nogen oFono-objekthåndtering, så oFono-motoren vil være " +"inaktiv. Enten er oFono ikke installeret, eller tjenesten kan ikke startes." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1278 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1248 msgid "Telepathy contacts representing the local user may not be removed." msgstr "" "Telepathy-kontakter som repræsenterer den lokale bruger må ikke fjernes." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1289 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1259 #, c-format msgid "Failed to remove a persona from store: %s" msgstr "Kunne ikke fjerne en persona fra kilden: %s" #. Translators: the first two parameters are store identifiers and #. * the third is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1324 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1294 #, c-format msgid "" "Persona store (%s, %s) requires the following details:\n" @@ -336,18 +414,18 @@ msgstr "" "Personakilde (%s, %s) kræver følgende detaljer:\n" " kontakt (givet: \"%s\")\n" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1339 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1309 msgid "Cannot create a new Telepathy contact while offline." msgstr "Kan ikke oprette en Telepathy-kontakt i offlinetilstand." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1357 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1327 #, c-format msgid "Failed to add a persona from details: %s" msgstr "Kunne ikke tilføje en persona fra detaljerne %s" #. Translators: "telepathy-logger" is the name of an application, #. * and should not be translated. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1377 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1347 msgid "" "Failed to change favorite without a connection to the telepathy-logger " "service." @@ -355,7 +433,7 @@ msgstr "" "Kunne ikke ændre favorit uden en forbindelse til \"telepathy-logger\"-" "tjenesten." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1383 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1353 msgid "" "Failed to change favorite status of Telepathy Persona because it has no " "attached TpContact." @@ -364,45 +442,45 @@ msgstr "" "TpContact." #. Translators: the parameter is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1401 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1371 #, c-format msgid "Failed to change favorite status for Telepathy contact ‘%s’." msgstr "Kunne ikke ændre favoritstatus for Telepathy-kontakt \"%s\"." #. Translators: the parameter is an error message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1433 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1403 #, c-format msgid "Failed to change contact's alias: %s" msgstr "Kunne ikke ændre kontakts alias: %s" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1514 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1484 msgid "Extended information may only be set on the user's Telepathy contact." msgstr "Udvidet information må kun indstilles på brugerens Telepathy-kontakt." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1543 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 msgid "" "Extended information cannot be written because the store is disconnected." msgstr "Udvidet information kan ikke skrives fordi kilden er afkoblet." -#: ../backends/telepathy/lib/tpf-persona.vala:499 -#: ../backends/telepathy/lib/tpf-persona.vala:520 -#: ../backends/telepathy/lib/tpf-persona.vala:572 -#: ../backends/telepathy/lib/tpf-persona.vala:586 +#: ../backends/telepathy/lib/tpf-persona.vala:511 +#: ../backends/telepathy/lib/tpf-persona.vala:532 +#: ../backends/telepathy/lib/tpf-persona.vala:584 +#: ../backends/telepathy/lib/tpf-persona.vala:598 #, c-format msgid "Failed to change group membership: %s" msgstr "Kunne ikke ændre gruppemedlemsskab: %s" #. Translators: "account" refers to an instant messaging #. * account. -#: ../backends/telepathy/lib/tpf-persona.vala:502 -#: ../backends/telepathy/lib/tpf-persona.vala:575 +#: ../backends/telepathy/lib/tpf-persona.vala:514 +#: ../backends/telepathy/lib/tpf-persona.vala:587 msgid "Account is offline." msgstr "Konto er offline." #. Translators: the first parameter is the unknown key that #. * was received with the details params, and the second #. * identifies the persona store. -#: ../backends/tracker/lib/trf-persona-store.vala:742 +#: ../backends/tracker/lib/trf-persona-store.vala:743 #, c-format msgid "Unrecognized parameter '%s' passed to persona store '%s'." msgstr "Ukendt parameter \"%s\" givet til personakilde \"%s\"." @@ -413,19 +491,19 @@ msgstr "Alias kan ikke skrives til denne kontakt." #. Translators: the first parameter is a folder path and the second #. * is an error message. -#: ../folks/backend-store.vala:627 +#: ../folks/backend-store.vala:651 #, c-format msgid "Error listing contents of folder '%s': %s" msgstr "Fejl ved visning af indhold i mappen \"%s\": %s" #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:757 +#: ../folks/backend-store.vala:786 #, c-format msgid "File or directory '%s' does not exist." msgstr "Fil eller mappe \"%s\" eksisterer ikke." #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:763 +#: ../folks/backend-store.vala:792 #, c-format msgid "Failed to get content type for '%s'." msgstr "Kunne ikke hente indholdstype for \"%s\"." @@ -447,31 +525,31 @@ msgstr "IM-adressen \"%s\" kunne ikke forstås." #. Translators: the first parameter is a persona store identifier #. * and the second is an error message. -#: ../folks/individual-aggregator.vala:935 +#: ../folks/individual-aggregator.vala:1040 #, c-format msgid "Error preparing persona store '%s': %s" msgstr "Fejl ved forberedelse af personakilde \"%s\": %s" #. Translators: the parameter is a property name. -#: ../folks/individual-aggregator.vala:1158 -#: ../folks/individual-aggregator.vala:1386 +#: ../folks/individual-aggregator.vala:1269 +#: ../folks/individual-aggregator.vala:1536 #, c-format msgid "Unknown property '%s' in linkable property list." msgstr "Ukendt egenskab \"%s\" i sammenkædelig egenskabsliste." #. Translators: the first parameter is a store identifier #. * and the second parameter is an error message. -#: ../folks/individual-aggregator.vala:1857 +#: ../folks/individual-aggregator.vala:2022 #, c-format msgid "Failed to add contact for persona store ID '%s': %s" msgstr "Kunne ikke tilføje kontakt til personakilde-id \"%s\": %s" -#: ../folks/individual-aggregator.vala:1958 +#: ../folks/individual-aggregator.vala:2119 msgid "Can’t link personas with no primary store." msgstr "Kan ikke sammenkæde personaer uden en primær kilde." -#: ../folks/individual-aggregator.vala:1959 -#: ../folks/individual-aggregator.vala:2291 +#: ../folks/individual-aggregator.vala:2120 +#: ../folks/individual-aggregator.vala:2451 #, c-format msgid "" "Persona store ‘%s:%s’ is configured as primary, but could not be found or " @@ -480,8 +558,8 @@ msgstr "" "Personakilde \"%s:%s\" er konfigureret som den primære, men kunne ikke " "findes eller indlæses." -#: ../folks/individual-aggregator.vala:1960 -#: ../folks/individual-aggregator.vala:2292 +#: ../folks/individual-aggregator.vala:2121 +#: ../folks/individual-aggregator.vala:2452 #, c-format msgid "" "Check the relevant service is running, or change the default store in that " @@ -490,29 +568,81 @@ msgstr "" "Tjek om den relevante tjeneste kører, eller ændr standardkilden i den " "tjeneste eller ved hjælp at GSettings-nøglen “%s”." -#: ../folks/individual-aggregator.vala:1992 +#: ../folks/individual-aggregator.vala:2153 msgid "Anti-links can't be removed between personas being linked." msgstr "" "Anti-henvisninger kan ikke fjernes mellem personaer som er ved at blive " "sammenkædet." -#: ../folks/individual-aggregator.vala:2290 +#: ../folks/individual-aggregator.vala:2450 msgid "Can’t add personas with no primary store." msgstr "Kan ikke tilføje personaer uden en primær kilde." -#: ../folks/individual-aggregator.vala:2301 +#: ../folks/individual-aggregator.vala:2461 #, c-format msgid "Can't write to requested property (“%s”) of the writeable store." msgstr "" "Kan ikke skrive til den anmodede egenskab (“%s”) i den skrivbare kilde." -#: ../folks/individual.vala:217 ../folks/individual.vala:370 -#: ../folks/individual.vala:479 ../folks/individual.vala:730 -#: ../folks/individual.vala:808 +#: ../folks/individual.vala:216 ../folks/individual.vala:402 +#: ../folks/individual.vala:511 ../folks/individual.vala:762 +#: ../folks/individual.vala:840 #, c-format msgid "Failed to change property ‘%s’: No suitable personas were found." msgstr "Kunne ikke ændre egenskaben \"%s\": Ingen passende personaer fundet." +#. Translators: This is the default name for an Individual +#. * when displayed in the UI if no personal details are available +#. * for them. +#: ../folks/individual.vala:1951 +msgid "Unnamed Person" +msgstr "Unavngivet person" + +# Okay, alt dette betyder bare fornavn-mellemnavn-efternavn, adskilt af punktummer (%t) +# +#. FIXME: Ideally we’d use a format string translated to the locale of the +#. * persona whose name is being formatted, but no backend provides +#. * information about personas’ locales, so we have to settle for the +#. * current user’s locale. +#. * +#. * We thought about using nl_langinfo(_NL_NAME_NAME_FMT) here, but +#. * decided against it because: +#. * 1. It’s not the best documented API in the world, and its stability +#. * is in question. +#. * 2. An attempt to improve the interface in glibc met with a wall of +#. * complaints: https://sourceware.org/bugzilla/show_bug.cgi?id=14641. +#. * +#. * However, we do re-use the string format placeholders from +#. * _NL_NAME_NAME_FMT (as documented here: +#. * http://lh.2xlibre.net/values/name_fmt/) because there’s a chance glibc +#. * might eventually grow a useful interface for this. +#. * +#. * It does mean we have to implement our own parser for the name_fmt +#. * format though, since glibc doesn’t provide a formatting function. +#. Translators: This is a format string used to convert structured names +#. * to a single string. It should be translated to the predominant +#. * semi-formal name format for your locale, using the placeholders +#. * documented here: http://lh.2xlibre.net/values/name_fmt/. You may be +#. * able to re-use the existing glibc format string for your locale on that +#. * page if it’s suitable. +#. * +#. * More explicitly: the supported placeholders are %f, %F, %g, %G, %m, %M, +#. * %t. The romanisation modifier (e.g. %Rf) is recognized but ignored. +#. * %s, %S and %d are all replaced by the same thing (the ‘Honorific +#. * Prefixes’ from vCard) so please avoid using more than one. +#. * +#. * For example, the format string ‘%g%t%m%t%f’ expands to ‘John Andrew +#. * Lees’ when used for a persona with first name ‘John’, additional names +#. * ‘Andrew’ and family names ‘Lees’. +#. * +#. * If you need additional placeholders with other information or +#. * punctuation, please file a bug against libfolks: +#. * https://bugzilla.gnome.org/enter_bug.cgi?product=folks +#. +#: ../folks/name-details.vala:268 +msgid "%g%t%m%t%f" +msgstr "%g%t%m%t%f" + #: ../folks/org.freedesktop.folks.gschema.xml.in.h:1 msgid "Primary store ID" msgstr "Id for primær kilde" @@ -533,35 +663,35 @@ msgstr "" msgid "%s, %s, %s, %s, %s, %s, %s" msgstr "%s, %s, %s, %s, %s, %s, %s" -#: ../folks/presence-details.vala:159 +#: ../folks/presence-details.vala:171 msgid "Unknown status" msgstr "Ukendt status" -#: ../folks/presence-details.vala:161 +#: ../folks/presence-details.vala:173 msgid "Offline" msgstr "Offline" -#: ../folks/presence-details.vala:165 +#: ../folks/presence-details.vala:177 msgid "Error" msgstr "Fejl" -#: ../folks/presence-details.vala:167 +#: ../folks/presence-details.vala:179 msgid "Available" msgstr "Tilgængelig" -#: ../folks/presence-details.vala:169 +#: ../folks/presence-details.vala:181 msgid "Away" msgstr "Ikke til stede" -#: ../folks/presence-details.vala:171 +#: ../folks/presence-details.vala:183 msgid "Extended away" msgstr "Længerevarende fravær" -#: ../folks/presence-details.vala:173 +#: ../folks/presence-details.vala:185 msgid "Busy" msgstr "Optaget" -#: ../folks/presence-details.vala:175 +#: ../folks/presence-details.vala:187 msgid "Hidden" msgstr "Skjult" @@ -662,54 +792,54 @@ msgstr "Kildeprogramnavn (backend) (standard: \"pidgin\")" msgid "Source filename (default: specific to source backend)" msgstr "Kildefilnavn (standard: specifik for kildeprogrammet (backend))" -#: ../tools/import.vala:57 +#: ../tools/import.vala:58 msgid "— import meta-contact information to libfolks" msgstr "— importér metakontaktinformation til libfolks" #. Translators: the parameter is an error message. -#: ../tools/import.vala:67 +#: ../tools/import.vala:68 #, c-format msgid "Couldn't parse command line options: %s" msgstr "Kunne ikke fortolke kommandolinjetilvalg: %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:108 +#: ../tools/import.vala:109 #, c-format msgid "Couldn't load the backends: %s" msgstr "Kunne ikke indlæse kildeprogrammerne: %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:119 +#: ../tools/import.vala:120 #, c-format msgid "Couldn't load the ‘%s’ backend." msgstr "Kunne ikke indlæse kildeprogrammet \"%s\"." #. Translators: the first parameter is a backend identifier and the #. * second parameter is an error message. -#: ../tools/import.vala:132 +#: ../tools/import.vala:133 #, c-format msgid "Couldn't prepare the ‘%s’ backend: %s" msgstr "Kunne ikke forberede kildeprogrammet \"%s\": %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:145 +#: ../tools/import.vala:146 #, c-format msgid "Couldn't load the ‘%s’ backend's persona store." msgstr "Kunne ikke indlæse personakilder for kildeprogrammet \"%s\"." -#: ../tools/import.vala:166 +#: ../tools/import.vala:167 #, c-format msgid "Couldn't prepare the ‘%s’ backend's persona store: %s" msgstr "Kunne ikke forberede personakilden for kildeprogrammet \"%s\": %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:184 +#: ../tools/import.vala:185 #, c-format msgid "Error importing contacts: %s" msgstr "Fejl ved import af kontakter: %s" #. Translators: both parameters are identifiers for backends. -#: ../tools/import.vala:198 +#: ../tools/import.vala:199 #, c-format msgid "" "Unrecognized source backend name ‘%s’. ‘%s’ is currently the only supported " @@ -717,3 +847,10 @@ msgid "" msgstr "" "Ukendt navn \"%s\" for kildeprogram. \"%s\" er på nuværende tidspunkt det " "eneste understøttede kildeprogram." + +#~ msgid "" +#~ "Failed to determine whether we can set aliases on Telepathy account '%s': " +#~ "%s" +#~ msgstr "" +#~ "Kunne ikke finde ud af om vi kan indstille aliasser på Telepathy-kontoen " +#~ "\"%s\": %s" @@ -8,10 +8,11 @@ msgid "" msgstr "" "Project-Id-Version: folks master\n" -"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" -"product=folks&keywords=I18N+L10N&component=general\n" -"POT-Creation-Date: 2013-02-20 14:29+0000\n" -"PO-Revision-Date: 2013-02-20 20:19+0100\n" +"Report-Msgid-Bugs-To: " +"http://bugzilla.gnome.org/enter_bug.cgi?product=folks&keywords=I18N+L10N&component=general" +"\n" +"POT-Creation-Date: 2014-03-15 05:53+0000\n" +"PO-Revision-Date: 2014-03-15 20:32+0100\n" "Last-Translator: Bruno Brouard <annoa.b@gmail.com>\n" "Language-Team: GNOME French Team <gnomefr@traduc.org>\n" "Language: \n" @@ -20,6 +21,91 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#: ../backends/bluez/bluez-backend.vala:600 +msgid "" +"No BlueZ 5 object manager running, so the BlueZ backend will be inactive. " +"Either your BlueZ installation is too old (only version 5 is supported) or " +"the service can’t be started." +msgstr "" +"Le gestionnaire d'objets BlueZ 5 n'est pas en cours d'exécution, le moteur " +"BlueZ sera inactif. Soit votre installation de BlueZ est trop ancienne " +"(seule la version 5 est prise en charge) soit le service ne peut être " +"démarré." + +#: ../backends/bluez/bluez-backend.vala:613 +msgid "" +"Error connecting to OBEX transfer daemon over D-Bus. Ensure BlueZ and obexd " +"are installed." +msgstr "" +"Erreur à la connexion au service de transfert OBEX sur D-Bus. Vérifiez que " +"BlueZ et obexd sont installés." + +#. Translators: the parameter is an error message. +#: ../backends/bluez/bluez-persona-store.vala:385 +#, c-format +msgid "Error reading the transferred address book file: %s" +msgstr "Erreur à la lecture du fichier de carnet d'adresses transféré : %s" + +#. Translators: the first parameter is the name of the +#. * failed transfer, and the second is a Bluetooth device +#. * alias. +#. Translators: the first parameter is the name of the failed +#. * transfer, and the second is a Bluetooth device alias. +#: ../backends/bluez/bluez-persona-store.vala:667 +#: ../backends/bluez/bluez-persona-store.vala:689 +#, c-format +msgid "" +"Error during transfer of the address book ‘%s’ from Bluetooth device " +"‘%s’." +msgstr "" +"Erreur lors du transfert du carnet d'adresses « %s » du périphérique " +"Bluetooth « %s »." + +#: ../backends/bluez/bluez-persona-store.vala:782 +#, c-format +msgid "" +"Permission to access the address book on Bluetooth device ‘%s’ was " +"denied by the user." +msgstr "" +"L'accès au carnet d'adresses du périphérique Bluetooth « %s » a été " +"refusé par l'utilisateur." + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:789 +#, c-format +msgid "" +"An OBEX address book transfer from device ‘%s’ could not be started: %s" +msgstr "" +"Un transfert par OBEX d'un carnet d'adresses du périphérique « %s » n'a " +"pas pu être démarré : %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:829 +#, c-format +msgid "The OBEX address book transfer from device ‘%s’ failed: %s" +msgstr "" +"Le transfert par OBEX d'un carnet d'adresses du périphérique « %s » a " +"échoué : %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:846 +#, c-format +msgid "" +"Error during transfer of the address book from Bluetooth device ‘%s’: %s" +msgstr "" +"Erreur lors du transfert du carnet d'adresses du périphérique Bluetooth " +"« %s » : %s" + +#: ../backends/bluez/bluez-persona-store.vala:1064 +#, c-format +msgid "Bluetooth device ‘%s’ disappeared during address book transfer." +msgstr "" +"Le périphérique Bluetooth « %s » a disparu pendant le transfert du " +"carnet d'adresses." + #. The timeout after which we consider a property change to have failed if we #. * haven't received a property change notification for it. #. seconds @@ -34,72 +120,73 @@ msgstr "Starred in Android" #. Translators: the first parameter is an address book #. * URI and the second is a persona UID. -#: ../backends/eds/lib/edsf-persona-store.vala:671 +#: ../backends/eds/lib/edsf-persona-store.vala:673 #, c-format -msgid "Address book ‘%s’ is offline, so contact ‘%s’ cannot be removed." +msgid "" +"Address book ‘%s’ is offline, so contact ‘%s’ cannot be removed." msgstr "" -"Le carnet d'adresses «%s » est hors ligne, par conséquent le contact « %s » " -"ne peut pas être supprimé." +"Le carnet d'adresses «%s » est hors ligne, par conséquent le contact " +"« %s » ne peut pas être supprimé." #. Translators: the first parameter is an address book #. * URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:677 +#: ../backends/eds/lib/edsf-persona-store.vala:679 #, c-format msgid "Permission denied to remove contact ‘%s’: %s" msgstr "Permission refusée de supprimer le contact « %s » : %s" #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:682 +#: ../backends/eds/lib/edsf-persona-store.vala:684 #, c-format msgid "Removing contacts isn't supported by this persona store: %s" msgstr "" "La suppression de contacts n'est pas prise en charge par cet palette de " "personnages : %s" -#: ../backends/eds/lib/edsf-persona-store.vala:711 +#: ../backends/eds/lib/edsf-persona-store.vala:713 #, c-format msgid "Can't remove contact ‘%s’: %s" msgstr "Impossible de supprimer le contact « %s » : %s" #. Translators: the parameter is an address book #. * URI. -#: ../backends/eds/lib/edsf-persona-store.vala:801 -#: ../backends/eds/lib/edsf-persona-store.vala:992 +#: ../backends/eds/lib/edsf-persona-store.vala:802 +#: ../backends/eds/lib/edsf-persona-store.vala:993 #, c-format msgid "Address book ‘%s’ is offline." msgstr "Le carnet d'adresses « %s » est hors ligne." #. Translators: the first parameter is an address #. * book URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:806 -#: ../backends/eds/lib/edsf-persona-store.vala:997 +#: ../backends/eds/lib/edsf-persona-store.vala:807 +#: ../backends/eds/lib/edsf-persona-store.vala:998 #, c-format msgid "Permission denied to open address book ‘%s’: %s" msgstr "Permission refusée d'ouvrir le carnet d'adresses « %s » : %s" #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:839 +#: ../backends/eds/lib/edsf-persona-store.vala:840 #, c-format msgid "Couldn't open address book ‘%s’: %s" msgstr "Impossible d'ouvrir le carnet d'adresses « %s » : %s" #. Translators: the parameteter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:905 -#: ../backends/eds/lib/edsf-persona-store.vala:935 +#: ../backends/eds/lib/edsf-persona-store.vala:906 +#: ../backends/eds/lib/edsf-persona-store.vala:936 #, c-format msgid "Couldn't get address book capabilities: %s" msgstr "Impossible d'obtenir les capacités du carnet d'adresses : %s" #. Translators: the parameter is an address book URI. -#: ../backends/eds/lib/edsf-persona-store.vala:951 +#: ../backends/eds/lib/edsf-persona-store.vala:952 #, c-format msgid "Couldn't get view for address book ‘%s’." msgstr "Impossible d'obtenir la vue pour le carnet d'adresses « %s »." #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1030 +#: ../backends/eds/lib/edsf-persona-store.vala:1031 #, c-format msgid "Couldn't get view for address book ‘%s’: %s" msgstr "Impossible d'obtenir la vue pour le carnet d'adresses « %s » : %s" @@ -107,123 +194,123 @@ msgstr "Impossible d'obtenir la vue pour le carnet d'adresses « %s » : %s" #. Translators: the parameter is the name of a property on a #. * contact, formatted in the normal GObject style (e.g. #. * lowercase with hyphens to separate words). -#: ../backends/eds/lib/edsf-persona-store.vala:1390 +#: ../backends/eds/lib/edsf-persona-store.vala:1303 #, c-format msgid "Changing the ‘%s’ property failed due to reaching the timeout." msgstr "" -"Le changement de la propriété « %s » a échoué en raison d'un délai d'attente " -"dépassé." +"Le changement de la propriété « %s » a échoué en raison d'un délai " +"d'attente dépassé." -#: ../backends/eds/lib/edsf-persona-store.vala:1428 +#: ../backends/eds/lib/edsf-persona-store.vala:1337 #: ../folks/avatar-details.vala:63 msgid "Avatar is not writeable on this contact." msgstr "L'avatar n'est pas modifiable pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1449 +#: ../backends/eds/lib/edsf-persona-store.vala:1358 #: ../folks/web-service-details.vala:123 msgid "Web service addresses are not writeable on this contact." msgstr "Les adresses des services Web ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1485 +#: ../backends/eds/lib/edsf-persona-store.vala:1394 #: ../folks/url-details.vala:152 msgid "URLs are not writeable on this contact." msgstr "Les URL ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1566 +#: ../backends/eds/lib/edsf-persona-store.vala:1475 #: ../folks/local-id-details.vala:64 msgid "Local IDs are not writeable on this contact." msgstr "Les identifiants locaux ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1595 +#: ../backends/eds/lib/edsf-persona-store.vala:1504 msgid "The contact cannot be marked as favourite." msgstr "Impossible de marquer le contact comme favori." #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1667 +#: ../backends/eds/lib/edsf-persona-store.vala:1576 #, c-format msgid "Can't update avatar: %s" msgstr "Impossible de mettre à jour l'avatar : %s" -#: ../backends/eds/lib/edsf-persona-store.vala:1678 +#: ../backends/eds/lib/edsf-persona-store.vala:1587 #: ../folks/email-details.vala:120 msgid "E-mail addresses are not writeable on this contact." msgstr "Les adresses électroniques ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1696 -#: ../folks/phone-details.vala:224 +#: ../backends/eds/lib/edsf-persona-store.vala:1605 +#: ../folks/phone-details.vala:255 msgid "Phone numbers are not writeable on this contact." msgstr "Les numéros de téléphone ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1714 +#: ../backends/eds/lib/edsf-persona-store.vala:1623 #: ../folks/postal-address-details.vala:361 msgid "Postal addresses are not writeable on this contact." msgstr "Les adresses postales ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1785 -#: ../folks/name-details.vala:283 +#: ../backends/eds/lib/edsf-persona-store.vala:1694 +#: ../folks/name-details.vala:454 msgid "Full name is not writeable on this contact." msgstr "Le nom complet n'est pas modifiable pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1807 -#: ../folks/name-details.vala:321 +#: ../backends/eds/lib/edsf-persona-store.vala:1716 +#: ../folks/name-details.vala:492 msgid "Nickname is not writeable on this contact." msgstr "Le pseudonyme n'est pas modifiable pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1829 +#: ../backends/eds/lib/edsf-persona-store.vala:1738 #: ../folks/note-details.vala:138 msgid "Notes are not writeable on this contact." msgstr "Les notes ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1861 +#: ../backends/eds/lib/edsf-persona-store.vala:1770 #: ../folks/birthday-details.vala:62 msgid "Birthday is not writeable on this contact." msgstr "La date de naissance n'est pas modifiable pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:1905 +#: ../backends/eds/lib/edsf-persona-store.vala:1814 #: ../folks/role-details.vala:279 msgid "Roles are not writeable on this contact." msgstr "Les rôles ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:2006 -#: ../folks/name-details.vala:246 +#: ../backends/eds/lib/edsf-persona-store.vala:1915 +#: ../folks/name-details.vala:417 msgid "Structured name is not writeable on this contact." msgstr "Le nom structuré n'est pas modifiable pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:2045 +#: ../backends/eds/lib/edsf-persona-store.vala:1954 #: ../folks/im-details.vala:136 msgid "IM addresses are not writeable on this contact." msgstr "" "Les adresses de messagerie instantanée ne sont pas modifiables pour ce " "contact." -#: ../backends/eds/lib/edsf-persona-store.vala:2095 +#: ../backends/eds/lib/edsf-persona-store.vala:2004 #: ../folks/group-details.vala:174 msgid "Groups are not writeable on this contact." msgstr "Les groupes ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:2110 +#: ../backends/eds/lib/edsf-persona-store.vala:2019 msgid "My Contacts is only available for Google Contacts" msgstr "Mes contacts est seulement disponible pour les contacts Google" -#: ../backends/eds/lib/edsf-persona-store.vala:2181 +#: ../backends/eds/lib/edsf-persona-store.vala:2090 #: ../folks/gender-details.vala:79 msgid "Gender is not writeable on this contact." msgstr "Le genre n'est pas modifiable pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:2219 -#: ../folks/anti-linkable.vala:81 +#: ../backends/eds/lib/edsf-persona-store.vala:2128 +#: ../folks/anti-linkable.vala:84 msgid "Anti-links are not writeable on this contact." msgstr "Les anti-liens ne sont pas modifiables pour ce contact." -#: ../backends/eds/lib/edsf-persona-store.vala:2262 -#: ../folks/location-details.vala:129 +#: ../backends/eds/lib/edsf-persona-store.vala:2171 +#: ../folks/location-details.vala:135 msgid "Location is not writeable on this contact." msgstr "La position n'est pas modifiable pour ce contact." #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2439 +#: ../backends/eds/lib/edsf-persona-store.vala:2484 #, c-format msgid "Property ‘%s’ is not writeable: %s" msgstr "La propriété « %s » n'est pas modifiable : %s" @@ -231,43 +318,47 @@ msgstr "La propriété « %s » n'est pas modifiable : %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2448 +#: ../backends/eds/lib/edsf-persona-store.vala:2493 #, c-format msgid "Invalid value for property ‘%s’: %s" msgstr "Valeur non valide pour la propriété « %s » : %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:2474 +#: ../backends/eds/lib/edsf-persona-store.vala:2519 #, c-format msgid "Unknown error setting property ‘%s’: %s" -msgstr "Erreur inconnue au changement de valeur de la propriété « %s » : %s" +msgstr "" +"Erreur inconnue au changement de valeur de la propriété « %s » : %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:233 +#: ../backends/key-file/kf-persona-store.vala:234 #, c-format msgid "The relationship key file '%s' could not be loaded: %s" -msgstr "Le fichier de clé de relation « %s » n'a pas pu être chargé : %s" +msgstr "" +"Le fichier de clé de relation « %s » n'a pas pu être chargé : %s" #. Translators: the first parameter is a path, and the #. * second is an error message. -#: ../backends/key-file/kf-persona-store.vala:255 +#: ../backends/key-file/kf-persona-store.vala:256 #, c-format msgid "The relationship key file directory '%s' could not be created: %s" msgstr "" -"Le répertoire du fichier de clé de relation « %s » n'a pas pu être créé : %s" +"Le répertoire du fichier de clé de relation « %s » n'a pas pu être " +"créé : %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:279 +#: ../backends/key-file/kf-persona-store.vala:280 #, c-format msgid "The relationship key file '%s' could not be created: %s" -msgstr "Le fichier de clé de relation « %s » n'a pas pu être créé : %s" +msgstr "" +"Le fichier de clé de relation « %s » n'a pas pu être créé : %s" #. Translators: the first parameter is a filename, the second is #. * an error message. -#: ../backends/key-file/kf-persona-store.vala:470 +#: ../backends/key-file/kf-persona-store.vala:471 #, c-format msgid "Could not write updated key file '%s': %s" msgstr "Impossible de mettre à jour le fichier de clé « %s » : %s" @@ -277,7 +368,7 @@ msgstr "Impossible de mettre à jour le fichier de clé « %s » : %s" #. * an IM address (e.g. “foo@jabber.org”), the second is #. * the name of a protocol (e.g. “jabber”) and the third is #. * an error message. -#: ../backends/key-file/kf-persona.vala:172 +#: ../backends/key-file/kf-persona.vala:174 #, c-format msgid "Invalid IM address ‘%s’ for protocol ‘%s’: %s" msgstr "" @@ -285,7 +376,7 @@ msgstr "" "« %s » : %s" #. Translators: the parameter is an error message. -#: ../backends/key-file/kf-persona.vala:430 +#: ../backends/key-file/kf-persona.vala:432 #, c-format msgid "Couldn't load data from key file: %s" msgstr "Impossible de charger les données du fichier de clé : %s" @@ -310,31 +401,29 @@ msgstr "Aucune capacité de contacts n'a été trouvée." msgid "Error opening contacts view." msgstr "Erreur lors de l'ouverture de la vue des contacts." -#. Translators: the first parameter is the display name for -#. * the Telepathy account, and the second is an error -#. * message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:814 -#, c-format +#: ../backends/ofono/ofono-backend.vala:196 msgid "" -"Failed to determine whether we can set aliases on Telepathy account '%s': %s" +"No oFono object manager running, so the oFono backend will be inactive. " +"Either oFono isn’t installed or the service can’t be started." msgstr "" -"Impossible de déterminer s'il est possible de définir des alias sur le " -"compte Telepathy « %s » : %s" +"Le gestionnaire d'objets oFono n'est pas en cours d'exécution, le moteur " +"oFono sera inactif. Soit oFono n'est pas installé soit le service ne peut " +"être démarré." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1278 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1248 msgid "Telepathy contacts representing the local user may not be removed." msgstr "" "Les contacts Telepathy représentant l'utilisateur local ne peuvent être " "supprimés." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1289 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1259 #, c-format msgid "Failed to remove a persona from store: %s" msgstr "Échec de la suppression d'un personnage de la palette : %s" #. Translators: the first two parameters are store identifiers and #. * the third is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1324 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1294 #, c-format msgid "" "Persona store (%s, %s) requires the following details:\n" @@ -343,26 +432,26 @@ msgstr "" "La palette de personnages (%s, %s) a besoin des détails suivants :\n" " contact (fourni : « %s »)\n" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1339 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1309 msgid "Cannot create a new Telepathy contact while offline." msgstr "Impossible de créer un nouveau contact Telepathy en mode hors ligne." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1357 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1327 #, c-format msgid "Failed to add a persona from details: %s" msgstr "Échec de l'ajout d'un personnage à partir des détails : %s" #. Translators: "telepathy-logger" is the name of an application, #. * and should not be translated. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1377 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1347 msgid "" "Failed to change favorite without a connection to the telepathy-logger " "service." msgstr "" -"Échec de la modification du favori sans une connexion au service telepathy-" -"logger." +"Échec de la modification du favori sans une connexion au service " +"telepathy-logger." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1383 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1353 msgid "" "Failed to change favorite status of Telepathy Persona because it has no " "attached TpContact." @@ -371,54 +460,56 @@ msgstr "" "possède aucun TpContact attaché." #. Translators: the parameter is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1401 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1371 #, c-format msgid "Failed to change favorite status for Telepathy contact ‘%s’." msgstr "" -"Échec de la modification du statut favori pour le contact Telepathy « %s »." +"Échec de la modification du statut favori pour le contact Telepathy " +"« %s »." #. Translators: the parameter is an error message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1433 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1403 #, c-format msgid "Failed to change contact's alias: %s" msgstr "Échec de la modification de l'alias du contact : %s" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1484 msgid "Extended information may only be set on the user's Telepathy contact." msgstr "" "Des informations étendues ne peuvent être définies que sur le contact " "Telepathy de l'utilisateur." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1542 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 msgid "" "Extended information cannot be written because the store is disconnected." msgstr "" -"Les informations étendues ne peuvent être écrites parce que la palette est " -"déconnectée." +"Les informations étendues ne peuvent être écrites parce que la palette " +"est déconnectée." -#: ../backends/telepathy/lib/tpf-persona.vala:499 -#: ../backends/telepathy/lib/tpf-persona.vala:520 -#: ../backends/telepathy/lib/tpf-persona.vala:572 -#: ../backends/telepathy/lib/tpf-persona.vala:586 +#: ../backends/telepathy/lib/tpf-persona.vala:511 +#: ../backends/telepathy/lib/tpf-persona.vala:532 +#: ../backends/telepathy/lib/tpf-persona.vala:584 +#: ../backends/telepathy/lib/tpf-persona.vala:598 #, c-format msgid "Failed to change group membership: %s" msgstr "Échec de la modification de l'appartenance au groupe : %s" #. Translators: "account" refers to an instant messaging #. * account. -#: ../backends/telepathy/lib/tpf-persona.vala:502 -#: ../backends/telepathy/lib/tpf-persona.vala:575 +#: ../backends/telepathy/lib/tpf-persona.vala:514 +#: ../backends/telepathy/lib/tpf-persona.vala:587 msgid "Account is offline." msgstr "Le compte est hors ligne." #. Translators: the first parameter is the unknown key that #. * was received with the details params, and the second #. * identifies the persona store. -#: ../backends/tracker/lib/trf-persona-store.vala:742 +#: ../backends/tracker/lib/trf-persona-store.vala:743 #, c-format msgid "Unrecognized parameter '%s' passed to persona store '%s'." msgstr "" -"Paramètre non reconnu « %s » transmis à la palette de personnages « %s »." +"Paramètre non reconnu « %s » transmis à la palette de personnages " +"« %s »." #: ../folks/alias-details.vala:61 msgid "Alias is not writeable on this contact." @@ -426,26 +517,28 @@ msgstr "L'alias n'est pas modifiable pour ce contact." #. Translators: the first parameter is a folder path and the second #. * is an error message. -#: ../folks/backend-store.vala:609 +#: ../folks/backend-store.vala:651 #, c-format msgid "Error listing contents of folder '%s': %s" -msgstr "Erreur lors de l'énumération du contenu du répertoire « %s » : %s" +msgstr "" +"Erreur lors de l'énumération du contenu du répertoire « %s » : %s" #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:739 +#: ../folks/backend-store.vala:786 #, c-format msgid "File or directory '%s' does not exist." msgstr "Le fichier ou le répertoire « %s » n'existe pas." #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:745 +#: ../folks/backend-store.vala:792 #, c-format msgid "Failed to get content type for '%s'." msgstr "Échec de l'obtention du type de contenu pour « %s »." #: ../folks/birthday-details.vala:93 msgid "Birthday event ID is not writeable on this contact." -msgstr "L'ID de l'événement anniversaire n'est pas modifiable pour ce contact." +msgstr "" +"L'ID de l'événement anniversaire n'est pas modifiable pour ce contact." #: ../folks/favourite-details.vala:58 msgid "Favorite status is not writeable on this contact." @@ -456,47 +549,50 @@ msgstr "Le statut favori n'est pas modifiable pour ce contact." #: ../folks/im-details.vala:214 ../folks/im-details.vala:241 #, c-format msgid "The IM address '%s' could not be understood." -msgstr "L'adresse de messagerie instantanée « %s » n'a pas pu être comprise." +msgstr "" +"L'adresse de messagerie instantanée « %s » n'a pas pu être comprise." #. Translators: the first parameter is a persona store identifier #. * and the second is an error message. -#: ../folks/individual-aggregator.vala:921 +#: ../folks/individual-aggregator.vala:1040 #, c-format msgid "Error preparing persona store '%s': %s" -msgstr "Erreur lors de la préparation de la palette de personnages « %s » : %s" +msgstr "" +"Erreur lors de la préparation de la palette de personnages « %s » : %s" #. Translators: the parameter is a property name. -#: ../folks/individual-aggregator.vala:1142 -#: ../folks/individual-aggregator.vala:1368 +#: ../folks/individual-aggregator.vala:1269 +#: ../folks/individual-aggregator.vala:1536 #, c-format msgid "Unknown property '%s' in linkable property list." -msgstr "Propriété inconnue « %s » dans la liste de propriétés connectables." +msgstr "" +"Propriété inconnue « %s » dans la liste de propriétés connectables." #. Translators: the first parameter is a store identifier #. * and the second parameter is an error message. -#: ../folks/individual-aggregator.vala:1830 +#: ../folks/individual-aggregator.vala:2022 #, c-format msgid "Failed to add contact for persona store ID '%s': %s" msgstr "" "Échec lors de l'ajout du contact pour l'identifiant de la palette de " "personnages « %s » : %s" -#: ../folks/individual-aggregator.vala:1931 +#: ../folks/individual-aggregator.vala:2119 msgid "Can’t link personas with no primary store." msgstr "Impossible de connecter des personnages sans palette principale." -#: ../folks/individual-aggregator.vala:1932 -#: ../folks/individual-aggregator.vala:2276 +#: ../folks/individual-aggregator.vala:2120 +#: ../folks/individual-aggregator.vala:2451 #, c-format msgid "" -"Persona store ‘%s:%s’ is configured as primary, but could not be found or " -"failed to load." +"Persona store ‘%s:%s’ is configured as primary, but could not be found " +"or failed to load." msgstr "" -"La palette de personnages « %s:%s » est configurée comme principale, mais " -"elle n'a pas pu être trouvée ou son chargement a échoué." +"La palette de personnages « %s:%s » est configurée comme principale, " +"mais elle n'a pas pu être trouvée ou son chargement a échoué." -#: ../folks/individual-aggregator.vala:1933 -#: ../folks/individual-aggregator.vala:2277 +#: ../folks/individual-aggregator.vala:2121 +#: ../folks/individual-aggregator.vala:2452 #, c-format msgid "" "Check the relevant service is running, or change the default store in that " @@ -505,32 +601,82 @@ msgstr "" "Vérifiez que le service pertinent est lancé ou modifiez la palette par " "défaut dans ce service ou en utilisant la clé GSettings « %s »." -#: ../folks/individual-aggregator.vala:1965 +#: ../folks/individual-aggregator.vala:2153 msgid "Anti-links can't be removed between personas being linked." msgstr "" -"Les anti-liens ne peuvent pas être supprimés entre des personnages qui sont " -"connectés." +"Les anti-liens ne peuvent pas être supprimés entre des personnages qui " +"sont connectés." -#: ../folks/individual-aggregator.vala:2275 +#: ../folks/individual-aggregator.vala:2450 msgid "Can’t add personas with no primary store." msgstr "Impossible d'ajouter des personnages sans palette principale." -#: ../folks/individual-aggregator.vala:2286 +#: ../folks/individual-aggregator.vala:2461 #, c-format msgid "Can't write to requested property (“%s”) of the writeable store." msgstr "" "Impossible d'écrire à la propriété demandée (« %s ») de la palette " "modifiable." -#: ../folks/individual.vala:217 ../folks/individual.vala:370 -#: ../folks/individual.vala:479 ../folks/individual.vala:730 -#: ../folks/individual.vala:808 +#: ../folks/individual.vala:216 ../folks/individual.vala:402 +#: ../folks/individual.vala:511 ../folks/individual.vala:762 +#: ../folks/individual.vala:840 #, c-format msgid "Failed to change property ‘%s’: No suitable personas were found." msgstr "" "Échec lors du changement de la propriété « %s » : aucun personnage " "correspondant trouvé." +#. Translators: This is the default name for an Individual +#. * when displayed in the UI if no personal details are available +#. * for them. +#: ../folks/individual.vala:1951 +msgid "Unnamed Person" +msgstr "Personne sans nom" + +#. FIXME: Ideally we’d use a format string translated to the locale of the +#. * persona whose name is being formatted, but no backend provides +#. * information about personas’ locales, so we have to settle for the +#. * current user’s locale. +#. * +#. * We thought about using nl_langinfo(_NL_NAME_NAME_FMT) here, but +#. * decided against it because: +#. * 1. It’s not the best documented API in the world, and its stability +#. * is in question. +#. * 2. An attempt to improve the interface in glibc met with a wall of +#. * complaints: https://sourceware.org/bugzilla/show_bug.cgi?id=14641. +#. * +#. * However, we do re-use the string format placeholders from +#. * _NL_NAME_NAME_FMT (as documented here: +#. * http://lh.2xlibre.net/values/name_fmt/) because there’s a chance glibc +#. * might eventually grow a useful interface for this. +#. * +#. * It does mean we have to implement our own parser for the name_fmt +#. * format though, since glibc doesn’t provide a formatting function. +#. Translators: This is a format string used to convert structured names +#. * to a single string. It should be translated to the predominant +#. * semi-formal name format for your locale, using the placeholders +#. * documented here: http://lh.2xlibre.net/values/name_fmt/. You may be +#. * able to re-use the existing glibc format string for your locale on that +#. * page if it’s suitable. +#. * +#. * More explicitly: the supported placeholders are %f, %F, %g, %G, %m, %M, +#. * %t. The romanisation modifier (e.g. %Rf) is recognized but ignored. +#. * %s, %S and %d are all replaced by the same thing (the ‘Honorific +#. * Prefixes’ from vCard) so please avoid using more than one. +#. * +#. * For example, the format string ‘%g%t%m%t%f’ expands to ‘John Andrew +#. * Lees’ when used for a persona with first name ‘John’, additional names +#. * ‘Andrew’ and family names ‘Lees’. +#. * +#. * If you need additional placeholders with other information or +#. * punctuation, please file a bug against libfolks: +#. * https://bugzilla.gnome.org/enter_bug.cgi?product=folks +#. +#: ../folks/name-details.vala:268 +msgid "%g%t%m%t%f" +msgstr "%g%t%m%t%f" + #: ../folks/org.freedesktop.folks.gschema.xml.in.h:1 msgid "Primary store ID" msgstr "Identifiant de la palette principale" @@ -539,48 +685,49 @@ msgstr "Identifiant de la palette principale" msgid "" "The ID of the persona store which folks should use as primary (i.e. to store " "linking data in). The type ID of the store may optionally be prepended, " -"separated by a colon. For example: “eds:system-address-book” or “key-file”." +"separated by a colon. For example: “eds:system-address-book” or " +"“key-file”." msgstr "" "L'identifiant de la palette de personnages que folks utilise comme " "principale (c.-à-d. pour y enregistrer les données de connexion). " "L'identifiant du type de la palette peut être éventuellement ajouté au " -"début, séparé par deux points. Par exemple : « eds:system-address-book » ou " -"« key-file »." +"début, séparé par deux points. Par exemple : " +"« eds:system-address-book » ou « key-file »." #: ../folks/postal-address-details.vala:231 #, c-format msgid "%s, %s, %s, %s, %s, %s, %s" msgstr "%s, %s, %s, %s, %s, %s, %s" -#: ../folks/presence-details.vala:159 +#: ../folks/presence-details.vala:171 msgid "Unknown status" msgstr "Statut inconnu" -#: ../folks/presence-details.vala:161 +#: ../folks/presence-details.vala:173 msgid "Offline" msgstr "Hors ligne" -#: ../folks/presence-details.vala:165 +#: ../folks/presence-details.vala:177 msgid "Error" msgstr "Erreur" -#: ../folks/presence-details.vala:167 +#: ../folks/presence-details.vala:179 msgid "Available" msgstr "Disponible" -#: ../folks/presence-details.vala:169 +#: ../folks/presence-details.vala:181 msgid "Away" msgstr "Absent" -#: ../folks/presence-details.vala:171 +#: ../folks/presence-details.vala:183 msgid "Extended away" msgstr "Absence prolongée" -#: ../folks/presence-details.vala:173 +#: ../folks/presence-details.vala:185 msgid "Busy" msgstr "Occupé" -#: ../folks/presence-details.vala:175 +#: ../folks/presence-details.vala:187 msgid "Hidden" msgstr "Masqué" @@ -612,17 +759,18 @@ msgstr "Le fichier %s n'est pas lisible." #: ../tools/import-pidgin.vala:82 #, c-format msgid "The Pidgin buddy list file '%s' could not be loaded." -msgstr "Le fichier de liste de contacts Pidgin « %s » n'a pas pu être chargé." +msgstr "" +"Le fichier de liste de contacts Pidgin « %s » n'a pas pu être chargé." #. Translators: the parameter is a filename. #: ../tools/import-pidgin.vala:97 #, c-format msgid "" -"The Pidgin buddy list file ‘%s’ could not be loaded: the root element could " -"not be found or was not recognized." +"The Pidgin buddy list file ‘%s’ could not be loaded: the root element " +"could not be found or was not recognized." msgstr "" -"Le fichier de liste de contacts Pidgin « %s » n'a pas pu être chargé : " -"l'élément racine n'a pas pu être retrouvé ou reconnu." +"Le fichier de liste de contacts Pidgin « %s » n'a pas pu être " +"chargé : l'élément racine n'a pas pu être retrouvé ou reconnu." #. Translators: the first parameter is the number of buddies which #. * were successfully imported, and the second is a filename. @@ -654,12 +802,13 @@ msgstr "" #: ../tools/import-pidgin.vala:244 #, c-format msgid "" -"Failed to create new contact for buddy with alias ‘%s’ and IM addresses:\n" +"Failed to create new contact for buddy with alias ‘%s’ and IM " +"addresses:\n" "%s\n" "Error: %s\n" msgstr "" -"Impossible de créer le nouveau contact pour l'ami possédant l'alias « %s » " -"et les adresses de messagerie instantanée : \n" +"Impossible de créer le nouveau contact pour l'ami possédant l'alias " +"« %s » et les adresses de messagerie instantanée : \n" "%s\n" "Erreur : %s\n" @@ -672,8 +821,8 @@ msgid "" "Created contact ‘%s’ for buddy with alias ‘%s’ and IM addresses:\n" "%s" msgstr "" -"Création du contact « %s » pour l'ami possédant l'alias « %s » et les " -"adresses de messagerie instantanée : \n" +"Création du contact « %s » pour l'ami possédant l'alias « %s » et " +"les adresses de messagerie instantanée : \n" "%s" #: ../tools/import.vala:44 @@ -684,58 +833,66 @@ msgstr "Nom de moteur source (par défaut : « pidgin »)" msgid "Source filename (default: specific to source backend)" msgstr "Nom de fichier source (par défaut : spécifique au moteur source)" -#: ../tools/import.vala:57 +#: ../tools/import.vala:58 msgid "— import meta-contact information to libfolks" msgstr "— importer les informations du méta-contact vers libfolks" #. Translators: the parameter is an error message. -#: ../tools/import.vala:67 +#: ../tools/import.vala:68 #, c-format msgid "Couldn't parse command line options: %s" msgstr "Impossible d'analyser les options de la ligne de commande : %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:108 +#: ../tools/import.vala:109 #, c-format msgid "Couldn't load the backends: %s" msgstr "Impossible de charger les moteurs : %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:119 +#: ../tools/import.vala:120 #, c-format msgid "Couldn't load the ‘%s’ backend." msgstr "Impossible de charger le moteur « %s »." #. Translators: the first parameter is a backend identifier and the #. * second parameter is an error message. -#: ../tools/import.vala:132 +#: ../tools/import.vala:133 #, c-format msgid "Couldn't prepare the ‘%s’ backend: %s" msgstr "Impossible de préparer le moteur « %s » : %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:145 +#: ../tools/import.vala:146 #, c-format msgid "Couldn't load the ‘%s’ backend's persona store." msgstr "Impossible de charger la palette de personnages du moteur « %s »." -#: ../tools/import.vala:166 +#: ../tools/import.vala:167 #, c-format msgid "Couldn't prepare the ‘%s’ backend's persona store: %s" -msgstr "Impossible de préparer la palette de personnages du moteur « %s » : %s" +msgstr "" +"Impossible de préparer la palette de personnages du moteur « %s » : %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:184 +#: ../tools/import.vala:185 #, c-format msgid "Error importing contacts: %s" msgstr "Erreur d'importation de contacts : %s" #. Translators: both parameters are identifiers for backends. -#: ../tools/import.vala:198 +#: ../tools/import.vala:199 #, c-format msgid "" -"Unrecognized source backend name ‘%s’. ‘%s’ is currently the only supported " -"source backend." +"Unrecognized source backend name ‘%s’. ‘%s’ is currently the only " +"supported source backend." msgstr "" -"Nom de moteur source non reconnu « %s ». « %s » est actuellement le seul " -"moteur source pris en charge." +"Nom de moteur source non reconnu « %s ». « %s » est actuellement le " +"seul moteur source pris en charge." + +#~ msgid "" +#~ "Failed to determine whether we can set aliases on Telepathy account '%s': " +#~ "%s" +#~ msgstr "" +#~ "Impossible de déterminer s'il est possible de définir des alias sur le " +#~ "compte Telepathy « %s » : %s" @@ -1,17 +1,17 @@ # Italian translation of Folks # Copyright (C) 2012 # This file is distributed under the same license as the Folks package. -# Gianvito Cavasoli <gianvito@gmx.it>, 2012, 2013. +# Gianvito Cavasoli <gianvito@gmx.it>, 2012, 2013, 2014. # msgid "" msgstr "" "Project-Id-Version: folks\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=folks&keywords=I18N+L10N&component=general\n" -"POT-Creation-Date: 2013-03-15 10:51+0000\n" -"PO-Revision-Date: 2013-03-16 14:23+0100\n" +"POT-Creation-Date: 2014-03-07 05:54+0000\n" +"PO-Revision-Date: 2014-03-07 11:08+0100\n" "Last-Translator: Gianvito Cavasoli <gianvito@gmx.it>\n" -"Language-Team: Italiano <tp@linux.it>\n" +"Language-Team: Italiano <tp@lists.linux.it>\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,6 +19,88 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 2.91.6\n" +#: ../backends/bluez/bluez-backend.vala:600 +msgid "" +"No BlueZ 5 object manager running, so the BlueZ backend will be inactive. " +"Either your BlueZ installation is too old (only version 5 is supported) or " +"the service can’t be started." +msgstr "" +"Nessun gestore oggetto BlueZ 5 in esecuzione, così il backend BlueZ sarà " +"inattivo. L'installazione di BlueZ potrebbe essere troppo vecchia (solo la " +"versione 5 è supportata) o il servizio non può essere avviato." + +#: ../backends/bluez/bluez-backend.vala:613 +msgid "" +"Error connecting to OBEX transfer daemon over D-Bus. Ensure BlueZ and obexd " +"are installed." +msgstr "" +"Si è verificato un problema nella connessione al demone di trasferimento " +"OBEX verso D-Bus. Assicurarsi che BlueZ e obexd siano installati." + +#. Translators: the parameter is an error message. +#: ../backends/bluez/bluez-persona-store.vala:385 +#, c-format +msgid "Error reading the transferred address book file: %s" +msgstr "" +"Si è verificato un errore leggendo il file della rubrica trasferita: %s" + +#. Translators: the first parameter is the name of the +#. * failed transfer, and the second is a Bluetooth device +#. * alias. +#. Translators: the first parameter is the name of the failed +#. * transfer, and the second is a Bluetooth device alias. +#: ../backends/bluez/bluez-persona-store.vala:667 +#: ../backends/bluez/bluez-persona-store.vala:689 +#, c-format +msgid "" +"Error during transfer of the address book ‘%s’ from Bluetooth device ‘%s’." +msgstr "" +"Si è verificato un errore durante il trasferimento della rubrica «%s» dal " +"dispositivo Bluetooth «%s»." + +#: ../backends/bluez/bluez-persona-store.vala:782 +#, c-format +msgid "" +"Permission to access the address book on Bluetooth device ‘%s’ was denied by " +"the user." +msgstr "" +"Il permesso per accedere alla rubrica sul dispositivo Bluetooth «%s» è stato " +"negato dall'utente." + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:789 +#, c-format +msgid "An OBEX address book transfer from device ‘%s’ could not be started: %s" +msgstr "" +"Impossibile avviare il trasferimento OBEX della rubrica dal dispositivo " +"«%s»: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:829 +#, c-format +msgid "The OBEX address book transfer from device ‘%s’ failed: %s" +msgstr "" +"Il trasferimento OBEX della rubrica dal dispositivo «%s» non è riuscito: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:846 +#, c-format +msgid "" +"Error during transfer of the address book from Bluetooth device ‘%s’: %s" +msgstr "" +"Si è verificato un errore nel trasferimento della rubrica dal dispositivo " +"Bluetooth «%s»: %s" + +#: ../backends/bluez/bluez-persona-store.vala:1064 +#, c-format +msgid "Bluetooth device ‘%s’ disappeared during address book transfer." +msgstr "" +"Il dispositivo Bluetooth «%s» è scomparso durante il trasferimento della " +"rubrica." + #. The timeout after which we consider a property change to have failed if we #. * haven't received a property change notification for it. #. seconds @@ -33,7 +115,7 @@ msgstr "" #. Translators: the first parameter is an address book #. * URI and the second is a persona UID. -#: ../backends/eds/lib/edsf-persona-store.vala:671 +#: ../backends/eds/lib/edsf-persona-store.vala:673 #, c-format msgid "Address book ‘%s’ is offline, so contact ‘%s’ cannot be removed." msgstr "" @@ -42,62 +124,62 @@ msgstr "" #. Translators: the first parameter is an address book #. * URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:677 +#: ../backends/eds/lib/edsf-persona-store.vala:679 #, c-format msgid "Permission denied to remove contact ‘%s’: %s" msgstr "Permesso negato per rimuovere il contatto «%s»: %s" #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:682 +#: ../backends/eds/lib/edsf-persona-store.vala:684 #, c-format msgid "Removing contacts isn't supported by this persona store: %s" msgstr "" "La rimozione dei contatti non è supportata da questo archivio personale: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:711 +#: ../backends/eds/lib/edsf-persona-store.vala:713 #, c-format msgid "Can't remove contact ‘%s’: %s" msgstr "Impossibile rimuovere il contatto «%s»: %s" #. Translators: the parameter is an address book #. * URI. -#: ../backends/eds/lib/edsf-persona-store.vala:801 -#: ../backends/eds/lib/edsf-persona-store.vala:992 +#: ../backends/eds/lib/edsf-persona-store.vala:802 +#: ../backends/eds/lib/edsf-persona-store.vala:993 #, c-format msgid "Address book ‘%s’ is offline." msgstr "La rubrica «%s» non è in rete." #. Translators: the first parameter is an address #. * book URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:806 -#: ../backends/eds/lib/edsf-persona-store.vala:997 +#: ../backends/eds/lib/edsf-persona-store.vala:807 +#: ../backends/eds/lib/edsf-persona-store.vala:998 #, c-format msgid "Permission denied to open address book ‘%s’: %s" msgstr "Permesso negato per aprire la rubrica «%s»: %s" #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:839 +#: ../backends/eds/lib/edsf-persona-store.vala:840 #, c-format msgid "Couldn't open address book ‘%s’: %s" msgstr "Impossibile aprire la rubrica «%s»: %s" #. Translators: the parameteter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:905 -#: ../backends/eds/lib/edsf-persona-store.vala:935 +#: ../backends/eds/lib/edsf-persona-store.vala:906 +#: ../backends/eds/lib/edsf-persona-store.vala:936 #, c-format msgid "Couldn't get address book capabilities: %s" msgstr "Impossibile ottenere le funzionalità della rubrica: %s" #. Translators: the parameter is an address book URI. -#: ../backends/eds/lib/edsf-persona-store.vala:951 +#: ../backends/eds/lib/edsf-persona-store.vala:952 #, c-format msgid "Couldn't get view for address book ‘%s’." msgstr "Impossibile ottenere la visualizzazione per la rubrica «%s»" #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1030 +#: ../backends/eds/lib/edsf-persona-store.vala:1031 #, c-format msgid "Couldn't get view for address book ‘%s’: %s" msgstr "Impossibile ottenere la visualizzazione per la rubrica «%s»: %s" @@ -105,122 +187,122 @@ msgstr "Impossibile ottenere la visualizzazione per la rubrica «%s»: %s" #. Translators: the parameter is the name of a property on a #. * contact, formatted in the normal GObject style (e.g. #. * lowercase with hyphens to separate words). -#: ../backends/eds/lib/edsf-persona-store.vala:1390 +#: ../backends/eds/lib/edsf-persona-store.vala:1303 #, c-format msgid "Changing the ‘%s’ property failed due to reaching the timeout." msgstr "" "La modifica della proprietà «%s» non è riuscita a causa del tempo scaduto." -#: ../backends/eds/lib/edsf-persona-store.vala:1428 +#: ../backends/eds/lib/edsf-persona-store.vala:1337 #: ../folks/avatar-details.vala:63 msgid "Avatar is not writeable on this contact." msgstr "L'avatar non è scrivibile in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1449 +#: ../backends/eds/lib/edsf-persona-store.vala:1358 #: ../folks/web-service-details.vala:123 msgid "Web service addresses are not writeable on this contact." msgstr "Gli indirizzi dei servizi web non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1485 +#: ../backends/eds/lib/edsf-persona-store.vala:1394 #: ../folks/url-details.vala:152 msgid "URLs are not writeable on this contact." msgstr "Gli URL non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1566 +#: ../backends/eds/lib/edsf-persona-store.vala:1475 #: ../folks/local-id-details.vala:64 msgid "Local IDs are not writeable on this contact." msgstr "Gli ID locali non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1595 +#: ../backends/eds/lib/edsf-persona-store.vala:1504 msgid "The contact cannot be marked as favourite." msgstr "Impossibile marcare il contatto come preferito." #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1667 +#: ../backends/eds/lib/edsf-persona-store.vala:1576 #, c-format msgid "Can't update avatar: %s" msgstr "Impossibile aggiornare l'avatar: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:1678 +#: ../backends/eds/lib/edsf-persona-store.vala:1587 #: ../folks/email-details.vala:120 msgid "E-mail addresses are not writeable on this contact." msgstr "Gli indirizzi mail non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1696 -#: ../folks/phone-details.vala:224 +#: ../backends/eds/lib/edsf-persona-store.vala:1605 +#: ../folks/phone-details.vala:255 msgid "Phone numbers are not writeable on this contact." msgstr "I numeri di telefono non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1714 +#: ../backends/eds/lib/edsf-persona-store.vala:1623 #: ../folks/postal-address-details.vala:361 msgid "Postal addresses are not writeable on this contact." msgstr "Gli indirizzi postali non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1785 -#: ../folks/name-details.vala:283 +#: ../backends/eds/lib/edsf-persona-store.vala:1694 +#: ../folks/name-details.vala:454 msgid "Full name is not writeable on this contact." msgstr "Il nome completo non è scrivibile in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1807 -#: ../folks/name-details.vala:321 +#: ../backends/eds/lib/edsf-persona-store.vala:1716 +#: ../folks/name-details.vala:492 msgid "Nickname is not writeable on this contact." msgstr "Il soprannome non è scrivibile in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1829 +#: ../backends/eds/lib/edsf-persona-store.vala:1738 #: ../folks/note-details.vala:138 msgid "Notes are not writeable on this contact." msgstr "Le note non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1861 +#: ../backends/eds/lib/edsf-persona-store.vala:1770 #: ../folks/birthday-details.vala:62 msgid "Birthday is not writeable on this contact." msgstr "Il compleanno non è scrivibile in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:1905 +#: ../backends/eds/lib/edsf-persona-store.vala:1814 #: ../folks/role-details.vala:279 msgid "Roles are not writeable on this contact." msgstr "I ruoli non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:2006 -#: ../folks/name-details.vala:246 +#: ../backends/eds/lib/edsf-persona-store.vala:1915 +#: ../folks/name-details.vala:417 msgid "Structured name is not writeable on this contact." msgstr "Il nome strutturato non è scrivibile in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:2045 +#: ../backends/eds/lib/edsf-persona-store.vala:1954 #: ../folks/im-details.vala:136 msgid "IM addresses are not writeable on this contact." msgstr "" "Gli indirizzi di messaggistica istantanea non sono scrivibili in questo " "contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:2095 +#: ../backends/eds/lib/edsf-persona-store.vala:2004 #: ../folks/group-details.vala:174 msgid "Groups are not writeable on this contact." msgstr "I gruppi non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:2110 +#: ../backends/eds/lib/edsf-persona-store.vala:2019 msgid "My Contacts is only available for Google Contacts" msgstr "Miei contatti è solo disponibile per i Contatti Google" -#: ../backends/eds/lib/edsf-persona-store.vala:2181 +#: ../backends/eds/lib/edsf-persona-store.vala:2090 #: ../folks/gender-details.vala:79 msgid "Gender is not writeable on this contact." msgstr "Il sesso non è scrivibile in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:2219 -#: ../folks/anti-linkable.vala:81 +#: ../backends/eds/lib/edsf-persona-store.vala:2128 +#: ../folks/anti-linkable.vala:84 msgid "Anti-links are not writeable on this contact." msgstr "Gli anti-links non sono scrivibili in questo contatto." -#: ../backends/eds/lib/edsf-persona-store.vala:2262 -#: ../folks/location-details.vala:129 +#: ../backends/eds/lib/edsf-persona-store.vala:2171 +#: ../folks/location-details.vala:135 msgid "Location is not writeable on this contact." msgstr "La posizione non è scrivibile in questo contatto." #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2439 +#: ../backends/eds/lib/edsf-persona-store.vala:2484 #, c-format msgid "Property ‘%s’ is not writeable: %s" msgstr "La proprietà «%s» non è scrivibile: %s" @@ -228,42 +310,42 @@ msgstr "La proprietà «%s» non è scrivibile: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2448 +#: ../backends/eds/lib/edsf-persona-store.vala:2493 #, c-format msgid "Invalid value for property ‘%s’: %s" msgstr "Valore non valido per la proprietà «%s»: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:2474 +#: ../backends/eds/lib/edsf-persona-store.vala:2519 #, c-format msgid "Unknown error setting property ‘%s’: %s" msgstr "Errore sconosciuto di impostazione della proprietà «%s»: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:233 +#: ../backends/key-file/kf-persona-store.vala:234 #, c-format msgid "The relationship key file '%s' could not be loaded: %s" msgstr "La chiave di relazione del file «%s» non può essere caricata: %s" #. Translators: the first parameter is a path, and the #. * second is an error message. -#: ../backends/key-file/kf-persona-store.vala:255 +#: ../backends/key-file/kf-persona-store.vala:256 #, c-format msgid "The relationship key file directory '%s' could not be created: %s" msgstr "La chiave di relazione della directory «%s» non può essere creata: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:279 +#: ../backends/key-file/kf-persona-store.vala:280 #, c-format msgid "The relationship key file '%s' could not be created: %s" msgstr "La chiave di relazione del file «%s» non può essere creata: %s" #. Translators: the first parameter is a filename, the second is #. * an error message. -#: ../backends/key-file/kf-persona-store.vala:470 +#: ../backends/key-file/kf-persona-store.vala:471 #, c-format msgid "Could not write updated key file '%s': %s" msgstr "Impossibile scrivere un file chiave «%s» aggiornato: %s" @@ -273,7 +355,7 @@ msgstr "Impossibile scrivere un file chiave «%s» aggiornato: %s" #. * an IM address (e.g. “foo@jabber.org”), the second is #. * the name of a protocol (e.g. “jabber”) and the third is #. * an error message. -#: ../backends/key-file/kf-persona.vala:172 +#: ../backends/key-file/kf-persona.vala:174 #, c-format msgid "Invalid IM address ‘%s’ for protocol ‘%s’: %s" msgstr "" @@ -281,7 +363,7 @@ msgstr "" "«%s»: %s" #. Translators: the parameter is an error message. -#: ../backends/key-file/kf-persona.vala:430 +#: ../backends/key-file/kf-persona.vala:432 #, c-format msgid "Couldn't load data from key file: %s" msgstr "Impossibile caricare i dati dal file chiave: %s" @@ -306,31 +388,29 @@ msgstr "Nessuna funzionalità di contatti è stata trovata." msgid "Error opening contacts view." msgstr "Errore nell'apertura della visualizzazione dei contatti." -#. Translators: the first parameter is the display name for -#. * the Telepathy account, and the second is an error -#. * message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:814 -#, c-format +#: ../backends/ofono/ofono-backend.vala:196 msgid "" -"Failed to determine whether we can set aliases on Telepathy account '%s': %s" +"No oFono object manager running, so the oFono backend will be inactive. " +"Either oFono isn’t installed or the service can’t be started." msgstr "" -"Impossibile determinare se si può impostare degli alias nell'account " -"Telepathy «%s»: %s" +"Nessun gestore oggetto oFono in esecuzione, così il backend oFono sarà " +"inattivo. oFono potrebbe essere non installato o il servizio non può essere " +"avviato." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1278 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1248 msgid "Telepathy contacts representing the local user may not be removed." msgstr "" "I contatti Telepathy che rappresentano l'utente locale non possono essere " "rimossi." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1289 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1259 #, c-format msgid "Failed to remove a persona from store: %s" msgstr "Rimozione di un contatto dall'archivio non riuscita: %s" #. Translators: the first two parameters are store identifiers and #. * the third is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1324 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1294 #, c-format msgid "" "Persona store (%s, %s) requires the following details:\n" @@ -339,19 +419,19 @@ msgstr "" "L'archivio personale (%s, %s) richiede i seguenti dettagli:\n" " contatto (fornito da: «%s»)\n" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1339 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1309 msgid "Cannot create a new Telepathy contact while offline." msgstr "" "Impossibile creare un nuovo contatto Telepathy quando non si è in rete." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1357 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1327 #, c-format msgid "Failed to add a persona from details: %s" msgstr "Aggiunta di un profilo dai dettagli non riuscita: %s" #. Translators: "telepathy-logger" is the name of an application, #. * and should not be translated. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1377 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1347 msgid "" "Failed to change favorite without a connection to the telepathy-logger " "service." @@ -359,7 +439,7 @@ msgstr "" "Modifica dei preferiti non riuscita senza una connessione al servizio " "telepathy-logger." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1383 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1353 msgid "" "Failed to change favorite status of Telepathy Persona because it has no " "attached TpContact." @@ -368,50 +448,50 @@ msgstr "" "non ha allegato TpContact." #. Translators: the parameter is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1401 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1371 #, c-format msgid "Failed to change favorite status for Telepathy contact ‘%s’." msgstr "" "Modifica dello stato di preferito del contatto Telepathy «%s» non riuscita." #. Translators: the parameter is an error message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1433 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1403 #, c-format msgid "Failed to change contact's alias: %s" msgstr "Modifica dell'alias del contatto non riuscita: %s" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1514 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1484 msgid "Extended information may only be set on the user's Telepathy contact." msgstr "" "Le informazioni estese possono essere impostate solo sul contatto Telepathy " "dell'utente." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1543 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 msgid "" "Extended information cannot be written because the store is disconnected." msgstr "" "Le informazioni estese non possono essere scritte perché l'archivio non è " "connesso." -#: ../backends/telepathy/lib/tpf-persona.vala:499 -#: ../backends/telepathy/lib/tpf-persona.vala:520 -#: ../backends/telepathy/lib/tpf-persona.vala:572 -#: ../backends/telepathy/lib/tpf-persona.vala:586 +#: ../backends/telepathy/lib/tpf-persona.vala:511 +#: ../backends/telepathy/lib/tpf-persona.vala:532 +#: ../backends/telepathy/lib/tpf-persona.vala:584 +#: ../backends/telepathy/lib/tpf-persona.vala:598 #, c-format msgid "Failed to change group membership: %s" msgstr "Cambio di appartenenza a un gruppo non riuscito: %s" #. Translators: "account" refers to an instant messaging #. * account. -#: ../backends/telepathy/lib/tpf-persona.vala:502 -#: ../backends/telepathy/lib/tpf-persona.vala:575 +#: ../backends/telepathy/lib/tpf-persona.vala:514 +#: ../backends/telepathy/lib/tpf-persona.vala:587 msgid "Account is offline." msgstr "L'account è fuori rete." #. Translators: the first parameter is the unknown key that #. * was received with the details params, and the second #. * identifies the persona store. -#: ../backends/tracker/lib/trf-persona-store.vala:742 +#: ../backends/tracker/lib/trf-persona-store.vala:743 #, c-format msgid "Unrecognized parameter '%s' passed to persona store '%s'." msgstr "Parametro «%s» passato all'archivio personale «%s» non riconosciuto." @@ -422,19 +502,19 @@ msgstr "L'alias non è scrivibile in questo contatto." #. Translators: the first parameter is a folder path and the second #. * is an error message. -#: ../folks/backend-store.vala:627 +#: ../folks/backend-store.vala:651 #, c-format msgid "Error listing contents of folder '%s': %s" msgstr "Errore nell'elencare i contenuti della cartella «%s»: «%s»" #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:757 +#: ../folks/backend-store.vala:786 #, c-format msgid "File or directory '%s' does not exist." msgstr "Il file o la directory «%s» non esiste." #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:763 +#: ../folks/backend-store.vala:792 #, c-format msgid "Failed to get content type for '%s'." msgstr "Recupero del tipo di contenuto di «%s» non riuscito." @@ -456,32 +536,32 @@ msgstr "Impossibile riconoscere l'indirizzo di messaggistica istantanea «%s»." #. Translators: the first parameter is a persona store identifier #. * and the second is an error message. -#: ../folks/individual-aggregator.vala:935 +#: ../folks/individual-aggregator.vala:1040 #, c-format msgid "Error preparing persona store '%s': %s" msgstr "Errore nella preparazione dell'archivio personale «%s»: %s" #. Translators: the parameter is a property name. -#: ../folks/individual-aggregator.vala:1158 -#: ../folks/individual-aggregator.vala:1386 +#: ../folks/individual-aggregator.vala:1269 +#: ../folks/individual-aggregator.vala:1536 #, c-format msgid "Unknown property '%s' in linkable property list." msgstr "Proprietà «%s» nell'elenco delle proprietà collegabili sconosciuta." #. Translators: the first parameter is a store identifier #. * and the second parameter is an error message. -#: ../folks/individual-aggregator.vala:1857 +#: ../folks/individual-aggregator.vala:2022 #, c-format msgid "Failed to add contact for persona store ID '%s': %s" msgstr "" "Aggiunta del contatto per l'ID dell'archivio personale «%s» non riuscita: %s" -#: ../folks/individual-aggregator.vala:1958 +#: ../folks/individual-aggregator.vala:2119 msgid "Can’t link personas with no primary store." msgstr "Impossibile collegare dei profili senza un archivio primario." -#: ../folks/individual-aggregator.vala:1959 -#: ../folks/individual-aggregator.vala:2291 +#: ../folks/individual-aggregator.vala:2120 +#: ../folks/individual-aggregator.vala:2451 #, c-format msgid "" "Persona store ‘%s:%s’ is configured as primary, but could not be found or " @@ -490,8 +570,8 @@ msgstr "" "L'archivio personale «%s:%s» è configurato come primario, ma non può essere " "trovato oppure il caricamento non è riuscito." -#: ../folks/individual-aggregator.vala:1960 -#: ../folks/individual-aggregator.vala:2292 +#: ../folks/individual-aggregator.vala:2121 +#: ../folks/individual-aggregator.vala:2452 #, c-format msgid "" "Check the relevant service is running, or change the default store in that " @@ -500,30 +580,80 @@ msgstr "" "Verificare che il corrispondente servizio sia in esecuzione, o cambiare " "l'archivio predefinito del servizio o usare la chiave GSettings «%s»." -#: ../folks/individual-aggregator.vala:1992 +#: ../folks/individual-aggregator.vala:2153 msgid "Anti-links can't be removed between personas being linked." msgstr "" "Gli anti-links non possono essere rimossi fra contatti che sono collegati." -#: ../folks/individual-aggregator.vala:2290 +#: ../folks/individual-aggregator.vala:2450 msgid "Can’t add personas with no primary store." msgstr "Impossibile aggiungere dei profili senza un archivio primario." -#: ../folks/individual-aggregator.vala:2301 +#: ../folks/individual-aggregator.vala:2461 #, c-format msgid "Can't write to requested property (“%s”) of the writeable store." msgstr "" "Impossibile scrivere le proprietà richieste («%s») dell'archivio scrivibile." -#: ../folks/individual.vala:217 ../folks/individual.vala:370 -#: ../folks/individual.vala:479 ../folks/individual.vala:730 -#: ../folks/individual.vala:808 +#: ../folks/individual.vala:216 ../folks/individual.vala:402 +#: ../folks/individual.vala:511 ../folks/individual.vala:762 +#: ../folks/individual.vala:840 #, c-format msgid "Failed to change property ‘%s’: No suitable personas were found." msgstr "" "Modifica della proprietà «%s» non riuscita: nessun profilo adatto è stato " "trovato." +#. Translators: This is the default name for an Individual +#. * when displayed in the UI if no personal details are available +#. * for them. +#: ../folks/individual.vala:1951 +msgid "Unnamed Person" +msgstr "Persona senza nome" + +#. FIXME: Ideally we’d use a format string translated to the locale of the +#. * persona whose name is being formatted, but no backend provides +#. * information about personas’ locales, so we have to settle for the +#. * current user’s locale. +#. * +#. * We thought about using nl_langinfo(_NL_NAME_NAME_FMT) here, but +#. * decided against it because: +#. * 1. It’s not the best documented API in the world, and its stability +#. * is in question. +#. * 2. An attempt to improve the interface in glibc met with a wall of +#. * complaints: https://sourceware.org/bugzilla/show_bug.cgi?id=14641. +#. * +#. * However, we do re-use the string format placeholders from +#. * _NL_NAME_NAME_FMT (as documented here: +#. * http://lh.2xlibre.net/values/name_fmt/) because there’s a chance glibc +#. * might eventually grow a useful interface for this. +#. * +#. * It does mean we have to implement our own parser for the name_fmt +#. * format though, since glibc doesn’t provide a formatting function. +#. Translators: This is a format string used to convert structured names +#. * to a single string. It should be translated to the predominant +#. * semi-formal name format for your locale, using the placeholders +#. * documented here: http://lh.2xlibre.net/values/name_fmt/. You may be +#. * able to re-use the existing glibc format string for your locale on that +#. * page if it’s suitable. +#. * +#. * More explicitly: the supported placeholders are %f, %F, %g, %G, %m, %M, +#. * %t. The romanisation modifier (e.g. %Rf) is recognized but ignored. +#. * %s, %S and %d are all replaced by the same thing (the ‘Honorific +#. * Prefixes’ from vCard) so please avoid using more than one. +#. * +#. * For example, the format string ‘%g%t%m%t%f’ expands to ‘John Andrew +#. * Lees’ when used for a persona with first name ‘John’, additional names +#. * ‘Andrew’ and family names ‘Lees’. +#. * +#. * If you need additional placeholders with other information or +#. * punctuation, please file a bug against libfolks: +#. * https://bugzilla.gnome.org/enter_bug.cgi?product=folks +#. +#: ../folks/name-details.vala:268 +msgid "%g%t%m%t%f" +msgstr "%g%t%m%t%f" + #: ../folks/org.freedesktop.folks.gschema.xml.in.h:1 msgid "Primary store ID" msgstr "ID archivio primario" @@ -544,35 +674,35 @@ msgstr "" msgid "%s, %s, %s, %s, %s, %s, %s" msgstr "%s, %s, %s, %s, %s, %s, %s" -#: ../folks/presence-details.vala:159 +#: ../folks/presence-details.vala:171 msgid "Unknown status" msgstr "Stato sconosciuto" -#: ../folks/presence-details.vala:161 +#: ../folks/presence-details.vala:173 msgid "Offline" msgstr "Fuori rete" -#: ../folks/presence-details.vala:165 +#: ../folks/presence-details.vala:177 msgid "Error" msgstr "Errore" -#: ../folks/presence-details.vala:167 +#: ../folks/presence-details.vala:179 msgid "Available" msgstr "Disponibile" -#: ../folks/presence-details.vala:169 +#: ../folks/presence-details.vala:181 msgid "Away" msgstr "Assente" -#: ../folks/presence-details.vala:171 +#: ../folks/presence-details.vala:183 msgid "Extended away" msgstr "Assenza prolungata" -#: ../folks/presence-details.vala:173 +#: ../folks/presence-details.vala:185 msgid "Busy" msgstr "Non disponibile" -#: ../folks/presence-details.vala:175 +#: ../folks/presence-details.vala:187 msgid "Hidden" msgstr "Nascosto" @@ -677,54 +807,54 @@ msgid "Source filename (default: specific to source backend)" msgstr "" "Nome del file sorgente (predefinito: specifico per il sorgente del backend)" -#: ../tools/import.vala:57 +#: ../tools/import.vala:58 msgid "— import meta-contact information to libfolks" msgstr "— importa in libfolks le informazioni sui meta contatti" #. Translators: the parameter is an error message. -#: ../tools/import.vala:67 +#: ../tools/import.vala:68 #, c-format msgid "Couldn't parse command line options: %s" msgstr "Impossibile analizzare le opzioni della riga di comando: %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:108 +#: ../tools/import.vala:109 #, c-format msgid "Couldn't load the backends: %s" msgstr "Impossibile caricare i backend: %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:119 +#: ../tools/import.vala:120 #, c-format msgid "Couldn't load the ‘%s’ backend." msgstr "Impossibile caricare il backend «%s»." #. Translators: the first parameter is a backend identifier and the #. * second parameter is an error message. -#: ../tools/import.vala:132 +#: ../tools/import.vala:133 #, c-format msgid "Couldn't prepare the ‘%s’ backend: %s" msgstr "Impossibile preparare il backend «%s»: %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:145 +#: ../tools/import.vala:146 #, c-format msgid "Couldn't load the ‘%s’ backend's persona store." msgstr "Impossibile caricare il backend dell'archivio personale «%s»." -#: ../tools/import.vala:166 +#: ../tools/import.vala:167 #, c-format msgid "Couldn't prepare the ‘%s’ backend's persona store: %s" msgstr "Impossibile preparare il backend dell'archivio personale «%s»: %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:184 +#: ../tools/import.vala:185 #, c-format msgid "Error importing contacts: %s" msgstr "Errore nell'importazione dei contatti: %s" #. Translators: both parameters are identifiers for backends. -#: ../tools/import.vala:198 +#: ../tools/import.vala:199 #, c-format msgid "" "Unrecognized source backend name ‘%s’. ‘%s’ is currently the only supported " @@ -1,7 +1,7 @@ # Korean translation for folks. # Copyright (C) 2012, 2013 Seong-ho Cho et al. # This file is distributed under the same license as the folks package. -# Seong-ho Cho <darkcircle.0426@gmail.com>, 2012, 2013. +# Seong-ho Cho <darkcircle.0426@gmail.com>, 2012, 2013, 2014. # # # 참고 : @@ -12,8 +12,8 @@ msgstr "" "Project-Id-Version: folks master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=folks&keywords=I18N+L10N&component=general\n" -"POT-Creation-Date: 2013-03-19 21:58+0000\n" -"PO-Revision-Date: 2013-03-21 00:01+0900\n" +"POT-Creation-Date: 2014-03-12 05:54+0000\n" +"PO-Revision-Date: 2014-03-12 14:59+0900\n" "Last-Translator: Seong-ho Cho <darkcircle.0426@gmail.com>\n" "Language-Team: Korean <gnome-kr@googlegroups.com>\n" "Language: ko\n" @@ -23,6 +23,77 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 1.5.5\n" +#: ../backends/bluez/bluez-backend.vala:600 +msgid "" +"No BlueZ 5 object manager running, so the BlueZ backend will be inactive. " +"Either your BlueZ installation is too old (only version 5 is supported) or " +"the service can’t be started." +msgstr "" +"BlueZ 5 객체 관리자가 실행중이 아니어서 BlueZ 백엔드를 비활성화합니다. BlueZ " +"설치가 오래되지 않았는지(버전 5만 지원함), 서비스를 시작할 수 없는지 확인하십" +"시오." + +#: ../backends/bluez/bluez-backend.vala:613 +msgid "" +"Error connecting to OBEX transfer daemon over D-Bus. Ensure BlueZ and obexd " +"are installed." +msgstr "" +"D-Bus를 통해 OBEX 전송 데몬에 연결하는데 오류가 발생했습니다. BlueZ와 obexd" +"를 설치했는지 확인하십시오." + +#. Translators: the parameter is an error message. +#: ../backends/bluez/bluez-persona-store.vala:385 +#, c-format +msgid "Error reading the transferred address book file: %s" +msgstr "전송한 주소록 파일을 읽는 도중 오류가 발생했습니다: %s" + +#. Translators: the first parameter is the name of the +#. * failed transfer, and the second is a Bluetooth device +#. * alias. +#. Translators: the first parameter is the name of the failed +#. * transfer, and the second is a Bluetooth device alias. +#: ../backends/bluez/bluez-persona-store.vala:667 +#: ../backends/bluez/bluez-persona-store.vala:689 +#, c-format +msgid "" +"Error during transfer of the address book ‘%s’ from Bluetooth device ‘%s’." +msgstr "" +"‘%2$s’ 블루투스 장치에서 ‘%1$s’ 주소록을 전송하는 도중 오류가 발생했습니다." + +#: ../backends/bluez/bluez-persona-store.vala:782 +#, c-format +msgid "" +"Permission to access the address book on Bluetooth device ‘%s’ was denied by " +"the user." +msgstr "‘%s’ 블루투스 장치의 주소록 접근 권한을 사용자가 거부했습니다." + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:789 +#, c-format +msgid "An OBEX address book transfer from device ‘%s’ could not be started: %s" +msgstr "‘%s’ 장치에서 OBEX 주소록 전송을 시작할 수 없습니다: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:829 +#, c-format +msgid "The OBEX address book transfer from device ‘%s’ failed: %s" +msgstr "‘%s’ 장치에서 OBEX 주소록 전송에 실패했습니다: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:846 +#, c-format +msgid "" +"Error during transfer of the address book from Bluetooth device ‘%s’: %s" +msgstr "‘%s’ 블루투스 장치에서 주소록을 전송하는 도중 오류가 발생했습니다: %s" + +#: ../backends/bluez/bluez-persona-store.vala:1064 +#, c-format +msgid "Bluetooth device ‘%s’ disappeared during address book transfer." +msgstr "주소록을 전송하는 도중 ‘%s’ 블루투스 장치가 사라졌습니다." + #. The timeout after which we consider a property change to have failed if we #. * haven't received a property change notification for it. #. seconds @@ -37,68 +108,68 @@ msgstr "안드로이드의 즐겨찾기" #. Translators: the first parameter is an address book #. * URI and the second is a persona UID. -#: ../backends/eds/lib/edsf-persona-store.vala:671 +#: ../backends/eds/lib/edsf-persona-store.vala:673 #, c-format msgid "Address book ‘%s’ is offline, so contact ‘%s’ cannot be removed." msgstr "‘%s’ 주소록이 오프라인입니다. 따라서 ‘%s’ 연락처를 제거할 수 없습니다." #. Translators: the first parameter is an address book #. * URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:677 +#: ../backends/eds/lib/edsf-persona-store.vala:679 #, c-format msgid "Permission denied to remove contact ‘%s’: %s" msgstr "‘%s’ 연락처를 제거할 권한이 거부되었습니다: %s" #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:682 +#: ../backends/eds/lib/edsf-persona-store.vala:684 #, c-format msgid "Removing contacts isn't supported by this persona store: %s" msgstr "이 페르소나 저장소에서 연락처 제거를 지원하지 않습니다: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:711 +#: ../backends/eds/lib/edsf-persona-store.vala:713 #, c-format msgid "Can't remove contact ‘%s’: %s" msgstr "‘%s’ 연락처를 제거할 수 없습니다: %s" #. Translators: the parameter is an address book #. * URI. -#: ../backends/eds/lib/edsf-persona-store.vala:801 -#: ../backends/eds/lib/edsf-persona-store.vala:992 +#: ../backends/eds/lib/edsf-persona-store.vala:802 +#: ../backends/eds/lib/edsf-persona-store.vala:993 #, c-format msgid "Address book ‘%s’ is offline." msgstr "‘%s’ 주소록이 오프라인입니다." #. Translators: the first parameter is an address #. * book URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:806 -#: ../backends/eds/lib/edsf-persona-store.vala:997 +#: ../backends/eds/lib/edsf-persona-store.vala:807 +#: ../backends/eds/lib/edsf-persona-store.vala:998 #, c-format msgid "Permission denied to open address book ‘%s’: %s" msgstr "‘%s’ 주소록을 열 권한이 거부되었습니다: %s" #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:839 +#: ../backends/eds/lib/edsf-persona-store.vala:840 #, c-format msgid "Couldn't open address book ‘%s’: %s" msgstr "‘%s’ 주소록을 열 수 없습니다: %s" #. Translators: the parameteter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:905 -#: ../backends/eds/lib/edsf-persona-store.vala:935 +#: ../backends/eds/lib/edsf-persona-store.vala:906 +#: ../backends/eds/lib/edsf-persona-store.vala:936 #, c-format msgid "Couldn't get address book capabilities: %s" msgstr "주소록 사용 가능 여부를 가져올 수 없습니다: %s" #. Translators: the parameter is an address book URI. -#: ../backends/eds/lib/edsf-persona-store.vala:951 +#: ../backends/eds/lib/edsf-persona-store.vala:952 #, c-format msgid "Couldn't get view for address book ‘%s’." msgstr "‘%s’ 주소록 보기를 가져올 수 없습니다." #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1030 +#: ../backends/eds/lib/edsf-persona-store.vala:1031 #, c-format msgid "Couldn't get view for address book ‘%s’: %s" msgstr "‘%s’ 주소록 보기를 가져올 수 없습니다: %s" @@ -106,162 +177,162 @@ msgstr "‘%s’ 주소록 보기를 가져올 수 없습니다: %s" #. Translators: the parameter is the name of a property on a #. * contact, formatted in the normal GObject style (e.g. #. * lowercase with hyphens to separate words). -#: ../backends/eds/lib/edsf-persona-store.vala:1390 +#: ../backends/eds/lib/edsf-persona-store.vala:1303 #, c-format msgid "Changing the ‘%s’ property failed due to reaching the timeout." -msgstr "제한 시간에 도달하여 ‘%s’ 속성을 변경하는데 실패했습니다." +msgstr "제한 시간에 도달하여 ‘%s’ 속성 값을 바꾸는데 실패했습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1428 +#: ../backends/eds/lib/edsf-persona-store.vala:1337 #: ../folks/avatar-details.vala:63 msgid "Avatar is not writeable on this contact." msgstr "이 연락처에 아바타를 기록할 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1449 +#: ../backends/eds/lib/edsf-persona-store.vala:1358 #: ../folks/web-service-details.vala:123 msgid "Web service addresses are not writeable on this contact." msgstr "이 연락처에 웹 서비스 주소를 기록할 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1485 +#: ../backends/eds/lib/edsf-persona-store.vala:1394 #: ../folks/url-details.vala:152 msgid "URLs are not writeable on this contact." msgstr "이 연락처에 URL을 기록할 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1566 +#: ../backends/eds/lib/edsf-persona-store.vala:1475 #: ../folks/local-id-details.vala:64 msgid "Local IDs are not writeable on this contact." msgstr "이 연락처에 로컬 ID를 기록할 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1595 +#: ../backends/eds/lib/edsf-persona-store.vala:1504 msgid "The contact cannot be marked as favourite." msgstr "이 연락처를 즐겨찾기로 표시할 수 없습니다." #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1667 +#: ../backends/eds/lib/edsf-persona-store.vala:1576 #, c-format msgid "Can't update avatar: %s" -msgstr "아바타를 업데이트 할 수 없습니다: %s" +msgstr "아바타를 업데이트할 수 없습니다: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:1678 +#: ../backends/eds/lib/edsf-persona-store.vala:1587 #: ../folks/email-details.vala:120 msgid "E-mail addresses are not writeable on this contact." msgstr "이 연락처에 전자메일 주소를 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1696 -#: ../folks/phone-details.vala:224 +#: ../backends/eds/lib/edsf-persona-store.vala:1605 +#: ../folks/phone-details.vala:255 msgid "Phone numbers are not writeable on this contact." msgstr "이 연락처에 전화번호를 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1714 +#: ../backends/eds/lib/edsf-persona-store.vala:1623 #: ../folks/postal-address-details.vala:361 msgid "Postal addresses are not writeable on this contact." msgstr "이 연락처에 우편 주소를 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1785 -#: ../folks/name-details.vala:283 +#: ../backends/eds/lib/edsf-persona-store.vala:1694 +#: ../folks/name-details.vala:454 msgid "Full name is not writeable on this contact." msgstr "이 연락처에 전체 이름을 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1807 -#: ../folks/name-details.vala:321 +#: ../backends/eds/lib/edsf-persona-store.vala:1716 +#: ../folks/name-details.vala:492 msgid "Nickname is not writeable on this contact." msgstr "이 연락처에 닉네임을 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1829 +#: ../backends/eds/lib/edsf-persona-store.vala:1738 #: ../folks/note-details.vala:138 msgid "Notes are not writeable on this contact." msgstr "이 연락처에 참고 사항을 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1861 +#: ../backends/eds/lib/edsf-persona-store.vala:1770 #: ../folks/birthday-details.vala:62 msgid "Birthday is not writeable on this contact." msgstr "이 연락처에 생일을 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:1905 +#: ../backends/eds/lib/edsf-persona-store.vala:1814 #: ../folks/role-details.vala:279 msgid "Roles are not writeable on this contact." msgstr "이 연락처에 역할을 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:2006 -#: ../folks/name-details.vala:246 +#: ../backends/eds/lib/edsf-persona-store.vala:1915 +#: ../folks/name-details.vala:417 msgid "Structured name is not writeable on this contact." msgstr "이 연락처에 구조화된 이름을 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:2045 +#: ../backends/eds/lib/edsf-persona-store.vala:1954 #: ../folks/im-details.vala:136 msgid "IM addresses are not writeable on this contact." msgstr "이 연락처에 메신저 주소를 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:2095 +#: ../backends/eds/lib/edsf-persona-store.vala:2004 #: ../folks/group-details.vala:174 msgid "Groups are not writeable on this contact." msgstr "이 연락처에 그룹을 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:2110 +#: ../backends/eds/lib/edsf-persona-store.vala:2019 msgid "My Contacts is only available for Google Contacts" msgstr "내 연락처는 구글 연락처에서만 사용할 수 있습니다" -#: ../backends/eds/lib/edsf-persona-store.vala:2181 +#: ../backends/eds/lib/edsf-persona-store.vala:2090 #: ../folks/gender-details.vala:79 msgid "Gender is not writeable on this contact." msgstr "이 연락처에 성별을 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:2219 -#: ../folks/anti-linkable.vala:81 +#: ../backends/eds/lib/edsf-persona-store.vala:2128 +#: ../folks/anti-linkable.vala:84 msgid "Anti-links are not writeable on this contact." msgstr "이 연락처에 연결 방지를 쓸 수 없습니다." -#: ../backends/eds/lib/edsf-persona-store.vala:2262 -#: ../folks/location-details.vala:129 +#: ../backends/eds/lib/edsf-persona-store.vala:2171 +#: ../folks/location-details.vala:135 msgid "Location is not writeable on this contact." msgstr "이 연락처에 위치를 기록할 수 없습니다." #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2439 +#: ../backends/eds/lib/edsf-persona-store.vala:2484 #, c-format msgid "Property ‘%s’ is not writeable: %s" -msgstr "‘%s’ 속성을 쓸 수 없습니다: %s" +msgstr "‘%s’ 속성 값을 쓸 수 없습니다: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2448 +#: ../backends/eds/lib/edsf-persona-store.vala:2493 #, c-format msgid "Invalid value for property ‘%s’: %s" -msgstr "‘%s’ 속성에 대한 값이 잘못되었습니다: %s" +msgstr "‘%s’ 속성 값이 잘못되었습니다: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:2474 +#: ../backends/eds/lib/edsf-persona-store.vala:2519 #, c-format msgid "Unknown error setting property ‘%s’: %s" -msgstr "‘%s’ 속성을 설정하는 중 알 수 없는 오류가 발생했습니다: %s" +msgstr "‘%s’ 속성 값 설정 도중 알 수 없는 오류가 발생했습니다: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:233 +#: ../backends/key-file/kf-persona-store.vala:234 #, c-format msgid "The relationship key file '%s' could not be loaded: %s" msgstr "'%s' 관계 키 파일을 불러올 수 없습니다: %s" #. Translators: the first parameter is a path, and the #. * second is an error message. -#: ../backends/key-file/kf-persona-store.vala:255 +#: ../backends/key-file/kf-persona-store.vala:256 #, c-format msgid "The relationship key file directory '%s' could not be created: %s" msgstr "'%s' 관계 키 파일 디렉터리를 만들 수 없습니다: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:279 +#: ../backends/key-file/kf-persona-store.vala:280 #, c-format msgid "The relationship key file '%s' could not be created: %s" msgstr "'%s' 관계 키 파일을 만들 수 없습니다: %s" #. Translators: the first parameter is a filename, the second is #. * an error message. -#: ../backends/key-file/kf-persona-store.vala:470 +#: ../backends/key-file/kf-persona-store.vala:471 #, c-format msgid "Could not write updated key file '%s': %s" msgstr "업데이트한 '%s' 키 파일에 쓸 수 없습니다: %s" @@ -271,13 +342,13 @@ msgstr "업데이트한 '%s' 키 파일에 쓸 수 없습니다: %s" #. * an IM address (e.g. “foo@jabber.org”), the second is #. * the name of a protocol (e.g. “jabber”) and the third is #. * an error message. -#: ../backends/key-file/kf-persona.vala:172 +#: ../backends/key-file/kf-persona.vala:174 #, c-format msgid "Invalid IM address ‘%s’ for protocol ‘%s’: %s" -msgstr "‘%2$s’ 프로토콜에 대해 메신저의 ‘%1$s’ 주소가 잘못되었습니다: %3$s" +msgstr "‘%2$s’ 프로토콜에 대해 ‘%1$s’ 메신저 주소가 잘못되었습니다: %3$s" #. Translators: the parameter is an error message. -#: ../backends/key-file/kf-persona.vala:430 +#: ../backends/key-file/kf-persona.vala:432 #, c-format msgid "Couldn't load data from key file: %s" msgstr "키 파일로부터 데이터를 불러올 수 없습니다: %s" @@ -302,27 +373,26 @@ msgstr "사용 가능한 연락처를 찾을 수 없습니다." msgid "Error opening contacts view." msgstr "연락처 보기를 여는 중 오류가 발생했습니다." -#. Translators: the first parameter is the display name for -#. * the Telepathy account, and the second is an error -#. * message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:814 -#, c-format +#: ../backends/ofono/ofono-backend.vala:196 msgid "" -"Failed to determine whether we can set aliases on Telepathy account '%s': %s" -msgstr "'%s' 텔레파시 계정의 별명을 설정할 지 결정하는데 실패했습니다: %s" +"No oFono object manager running, so the oFono backend will be inactive. " +"Either oFono isn’t installed or the service can’t be started." +msgstr "" +"oFono 객체 관리자가 실행중이 아니어서 oFono 백엔드를 비활성화합니다. oFono를 " +"설치하지 않았는지, 서비스를 시작할 수 없는지 확인하십시오." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1278 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1248 msgid "Telepathy contacts representing the local user may not be removed." -msgstr "로컬 사용자를 표현하는 텔레파시 연락처는 지워지지 않습니다." +msgstr "로컬 사용자를 나타내는 텔레파시 연락처는 지워지지 않습니다." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1289 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1259 #, c-format msgid "Failed to remove a persona from store: %s" msgstr "저장소에서 페르소나를 제거하는데 실패했습니다: %s" #. Translators: the first two parameters are store identifiers and #. * the third is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1324 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1294 #, c-format msgid "" "Persona store (%s, %s) requires the following details:\n" @@ -331,18 +401,18 @@ msgstr "" "페르소나 저장소(%s, %s)에 다음 세부 요소가 필요합니다:\n" " 연락처(제공: '%s')\n" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1339 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1309 msgid "Cannot create a new Telepathy contact while offline." msgstr "오프라인일 때 새 텔레파시 연락처를 만들 수 없습니다." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1357 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1327 #, c-format msgid "Failed to add a persona from details: %s" msgstr "세부 요소로부터 페르소나를 추가하는데 실패했습니다: %s" #. Translators: "telepathy-logger" is the name of an application, #. * and should not be translated. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1377 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1347 msgid "" "Failed to change favorite without a connection to the telepathy-logger " "service." @@ -350,7 +420,7 @@ msgstr "" "텔레파시 로거 서비스에 연결하지 않은 상태에서 즐겨찾기를 바꾸는데 실패했습니" "다." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1383 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1353 msgid "" "Failed to change favorite status of Telepathy Persona because it has no " "attached TpContact." @@ -359,45 +429,45 @@ msgstr "" "패했습니다." #. Translators: the parameter is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1401 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1371 #, c-format msgid "Failed to change favorite status for Telepathy contact ‘%s’." msgstr "‘%s’ 텔레파시 연락처에서 즐겨찾기 상태를 바꾸는데 실패했습니다." #. Translators: the parameter is an error message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1433 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1403 #, c-format msgid "Failed to change contact's alias: %s" msgstr "연락처 별명을 바꾸는데 실패했습니다: %s" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1514 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1484 msgid "Extended information may only be set on the user's Telepathy contact." msgstr "확장 정보는 사용자의 텔레파시 연락처에만 설정할 수 있습니다." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1543 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 msgid "" "Extended information cannot be written because the store is disconnected." msgstr "저장소의 연결이 끊겨서 확장 정보를 쓸 수 없습니다." -#: ../backends/telepathy/lib/tpf-persona.vala:499 -#: ../backends/telepathy/lib/tpf-persona.vala:520 -#: ../backends/telepathy/lib/tpf-persona.vala:572 -#: ../backends/telepathy/lib/tpf-persona.vala:586 +#: ../backends/telepathy/lib/tpf-persona.vala:511 +#: ../backends/telepathy/lib/tpf-persona.vala:532 +#: ../backends/telepathy/lib/tpf-persona.vala:584 +#: ../backends/telepathy/lib/tpf-persona.vala:598 #, c-format msgid "Failed to change group membership: %s" msgstr "그룹 구성원 관계를 바꾸는데 실패했습니다: %s" #. Translators: "account" refers to an instant messaging #. * account. -#: ../backends/telepathy/lib/tpf-persona.vala:502 -#: ../backends/telepathy/lib/tpf-persona.vala:575 +#: ../backends/telepathy/lib/tpf-persona.vala:514 +#: ../backends/telepathy/lib/tpf-persona.vala:587 msgid "Account is offline." msgstr "계정이 오프라인입니다." #. Translators: the first parameter is the unknown key that #. * was received with the details params, and the second #. * identifies the persona store. -#: ../backends/tracker/lib/trf-persona-store.vala:742 +#: ../backends/tracker/lib/trf-persona-store.vala:743 #, c-format msgid "Unrecognized parameter '%s' passed to persona store '%s'." msgstr "인식할 수 없는 '%s' 매개변수를 페르소나 저장소 '%s'에 전달했습니다." @@ -408,19 +478,19 @@ msgstr "이 연락처에 별명을 기록할 수 없습니다." #. Translators: the first parameter is a folder path and the second #. * is an error message. -#: ../folks/backend-store.vala:627 +#: ../folks/backend-store.vala:651 #, c-format msgid "Error listing contents of folder '%s': %s" msgstr "'%s' 폴더의 내용을 나열하는 중 오류가 발생했습니다: %s" #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:757 +#: ../folks/backend-store.vala:786 #, c-format msgid "File or directory '%s' does not exist." -msgstr "'%s' 파일 또는 디렉터리가 존재하지 않습니다." +msgstr "'%s' 파일 또는 디렉터리가 없습니다." #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:763 +#: ../folks/backend-store.vala:792 #, c-format msgid "Failed to get content type for '%s'." msgstr "'%s'에 대한 내용 형식을 가져오는데 실패했습니다." @@ -442,31 +512,31 @@ msgstr "'%s' 메신저 주소를 인지할 수 없습니다." #. Translators: the first parameter is a persona store identifier #. * and the second is an error message. -#: ../folks/individual-aggregator.vala:935 +#: ../folks/individual-aggregator.vala:1040 #, c-format msgid "Error preparing persona store '%s': %s" msgstr "'%s' 페르소나 저장소를 준비하는 중 오류가 발생했습니다: %s" #. Translators: the parameter is a property name. -#: ../folks/individual-aggregator.vala:1158 -#: ../folks/individual-aggregator.vala:1386 +#: ../folks/individual-aggregator.vala:1269 +#: ../folks/individual-aggregator.vala:1536 #, c-format msgid "Unknown property '%s' in linkable property list." msgstr "연결할 수 있는 속성 목록에서 '%s' 속성을 알 수 없습니다." #. Translators: the first parameter is a store identifier #. * and the second parameter is an error message. -#: ../folks/individual-aggregator.vala:1857 +#: ../folks/individual-aggregator.vala:2022 #, c-format msgid "Failed to add contact for persona store ID '%s': %s" msgstr "'%s' 페르소나 저장소 ID에 대한 연락처를 추가하는데 실패했습니다: %s" -#: ../folks/individual-aggregator.vala:1958 +#: ../folks/individual-aggregator.vala:2119 msgid "Can’t link personas with no primary store." msgstr "주 저장소 없이는 페르소나에 연결할 수 없습니다." -#: ../folks/individual-aggregator.vala:1959 -#: ../folks/individual-aggregator.vala:2291 +#: ../folks/individual-aggregator.vala:2120 +#: ../folks/individual-aggregator.vala:2451 #, c-format msgid "" "Persona store ‘%s:%s’ is configured as primary, but could not be found or " @@ -475,8 +545,8 @@ msgstr "" "‘%s:%s’ 페르소나 저장소를 주 저장소로 설정했지만, 찾을 수 없거나 불러오는데 " "실패했습니다." -#: ../folks/individual-aggregator.vala:1960 -#: ../folks/individual-aggregator.vala:2292 +#: ../folks/individual-aggregator.vala:2121 +#: ../folks/individual-aggregator.vala:2452 #, c-format msgid "" "Check the relevant service is running, or change the default store in that " @@ -485,26 +555,78 @@ msgstr "" "관련 서비스가 실행중인지 확인하거나 서비스의 기본 저장소를 바꾸거나 “%s” " "GSettings 키를 사용하십시오." -#: ../folks/individual-aggregator.vala:1992 +#: ../folks/individual-aggregator.vala:2153 msgid "Anti-links can't be removed between personas being linked." msgstr "연결된 페르소나 사이에서 링크 방지를 제거할 수 없습니다." -#: ../folks/individual-aggregator.vala:2290 +#: ../folks/individual-aggregator.vala:2450 msgid "Can’t add personas with no primary store." msgstr "주 저장소에 페르소나를 추가할 수 없습니다." -#: ../folks/individual-aggregator.vala:2301 +#: ../folks/individual-aggregator.vala:2461 #, c-format msgid "Can't write to requested property (“%s”) of the writeable store." msgstr "쓰기 가능한 요청한 속성(“%s”)에 쓸 수 없습니다." -#: ../folks/individual.vala:217 ../folks/individual.vala:370 -#: ../folks/individual.vala:479 ../folks/individual.vala:730 -#: ../folks/individual.vala:808 +#: ../folks/individual.vala:216 ../folks/individual.vala:402 +#: ../folks/individual.vala:511 ../folks/individual.vala:762 +#: ../folks/individual.vala:840 #, c-format msgid "Failed to change property ‘%s’: No suitable personas were found." msgstr "‘%s’ 속성을 바꾸는데 실패했습니다: 적당한 페르소나를 찾지 못했습니다." +#. Translators: This is the default name for an Individual +#. * when displayed in the UI if no personal details are available +#. * for them. +#: ../folks/individual.vala:1951 +msgid "Unnamed Person" +msgstr "이름 없는 사용자" + +# Note: 한국은 성 이름 중간이름 순으로 가므로 %t를 고려하지 않고 +# %f %g %m 순으로 갑니다. (FIXME 참고) +#. FIXME: Ideally we’d use a format string translated to the locale of the +#. * persona whose name is being formatted, but no backend provides +#. * information about personas’ locales, so we have to settle for the +#. * current user’s locale. +#. * +#. * We thought about using nl_langinfo(_NL_NAME_NAME_FMT) here, but +#. * decided against it because: +#. * 1. It’s not the best documented API in the world, and its stability +#. * is in question. +#. * 2. An attempt to improve the interface in glibc met with a wall of +#. * complaints: https://sourceware.org/bugzilla/show_bug.cgi?id=14641. +#. * +#. * However, we do re-use the string format placeholders from +#. * _NL_NAME_NAME_FMT (as documented here: +#. * http://lh.2xlibre.net/values/name_fmt/) because there’s a chance glibc +#. * might eventually grow a useful interface for this. +#. * +#. * It does mean we have to implement our own parser for the name_fmt +#. * format though, since glibc doesn’t provide a formatting function. +#. Translators: This is a format string used to convert structured names +#. * to a single string. It should be translated to the predominant +#. * semi-formal name format for your locale, using the placeholders +#. * documented here: http://lh.2xlibre.net/values/name_fmt/. You may be +#. * able to re-use the existing glibc format string for your locale on that +#. * page if it’s suitable. +#. * +#. * More explicitly: the supported placeholders are %f, %F, %g, %G, %m, %M, +#. * %t. The romanisation modifier (e.g. %Rf) is recognized but ignored. +#. * %s, %S and %d are all replaced by the same thing (the ‘Honorific +#. * Prefixes’ from vCard) so please avoid using more than one. +#. * +#. * For example, the format string ‘%g%t%m%t%f’ expands to ‘John Andrew +#. * Lees’ when used for a persona with first name ‘John’, additional names +#. * ‘Andrew’ and family names ‘Lees’. +#. * +#. * If you need additional placeholders with other information or +#. * punctuation, please file a bug against libfolks: +#. * https://bugzilla.gnome.org/enter_bug.cgi?product=folks +#. +#: ../folks/name-details.vala:268 +msgid "%g%t%m%t%f" +msgstr "%f%t%g%t%m" + #: ../folks/org.freedesktop.folks.gschema.xml.in.h:1 msgid "Primary store ID" msgstr "주 저장소 ID" @@ -524,35 +646,35 @@ msgstr "" msgid "%s, %s, %s, %s, %s, %s, %s" msgstr "%s, %s, %s, %s, %s, %s, %s" -#: ../folks/presence-details.vala:159 +#: ../folks/presence-details.vala:171 msgid "Unknown status" msgstr "알 수 없는 상태" -#: ../folks/presence-details.vala:161 +#: ../folks/presence-details.vala:173 msgid "Offline" msgstr "오프라인" -#: ../folks/presence-details.vala:165 +#: ../folks/presence-details.vala:177 msgid "Error" msgstr "오류" -#: ../folks/presence-details.vala:167 +#: ../folks/presence-details.vala:179 msgid "Available" msgstr "자리에 있음" -#: ../folks/presence-details.vala:169 +#: ../folks/presence-details.vala:181 msgid "Away" msgstr "자리 비움" -#: ../folks/presence-details.vala:171 +#: ../folks/presence-details.vala:183 msgid "Extended away" msgstr "오래 자리 비움" -#: ../folks/presence-details.vala:173 +#: ../folks/presence-details.vala:185 msgid "Busy" msgstr "바쁨" -#: ../folks/presence-details.vala:175 +#: ../folks/presence-details.vala:187 msgid "Hidden" msgstr "숨김" @@ -565,7 +687,7 @@ msgstr "직함: %s, 조직: %s, 역할: %s" #: ../tools/import-pidgin.vala:49 #, c-format msgid "File %s does not exist." -msgstr "%s 파일이 존재하지 않습니다." +msgstr "%s 파일이 없습니다." #. Translators: the first parameter is a filename, and the second #. * is an error message. @@ -652,58 +774,58 @@ msgstr "원본 백엔드 이름(기본값: 'pidgin')" msgid "Source filename (default: specific to source backend)" msgstr "원본 파일 이름(기본값: 원본 백엔드로 지정)" -#: ../tools/import.vala:57 +#: ../tools/import.vala:58 msgid "— import meta-contact information to libfolks" msgstr "— 메타 연락처 정보를 libforks로 가져옵니다" #. Translators: the parameter is an error message. -#: ../tools/import.vala:67 +#: ../tools/import.vala:68 #, c-format msgid "Couldn't parse command line options: %s" msgstr "명령줄 옵션을 해석할 수 없습니다: %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:108 +#: ../tools/import.vala:109 #, c-format msgid "Couldn't load the backends: %s" msgstr "백엔드를 불러올 수 없습니다: %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:119 +#: ../tools/import.vala:120 #, c-format msgid "Couldn't load the ‘%s’ backend." msgstr "‘%s’ 백엔드를 불러올 수 없습니다." #. Translators: the first parameter is a backend identifier and the #. * second parameter is an error message. -#: ../tools/import.vala:132 +#: ../tools/import.vala:133 #, c-format msgid "Couldn't prepare the ‘%s’ backend: %s" msgstr "‘%s’ 백엔드를 준비할 수 없습니다: %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:145 +#: ../tools/import.vala:146 #, c-format msgid "Couldn't load the ‘%s’ backend's persona store." msgstr "‘%s’ 백엔드의 페르소나 저장소를 불러올 수 없습니다." -#: ../tools/import.vala:166 +#: ../tools/import.vala:167 #, c-format msgid "Couldn't prepare the ‘%s’ backend's persona store: %s" msgstr "‘%s’ 백엔드의 페르소나 저장소를 준비할 수 없습니다: %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:184 +#: ../tools/import.vala:185 #, c-format msgid "Error importing contacts: %s" msgstr "연락처를 가져오는 중 오류가 발생했습니다: %s" #. Translators: both parameters are identifiers for backends. -#: ../tools/import.vala:198 +#: ../tools/import.vala:199 #, c-format msgid "" "Unrecognized source backend name ‘%s’. ‘%s’ is currently the only supported " "source backend." msgstr "" -"‘%s’ 백엔드 이름을 인식할 수 없습니다. ‘%s’은(는) 현재 원본 백엔드만 지원합" -"니다." +"‘%s’ 원본 백엔드 이름을 인식할 수 없습니다. ‘%s’은(는) 현재 원본 백엔드만 지" +"원합니다." @@ -3,14 +3,14 @@ # This file is distributed under the same license as the folks package. # # Arvis Lacis <arvis.lacis@gmail.com>, 2012. -# Rūdolfs Mazurs <rudolfs.mazurs@gmail.com>, 2012, 2013. +# Rūdolfs Mazurs <rudolfs.mazurs@gmail.com>, 2012, 2013, 2014. msgid "" msgstr "" "Project-Id-Version: folks master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=folks&keywords=I18N+L10N&component=general\n" -"POT-Creation-Date: 2013-02-20 14:29+0000\n" -"PO-Revision-Date: 2013-03-17 20:26+0200\n" +"POT-Creation-Date: 2014-03-07 05:54+0000\n" +"PO-Revision-Date: 2014-03-07 21:57+0200\n" "Last-Translator: Rūdolfs Mazurs <rudolfs.mazurs@gmail.com>\n" "Language-Team: Latvian <lata-l10n@googlegroups.com>\n" "Language: lv\n" @@ -19,7 +19,77 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : " "2);\n" -"X-Generator: Lokalize 1.4\n" +"X-Generator: Lokalize 1.5\n" + +#: ../backends/bluez/bluez-backend.vala:600 +msgid "" +"No BlueZ 5 object manager running, so the BlueZ backend will be inactive. " +"Either your BlueZ installation is too old (only version 5 is supported) or " +"the service can’t be started." +msgstr "" +"Pašlaik darbojas BlueZ 5 objektu pārvaldnieks, tāpēc BlueZ aizmugure būs " +"neaktīva. Vai nu jūsu BlueZ instalācija ir pārāk veca (ir atbalstīta tikai 5. " +"versija), vai arī pakalpojumu nevar palaist." + +#: ../backends/bluez/bluez-backend.vala:613 +msgid "" +"Error connecting to OBEX transfer daemon over D-Bus. Ensure BlueZ and obexd " +"are installed." +msgstr "" +"Kļūda, savienojoties ar OBEX pārsūtīšanas dēmonu, izmantojot D-Bus. " +"Pārliecinieties, ka ir uzinstalēti BlueZ un obexd." + +#. Translators: the parameter is an error message. +#: ../backends/bluez/bluez-persona-store.vala:385 +#, c-format +msgid "Error reading the transferred address book file: %s" +msgstr "Kļūda, lasot pārsūtīto adrešu grāmatas datni — %s" + +#. Translators: the first parameter is the name of the +#. * failed transfer, and the second is a Bluetooth device +#. * alias. +#. Translators: the first parameter is the name of the failed +#. * transfer, and the second is a Bluetooth device alias. +#: ../backends/bluez/bluez-persona-store.vala:667 +#: ../backends/bluez/bluez-persona-store.vala:689 +#, c-format +msgid "" +"Error during transfer of the address book ‘%s’ from Bluetooth device ‘%s’." +msgstr "Kļūda, pārsūtot adrešu grāmatu “%s” no Bluetooth ierīces “%s”." + +#: ../backends/bluez/bluez-persona-store.vala:782 +#, c-format +msgid "" +"Permission to access the address book on Bluetooth device ‘%s’ was denied by " +"the user." +msgstr "Lietotājs liedza piekļuvi adrešu grāmatai uz “%s” Bluetooth ierīces." + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:789 +#, c-format +msgid "An OBEX address book transfer from device ‘%s’ could not be started: %s" +msgstr "Nevarēja sākt OBEX adrešu grāmatas pārsūtīšanu no ierīces “%s” — %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:829 +#, c-format +msgid "The OBEX address book transfer from device ‘%s’ failed: %s" +msgstr "Neizdevās veikt OBEX adrešu grāmatas pārsūtīšanu no ierīces “%s” — %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:846 +#, c-format +msgid "" +"Error during transfer of the address book from Bluetooth device ‘%s’: %s" +msgstr "Kļūda, pārsūtot adrešu grāmatu no “%s” Bluetooth ierīces — %s" + +#: ../backends/bluez/bluez-persona-store.vala:1064 +#, c-format +msgid "Bluetooth device ‘%s’ disappeared during address book transfer." +msgstr "Pārsūtot adrešu grāmatu, pazuda “%s” Bluetooth ierīce." #. The timeout after which we consider a property change to have failed if we #. * haven't received a property change notification for it. @@ -35,68 +105,68 @@ msgstr "Atzīmēts Android" #. Translators: the first parameter is an address book #. * URI and the second is a persona UID. -#: ../backends/eds/lib/edsf-persona-store.vala:671 +#: ../backends/eds/lib/edsf-persona-store.vala:673 #, c-format msgid "Address book ‘%s’ is offline, so contact ‘%s’ cannot be removed." msgstr "Adrešu grāmata “%s” ir bezsaistē, tādēļ kontaktu “%s” nevar izņemt." #. Translators: the first parameter is an address book #. * URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:677 +#: ../backends/eds/lib/edsf-persona-store.vala:679 #, c-format msgid "Permission denied to remove contact ‘%s’: %s" msgstr "Piekļuve liegta, lai izņemtu kontaktu “%s” — %s" #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:682 +#: ../backends/eds/lib/edsf-persona-store.vala:684 #, c-format msgid "Removing contacts isn't supported by this persona store: %s" msgstr "Kontaktu izņemšana nav atbalstīta šai personu krātuvei — %s" -#: ../backends/eds/lib/edsf-persona-store.vala:711 +#: ../backends/eds/lib/edsf-persona-store.vala:713 #, c-format msgid "Can't remove contact ‘%s’: %s" msgstr "Nevar izņemt kontaktu “%s” — %s" #. Translators: the parameter is an address book #. * URI. -#: ../backends/eds/lib/edsf-persona-store.vala:801 -#: ../backends/eds/lib/edsf-persona-store.vala:992 +#: ../backends/eds/lib/edsf-persona-store.vala:802 +#: ../backends/eds/lib/edsf-persona-store.vala:993 #, c-format msgid "Address book ‘%s’ is offline." msgstr "Adrešu grāmata “%s” ir bezsaistē." #. Translators: the first parameter is an address #. * book URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:806 -#: ../backends/eds/lib/edsf-persona-store.vala:997 +#: ../backends/eds/lib/edsf-persona-store.vala:807 +#: ../backends/eds/lib/edsf-persona-store.vala:998 #, c-format msgid "Permission denied to open address book ‘%s’: %s" msgstr "Liegta piekļuve atvērt adrešu grāmatu “%s” — %s" #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:839 +#: ../backends/eds/lib/edsf-persona-store.vala:840 #, c-format msgid "Couldn't open address book ‘%s’: %s" msgstr "Neizdevās atvērt adrešu grāmatu “%s” — %s" #. Translators: the parameteter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:905 -#: ../backends/eds/lib/edsf-persona-store.vala:935 +#: ../backends/eds/lib/edsf-persona-store.vala:906 +#: ../backends/eds/lib/edsf-persona-store.vala:936 #, c-format msgid "Couldn't get address book capabilities: %s" msgstr "Nevarēja saņemt adrešu grāmatas iespējas — %s" #. Translators: the parameter is an address book URI. -#: ../backends/eds/lib/edsf-persona-store.vala:951 +#: ../backends/eds/lib/edsf-persona-store.vala:952 #, c-format msgid "Couldn't get view for address book ‘%s’." msgstr "Neizdevās iegūt skatu adrešu grāmatai “%s”." #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1030 +#: ../backends/eds/lib/edsf-persona-store.vala:1031 #, c-format msgid "Couldn't get view for address book ‘%s’: %s" msgstr "Neizdevās iegūt skatu adrešu grāmatai “%s” — %s" @@ -104,120 +174,119 @@ msgstr "Neizdevās iegūt skatu adrešu grāmatai “%s” — %s" #. Translators: the parameter is the name of a property on a #. * contact, formatted in the normal GObject style (e.g. #. * lowercase with hyphens to separate words). -#: ../backends/eds/lib/edsf-persona-store.vala:1390 +#: ../backends/eds/lib/edsf-persona-store.vala:1303 #, c-format msgid "Changing the ‘%s’ property failed due to reaching the timeout." msgstr "Neizdevās izmainīt “%s” īpašību, jo tika sasniegts taimauts." -#: ../backends/eds/lib/edsf-persona-store.vala:1428 +#: ../backends/eds/lib/edsf-persona-store.vala:1337 #: ../folks/avatar-details.vala:63 msgid "Avatar is not writeable on this contact." msgstr "Iemiesojums nav rakstāms šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1449 +#: ../backends/eds/lib/edsf-persona-store.vala:1358 #: ../folks/web-service-details.vala:123 msgid "Web service addresses are not writeable on this contact." msgstr "Tīkla servisu adreses nav rakstāmas šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1485 +#: ../backends/eds/lib/edsf-persona-store.vala:1394 #: ../folks/url-details.vala:152 msgid "URLs are not writeable on this contact." msgstr "URL saites nav rakstāmas šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1566 +#: ../backends/eds/lib/edsf-persona-store.vala:1475 #: ../folks/local-id-details.vala:64 msgid "Local IDs are not writeable on this contact." msgstr "Lokālie ID nav rakstāmi šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1595 +#: ../backends/eds/lib/edsf-persona-store.vala:1504 msgid "The contact cannot be marked as favourite." msgstr "Šo kontaktu nevar atzīmēt kā iecienītu." #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1667 +#: ../backends/eds/lib/edsf-persona-store.vala:1576 #, c-format msgid "Can't update avatar: %s" msgstr "Nevar atjaunināt iemiesojumu — %s" -#: ../backends/eds/lib/edsf-persona-store.vala:1678 +#: ../backends/eds/lib/edsf-persona-store.vala:1587 #: ../folks/email-details.vala:120 msgid "E-mail addresses are not writeable on this contact." msgstr "E-pasta adreses nav rakstāmas šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1696 -#: ../folks/phone-details.vala:224 +#: ../backends/eds/lib/edsf-persona-store.vala:1605 +#: ../folks/phone-details.vala:255 msgid "Phone numbers are not writeable on this contact." msgstr "Tālruņa numuri nav rakstāmi šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1714 +#: ../backends/eds/lib/edsf-persona-store.vala:1623 #: ../folks/postal-address-details.vala:361 msgid "Postal addresses are not writeable on this contact." msgstr "Pasta adreses nav rakstāmas šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1785 -#: ../folks/name-details.vala:283 +#: ../backends/eds/lib/edsf-persona-store.vala:1694 +#: ../folks/name-details.vala:454 msgid "Full name is not writeable on this contact." msgstr "Pilns vārds nav rakstāms šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1807 -#: ../folks/name-details.vala:321 +#: ../backends/eds/lib/edsf-persona-store.vala:1716 +#: ../folks/name-details.vala:492 msgid "Nickname is not writeable on this contact." msgstr "Segvārds nav rakstāms šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1829 +#: ../backends/eds/lib/edsf-persona-store.vala:1738 #: ../folks/note-details.vala:138 msgid "Notes are not writeable on this contact." msgstr "Piezīmes nav rakstāmas šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1861 +#: ../backends/eds/lib/edsf-persona-store.vala:1770 #: ../folks/birthday-details.vala:62 msgid "Birthday is not writeable on this contact." msgstr "Dzimšanas diena nav rakstāma šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:1905 +#: ../backends/eds/lib/edsf-persona-store.vala:1814 #: ../folks/role-details.vala:279 msgid "Roles are not writeable on this contact." msgstr "Lomas nav rakstāmas šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:2006 -#: ../folks/name-details.vala:246 +#: ../backends/eds/lib/edsf-persona-store.vala:1915 +#: ../folks/name-details.vala:417 msgid "Structured name is not writeable on this contact." msgstr "Strukturētais vārds nav rakstāms šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:2045 +#: ../backends/eds/lib/edsf-persona-store.vala:1954 #: ../folks/im-details.vala:136 msgid "IM addresses are not writeable on this contact." msgstr "TZ adreses nav rakstāmas šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:2095 +#: ../backends/eds/lib/edsf-persona-store.vala:2004 #: ../folks/group-details.vala:174 msgid "Groups are not writeable on this contact." msgstr "Grupas nav rakstāmas šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:2110 +#: ../backends/eds/lib/edsf-persona-store.vala:2019 msgid "My Contacts is only available for Google Contacts" msgstr "Mani kontakti ir pieejami tikai Google kontaktiem" -#: ../backends/eds/lib/edsf-persona-store.vala:2181 +#: ../backends/eds/lib/edsf-persona-store.vala:2090 #: ../folks/gender-details.vala:79 msgid "Gender is not writeable on this contact." msgstr "Dzimums nav rakstāms šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:2219 -#: ../folks/anti-linkable.vala:81 +#: ../backends/eds/lib/edsf-persona-store.vala:2128 +#: ../folks/anti-linkable.vala:84 msgid "Anti-links are not writeable on this contact." msgstr "Anti-saites nav rakstāmas šim kontaktam." -#: ../backends/eds/lib/edsf-persona-store.vala:2262 -#: ../folks/location-details.vala:129 -#| msgid "Avatar is not writeable on this contact." +#: ../backends/eds/lib/edsf-persona-store.vala:2171 +#: ../folks/location-details.vala:135 msgid "Location is not writeable on this contact." msgstr "Atrašanās vieta nav rakstāma šim kontaktam." #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2439 +#: ../backends/eds/lib/edsf-persona-store.vala:2484 #, c-format msgid "Property ‘%s’ is not writeable: %s" msgstr "Īpašība “%s” nav rakstāma — %s" @@ -225,42 +294,42 @@ msgstr "Īpašība “%s” nav rakstāma — %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2448 +#: ../backends/eds/lib/edsf-persona-store.vala:2493 #, c-format msgid "Invalid value for property ‘%s’: %s" msgstr "Nederīga vērtība īpašībai “%s” — %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:2474 +#: ../backends/eds/lib/edsf-persona-store.vala:2519 #, c-format msgid "Unknown error setting property ‘%s’: %s" msgstr "Nezināma kļūda, iestatot īpašību “%s” — %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:233 +#: ../backends/key-file/kf-persona-store.vala:234 #, c-format msgid "The relationship key file '%s' could not be loaded: %s" msgstr "Attiecību atslēgu datni “%s” neizdevās ielādēt — %s" #. Translators: the first parameter is a path, and the #. * second is an error message. -#: ../backends/key-file/kf-persona-store.vala:255 +#: ../backends/key-file/kf-persona-store.vala:256 #, c-format msgid "The relationship key file directory '%s' could not be created: %s" msgstr "Neizdevās izveidot attiecību atslēgas datnes direktoriju “%s” — %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:279 +#: ../backends/key-file/kf-persona-store.vala:280 #, c-format msgid "The relationship key file '%s' could not be created: %s" msgstr "Neizdevās izveidot attiecību atslēgas datni “%s” — %s" #. Translators: the first parameter is a filename, the second is #. * an error message. -#: ../backends/key-file/kf-persona-store.vala:470 +#: ../backends/key-file/kf-persona-store.vala:471 #, c-format msgid "Could not write updated key file '%s': %s" msgstr "Neizdevās ierakstīt atjaunināto atslēgas datni “%s” — %s" @@ -270,13 +339,13 @@ msgstr "Neizdevās ierakstīt atjaunināto atslēgas datni “%s” — %s" #. * an IM address (e.g. “foo@jabber.org”), the second is #. * the name of a protocol (e.g. “jabber”) and the third is #. * an error message. -#: ../backends/key-file/kf-persona.vala:172 +#: ../backends/key-file/kf-persona.vala:174 #, c-format msgid "Invalid IM address ‘%s’ for protocol ‘%s’: %s" msgstr "Nederīga TZ adrese “%s” protokolam “%s” — %s" #. Translators: the parameter is an error message. -#: ../backends/key-file/kf-persona.vala:430 +#: ../backends/key-file/kf-persona.vala:432 #, c-format msgid "Couldn't load data from key file: %s" msgstr "Neizdevās ielādēt datus no atslēgas datnes — %s" @@ -301,28 +370,26 @@ msgstr "Netika atrastas kontakta iespējas." msgid "Error opening contacts view." msgstr "Kļūda, atverot kontaktu skatu." -#. Translators: the first parameter is the display name for -#. * the Telepathy account, and the second is an error -#. * message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:814 -#, c-format +#: ../backends/ofono/ofono-backend.vala:196 msgid "" -"Failed to determine whether we can set aliases on Telepathy account '%s': %s" +"No oFono object manager running, so the oFono backend will be inactive. " +"Either oFono isn’t installed or the service can’t be started." msgstr "" -"Neizdevās noteikt, vai var iestatīt aizstājvārdus Telepathy kontā “%s” — %s" +"Pašlaik darbojas oFono objektu pārvaldnieks, tāpēc oFono būs neaktīvs. Vai nu " +"oFono nav instalēts, vai arī pakalpojumu nevar palaist.\t" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1278 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1248 msgid "Telepathy contacts representing the local user may not be removed." msgstr "Nevar izņemt Telepathy kontaktus, kuri pārstāv lokālo lietotāju." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1289 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1259 #, c-format msgid "Failed to remove a persona from store: %s" msgstr "Neizdevās izņemt personu no krātuves — %s" #. Translators: the first two parameters are store identifiers and #. * the third is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1324 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1294 #, c-format msgid "" "Persona store (%s, %s) requires the following details:\n" @@ -331,25 +398,25 @@ msgstr "" "Personas krātuvei (%s, %s) ir nepieciešamas sekojošā informācija:\n" " kontakts (nodrošināts — “%s”)\n" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1339 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1309 msgid "Cannot create a new Telepathy contact while offline." msgstr "Nevar izveidot jaunu Telepathy kontaktu, kamēr atrodas bezsaistē." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1357 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1327 #, c-format msgid "Failed to add a persona from details: %s" msgstr "Neizdevās pievienot personu no informācijas — %s" #. Translators: "telepathy-logger" is the name of an application, #. * and should not be translated. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1377 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1347 msgid "" "Failed to change favorite without a connection to the telepathy-logger " "service." msgstr "" "Neizdevās izmainīt iecienīto bez savienojuma ar telepathy-logger servisu." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1383 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1353 msgid "" "Failed to change favorite status of Telepathy Persona because it has no " "attached TpContact." @@ -358,45 +425,45 @@ msgstr "" "pievienota TpContact." #. Translators: the parameter is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1401 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1371 #, c-format msgid "Failed to change favorite status for Telepathy contact ‘%s’." msgstr "Neizdevās izmainīt iecienītā statusu Telepathy kontaktam “%s”." #. Translators: the parameter is an error message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1433 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1403 #, c-format msgid "Failed to change contact's alias: %s" msgstr "Neizdevās izmainīt kontakta segvārdu — %s" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1484 msgid "Extended information may only be set on the user's Telepathy contact." msgstr "Paplašinātu informāciju var iestatīt tikai Telepathy kontaktiem." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1542 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 msgid "" "Extended information cannot be written because the store is disconnected." msgstr "Paplašināto informāciju nevar ierakstīt, jo krātuve ir atvienota." -#: ../backends/telepathy/lib/tpf-persona.vala:499 -#: ../backends/telepathy/lib/tpf-persona.vala:520 -#: ../backends/telepathy/lib/tpf-persona.vala:572 -#: ../backends/telepathy/lib/tpf-persona.vala:586 +#: ../backends/telepathy/lib/tpf-persona.vala:511 +#: ../backends/telepathy/lib/tpf-persona.vala:532 +#: ../backends/telepathy/lib/tpf-persona.vala:584 +#: ../backends/telepathy/lib/tpf-persona.vala:598 #, c-format msgid "Failed to change group membership: %s" msgstr "Neizdevās izmainīt grupas piederību — %s" #. Translators: "account" refers to an instant messaging #. * account. -#: ../backends/telepathy/lib/tpf-persona.vala:502 -#: ../backends/telepathy/lib/tpf-persona.vala:575 +#: ../backends/telepathy/lib/tpf-persona.vala:514 +#: ../backends/telepathy/lib/tpf-persona.vala:587 msgid "Account is offline." msgstr "Konts ir bezsaistē." #. Translators: the first parameter is the unknown key that #. * was received with the details params, and the second #. * identifies the persona store. -#: ../backends/tracker/lib/trf-persona-store.vala:742 +#: ../backends/tracker/lib/trf-persona-store.vala:743 #, c-format msgid "Unrecognized parameter '%s' passed to persona store '%s'." msgstr "Neatpazīts parametrs “%s” nodots personas krātuvei “%s”." @@ -407,19 +474,19 @@ msgstr "Segvārds nav rakstāms šim kontaktam." #. Translators: the first parameter is a folder path and the second #. * is an error message. -#: ../folks/backend-store.vala:609 +#: ../folks/backend-store.vala:651 #, c-format msgid "Error listing contents of folder '%s': %s" msgstr "Kļūda, uzskaitot mapes “%s” saturu — %s" #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:739 +#: ../folks/backend-store.vala:786 #, c-format msgid "File or directory '%s' does not exist." msgstr "Datne vai direktorija “%s” neeksistē." #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:745 +#: ../folks/backend-store.vala:792 #, c-format msgid "Failed to get content type for '%s'." msgstr "Neizdevās iegūt satura tipu “%s”·" @@ -441,31 +508,31 @@ msgstr "TZ adresi “%s” neizdevās atpazīt." #. Translators: the first parameter is a persona store identifier #. * and the second is an error message. -#: ../folks/individual-aggregator.vala:921 +#: ../folks/individual-aggregator.vala:1040 #, c-format msgid "Error preparing persona store '%s': %s" msgstr "Kļūda, sagatavojot personas krātuvi “%s” — %s" #. Translators: the parameter is a property name. -#: ../folks/individual-aggregator.vala:1142 -#: ../folks/individual-aggregator.vala:1368 +#: ../folks/individual-aggregator.vala:1269 +#: ../folks/individual-aggregator.vala:1536 #, c-format msgid "Unknown property '%s' in linkable property list." msgstr "Nezināma īpašība “%s” saistīto īpašību sarakstā." #. Translators: the first parameter is a store identifier #. * and the second parameter is an error message. -#: ../folks/individual-aggregator.vala:1830 +#: ../folks/individual-aggregator.vala:2022 #, c-format msgid "Failed to add contact for persona store ID '%s': %s" msgstr "Neizdevās pievienot kontaktu personas krātuves ID “%s” — %s" -#: ../folks/individual-aggregator.vala:1931 +#: ../folks/individual-aggregator.vala:2119 msgid "Can’t link personas with no primary store." msgstr "Nevar savienot personas, kurām nav primārās krātuves." -#: ../folks/individual-aggregator.vala:1932 -#: ../folks/individual-aggregator.vala:2276 +#: ../folks/individual-aggregator.vala:2120 +#: ../folks/individual-aggregator.vala:2451 #, c-format msgid "" "Persona store ‘%s:%s’ is configured as primary, but could not be found or " @@ -474,8 +541,8 @@ msgstr "" "Personu krātuve “%s:%s” ir konfigurēta kā primārā, bet to neizdevās atrast " "vai ielādēt." -#: ../folks/individual-aggregator.vala:1933 -#: ../folks/individual-aggregator.vala:2277 +#: ../folks/individual-aggregator.vala:2121 +#: ../folks/individual-aggregator.vala:2452 #, c-format msgid "" "Check the relevant service is running, or change the default store in that " @@ -484,26 +551,76 @@ msgstr "" "Pārbaudiet, vai atbilstošais serviss strādā vai nomainiet noklusējuma " "krātuvi tajā servisā, vai izmanto “%s” GSettings atslēgu." -#: ../folks/individual-aggregator.vala:1965 +#: ../folks/individual-aggregator.vala:2153 msgid "Anti-links can't be removed between personas being linked." msgstr "Anti-saites nevar izņemt starp savienotajām personām." -#: ../folks/individual-aggregator.vala:2275 +#: ../folks/individual-aggregator.vala:2450 msgid "Can’t add personas with no primary store." msgstr "Nevar pievienot personas, kurām nav primārās krātuves." -#: ../folks/individual-aggregator.vala:2286 +#: ../folks/individual-aggregator.vala:2461 #, c-format msgid "Can't write to requested property (“%s”) of the writeable store." msgstr "Nevar ierakstīt pieprasīto īpašību (“%s”) no rakstāmas krātuves." -#: ../folks/individual.vala:217 ../folks/individual.vala:370 -#: ../folks/individual.vala:479 ../folks/individual.vala:730 -#: ../folks/individual.vala:808 +#: ../folks/individual.vala:216 ../folks/individual.vala:402 +#: ../folks/individual.vala:511 ../folks/individual.vala:762 +#: ../folks/individual.vala:840 #, c-format msgid "Failed to change property ‘%s’: No suitable personas were found." msgstr "Neizdevās mainīt īpašību “%s” — netika atrasta piemērotas personas." +#. Translators: This is the default name for an Individual +#. * when displayed in the UI if no personal details are available +#. * for them. +#: ../folks/individual.vala:1951 +msgid "Unnamed Person" +msgstr "Nenosaukta persona" + +#. FIXME: Ideally we’d use a format string translated to the locale of the +#. * persona whose name is being formatted, but no backend provides +#. * information about personas’ locales, so we have to settle for the +#. * current user’s locale. +#. * +#. * We thought about using nl_langinfo(_NL_NAME_NAME_FMT) here, but +#. * decided against it because: +#. * 1. It’s not the best documented API in the world, and its stability +#. * is in question. +#. * 2. An attempt to improve the interface in glibc met with a wall of +#. * complaints: https://sourceware.org/bugzilla/show_bug.cgi?id=14641. +#. * +#. * However, we do re-use the string format placeholders from +#. * _NL_NAME_NAME_FMT (as documented here: +#. * http://lh.2xlibre.net/values/name_fmt/) because there’s a chance glibc +#. * might eventually grow a useful interface for this. +#. * +#. * It does mean we have to implement our own parser for the name_fmt +#. * format though, since glibc doesn’t provide a formatting function. +#. Translators: This is a format string used to convert structured names +#. * to a single string. It should be translated to the predominant +#. * semi-formal name format for your locale, using the placeholders +#. * documented here: http://lh.2xlibre.net/values/name_fmt/. You may be +#. * able to re-use the existing glibc format string for your locale on that +#. * page if it’s suitable. +#. * +#. * More explicitly: the supported placeholders are %f, %F, %g, %G, %m, %M, +#. * %t. The romanisation modifier (e.g. %Rf) is recognized but ignored. +#. * %s, %S and %d are all replaced by the same thing (the ‘Honorific +#. * Prefixes’ from vCard) so please avoid using more than one. +#. * +#. * For example, the format string ‘%g%t%m%t%f’ expands to ‘John Andrew +#. * Lees’ when used for a persona with first name ‘John’, additional names +#. * ‘Andrew’ and family names ‘Lees’. +#. * +#. * If you need additional placeholders with other information or +#. * punctuation, please file a bug against libfolks: +#. * https://bugzilla.gnome.org/enter_bug.cgi?product=folks +#. +#: ../folks/name-details.vala:268 +msgid "%g%t%m%t%f" +msgstr "%g%t%m%t%f" + #: ../folks/org.freedesktop.folks.gschema.xml.in.h:1 msgid "Primary store ID" msgstr "Primārās krātuves ID" @@ -523,35 +640,35 @@ msgstr "" msgid "%s, %s, %s, %s, %s, %s, %s" msgstr "%s, %s, %s, %s, %s, %s, %s" -#: ../folks/presence-details.vala:159 +#: ../folks/presence-details.vala:171 msgid "Unknown status" msgstr "Nezināms statuss" -#: ../folks/presence-details.vala:161 +#: ../folks/presence-details.vala:173 msgid "Offline" msgstr "Bezsaistē" -#: ../folks/presence-details.vala:165 +#: ../folks/presence-details.vala:177 msgid "Error" msgstr "Kļūda" -#: ../folks/presence-details.vala:167 +#: ../folks/presence-details.vala:179 msgid "Available" msgstr "Pieejams" -#: ../folks/presence-details.vala:169 +#: ../folks/presence-details.vala:181 msgid "Away" msgstr "Projām" -#: ../folks/presence-details.vala:171 +#: ../folks/presence-details.vala:183 msgid "Extended away" msgstr "Ilglaicīgi projām" -#: ../folks/presence-details.vala:173 +#: ../folks/presence-details.vala:185 msgid "Busy" msgstr "Aizņemts" -#: ../folks/presence-details.vala:175 +#: ../folks/presence-details.vala:187 msgid "Hidden" msgstr "Slēpts" @@ -653,54 +770,54 @@ msgstr "Avota aizmugures nosaukums (noklusējums — “pidgin”)" msgid "Source filename (default: specific to source backend)" msgstr "Avota datnes nosaukums (noklusējums — specifisks aizmugures avotam)" -#: ../tools/import.vala:57 +#: ../tools/import.vala:58 msgid "— import meta-contact information to libfolks" msgstr "— importēt meta-kontakta informāciju libfolks" #. Translators: the parameter is an error message. -#: ../tools/import.vala:67 +#: ../tools/import.vala:68 #, c-format msgid "Couldn't parse command line options: %s" msgstr "Neizdevās parsēt komandrindas opcijas — %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:108 +#: ../tools/import.vala:109 #, c-format msgid "Couldn't load the backends: %s" msgstr "Neizdevās ielādēt aizmugures — %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:119 +#: ../tools/import.vala:120 #, c-format msgid "Couldn't load the ‘%s’ backend." msgstr "Neizdevās ielādēt “%s” aizmuguri." #. Translators: the first parameter is a backend identifier and the #. * second parameter is an error message. -#: ../tools/import.vala:132 +#: ../tools/import.vala:133 #, c-format msgid "Couldn't prepare the ‘%s’ backend: %s" msgstr "Neizdevās sagatavot “%s” aizmuguri — %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:145 +#: ../tools/import.vala:146 #, c-format msgid "Couldn't load the ‘%s’ backend's persona store." msgstr "Neizdevās ielādēt “%s” aizmugures personas krātuvi." -#: ../tools/import.vala:166 +#: ../tools/import.vala:167 #, c-format msgid "Couldn't prepare the ‘%s’ backend's persona store: %s" msgstr "Neizdevās sagatavot “%s” aizmugures personas krātuvi — %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:184 +#: ../tools/import.vala:185 #, c-format msgid "Error importing contacts: %s" msgstr "Kļūda, importējot kontaktus — %s" #. Translators: both parameters are identifiers for backends. -#: ../tools/import.vala:198 +#: ../tools/import.vala:199 #, c-format msgid "" "Unrecognized source backend name ‘%s’. ‘%s’ is currently the only supported " @@ -709,3 +826,9 @@ msgstr "" "Neatpazīts avota aizmugures nosaukums “%s”. “%s” pašlaik ir vienīgā " "atbalstītā avota aizmugure." +#~ msgid "" +#~ "Failed to determine whether we can set aliases on Telepathy account '%s': " +#~ "%s" +#~ msgstr "" +#~ "Neizdevās noteikt, vai var iestatīt aizstājvārdus Telepathy kontā “%s” — " +#~ "%s" @@ -1,14 +1,14 @@ # Norwegian bokmål translation of folks. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# Kjartan Maraas <kmaraas@gnome.org>, 2011-2013. +# Kjartan Maraas <kmaraas@gnome.org>, 2011-2014. # msgid "" msgstr "" -"Project-Id-Version: folks 0.7.x\n" +"Project-Id-Version: folks 0.9.7\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-04 14:59+0100\n" -"PO-Revision-Date: 2013-03-04 15:00+0100\n" +"POT-Creation-Date: 2014-03-05 18:12+0100\n" +"PO-Revision-Date: 2014-03-05 18:15+0100\n" "Last-Translator: Kjartan Maraas <kmaraas@gnome.org>\n" "Language-Team: Norwegian bokmål <i18n-nb@lister.ping.uio.no>\n" "Language: \n" @@ -17,6 +17,71 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" +#: ../backends/bluez/bluez-backend.vala:600 +msgid "" +"No BlueZ 5 object manager running, so the BlueZ backend will be inactive. " +"Either your BlueZ installation is too old (only version 5 is supported) or " +"the service can’t be started." +msgstr "" + +#: ../backends/bluez/bluez-backend.vala:613 +msgid "" +"Error connecting to OBEX transfer daemon over D-Bus. Ensure BlueZ and obexd " +"are installed." +msgstr "" + +#. Translators: the parameter is an error message. +#: ../backends/bluez/bluez-persona-store.vala:385 +#, c-format +msgid "Error reading the transferred address book file: %s" +msgstr "Feil ved lesing av overført adressebokfil: %s" + +#. Translators: the first parameter is the name of the +#. * failed transfer, and the second is a Bluetooth device +#. * alias. +#. Translators: the first parameter is the name of the failed +#. * transfer, and the second is a Bluetooth device alias. +#: ../backends/bluez/bluez-persona-store.vala:667 +#: ../backends/bluez/bluez-persona-store.vala:689 +#, c-format +msgid "" +"Error during transfer of the address book ‘%s’ from Bluetooth device ‘%s’." +msgstr "Feil under overføring av adressebok «%s» fra Bluetooth-enhet «%s»." + +#: ../backends/bluez/bluez-persona-store.vala:782 +#, c-format +msgid "" +"Permission to access the address book on Bluetooth device ‘%s’ was denied by " +"the user." +msgstr "" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:789 +#, c-format +msgid "An OBEX address book transfer from device ‘%s’ could not be started: %s" +msgstr "" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:829 +#, c-format +msgid "The OBEX address book transfer from device ‘%s’ failed: %s" +msgstr "" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:846 +#, c-format +msgid "" +"Error during transfer of the address book from Bluetooth device ‘%s’: %s" +msgstr "" + +#: ../backends/bluez/bluez-persona-store.vala:1064 +#, c-format +msgid "Bluetooth device ‘%s’ disappeared during address book transfer." +msgstr "Bluetooth-enhet «%s» forsvant under overføring av adressebok." + #. The timeout after which we consider a property change to have failed if we #. * haven't received a property change notification for it. #. seconds @@ -31,68 +96,68 @@ msgstr "Stjernet i Android" #. Translators: the first parameter is an address book #. * URI and the second is a persona UID. -#: ../backends/eds/lib/edsf-persona-store.vala:671 +#: ../backends/eds/lib/edsf-persona-store.vala:673 #, c-format msgid "Address book ‘%s’ is offline, so contact ‘%s’ cannot be removed." msgstr "Adressebok «%s» er frakoblet så kontakt «%s» kan ikke fjernes." #. Translators: the first parameter is an address book #. * URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:677 +#: ../backends/eds/lib/edsf-persona-store.vala:679 #, c-format msgid "Permission denied to remove contact ‘%s’: %s" msgstr "Tilgang til å fjerne kontakt «%s» nektet: %s" #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:682 +#: ../backends/eds/lib/edsf-persona-store.vala:684 #, c-format msgid "Removing contacts isn't supported by this persona store: %s" msgstr "Fjerning av kontakter støttes ikke av dette persona-lageret: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:711 +#: ../backends/eds/lib/edsf-persona-store.vala:713 #, c-format msgid "Can't remove contact ‘%s’: %s" msgstr "Kan ikke fjerne kontakt «%s»: %s" #. Translators: the parameter is an address book #. * URI. -#: ../backends/eds/lib/edsf-persona-store.vala:801 -#: ../backends/eds/lib/edsf-persona-store.vala:992 +#: ../backends/eds/lib/edsf-persona-store.vala:802 +#: ../backends/eds/lib/edsf-persona-store.vala:993 #, c-format msgid "Address book ‘%s’ is offline." msgstr "Adressebok «%s» er frakoblet." #. Translators: the first parameter is an address #. * book URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:806 -#: ../backends/eds/lib/edsf-persona-store.vala:997 +#: ../backends/eds/lib/edsf-persona-store.vala:807 +#: ../backends/eds/lib/edsf-persona-store.vala:998 #, c-format msgid "Permission denied to open address book ‘%s’: %s" msgstr "Tilgang til å åpne adressebok «%s» nektet: %s" #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:839 +#: ../backends/eds/lib/edsf-persona-store.vala:840 #, c-format msgid "Couldn't open address book ‘%s’: %s" msgstr "Kunne ikke åpne adressebok «%s»: %s" #. Translators: the parameteter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:905 -#: ../backends/eds/lib/edsf-persona-store.vala:935 +#: ../backends/eds/lib/edsf-persona-store.vala:906 +#: ../backends/eds/lib/edsf-persona-store.vala:936 #, c-format msgid "Couldn't get address book capabilities: %s" msgstr "Fant ikke evner for adressebok: %s" #. Translators: the parameter is an address book URI. -#: ../backends/eds/lib/edsf-persona-store.vala:951 +#: ../backends/eds/lib/edsf-persona-store.vala:952 #, c-format msgid "Couldn't get view for address book ‘%s’." msgstr "Fant ikke visning for adressebok «%s»." #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1030 +#: ../backends/eds/lib/edsf-persona-store.vala:1031 #, c-format msgid "Couldn't get view for address book ‘%s’: %s" msgstr "Fant ikke visning for adressebokk «%s»: %s" @@ -100,119 +165,119 @@ msgstr "Fant ikke visning for adressebokk «%s»: %s" #. Translators: the parameter is the name of a property on a #. * contact, formatted in the normal GObject style (e.g. #. * lowercase with hyphens to separate words). -#: ../backends/eds/lib/edsf-persona-store.vala:1390 +#: ../backends/eds/lib/edsf-persona-store.vala:1303 #, c-format msgid "Changing the ‘%s’ property failed due to reaching the timeout." msgstr "Endring av egenskap «%s» feilet på grunn av tidsavbrudd." -#: ../backends/eds/lib/edsf-persona-store.vala:1428 +#: ../backends/eds/lib/edsf-persona-store.vala:1337 #: ../folks/avatar-details.vala:63 msgid "Avatar is not writeable on this contact." msgstr "Avatar er ikke skrivbar på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1449 +#: ../backends/eds/lib/edsf-persona-store.vala:1358 #: ../folks/web-service-details.vala:123 msgid "Web service addresses are not writeable on this contact." msgstr "Webservice adresser er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1485 +#: ../backends/eds/lib/edsf-persona-store.vala:1394 #: ../folks/url-details.vala:152 msgid "URLs are not writeable on this contact." msgstr "URLer er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1566 +#: ../backends/eds/lib/edsf-persona-store.vala:1475 #: ../folks/local-id-details.vala:64 msgid "Local IDs are not writeable on this contact." msgstr "Lokale IDer er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1595 +#: ../backends/eds/lib/edsf-persona-store.vala:1504 msgid "The contact cannot be marked as favourite." msgstr "Kontakten kan ikke merkes som favoritt." #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1667 +#: ../backends/eds/lib/edsf-persona-store.vala:1576 #, c-format msgid "Can't update avatar: %s" msgstr "Kan ikke oppdatere avatar: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:1678 +#: ../backends/eds/lib/edsf-persona-store.vala:1587 #: ../folks/email-details.vala:120 msgid "E-mail addresses are not writeable on this contact." msgstr "E-postadresser er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1696 -#: ../folks/phone-details.vala:224 +#: ../backends/eds/lib/edsf-persona-store.vala:1605 +#: ../folks/phone-details.vala:255 msgid "Phone numbers are not writeable on this contact." msgstr "Telefonnummer er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1714 +#: ../backends/eds/lib/edsf-persona-store.vala:1623 #: ../folks/postal-address-details.vala:361 msgid "Postal addresses are not writeable on this contact." msgstr "Postadresser er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1785 -#: ../folks/name-details.vala:283 +#: ../backends/eds/lib/edsf-persona-store.vala:1694 +#: ../folks/name-details.vala:454 msgid "Full name is not writeable on this contact." msgstr "Fullt navn er ikke skrivbart på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1807 -#: ../folks/name-details.vala:321 +#: ../backends/eds/lib/edsf-persona-store.vala:1716 +#: ../folks/name-details.vala:492 msgid "Nickname is not writeable on this contact." msgstr "Kallenavn er ikke skrivbart på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1829 +#: ../backends/eds/lib/edsf-persona-store.vala:1738 #: ../folks/note-details.vala:138 msgid "Notes are not writeable on this contact." msgstr "Notater er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1861 +#: ../backends/eds/lib/edsf-persona-store.vala:1770 #: ../folks/birthday-details.vala:62 msgid "Birthday is not writeable on this contact." msgstr "Fødselsdag er ikke skrivbar på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:1905 +#: ../backends/eds/lib/edsf-persona-store.vala:1814 #: ../folks/role-details.vala:279 msgid "Roles are not writeable on this contact." msgstr "Roller er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:2006 -#: ../folks/name-details.vala:246 +#: ../backends/eds/lib/edsf-persona-store.vala:1915 +#: ../folks/name-details.vala:417 msgid "Structured name is not writeable on this contact." msgstr "Strukturert navn er ikke skrivbart på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:2045 +#: ../backends/eds/lib/edsf-persona-store.vala:1954 #: ../folks/im-details.vala:136 msgid "IM addresses are not writeable on this contact." msgstr "Lynmeldingsadresser er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:2095 +#: ../backends/eds/lib/edsf-persona-store.vala:2004 #: ../folks/group-details.vala:174 msgid "Groups are not writeable on this contact." msgstr "Grupper er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:2110 +#: ../backends/eds/lib/edsf-persona-store.vala:2019 msgid "My Contacts is only available for Google Contacts" msgstr "Mine kontakter er kun tilgjengelig for Google-kontakter" -#: ../backends/eds/lib/edsf-persona-store.vala:2181 +#: ../backends/eds/lib/edsf-persona-store.vala:2090 #: ../folks/gender-details.vala:79 msgid "Gender is not writeable on this contact." msgstr "Kjønn er ikke skrivbart på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:2219 +#: ../backends/eds/lib/edsf-persona-store.vala:2128 #: ../folks/anti-linkable.vala:81 msgid "Anti-links are not writeable on this contact." msgstr "Anti-lenker er ikke skrivbare på denne kontakten." -#: ../backends/eds/lib/edsf-persona-store.vala:2262 -#: ../folks/location-details.vala:129 +#: ../backends/eds/lib/edsf-persona-store.vala:2171 +#: ../folks/location-details.vala:135 msgid "Location is not writeable on this contact." msgstr "Lokasjon er ikke skrivbar på denne kontakten." #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2439 +#: ../backends/eds/lib/edsf-persona-store.vala:2484 #, c-format msgid "Property ‘%s’ is not writeable: %s" msgstr "Egenskap «%s» er ikke skrivbar: %s" @@ -220,42 +285,42 @@ msgstr "Egenskap «%s» er ikke skrivbar: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2448 +#: ../backends/eds/lib/edsf-persona-store.vala:2493 #, c-format msgid "Invalid value for property ‘%s’: %s" msgstr "Ugyldig verdi for egenskap «%s»: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:2474 +#: ../backends/eds/lib/edsf-persona-store.vala:2519 #, c-format msgid "Unknown error setting property ‘%s’: %s" msgstr "Ukjent feil ved setting av egenskap «%s»: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:233 +#: ../backends/key-file/kf-persona-store.vala:234 #, c-format msgid "The relationship key file '%s' could not be loaded: %s" msgstr "Nøkkelfil «%s» for relasjon kunne ikke lastes: %s" #. Translators: the first parameter is a path, and the #. * second is an error message. -#: ../backends/key-file/kf-persona-store.vala:255 +#: ../backends/key-file/kf-persona-store.vala:256 #, c-format msgid "The relationship key file directory '%s' could not be created: %s" msgstr "Katalog «%s» for katalog for relasjonsfil kunne ikke opprettes: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:279 +#: ../backends/key-file/kf-persona-store.vala:280 #, c-format msgid "The relationship key file '%s' could not be created: %s" msgstr "Nøkkelfil «%s» for relasjon kunne ikke opprettes: %s" #. Translators: the first parameter is a filename, the second is #. * an error message. -#: ../backends/key-file/kf-persona-store.vala:470 +#: ../backends/key-file/kf-persona-store.vala:471 #, c-format msgid "Could not write updated key file '%s': %s" msgstr "Kunne ikke skrive oppdatert nøkkelfil «%s»: %s" @@ -265,13 +330,13 @@ msgstr "Kunne ikke skrive oppdatert nøkkelfil «%s»: %s" #. * an IM address (e.g. “foo@jabber.org”), the second is #. * the name of a protocol (e.g. “jabber”) and the third is #. * an error message. -#: ../backends/key-file/kf-persona.vala:172 +#: ../backends/key-file/kf-persona.vala:174 #, c-format msgid "Invalid IM address ‘%s’ for protocol ‘%s’: %s" msgstr "Ugyldig lynmeldingsadresse «%s» for protokoll «%s»: %s" #. Translators: the parameter is an error message. -#: ../backends/key-file/kf-persona.vala:430 +#: ../backends/key-file/kf-persona.vala:432 #, c-format msgid "Couldn't load data from key file: %s" msgstr "Kunne ikke laste data fra nøkkelfil: %s" @@ -296,27 +361,24 @@ msgstr "Ingen evner funnet for kontakter." msgid "Error opening contacts view." msgstr "Feil ved åpning av kontaktvisning." -#. Translators: the first parameter is the display name for -#. * the Telepathy account, and the second is an error -#. * message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:814 -#, c-format +#: ../backends/ofono/ofono-backend.vala:196 msgid "" -"Failed to determine whether we can set aliases on Telepathy account '%s': %s" +"No oFono object manager running, so the oFono backend will be inactive. " +"Either oFono isn’t installed or the service can’t be started." msgstr "" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1278 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1248 msgid "Telepathy contacts representing the local user may not be removed." msgstr "" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1289 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1259 #, c-format msgid "Failed to remove a persona from store: %s" msgstr "Klarte ikke å fjerne en persona fra lageret: %s" #. Translators: the first two parameters are store identifiers and #. * the third is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1324 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1294 #, c-format msgid "" "Persona store (%s, %s) requires the following details:\n" @@ -325,69 +387,69 @@ msgstr "" "Personalager (%s, %s) krever følgende detaljer:\n" " kontakt (oppgitt: «%s»)\n" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1339 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1309 msgid "Cannot create a new Telepathy contact while offline." msgstr "Kan ikke lage en ny Telepathy-kontakt i frakoblet modus." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1357 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1327 #, c-format msgid "Failed to add a persona from details: %s" msgstr "Klarte ikke å legge til persona fra detaljer: %s" #. Translators: "telepathy-logger" is the name of an application, #. * and should not be translated. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1377 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1347 msgid "" "Failed to change favorite without a connection to the telepathy-logger " "service." msgstr "" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1383 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1353 msgid "" "Failed to change favorite status of Telepathy Persona because it has no " "attached TpContact." msgstr "" #. Translators: the parameter is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1401 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1371 #, c-format msgid "Failed to change favorite status for Telepathy contact ‘%s’." msgstr "" #. Translators: the parameter is an error message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1433 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1403 #, c-format msgid "Failed to change contact's alias: %s" msgstr "Klarte ikke å endre kontaktens alias: %s" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1484 msgid "Extended information may only be set on the user's Telepathy contact." msgstr "" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1542 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 msgid "" "Extended information cannot be written because the store is disconnected." msgstr "" -#: ../backends/telepathy/lib/tpf-persona.vala:499 -#: ../backends/telepathy/lib/tpf-persona.vala:520 -#: ../backends/telepathy/lib/tpf-persona.vala:572 -#: ../backends/telepathy/lib/tpf-persona.vala:586 +#: ../backends/telepathy/lib/tpf-persona.vala:511 +#: ../backends/telepathy/lib/tpf-persona.vala:532 +#: ../backends/telepathy/lib/tpf-persona.vala:584 +#: ../backends/telepathy/lib/tpf-persona.vala:598 #, c-format msgid "Failed to change group membership: %s" msgstr "Klarte ikke å endre gruppemedlemskap: %s" #. Translators: "account" refers to an instant messaging #. * account. -#: ../backends/telepathy/lib/tpf-persona.vala:502 -#: ../backends/telepathy/lib/tpf-persona.vala:575 +#: ../backends/telepathy/lib/tpf-persona.vala:514 +#: ../backends/telepathy/lib/tpf-persona.vala:587 msgid "Account is offline." msgstr "Kontoen er frakoblet." #. Translators: the first parameter is the unknown key that #. * was received with the details params, and the second #. * identifies the persona store. -#: ../backends/tracker/lib/trf-persona-store.vala:742 +#: ../backends/tracker/lib/trf-persona-store.vala:743 #, c-format msgid "Unrecognized parameter '%s' passed to persona store '%s'." msgstr "" @@ -398,19 +460,19 @@ msgstr "Alias er ikke skrivbart på denne kontakten." #. Translators: the first parameter is a folder path and the second #. * is an error message. -#: ../folks/backend-store.vala:609 +#: ../folks/backend-store.vala:651 #, c-format msgid "Error listing contents of folder '%s': %s" msgstr "Feil ved visning av innhold for mappe «%s»: %s" #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:739 +#: ../folks/backend-store.vala:786 #, c-format msgid "File or directory '%s' does not exist." msgstr "Fil eller katalog «%s» eksisterer ikke." #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:745 +#: ../folks/backend-store.vala:792 #, c-format msgid "Failed to get content type for '%s'." msgstr "Klarte ikke å finne innholdstype for «%s»." @@ -432,65 +494,115 @@ msgstr "IM-adresse «%s» kunne ikke forstås." #. Translators: the first parameter is a persona store identifier #. * and the second is an error message. -#: ../folks/individual-aggregator.vala:921 +#: ../folks/individual-aggregator.vala:1040 #, c-format msgid "Error preparing persona store '%s': %s" msgstr "Feil ved klargjøring av persona-lager «%s»: %s" #. Translators: the parameter is a property name. -#: ../folks/individual-aggregator.vala:1142 -#: ../folks/individual-aggregator.vala:1368 +#: ../folks/individual-aggregator.vala:1269 +#: ../folks/individual-aggregator.vala:1536 #, c-format msgid "Unknown property '%s' in linkable property list." msgstr "Ukjent egenskap «%s» i lenkbar egenskapsliste." #. Translators: the first parameter is a store identifier #. * and the second parameter is an error message. -#: ../folks/individual-aggregator.vala:1830 +#: ../folks/individual-aggregator.vala:2022 #, c-format msgid "Failed to add contact for persona store ID '%s': %s" msgstr "" -#: ../folks/individual-aggregator.vala:1931 +#: ../folks/individual-aggregator.vala:2119 msgid "Can’t link personas with no primary store." msgstr "Kan ikke lenke personas uten primærlager." -#: ../folks/individual-aggregator.vala:1932 -#: ../folks/individual-aggregator.vala:2276 +#: ../folks/individual-aggregator.vala:2120 +#: ../folks/individual-aggregator.vala:2451 #, c-format msgid "" "Persona store ‘%s:%s’ is configured as primary, but could not be found or " "failed to load." msgstr "" -#: ../folks/individual-aggregator.vala:1933 -#: ../folks/individual-aggregator.vala:2277 +#: ../folks/individual-aggregator.vala:2121 +#: ../folks/individual-aggregator.vala:2452 #, c-format msgid "" "Check the relevant service is running, or change the default store in that " "service or using the “%s” GSettings key." msgstr "" -#: ../folks/individual-aggregator.vala:1965 +#: ../folks/individual-aggregator.vala:2153 msgid "Anti-links can't be removed between personas being linked." msgstr "" -#: ../folks/individual-aggregator.vala:2275 +#: ../folks/individual-aggregator.vala:2450 msgid "Can’t add personas with no primary store." msgstr "Kan ikke legge til personas uten primærlager." -#: ../folks/individual-aggregator.vala:2286 +#: ../folks/individual-aggregator.vala:2461 #, c-format msgid "Can't write to requested property (“%s”) of the writeable store." msgstr "" -#: ../folks/individual.vala:217 ../folks/individual.vala:370 -#: ../folks/individual.vala:479 ../folks/individual.vala:730 -#: ../folks/individual.vala:808 +#: ../folks/individual.vala:216 ../folks/individual.vala:402 +#: ../folks/individual.vala:511 ../folks/individual.vala:762 +#: ../folks/individual.vala:840 #, c-format msgid "Failed to change property ‘%s’: No suitable personas were found." msgstr "" +#. Translators: This is the default name for an Individual +#. * when displayed in the UI if no personal details are available +#. * for them. +#: ../folks/individual.vala:1951 +msgid "Unnamed Person" +msgstr "Person uten navn" + +#. FIXME: Ideally we’d use a format string translated to the locale of the +#. * persona whose name is being formatted, but no backend provides +#. * information about personas’ locales, so we have to settle for the +#. * current user’s locale. +#. * +#. * We thought about using nl_langinfo(_NL_NAME_NAME_FMT) here, but +#. * decided against it because: +#. * 1. It’s not the best documented API in the world, and its stability +#. * is in question. +#. * 2. An attempt to improve the interface in glibc met with a wall of +#. * complaints: https://sourceware.org/bugzilla/show_bug.cgi?id=14641. +#. * +#. * However, we do re-use the string format placeholders from +#. * _NL_NAME_NAME_FMT (as documented here: +#. * http://lh.2xlibre.net/values/name_fmt/) because there’s a chance glibc +#. * might eventually grow a useful interface for this. +#. * +#. * It does mean we have to implement our own parser for the name_fmt +#. * format though, since glibc doesn’t provide a formatting function. +#. Translators: This is a format string used to convert structured names +#. * to a single string. It should be translated to the predominant +#. * semi-formal name format for your locale, using the placeholders +#. * documented here: http://lh.2xlibre.net/values/name_fmt/. You may be +#. * able to re-use the existing glibc format string for your locale on that +#. * page if it’s suitable. +#. * +#. * More explicitly: the supported placeholders are %f, %F, %g, %G, %m, %M, +#. * %t. The romanisation modifier (e.g. %Rf) is recognized but ignored. +#. * %s, %S and %d are all replaced by the same thing (the ‘Honorific +#. * Prefixes’ from vCard) so please avoid using more than one. +#. * +#. * For example, the format string ‘%g%t%m%t%f’ expands to ‘John Andrew +#. * Lees’ when used for a persona with first name ‘John’, additional names +#. * ‘Andrew’ and family names ‘Lees’. +#. * +#. * If you need additional placeholders with other information or +#. * punctuation, please file a bug against libfolks: +#. * https://bugzilla.gnome.org/enter_bug.cgi?product=folks +#. +#: ../folks/name-details.vala:268 +msgid "%g%t%m%t%f" +msgstr "%g%t%m%t%f" + #: ../folks/org.freedesktop.folks.gschema.xml.in.h:1 msgid "Primary store ID" msgstr "ID for primærlager" @@ -507,35 +619,35 @@ msgstr "" msgid "%s, %s, %s, %s, %s, %s, %s" msgstr "%s, %s, %s, %s, %s, %s, %s" -#: ../folks/presence-details.vala:159 +#: ../folks/presence-details.vala:171 msgid "Unknown status" msgstr "Ukjent status" -#: ../folks/presence-details.vala:161 +#: ../folks/presence-details.vala:173 msgid "Offline" msgstr "Frakoblet" -#: ../folks/presence-details.vala:165 +#: ../folks/presence-details.vala:177 msgid "Error" msgstr "Feil" -#: ../folks/presence-details.vala:167 +#: ../folks/presence-details.vala:179 msgid "Available" msgstr "Tilgjengelig" -#: ../folks/presence-details.vala:169 +#: ../folks/presence-details.vala:181 msgid "Away" msgstr "Borte" -#: ../folks/presence-details.vala:171 +#: ../folks/presence-details.vala:183 msgid "Extended away" msgstr "Utvidet borte" -#: ../folks/presence-details.vala:173 +#: ../folks/presence-details.vala:185 msgid "Busy" msgstr "Opptatt" -#: ../folks/presence-details.vala:175 +#: ../folks/presence-details.vala:187 msgid "Hidden" msgstr "Skjult" @@ -628,60 +740,60 @@ msgstr "" #: ../tools/import.vala:44 msgid "Source backend name (default: 'pidgin')" -msgstr "" +msgstr "Navn på motor for kilde (forvalgt: «pidgin»)" #: ../tools/import.vala:47 msgid "Source filename (default: specific to source backend)" -msgstr "" +msgstr "Filnavn for kilde (forvalg: spesifikk for kildemotor)" -#: ../tools/import.vala:57 +#: ../tools/import.vala:58 msgid "— import meta-contact information to libfolks" msgstr "– importer metainformasjon for kontakt til libfolks" #. Translators: the parameter is an error message. -#: ../tools/import.vala:67 +#: ../tools/import.vala:68 #, c-format msgid "Couldn't parse command line options: %s" msgstr "Kunne ikke lese kommandolinjeflagg: %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:108 +#: ../tools/import.vala:109 #, c-format msgid "Couldn't load the backends: %s" msgstr "Kunne ikke laste motorer: %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:119 +#: ../tools/import.vala:120 #, c-format msgid "Couldn't load the ‘%s’ backend." msgstr "Kunne ikke laste motor «%s»" #. Translators: the first parameter is a backend identifier and the #. * second parameter is an error message. -#: ../tools/import.vala:132 +#: ../tools/import.vala:133 #, c-format msgid "Couldn't prepare the ‘%s’ backend: %s" msgstr "Kunne ikke klargjøre motor «%s»: %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:145 +#: ../tools/import.vala:146 #, c-format msgid "Couldn't load the ‘%s’ backend's persona store." msgstr "Kunne ikke laste personalager for motor «%s»." -#: ../tools/import.vala:166 +#: ../tools/import.vala:167 #, c-format msgid "Couldn't prepare the ‘%s’ backend's persona store: %s" msgstr "Kunne ikke klargjøre personalager for motor «%s»: %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:184 +#: ../tools/import.vala:185 #, c-format msgid "Error importing contacts: %s" msgstr "Feil ved import av kontakter: %s" #. Translators: both parameters are identifiers for backends. -#: ../tools/import.vala:198 +#: ../tools/import.vala:199 #, c-format msgid "" "Unrecognized source backend name ‘%s’. ‘%s’ is currently the only supported " @@ -1,14 +1,15 @@ # folks' Portuguese translation.
-# Copyright © 2012, 2013 folks
+# Copyright © 2012, 2013, 2014 folks
# This file is distributed under the same license as the folks package.
-# Duarte Loreto <happyguy_pt@hotmail.com>, 2012, 2013.
+# Duarte Loreto <happyguy_pt@hotmail.com>, 2012, 2013, 2014.
#
msgid "" msgstr "" -"Project-Id-Version: 3.8\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-15 01:26+0000\n" -"PO-Revision-Date: 2013-03-15 01:30+0100\n" +"Project-Id-Version: 3.12\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=folks&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2014-03-18 05:54+0000\n" +"PO-Revision-Date: 2014-03-18 10:20+0100\n" "Last-Translator: Duarte Loreto <happyguy_pt@hotmail.com>\n" "Language-Team: Portuguese <gnome_pt@yahoogroups.com>\n" "Language: pt\n" @@ -17,6 +18,81 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: ../backends/bluez/bluez-backend.vala:600 +msgid "" +"No BlueZ 5 object manager running, so the BlueZ backend will be inactive. " +"Either your BlueZ installation is too old (only version 5 is supported) or " +"the service can’t be started." +msgstr ""
+"Nenhum gestor de objetos BlueZ 5 em execução, pelo que o motor BlueZ irá "
+"estar inativo. Ou a sua instalação BlueZ é demasiado antiga (apenas é "
+"suportada a versão 5) ou não está a ser possível iniciar o serviço." + +#: ../backends/bluez/bluez-backend.vala:613 +msgid "" +"Error connecting to OBEX transfer daemon over D-Bus. Ensure BlueZ and obexd " +"are installed." +msgstr ""
+"Erro ao se ligar ao daemon de transferência OBEX através do D-Bus. "
+"Certifique-se de que o BlueZ e o obexd estão instalados." + +#. Translators: the parameter is an error message. +#: ../backends/bluez/bluez-persona-store.vala:385 +#, c-format +msgid "Error reading the transferred address book file: %s" +msgstr "Erro ao ler o ficheiro de livro de endereços transferido: %s" + +#. Translators: the first parameter is the name of the +#. * failed transfer, and the second is a Bluetooth device +#. * alias. +#. Translators: the first parameter is the name of the failed +#. * transfer, and the second is a Bluetooth device alias. +#: ../backends/bluez/bluez-persona-store.vala:667 +#: ../backends/bluez/bluez-persona-store.vala:689 +#, c-format +msgid "" +"Error during transfer of the address book ‘%s’ from Bluetooth device ‘%s’." +msgstr ""
+"Erro durante a transferência do livro de endereços ‘%s’ do dispositivo Bluetooth ‘%s’." + +#: ../backends/bluez/bluez-persona-store.vala:782 +#, c-format +msgid "" +"Permission to access the address book on Bluetooth device ‘%s’ was denied by " +"the user." +msgstr ""
+"Permissão negada pelo utilizador para aceder ao livro de endereços no dispositivo "
+"Bluetooth ‘%s’." + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:789 +#, c-format +msgid "An OBEX address book transfer from device ‘%s’ could not be started: %s" +msgstr "Um livro de endereços OBEX transferido do dispositivo ‘%s’ não pode ser iniciado: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:829 +#, c-format +msgid "The OBEX address book transfer from device ‘%s’ failed: %s" +msgstr "O livro de endereços OBEX transferido do dispositivo ‘%s’ falhou: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:846 +#, c-format +msgid "" +"Error during transfer of the address book from Bluetooth device ‘%s’: %s" +msgstr ""
+"Erro durante a transferência do livro de endereços do dispositivo Bluetooth "
+"‘%s’: %s" + +#: ../backends/bluez/bluez-persona-store.vala:1064 +#, c-format +msgid "Bluetooth device ‘%s’ disappeared during address book transfer." +msgstr "Dispositivo Bluetooth ‘%s’ desapareceu durante a transferência do livro de endereços." + #. The timeout after which we consider a property change to have failed if we #. * haven't received a property change notification for it. #. seconds @@ -31,7 +107,7 @@ msgstr "Starred in Android" #. Translators: the first parameter is an address book #. * URI and the second is a persona UID. -#: ../backends/eds/lib/edsf-persona-store.vala:671 +#: ../backends/eds/lib/edsf-persona-store.vala:673 #, c-format msgid "Address book ‘%s’ is offline, so contact ‘%s’ cannot be removed." msgstr "" @@ -40,62 +116,62 @@ msgstr "" #. Translators: the first parameter is an address book #. * URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:677 +#: ../backends/eds/lib/edsf-persona-store.vala:679 #, c-format msgid "Permission denied to remove contact ‘%s’: %s" msgstr "Autorização negada para remover o contacto ‘%s’: %s" #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:682 +#: ../backends/eds/lib/edsf-persona-store.vala:684 #, c-format msgid "Removing contacts isn't supported by this persona store: %s" msgstr "" "Remover contactos não é suportado por este armazenamento de personas: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:711 +#: ../backends/eds/lib/edsf-persona-store.vala:713 #, c-format msgid "Can't remove contact ‘%s’: %s" msgstr "Incapaz de remover o contacto ‘%s’: %s" #. Translators: the parameter is an address book #. * URI. -#: ../backends/eds/lib/edsf-persona-store.vala:801 -#: ../backends/eds/lib/edsf-persona-store.vala:992 +#: ../backends/eds/lib/edsf-persona-store.vala:802 +#: ../backends/eds/lib/edsf-persona-store.vala:993 #, c-format msgid "Address book ‘%s’ is offline." msgstr "O livro de endereços ‘%s’ está desligado." #. Translators: the first parameter is an address #. * book URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:806 -#: ../backends/eds/lib/edsf-persona-store.vala:997 +#: ../backends/eds/lib/edsf-persona-store.vala:807 +#: ../backends/eds/lib/edsf-persona-store.vala:998 #, c-format msgid "Permission denied to open address book ‘%s’: %s" msgstr "Autorização negada para abrir o calendário ‘%s’: %s" #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:839 +#: ../backends/eds/lib/edsf-persona-store.vala:840 #, c-format msgid "Couldn't open address book ‘%s’: %s" msgstr "Incapaz de abrir o livro de endereços ‘%s’: %s" #. Translators: the parameteter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:905 -#: ../backends/eds/lib/edsf-persona-store.vala:935 +#: ../backends/eds/lib/edsf-persona-store.vala:906 +#: ../backends/eds/lib/edsf-persona-store.vala:936 #, c-format msgid "Couldn't get address book capabilities: %s" msgstr "Incapaz de obter as capacidades do livro de endereços: %s" #. Translators: the parameter is an address book URI. -#: ../backends/eds/lib/edsf-persona-store.vala:951 +#: ../backends/eds/lib/edsf-persona-store.vala:952 #, c-format msgid "Couldn't get view for address book ‘%s’." msgstr "Incapaz de obter a vista do livro de endereços ‘%s’." #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1030 +#: ../backends/eds/lib/edsf-persona-store.vala:1031 #, c-format msgid "Couldn't get view for address book ‘%s’: %s" msgstr "Incapaz de obter a vista do livro de endereços ‘%s’: %s" @@ -103,120 +179,120 @@ msgstr "Incapaz de obter a vista do livro de endereços ‘%s’: %s" #. Translators: the parameter is the name of a property on a #. * contact, formatted in the normal GObject style (e.g. #. * lowercase with hyphens to separate words). -#: ../backends/eds/lib/edsf-persona-store.vala:1390 +#: ../backends/eds/lib/edsf-persona-store.vala:1303 #, c-format msgid "Changing the ‘%s’ property failed due to reaching the timeout." msgstr "" "Falha ao alterar a propriedade ‘%s’ por se ter excedido o tempo de espera." -#: ../backends/eds/lib/edsf-persona-store.vala:1428 +#: ../backends/eds/lib/edsf-persona-store.vala:1337 #: ../folks/avatar-details.vala:63 msgid "Avatar is not writeable on this contact." msgstr "Não é possível escrever o avatar neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1449 +#: ../backends/eds/lib/edsf-persona-store.vala:1358 #: ../folks/web-service-details.vala:123 msgid "Web service addresses are not writeable on this contact." msgstr "Não é possível escrever os endereços de serviço web neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1485 +#: ../backends/eds/lib/edsf-persona-store.vala:1394 #: ../folks/url-details.vala:152 msgid "URLs are not writeable on this contact." msgstr "Não é possível escrever os URLs neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1566 +#: ../backends/eds/lib/edsf-persona-store.vala:1475 #: ../folks/local-id-details.vala:64 msgid "Local IDs are not writeable on this contact." msgstr "Não é possível escrever os IDs locais neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1595 +#: ../backends/eds/lib/edsf-persona-store.vala:1504 msgid "The contact cannot be marked as favourite." msgstr "Este contacto não pode ser marcado como favorito." #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1667 +#: ../backends/eds/lib/edsf-persona-store.vala:1576 #, c-format msgid "Can't update avatar: %s" msgstr "Incapaz de atualizar avatar: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:1678 +#: ../backends/eds/lib/edsf-persona-store.vala:1587 #: ../folks/email-details.vala:120 msgid "E-mail addresses are not writeable on this contact." msgstr "Não é possível escrever os endereços de email neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1696 -#: ../folks/phone-details.vala:224 +#: ../backends/eds/lib/edsf-persona-store.vala:1605 +#: ../folks/phone-details.vala:255 msgid "Phone numbers are not writeable on this contact." msgstr "Não é possível escrever os números de telefone neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1714 +#: ../backends/eds/lib/edsf-persona-store.vala:1623 #: ../folks/postal-address-details.vala:361 msgid "Postal addresses are not writeable on this contact." msgstr "Não é possível escrever os endereços postais neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1785 -#: ../folks/name-details.vala:283 +#: ../backends/eds/lib/edsf-persona-store.vala:1694 +#: ../folks/name-details.vala:454 msgid "Full name is not writeable on this contact." msgstr "Não é possível escrever o nome completo neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1807 -#: ../folks/name-details.vala:321 +#: ../backends/eds/lib/edsf-persona-store.vala:1716 +#: ../folks/name-details.vala:492 msgid "Nickname is not writeable on this contact." msgstr "Não é possível escrever a alcunha neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1829 +#: ../backends/eds/lib/edsf-persona-store.vala:1738 #: ../folks/note-details.vala:138 msgid "Notes are not writeable on this contact." msgstr "Não é possível escrever notas sobre neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1861 +#: ../backends/eds/lib/edsf-persona-store.vala:1770 #: ../folks/birthday-details.vala:62 msgid "Birthday is not writeable on this contact." msgstr "Não é possível escrever o aniversário deste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:1905 +#: ../backends/eds/lib/edsf-persona-store.vala:1814 #: ../folks/role-details.vala:279 msgid "Roles are not writeable on this contact." msgstr "Não é possível escrever os papeis deste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:2006 -#: ../folks/name-details.vala:246 +#: ../backends/eds/lib/edsf-persona-store.vala:1915 +#: ../folks/name-details.vala:417 msgid "Structured name is not writeable on this contact." msgstr "Não é possível escrever o nome estruturado deste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:2045 +#: ../backends/eds/lib/edsf-persona-store.vala:1954 #: ../folks/im-details.vala:136 msgid "IM addresses are not writeable on this contact." msgstr "Não é possível escrever os endereços de MI neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:2095 +#: ../backends/eds/lib/edsf-persona-store.vala:2004 #: ../folks/group-details.vala:174 msgid "Groups are not writeable on this contact." msgstr "Não é possível escrever os grupos neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:2110 +#: ../backends/eds/lib/edsf-persona-store.vala:2019 msgid "My Contacts is only available for Google Contacts" msgstr "Os Meus Contactos apenas estão disponíveis para o Google Contacts" -#: ../backends/eds/lib/edsf-persona-store.vala:2181 +#: ../backends/eds/lib/edsf-persona-store.vala:2090 #: ../folks/gender-details.vala:79 msgid "Gender is not writeable on this contact." msgstr "Não é possível escrever o género deste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:2219 -#: ../folks/anti-linkable.vala:81 +#: ../backends/eds/lib/edsf-persona-store.vala:2128 +#: ../folks/anti-linkable.vala:84 msgid "Anti-links are not writeable on this contact." msgstr "Não é possível escrever as antiassociações neste contacto." -#: ../backends/eds/lib/edsf-persona-store.vala:2262 -#: ../folks/location-details.vala:129 +#: ../backends/eds/lib/edsf-persona-store.vala:2171 +#: ../folks/location-details.vala:135 msgid "Location is not writeable on this contact." msgstr "Não é possível escrever a localização neste contacto." #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2439 +#: ../backends/eds/lib/edsf-persona-store.vala:2484 #, c-format msgid "Property ‘%s’ is not writeable: %s" msgstr "Não é possível escrever a propriedade ‘%s’: %s" @@ -224,28 +300,28 @@ msgstr "Não é possível escrever a propriedade ‘%s’: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2448 +#: ../backends/eds/lib/edsf-persona-store.vala:2493 #, c-format msgid "Invalid value for property ‘%s’: %s" msgstr "Valor inválido para a propriedade ‘%s’: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:2474 +#: ../backends/eds/lib/edsf-persona-store.vala:2519 #, c-format msgid "Unknown error setting property ‘%s’: %s" msgstr "Erro desconhecido ao definir a propriedade ‘%s’: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:233 +#: ../backends/key-file/kf-persona-store.vala:234 #, c-format msgid "The relationship key file '%s' could not be loaded: %s" msgstr "Não foi possível ler o ficheiro de chaves de relacionamento ‘%s’: %s" #. Translators: the first parameter is a path, and the #. * second is an error message. -#: ../backends/key-file/kf-persona-store.vala:255 +#: ../backends/key-file/kf-persona-store.vala:256 #, c-format msgid "The relationship key file directory '%s' could not be created: %s" msgstr "" @@ -254,14 +330,14 @@ msgstr "" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:279 +#: ../backends/key-file/kf-persona-store.vala:280 #, c-format msgid "The relationship key file '%s' could not be created: %s" msgstr "Não foi possível criar o ficheiro de chaves de relacionamento '%s': %s" #. Translators: the first parameter is a filename, the second is #. * an error message. -#: ../backends/key-file/kf-persona-store.vala:470 +#: ../backends/key-file/kf-persona-store.vala:471 #, c-format msgid "Could not write updated key file '%s': %s" msgstr "Incapaz de escrever o ficheiro de chaves atualizado '%s': %s" @@ -271,13 +347,13 @@ msgstr "Incapaz de escrever o ficheiro de chaves atualizado '%s': %s" #. * an IM address (e.g. “foo@jabber.org”), the second is #. * the name of a protocol (e.g. “jabber”) and the third is #. * an error message. -#: ../backends/key-file/kf-persona.vala:172 +#: ../backends/key-file/kf-persona.vala:174 #, c-format msgid "Invalid IM address ‘%s’ for protocol ‘%s’: %s" msgstr "Endereço MI ‘%s’ inválido para o protocolo ‘%s’: %s" #. Translators: the parameter is an error message. -#: ../backends/key-file/kf-persona.vala:430 +#: ../backends/key-file/kf-persona.vala:432 #, c-format msgid "Couldn't load data from key file: %s" msgstr "Incapaz de ler dados do ficheiro de chaves: %s" @@ -302,30 +378,28 @@ msgstr "Não foi encontrada a capacidade de contactos." msgid "Error opening contacts view." msgstr "Erro ao abrir a vista de contactos." -#. Translators: the first parameter is the display name for -#. * the Telepathy account, and the second is an error -#. * message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:814 -#, c-format +#: ../backends/ofono/ofono-backend.vala:196 msgid "" -"Failed to determine whether we can set aliases on Telepathy account '%s': %s" -msgstr "" -"Falha ao determinar se é possível definir alias na conta Telepathy '%s': %s" +"No oFono object manager running, so the oFono backend will be inactive. " +"Either oFono isn’t installed or the service can’t be started." +msgstr ""
+"Nenhum gestor de objetos oFono em execução, o motor oFono irá estar inativo. "
+"Ou o oFono não está instalado ou não foi possível iniciar o serviço." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1278 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1248 msgid "Telepathy contacts representing the local user may not be removed." msgstr "" "Contactos Telepathy que representem o utilizador local poderão não ser " "removidos." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1289 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1259 #, c-format msgid "Failed to remove a persona from store: %s" msgstr "Falha ao remover uma persona do armazenamento: %s" #. Translators: the first two parameters are store identifiers and #. * the third is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1324 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1294 #, c-format msgid "" "Persona store (%s, %s) requires the following details:\n" @@ -334,25 +408,25 @@ msgstr "" "Armazenamento de personas (%s, %s) requer os seguintes detalhes:\n" " contacto (disponibilizado: '%s')\n" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1339 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1309 msgid "Cannot create a new Telepathy contact while offline." msgstr "Incapaz de criar um novo contacto Telepathy estando desligado." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1357 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1327 #, c-format msgid "Failed to add a persona from details: %s" msgstr "Falha ao adicionar uma persona a partir dos detalhes: %s" #. Translators: "telepathy-logger" is the name of an application, #. * and should not be translated. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1377 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1347 msgid "" "Failed to change favorite without a connection to the telepathy-logger " "service." msgstr "" "Falha ao alterar o favorito sem uma ligação ao serviço telepathy-logger" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1383 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1353 msgid "" "Failed to change favorite status of Telepathy Persona because it has no " "attached TpContact." @@ -361,49 +435,49 @@ msgstr "" "tem um TpContact associado." #. Translators: the parameter is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1401 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1371 #, c-format msgid "Failed to change favorite status for Telepathy contact ‘%s’." msgstr "Falha ao alterar o estado de favorito do contacto Telepathy ‘%s’." #. Translators: the parameter is an error message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1433 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1403 #, c-format msgid "Failed to change contact's alias: %s" msgstr "Falha al alterar o alias do contacto: %s" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1514 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1484 msgid "Extended information may only be set on the user's Telepathy contact." msgstr "" "Informação extendida apenas pode ser definida no contacto Telepathy do " "utilizador." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1543 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 msgid "" "Extended information cannot be written because the store is disconnected." msgstr "" "Não é possível escrever informação extendida pois o armazenamento está " "desligado." -#: ../backends/telepathy/lib/tpf-persona.vala:499 -#: ../backends/telepathy/lib/tpf-persona.vala:520 -#: ../backends/telepathy/lib/tpf-persona.vala:572 -#: ../backends/telepathy/lib/tpf-persona.vala:586 +#: ../backends/telepathy/lib/tpf-persona.vala:511 +#: ../backends/telepathy/lib/tpf-persona.vala:532 +#: ../backends/telepathy/lib/tpf-persona.vala:584 +#: ../backends/telepathy/lib/tpf-persona.vala:598 #, c-format msgid "Failed to change group membership: %s" msgstr "Falha ao alterar os membros do grupo: %s" #. Translators: "account" refers to an instant messaging #. * account. -#: ../backends/telepathy/lib/tpf-persona.vala:502 -#: ../backends/telepathy/lib/tpf-persona.vala:575 +#: ../backends/telepathy/lib/tpf-persona.vala:514 +#: ../backends/telepathy/lib/tpf-persona.vala:587 msgid "Account is offline." msgstr "A conta está em modo desligado." #. Translators: the first parameter is the unknown key that #. * was received with the details params, and the second #. * identifies the persona store. -#: ../backends/tracker/lib/trf-persona-store.vala:742 +#: ../backends/tracker/lib/trf-persona-store.vala:743 #, c-format msgid "Unrecognized parameter '%s' passed to persona store '%s'." msgstr "Parâmetro '%s' desconhecido passado ao armazenamento de personas '%s'." @@ -414,19 +488,19 @@ msgstr "Alias não pode ser alterado neste contacto." #. Translators: the first parameter is a folder path and the second #. * is an error message. -#: ../folks/backend-store.vala:627 +#: ../folks/backend-store.vala:651 #, c-format msgid "Error listing contents of folder '%s': %s" msgstr "Erro ao listar o conteúdo da pasta '%s': %s" #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:757 +#: ../folks/backend-store.vala:786 #, c-format msgid "File or directory '%s' does not exist." msgstr "O ficheiro ou diretório '%s' não existe." #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:763 +#: ../folks/backend-store.vala:792 #, c-format msgid "Failed to get content type for '%s'." msgstr "Falha ao obter o tipo de conteúdo de '%s'." @@ -448,32 +522,32 @@ msgstr "Incapaz de compreeder o endereço de MI '%s'." #. Translators: the first parameter is a persona store identifier #. * and the second is an error message. -#: ../folks/individual-aggregator.vala:935 +#: ../folks/individual-aggregator.vala:1040 #, c-format msgid "Error preparing persona store '%s': %s" msgstr "Erro ao preparar o armazenamento de personas '%s': %s" #. Translators: the parameter is a property name. -#: ../folks/individual-aggregator.vala:1158 -#: ../folks/individual-aggregator.vala:1386 +#: ../folks/individual-aggregator.vala:1269 +#: ../folks/individual-aggregator.vala:1536 #, c-format msgid "Unknown property '%s' in linkable property list." msgstr "Propriedade '%s' desconhecida na lista de propriedades associáveis." #. Translators: the first parameter is a store identifier #. * and the second parameter is an error message. -#: ../folks/individual-aggregator.vala:1857 +#: ../folks/individual-aggregator.vala:2022 #, c-format msgid "Failed to add contact for persona store ID '%s': %s" msgstr "" "Falha ao adicionar contacto no ID de armazenamento de personas '%s': %s" -#: ../folks/individual-aggregator.vala:1958 +#: ../folks/individual-aggregator.vala:2119 msgid "Can’t link personas with no primary store." msgstr "Incapaz de associar personas sem armazenamento primário." -#: ../folks/individual-aggregator.vala:1959 -#: ../folks/individual-aggregator.vala:2291 +#: ../folks/individual-aggregator.vala:2120 +#: ../folks/individual-aggregator.vala:2451 #, c-format msgid "" "Persona store ‘%s:%s’ is configured as primary, but could not be found or " @@ -482,8 +556,8 @@ msgstr "" "Armazenamento de personas ‘%s:%s’ está configurado como primário, mas não " "foi encontrado ou falhou a sua leitura." -#: ../folks/individual-aggregator.vala:1960 -#: ../folks/individual-aggregator.vala:2292 +#: ../folks/individual-aggregator.vala:2121 +#: ../folks/individual-aggregator.vala:2452 #, c-format msgid "" "Check the relevant service is running, or change the default store in that " @@ -492,31 +566,81 @@ msgstr "" "Verifique que o serviço relevante se encontra em execução ou altere o " "armazenamento por omissão nesse serviço ou utilizando a chave GSettings “%s”." -#: ../folks/individual-aggregator.vala:1992 +#: ../folks/individual-aggregator.vala:2153 msgid "Anti-links can't be removed between personas being linked." msgstr "" "Antiassociações não pode ser removido entre personas que estão a ser " "associadas" -#: ../folks/individual-aggregator.vala:2290 +#: ../folks/individual-aggregator.vala:2450 msgid "Can’t add personas with no primary store." msgstr "Incapaz de adicionar personas sem armazenamento primário." -#: ../folks/individual-aggregator.vala:2301 +#: ../folks/individual-aggregator.vala:2461 #, c-format msgid "Can't write to requested property (“%s”) of the writeable store." msgstr "" "Incapaz de alterar a propriedade pedida (“%s”) do armazenamento alterável." -#: ../folks/individual.vala:217 ../folks/individual.vala:370 -#: ../folks/individual.vala:479 ../folks/individual.vala:730 -#: ../folks/individual.vala:808 +#: ../folks/individual.vala:216 ../folks/individual.vala:402 +#: ../folks/individual.vala:511 ../folks/individual.vala:762 +#: ../folks/individual.vala:840 #, c-format msgid "Failed to change property ‘%s’: No suitable personas were found." msgstr "" "Falha ao alterar a propriedade ‘%s’: Não foram encontradas personas " "adequadas." +#. Translators: This is the default name for an Individual +#. * when displayed in the UI if no personal details are available +#. * for them. +#: ../folks/individual.vala:1951 +msgid "Unnamed Person" +msgstr "Pessoa Sem Nome" + +#. FIXME: Ideally we’d use a format string translated to the locale of the +#. * persona whose name is being formatted, but no backend provides +#. * information about personas’ locales, so we have to settle for the +#. * current user’s locale. +#. * +#. * We thought about using nl_langinfo(_NL_NAME_NAME_FMT) here, but +#. * decided against it because: +#. * 1. It’s not the best documented API in the world, and its stability +#. * is in question. +#. * 2. An attempt to improve the interface in glibc met with a wall of +#. * complaints: https://sourceware.org/bugzilla/show_bug.cgi?id=14641. +#. * +#. * However, we do re-use the string format placeholders from +#. * _NL_NAME_NAME_FMT (as documented here: +#. * http://lh.2xlibre.net/values/name_fmt/) because there’s a chance glibc +#. * might eventually grow a useful interface for this. +#. * +#. * It does mean we have to implement our own parser for the name_fmt +#. * format though, since glibc doesn’t provide a formatting function. +#. Translators: This is a format string used to convert structured names +#. * to a single string. It should be translated to the predominant +#. * semi-formal name format for your locale, using the placeholders +#. * documented here: http://lh.2xlibre.net/values/name_fmt/. You may be +#. * able to re-use the existing glibc format string for your locale on that +#. * page if it’s suitable. +#. * +#. * More explicitly: the supported placeholders are %f, %F, %g, %G, %m, %M, +#. * %t. The romanisation modifier (e.g. %Rf) is recognized but ignored. +#. * %s, %S and %d are all replaced by the same thing (the ‘Honorific +#. * Prefixes’ from vCard) so please avoid using more than one. +#. * +#. * For example, the format string ‘%g%t%m%t%f’ expands to ‘John Andrew +#. * Lees’ when used for a persona with first name ‘John’, additional names +#. * ‘Andrew’ and family names ‘Lees’. +#. * +#. * If you need additional placeholders with other information or +#. * punctuation, please file a bug against libfolks: +#. * https://bugzilla.gnome.org/enter_bug.cgi?product=folks +#. +#: ../folks/name-details.vala:268 +msgid "%g%t%m%t%f" +msgstr "%g%t%m%t%f" + #: ../folks/org.freedesktop.folks.gschema.xml.in.h:1 msgid "Primary store ID" msgstr "ID do armazenamento primário" @@ -537,35 +661,35 @@ msgstr "" msgid "%s, %s, %s, %s, %s, %s, %s" msgstr "%s, %s, %s, %s, %s, %s, %s" -#: ../folks/presence-details.vala:159 +#: ../folks/presence-details.vala:171 msgid "Unknown status" msgstr "Estado desconhecido" -#: ../folks/presence-details.vala:161 +#: ../folks/presence-details.vala:173 msgid "Offline" msgstr "Desligado" -#: ../folks/presence-details.vala:165 +#: ../folks/presence-details.vala:177 msgid "Error" msgstr "Erro" -#: ../folks/presence-details.vala:167 +#: ../folks/presence-details.vala:179 msgid "Available" msgstr "Disponível" -#: ../folks/presence-details.vala:169 +#: ../folks/presence-details.vala:181 msgid "Away" msgstr "Ausente" -#: ../folks/presence-details.vala:171 +#: ../folks/presence-details.vala:183 msgid "Extended away" msgstr "Ausente estendido" -#: ../folks/presence-details.vala:173 +#: ../folks/presence-details.vala:185 msgid "Busy" msgstr "Ocupado" -#: ../folks/presence-details.vala:175 +#: ../folks/presence-details.vala:187 msgid "Hidden" msgstr "Escondido" @@ -667,54 +791,54 @@ msgstr "Nome do motor de origem (omissão: 'pidgin')" msgid "Source filename (default: specific to source backend)" msgstr "Nome do ficheiro de origem (omissão: específico do motor de origem)" -#: ../tools/import.vala:57 +#: ../tools/import.vala:58 msgid "— import meta-contact information to libfolks" msgstr "— importar informação de meta-contacto para o libfolks" #. Translators: the parameter is an error message. -#: ../tools/import.vala:67 +#: ../tools/import.vala:68 #, c-format msgid "Couldn't parse command line options: %s" msgstr "Incapaz de processar opções de linha de comando: %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:108 +#: ../tools/import.vala:109 #, c-format msgid "Couldn't load the backends: %s" msgstr "Incapaz de ler os motores: %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:119 +#: ../tools/import.vala:120 #, c-format msgid "Couldn't load the ‘%s’ backend." msgstr "Incapaz de ler o motor ‘%s’." #. Translators: the first parameter is a backend identifier and the #. * second parameter is an error message. -#: ../tools/import.vala:132 +#: ../tools/import.vala:133 #, c-format msgid "Couldn't prepare the ‘%s’ backend: %s" msgstr "Incapaz de preparar o motor ‘%s’: %s" #. Translators: the parameter is a backend identifier. -#: ../tools/import.vala:145 +#: ../tools/import.vala:146 #, c-format msgid "Couldn't load the ‘%s’ backend's persona store." msgstr "Incapaz de ler o armazenamento de personas do motor ‘%s’." -#: ../tools/import.vala:166 +#: ../tools/import.vala:167 #, c-format msgid "Couldn't prepare the ‘%s’ backend's persona store: %s" msgstr "Incapaz de preparar o armazenamento de personas do motor ‘%s’: %s" #. Translators: the parameter is an error message. -#: ../tools/import.vala:184 +#: ../tools/import.vala:185 #, c-format msgid "Error importing contacts: %s" msgstr "Erro ao importar contactos: %s" #. Translators: both parameters are identifiers for backends. -#: ../tools/import.vala:198 +#: ../tools/import.vala:199 #, c-format msgid "" "Unrecognized source backend name ‘%s’. ‘%s’ is currently the only supported " @@ -10,9 +10,9 @@ msgstr "" "Project-Id-Version: folks master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=folks&keywords=I18N+L10N&component=general\n" -"POT-Creation-Date: 2013-03-20 16:54+0000\n" -"PO-Revision-Date: 2013-03-17 23:04+0400\n" -"Last-Translator: Dmitriy S. Seregin <dseregin@59.ru>\n" +"POT-Creation-Date: 2014-03-10 05:56+0000\n" +"PO-Revision-Date: 2014-03-10 21:25+0300\n" +"Last-Translator: Yuri Myasoedov <omerta13@yandex.ru>\n" "Language-Team: русский <gnome-cyr@gnome.org>\n" "Language: ru\n" "MIME-Version: 1.0\n" @@ -20,7 +20,82 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Poedit 1.5.5\n" +"X-Generator: Poedit 1.5.4\n" + +#: ../backends/bluez/bluez-backend.vala:600 +msgid "" +"No BlueZ 5 object manager running, so the BlueZ backend will be inactive. " +"Either your BlueZ installation is too old (only version 5 is supported) or " +"the service can’t be started." +msgstr "" +"Диспетчер объектов BlueZ 5 не запущен, BlueZ будет неактивен. Версия BlueZ " +"слишком старая (поддерживается только версия 5) или служба не может быть " +"запущена." + +#: ../backends/bluez/bluez-backend.vala:613 +msgid "" +"Error connecting to OBEX transfer daemon over D-Bus. Ensure BlueZ and obexd " +"are installed." +msgstr "" +"Ошибка подключения к службе передачи OBEX через D-Bus. Убедитесь, что BlueZ " +"и obexd установлены." + +#. Translators: the parameter is an error message. +#: ../backends/bluez/bluez-persona-store.vala:385 +#, c-format +msgid "Error reading the transferred address book file: %s" +msgstr "Ошибка чтения переданного файла адресной книги: %s" + +#. Translators: the first parameter is the name of the +#. * failed transfer, and the second is a Bluetooth device +#. * alias. +#. Translators: the first parameter is the name of the failed +#. * transfer, and the second is a Bluetooth device alias. +#: ../backends/bluez/bluez-persona-store.vala:667 +#: ../backends/bluez/bluez-persona-store.vala:689 +#, c-format +msgid "" +"Error during transfer of the address book ‘%s’ from Bluetooth device ‘%s’." +msgstr "" +"Ошибка во время передачи адресной книги «%s» с Bluetooth-устройства «%s»." + +#: ../backends/bluez/bluez-persona-store.vala:782 +#, c-format +msgid "" +"Permission to access the address book on Bluetooth device ‘%s’ was denied by " +"the user." +msgstr "" +"Доступ к адресной книге на Bluetooth-устройстве «%s» запрещён пользователем." + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:789 +#, c-format +msgid "An OBEX address book transfer from device ‘%s’ could not be started: %s" +msgstr "" +"Не удалось запустить OBEX-передачу адресной книги с устройства «%s»: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:829 +#, c-format +msgid "The OBEX address book transfer from device ‘%s’ failed: %s" +msgstr "" +"Не удалось выполнить OBEX-передачу адресной книги с устройства «%s»: %s" + +#. Translators: the first parameter is a Bluetooth device +#. * alias, and the second is an error message. +#: ../backends/bluez/bluez-persona-store.vala:846 +#, c-format +msgid "" +"Error during transfer of the address book from Bluetooth device ‘%s’: %s" +msgstr "" +"Ошибка во время передачи адресной книги с Bluetooth-устройства «%s»: %s" + +#: ../backends/bluez/bluez-persona-store.vala:1064 +#, c-format +msgid "Bluetooth device ‘%s’ disappeared during address book transfer." +msgstr "Bluetooth-устройство «%s» пропало во время передачи адресной книги." # данная группа контактов не переведена в Google Контакты, значит оставляем не переведенной и тут, по просьбе разрабов folks #. The timeout after which we consider a property change to have failed if we @@ -37,7 +112,7 @@ msgstr "Starred in Android" #. Translators: the first parameter is an address book #. * URI and the second is a persona UID. -#: ../backends/eds/lib/edsf-persona-store.vala:671 +#: ../backends/eds/lib/edsf-persona-store.vala:673 #, c-format msgid "Address book ‘%s’ is offline, so contact ‘%s’ cannot be removed." msgstr "" @@ -46,61 +121,61 @@ msgstr "" #. Translators: the first parameter is an address book #. * URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:677 +#: ../backends/eds/lib/edsf-persona-store.vala:679 #, c-format msgid "Permission denied to remove contact ‘%s’: %s" msgstr "Отказано в разрешении на удаление контакта «%s»: %s" #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:682 +#: ../backends/eds/lib/edsf-persona-store.vala:684 #, c-format msgid "Removing contacts isn't supported by this persona store: %s" msgstr "Удаление контактов не поддерживается этим персональным хранилищем: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:711 +#: ../backends/eds/lib/edsf-persona-store.vala:713 #, c-format msgid "Can't remove contact ‘%s’: %s" msgstr "Не удалось удалить контакт «%s»: %s" #. Translators: the parameter is an address book #. * URI. -#: ../backends/eds/lib/edsf-persona-store.vala:801 -#: ../backends/eds/lib/edsf-persona-store.vala:992 +#: ../backends/eds/lib/edsf-persona-store.vala:802 +#: ../backends/eds/lib/edsf-persona-store.vala:993 #, c-format msgid "Address book ‘%s’ is offline." msgstr "Адресная книга «%s» работает в автономном режиме." #. Translators: the first parameter is an address #. * book URI and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:806 -#: ../backends/eds/lib/edsf-persona-store.vala:997 +#: ../backends/eds/lib/edsf-persona-store.vala:807 +#: ../backends/eds/lib/edsf-persona-store.vala:998 #, c-format msgid "Permission denied to open address book ‘%s’: %s" msgstr "Отказано в разрешении на открытие адресной книги «%s»: %s" #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:839 +#: ../backends/eds/lib/edsf-persona-store.vala:840 #, c-format msgid "Couldn't open address book ‘%s’: %s" msgstr "Не удаётся открыть адресную книгу «%s»: %s" #. Translators: the parameteter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:905 -#: ../backends/eds/lib/edsf-persona-store.vala:935 +#: ../backends/eds/lib/edsf-persona-store.vala:906 +#: ../backends/eds/lib/edsf-persona-store.vala:936 #, c-format msgid "Couldn't get address book capabilities: %s" msgstr "Не удалось получить возможности адресной книги: %s" #. Translators: the parameter is an address book URI. -#: ../backends/eds/lib/edsf-persona-store.vala:951 +#: ../backends/eds/lib/edsf-persona-store.vala:952 #, c-format msgid "Couldn't get view for address book ‘%s’." msgstr "Не удалось показать адресную книгу «%s»." #. Translators: the first parameter is an address book URI #. * and the second is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1030 +#: ../backends/eds/lib/edsf-persona-store.vala:1031 #, c-format msgid "Couldn't get view for address book ‘%s’: %s" msgstr "Не удалось показать адресную книгу «%s»: %s" @@ -108,121 +183,121 @@ msgstr "Не удалось показать адресную книгу «%s»: #. Translators: the parameter is the name of a property on a #. * contact, formatted in the normal GObject style (e.g. #. * lowercase with hyphens to separate words). -#: ../backends/eds/lib/edsf-persona-store.vala:1390 +#: ../backends/eds/lib/edsf-persona-store.vala:1303 #, c-format msgid "Changing the ‘%s’ property failed due to reaching the timeout." msgstr "Не удалось изменить свойство «%s» из-за превышения лимита времени." -#: ../backends/eds/lib/edsf-persona-store.vala:1428 +#: ../backends/eds/lib/edsf-persona-store.vala:1337 #: ../folks/avatar-details.vala:63 msgid "Avatar is not writeable on this contact." msgstr "В этот контакт нельзя записать аватар." -#: ../backends/eds/lib/edsf-persona-store.vala:1449 +#: ../backends/eds/lib/edsf-persona-store.vala:1358 #: ../folks/web-service-details.vala:123 msgid "Web service addresses are not writeable on this contact." msgstr "В этот контакт нельзя записать адреса веб-служб." -#: ../backends/eds/lib/edsf-persona-store.vala:1485 +#: ../backends/eds/lib/edsf-persona-store.vala:1394 #: ../folks/url-details.vala:152 msgid "URLs are not writeable on this contact." msgstr "В этот контакт нельзя записать URL." -#: ../backends/eds/lib/edsf-persona-store.vala:1566 +#: ../backends/eds/lib/edsf-persona-store.vala:1475 #: ../folks/local-id-details.vala:64 msgid "Local IDs are not writeable on this contact." msgstr "В этот контакт нельзя записать локальный идентификатор." -#: ../backends/eds/lib/edsf-persona-store.vala:1595 +#: ../backends/eds/lib/edsf-persona-store.vala:1504 msgid "The contact cannot be marked as favourite." msgstr "Контакт нельзя сделать избранным." #. Translators: the parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:1667 +#: ../backends/eds/lib/edsf-persona-store.vala:1576 #, c-format msgid "Can't update avatar: %s" msgstr "Не удалось обновить аватар: %s" -#: ../backends/eds/lib/edsf-persona-store.vala:1678 +#: ../backends/eds/lib/edsf-persona-store.vala:1587 #: ../folks/email-details.vala:120 msgid "E-mail addresses are not writeable on this contact." msgstr "В этот контакт нельзя записывать адреса эл. почты." -#: ../backends/eds/lib/edsf-persona-store.vala:1696 -#: ../folks/phone-details.vala:224 +#: ../backends/eds/lib/edsf-persona-store.vala:1605 +#: ../folks/phone-details.vala:255 msgid "Phone numbers are not writeable on this contact." msgstr "В этот контакт нельзя записывать телефонные номера." -#: ../backends/eds/lib/edsf-persona-store.vala:1714 +#: ../backends/eds/lib/edsf-persona-store.vala:1623 #: ../folks/postal-address-details.vala:361 msgid "Postal addresses are not writeable on this contact." msgstr "В этот контакт нельзя записывать почтовые адреса." -#: ../backends/eds/lib/edsf-persona-store.vala:1785 -#: ../folks/name-details.vala:283 +#: ../backends/eds/lib/edsf-persona-store.vala:1694 +#: ../folks/name-details.vala:454 msgid "Full name is not writeable on this contact." msgstr "В этот контакт нельзя записать полное имя." -#: ../backends/eds/lib/edsf-persona-store.vala:1807 -#: ../folks/name-details.vala:321 +#: ../backends/eds/lib/edsf-persona-store.vala:1716 +#: ../folks/name-details.vala:492 msgid "Nickname is not writeable on this contact." msgstr "В этот контакт нельзя записать псевдоним." -#: ../backends/eds/lib/edsf-persona-store.vala:1829 +#: ../backends/eds/lib/edsf-persona-store.vala:1738 #: ../folks/note-details.vala:138 msgid "Notes are not writeable on this contact." msgstr "В этот контакт нельзя записать примечание." -#: ../backends/eds/lib/edsf-persona-store.vala:1861 +#: ../backends/eds/lib/edsf-persona-store.vala:1770 #: ../folks/birthday-details.vala:62 msgid "Birthday is not writeable on this contact." msgstr "В этот контакт нельзя записать день рождения." -#: ../backends/eds/lib/edsf-persona-store.vala:1905 +#: ../backends/eds/lib/edsf-persona-store.vala:1814 #: ../folks/role-details.vala:279 msgid "Roles are not writeable on this contact." msgstr "В этот контакт нельзя записывать роли." -#: ../backends/eds/lib/edsf-persona-store.vala:2006 -#: ../folks/name-details.vala:246 +#: ../backends/eds/lib/edsf-persona-store.vala:1915 +#: ../folks/name-details.vala:417 msgid "Structured name is not writeable on this contact." msgstr "В этот контакт нельзя записывать структурированные имена." -#: ../backends/eds/lib/edsf-persona-store.vala:2045 +#: ../backends/eds/lib/edsf-persona-store.vala:1954 #: ../folks/im-details.vala:136 msgid "IM addresses are not writeable on this contact." msgstr "" "В этот контакт нельзя записывать адреса клиентов для обмена мгновенными " "сообщениями." -#: ../backends/eds/lib/edsf-persona-store.vala:2095 +#: ../backends/eds/lib/edsf-persona-store.vala:2004 #: ../folks/group-details.vala:174 msgid "Groups are not writeable on this contact." msgstr "В этот контакт нельзя записывать группы." -#: ../backends/eds/lib/edsf-persona-store.vala:2110 +#: ../backends/eds/lib/edsf-persona-store.vala:2019 msgid "My Contacts is only available for Google Contacts" msgstr "Мои контакты доступны только из Контактов Google" -#: ../backends/eds/lib/edsf-persona-store.vala:2181 +#: ../backends/eds/lib/edsf-persona-store.vala:2090 #: ../folks/gender-details.vala:79 msgid "Gender is not writeable on this contact." msgstr "В этот контакт нельзя записать пол." -#: ../backends/eds/lib/edsf-persona-store.vala:2219 -#: ../folks/anti-linkable.vala:81 +#: ../backends/eds/lib/edsf-persona-store.vala:2128 +#: ../folks/anti-linkable.vala:84 msgid "Anti-links are not writeable on this contact." msgstr "В этот контакт нельзя записывать антиссылки." -#: ../backends/eds/lib/edsf-persona-store.vala:2262 -#: ../folks/location-details.vala:129 +#: ../backends/eds/lib/edsf-persona-store.vala:2171 +#: ../folks/location-details.vala:135 msgid "Location is not writeable on this contact." msgstr "Расположение не возможно записать в этот контакт." #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2439 +#: ../backends/eds/lib/edsf-persona-store.vala:2484 #, c-format msgid "Property ‘%s’ is not writeable: %s" msgstr "Свойство «%s» с недоступно для записи: %s" @@ -230,42 +305,42 @@ msgstr "Свойство «%s» с недоступно для записи: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error #. * message. -#: ../backends/eds/lib/edsf-persona-store.vala:2448 +#: ../backends/eds/lib/edsf-persona-store.vala:2493 #, c-format msgid "Invalid value for property ‘%s’: %s" msgstr "Неверное значение свойства «%s»: %s" #. Translators: the first parameter is a non-human-readable #. * property name and the second parameter is an error message. -#: ../backends/eds/lib/edsf-persona-store.vala:2474 +#: ../backends/eds/lib/edsf-persona-store.vala:2519 #, c-format msgid "Unknown error setting property ‘%s’: %s" msgstr "Неизвестная ошибка при установке свойства «%s»: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:233 +#: ../backends/key-file/kf-persona-store.vala:234 #, c-format msgid "The relationship key file '%s' could not be loaded: %s" msgstr "Файл сопутствующего ключа «%s» не может быть загружен: %s" #. Translators: the first parameter is a path, and the #. * second is an error message. -#: ../backends/key-file/kf-persona-store.vala:255 +#: ../backends/key-file/kf-persona-store.vala:256 #, c-format msgid "The relationship key file directory '%s' could not be created: %s" msgstr "Каталог файла сопутствующего ключа «%s» не может быть создан: %s" #. Translators: the first parameter is a filename, and #. * the second is an error message. -#: ../backends/key-file/kf-persona-store.vala:279 +#: ../backends/key-file/kf-persona-store.vala:280 #, c-format msgid "The relationship key file '%s' could not be created: %s" msgstr "Файл сопутствующего ключа «%s» не может быть создан: %s" #. Translators: the first parameter is a filename, the second is #. * an error message. -#: ../backends/key-file/kf-persona-store.vala:470 +#: ../backends/key-file/kf-persona-store.vala:471 #, c-format msgid "Could not write updated key file '%s': %s" msgstr "Не удалось записать обновлённый файл ключа «%s»: %s" @@ -275,13 +350,13 @@ msgstr "Не удалось записать обновлённый файл к #. * an IM address (e.g. “foo@jabber.org”), the second is #. * the name of a protocol (e.g. “jabber”) and the third is #. * an error message. -#: ../backends/key-file/kf-persona.vala:172 +#: ../backends/key-file/kf-persona.vala:174 #, c-format msgid "Invalid IM address ‘%s’ for protocol ‘%s’: %s" msgstr "Неверный адрес IM «%s» для протокола «%s»: %s" #. Translators: the parameter is an error message. -#: ../backends/key-file/kf-persona.vala:430 +#: ../backends/key-file/kf-persona.vala:432 #, c-format msgid "Couldn't load data from key file: %s" msgstr "Не удалось загрузить данные из файла ключа: %s" @@ -306,30 +381,27 @@ msgstr "Не найдены возможности контактов." msgid "Error opening contacts view." msgstr "Ошибка при открытии списка контактов." -#. Translators: the first parameter is the display name for -#. * the Telepathy account, and the second is an error -#. * message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:814 -#, c-format +#: ../backends/ofono/ofono-backend.vala:196 msgid "" -"Failed to determine whether we can set aliases on Telepathy account '%s': %s" +"No oFono object manager running, so the oFono backend will be inactive. " +"Either oFono isn’t installed or the service can’t be started." msgstr "" -"Не удалось определить возможность установки псевдонима на учётной записи " -"Telepathy '%s': %s" +"Диспетчер объектов oFono не запущен, oFono будет неактивен. Версия oFono " +"слишком старая или служба не может быть запущена." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1278 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1248 msgid "Telepathy contacts representing the local user may not be removed." msgstr "" "Нельзя удалить контакты Telepathy, представляющие локального пользователя." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1289 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1259 #, c-format msgid "Failed to remove a persona from store: %s" msgstr "Не удалось удалить контакт из хранилища: %s" #. Translators: the first two parameters are store identifiers and #. * the third is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1324 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1294 #, c-format msgid "" "Persona store (%s, %s) requires the following details:\n" @@ -338,18 +410,18 @@ msgstr "" "Хранилищу (%s, %s) требуются следущие сведения:\n" " контакт (идентификатор: «%s»)\n" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1339 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1309 msgid "Cannot create a new Telepathy contact while offline." msgstr "Невозможно создать новый контакт Telepathy в автономном режиме" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1357 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1327 #, c-format msgid "Failed to add a persona from details: %s" msgstr "Не удалось добавить контакт из дополнительной информации: %s" #. Translators: "telepathy-logger" is the name of an application, #. * and should not be translated. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1377 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1347 msgid "" "Failed to change favorite without a connection to the telepathy-logger " "service." @@ -357,7 +429,7 @@ msgstr "" "Не удалось изменить статус избранности без подключения к службе telepathy-" "logger." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1383 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1353 msgid "" "Failed to change favorite status of Telepathy Persona because it has no " "attached TpContact." @@ -366,49 +438,49 @@ msgstr "" "прикреплённого объекта TpContact." #. Translators: the parameter is a contact identifier. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1401 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1371 #, c-format msgid "Failed to change favorite status for Telepathy contact ‘%s’." msgstr "Не удалось изменить состояние избранности для контакта Telepathy «%s»." #. Translators: the parameter is an error message. -#: ../backends/telepathy/lib/tpf-persona-store.vala:1433 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1403 #, c-format msgid "Failed to change contact's alias: %s" msgstr "Не удалось изменить псевдоним контакта: %s" -#: ../backends/telepathy/lib/tpf-persona-store.vala:1514 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1484 msgid "Extended information may only be set on the user's Telepathy contact." msgstr "" "Дополнительная информация может быть установлена только для " "пользовательского контакта Telepathy." -#: ../backends/telepathy/lib/tpf-persona-store.vala:1543 +#: ../backends/telepathy/lib/tpf-persona-store.vala:1513 msgid "" "Extended information cannot be written because the store is disconnected." msgstr "" "Дополнительная информация не может быть записана из-за отсутствия " "подключения к хранилищу." -#: ../backends/telepathy/lib/tpf-persona.vala:499 -#: ../backends/telepathy/lib/tpf-persona.vala:520 -#: ../backends/telepathy/lib/tpf-persona.vala:572 -#: ../backends/telepathy/lib/tpf-persona.vala:586 +#: ../backends/telepathy/lib/tpf-persona.vala:511 +#: ../backends/telepathy/lib/tpf-persona.vala:532 +#: ../backends/telepathy/lib/tpf-persona.vala:584 +#: ../backends/telepathy/lib/tpf-persona.vala:598 #, c-format msgid "Failed to change group membership: %s" msgstr "Не удалось изменить членство в группе: %s" #. Translators: "account" refers to an instant messaging #. * account. -#: ../backends/telepathy/lib/tpf-persona.vala:502 -#: ../backends/telepathy/lib/tpf-persona.vala:575 +#: ../backends/telepathy/lib/tpf-persona.vala:514 +#: ../backends/telepathy/lib/tpf-persona.vala:587 msgid "Account is offline." msgstr "Учётная запись находится в автономном режиме." #. Translators: the first parameter is the unknown key that #. * was received with the details params, and the second #. * identifies the persona store. -#: ../backends/tracker/lib/trf-persona-store.vala:742 +#: ../backends/tracker/lib/trf-persona-store.vala:743 #, c-format msgid "Unrecognized parameter '%s' passed to persona store '%s'." msgstr "В личное хранилище «%s» передан нераспознанный параметр «%s»." @@ -419,19 +491,19 @@ msgstr "Нельзя записать псевдоним для этого ко #. Translators: the first parameter is a folder path and the second #. * is an error message. -#: ../folks/backend-store.vala:627 +#: ../folks/backend-store.vala:651 #, c-format msgid "Error listing contents of folder '%s': %s" msgstr "Не удалось получить содержимого папки «%s»: %s" #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:757 +#: ../folks/backend-store.vala:786 #, c-format msgid "File or directory '%s' does not exist." msgstr "Файл или каталог «%s» не существует." #. Translators: the parameter is a filename. -#: ../folks/backend-store.vala:763 +#: ../folks/backend-store.vala:792 #, c-format msgid "Failed to get content type for '%s'." msgstr "Не удалось получить тип содержимого для «%s»." @@ -453,31 +525,31 @@ msgstr "Не удалось разобрать адрес «%s»." #. Translators: the first parameter is a persona store identifier #. * and the second is an error message. -#: ../folks/individual-aggregator.vala:935 +#: ../folks/individual-aggregator.vala:1040 #, c-format msgid "Error preparing persona store '%s': %s" msgstr "Ошибка при подготовке хранилища контакта «%s»: %s" #. Translators: the parameter is a property name. -#: ../folks/individual-aggregator.vala:1158 -#: ../folks/individual-aggregator.vala:1386 +#: ../folks/individual-aggregator.vala:1269 +#: ../folks/individual-aggregator.vala:1536 #, c-format msgid "Unknown property '%s' in linkable property list." msgstr "Неизвестное свойство «%s» в ссылочном списке свойств." #. Translators: the first parameter is a store identifier #. * and the second parameter is an error message. -#: ../folks/individual-aggregator.vala:1857 +#: ../folks/individual-aggregator.vala:2022 #, c-format msgid "Failed to add contact for persona store ID '%s': %s" msgstr "Не удалось добавить контакт для хранилища с идентификатором «%s»: %s" -#: ../folks/individual-aggregator.vala:1958 +#: ../folks/individual-aggregator.vala:2119 msgid "Can’t link personas with no primary store." msgstr "Невозможно связать контакты без основного хранилища." -#: ../folks/individual-aggregator.vala:1959 -#: ../folks/individual-aggregator.vala:2291 +#: ../folks/individual-aggregator.vala:2120 +#: ../folks/individual-aggregator.vala:2451 #, c-format msgid "" "Persona store ‘%s:%s’ is configured as primary, but could not be found or " @@ -486,8 +558,8 @@ msgstr "" "Хранилище «%s:%s» настроено как главное, но его не удалось найти или " "загрузить." -#: ../folks/individual-aggregator.vala:1960 -#: ../folks/individual-aggregator.vala:2292 +#: ../folks/individual-aggregator.vala:2121 +#: ../folks/individual-aggregator.vala:2452 #, c-format msgid "" "Check the relevant service is running, or change the default store in that " @@ -496,27 +568,78 @@ msgstr "" "Проверьте, запущена ли соответствующая служба, или измените хранилище по " "умолчанию в этой службе, или воспользуйтесь ключом GSettings «%s»." -#: ../folks/individual-aggregator.vala:1992 +#: ../folks/individual-aggregator.vala:2153 msgid "Anti-links can't be removed between personas being linked." msgstr "Нельзя удалять антиссылки между связываемыми контактами." -#: ../folks/individual-aggregator.vala:2290 +#: ../folks/individual-aggregator.vala:2450 msgid "Can’t add personas with no primary store." msgstr "Невозможно добавить контакты без основного хранилища." -#: ../folks/individual-aggregator.vala:2301 +#: ../folks/individual-aggregator.vala:2461 #, c-format msgid "Can't write to requested property (“%s”) of the writeable store." msgstr "Не удалось выполнить запись в запрошенное свойство («%s») хранилища." -#: ../folks/individual.vala:217 ../folks/individual.vala:370 -#: ../folks/individual.vala:479 ../folks/individual.vala:730 -#: ../folks/individual.vala:808 +#: ../folks/individual.vala:216 ../folks/individual.vala:402 +#: ../folks/individual.vala:511 ../folks/individual.vala:762 +#: ../folks/individual.vala:840 #, c-format msgid "Failed to change property ‘%s’: No suitable personas were found." msgstr "" "Не удалось изменить свойство «%s»: не найдено соответствующих контактов." +#. Translators: This is the default name for an Individual +#. * when displayed in the UI if no personal details are available +#. * for them. +#: ../folks/individual.vala:1951 +msgid "Unnamed Person" +msgstr "Безымянный контакт" + +# http://lh.2xlibre.net/values/name_fmt/ +#. FIXME: Ideally we’d use a format string translated to the locale of the +#. * persona whose name is being formatted, but no backend provides +#. * information about personas’ locales, so we have to settle for the +#. * current user’s locale. +#. * +#. * We thought about using nl_langinfo(_NL_NAME_NAME_FMT) here, but +#. * decided against it because: +#. * 1. It’s not the best documented API in the world, and its stability +#. * is in question. +#. * 2. An attempt to improve the interface in glibc met with a wall of +#. * complaints: https://sourceware.org/bugzilla/show_bug.cgi?id=14641. +#. * +#. * However, we do re-use the string format placeholders from +#. * _NL_NAME_NAME_FMT (as documented here: +#. * http://lh.2xlibre.net/values/name_fmt/) because there’s a chance glibc +#. * might eventually grow a useful interface for this. +#. * +#. * It does mean we have to implement our own parser for the name_fmt +#. * format though, since glibc doesn’t provide a formatting function. +#. Translators: This is a format string used to convert structured names +#. * to a single string. It should be translated to the predominant +#. * semi-formal name format for your locale, using the placeholders +#. * documented here: http://lh.2xlibre.net/values/name_fmt/. You may be +#. * able to re-use the existing glibc format string for your locale on that +#. * page if it’s suitable. +#. * +#. * More explicitly: the supported placeholders are %f, %F, %g, %G, %m, %M, +#. * %t. The romanisation modifier (e.g. %Rf) is recognized but ignored. +#. * %s, %S and %d are all replaced by the same thing (the ‘Honorific +#. * Prefixes’ from vCard) so please avoid using more than one. +#. * +#. * For example, the format string ‘%g%t%m%t%f’ expands to ‘John Andrew +#. * Lees’ when used for a persona with first name ‘John’, additional names +#. * ‘Andrew’ and family names ‘Lees’. +#. * +#. * If you need additional placeholders with other information or +#. * punctuation, please file a bug against libfolks: +#. * https://bugzilla.gnome.org/enter_bug.cgi?product=folks +#. +#: ../folks/name-details.vala:268 +msgid "%g%t%m%t%f" +msgstr "%d%t%g%t%m%t%f" + #: ../folks/org.freedesktop.folks.gschema.xml.in.h:1 msgid "Primary store ID" msgstr "ID основного хранилища" @@ -537,35 +660,35 @@ msgstr "" msgid "%s, %s, %s, %s, %s, %s, %s" msgstr "%s, %s, %s, %s, %s, %s, %s" -#: ../folks/presence-details.vala:159 +#: ../folks/presence-details.vala:171 msgid "Unknown status" msgstr "Неизвестный статус" -#: ../folks/presence-details.vala:161 +#: ../folks/presence-details.vala:173 msgid "Offline" msgstr "Не в сети" -#: ../folks/presence-details.vala:165 +#: ../folks/presence-details.vala:177 msgid "Error" msgstr "Ошибка" -#: ../folks/presence-details.vala:167 +#: ../folks/presence-details.vala:179 msgid "Available" msgstr "В сети" -#: ../folks/presence-details.vala:169 +#: ../folks/presence-details.vala:181 msgid "Away" msgstr "Отсутствует" -#: ../folks/presence-details.vala:171 +#: ../folks/presence-details.vala:183 msgid "Extended away" msgstr "Давно отсутствует" -#: ../folks/presence-details.vala:173 +#: ../folks/presence-details.vala:185 msgid "Busy" msgstr "Занят" -#: ../folks/presence-details.vala:175 +#: ../folks/presence-details.vala:187 msgid "Hidden" msgstr "Невидимый" @@ -722,3 +845,10 @@ msgid "" msgstr "" "Нераспознанное имя драйвера источника «%s». «%s» в настоящий момент является " "единственным поддерживаемым драйвером источника." + +#~ msgid "" +#~ "Failed to determine whether we can set aliases on Telepathy account '%s': " +#~ "%s" +#~ msgstr "" +#~ "Не удалось определить возможность установки псевдонима на учётной записи " +#~ "Telepathy '%s': %s" diff --git a/tests/Makefile.am b/tests/Makefile.am index 2fad8ce4..38561942 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -8,6 +8,12 @@ SUBDIRS = \ tools \ $(NULL) +if ENABLE_BLUEZ +if HAVE_BLUEZ_TESTS +SUBDIRS += bluez +endif +endif + if ENABLE_TELEPATHY SUBDIRS += folks telepathy endif @@ -34,6 +40,7 @@ DIST_SUBDIRS = \ dummy \ eds \ key-file \ + bluez \ telepathy \ libsocialweb \ tracker \ diff --git a/tests/bluez/Makefile.am b/tests/bluez/Makefile.am new file mode 100644 index 00000000..46661fbf --- /dev/null +++ b/tests/bluez/Makefile.am @@ -0,0 +1,48 @@ +include $(top_srcdir)/tests/test.mk + +AM_VALAFLAGS = \ + $(test_valaflags) \ + --vapidir=$(top_srcdir)/tests/lib/bluez \ + --pkg bluez-test \ + --pkg folks-generics \ + $(NULL) + +AM_CPPFLAGS = \ + $(test_cppflags) \ + -I$(top_srcdir)/tests/lib/bluez \ + $(NULL) + +AM_CFLAGS = \ + $(test_cflags) \ + $(NULL) + +LDADD = \ + $(AM_LDADD) \ + $(test_ldadd) \ + $(top_builddir)/tests/lib/bluez/libbluez-test.la \ + $(NULL) + +# in order from least to most complex +noinst_PROGRAMS = \ + device-properties \ + individual-retrieval \ + vcard-parsing \ + $(NULL) + +TESTS = $(noinst_PROGRAMS) + +device_properties_SOURCES = \ + device-properties.vala \ + $(NULL) + +individual_retrieval_SOURCES = \ + individual-retrieval.vala \ + $(NULL) + +vcard_parsing_SOURCES = \ + vcard-parsing.vala \ + $(NULL) + +-include $(top_srcdir)/git.mk +-include $(top_srcdir)/valgrind.mk +-include $(top_srcdir)/check.mk diff --git a/tests/bluez/device-properties.vala b/tests/bluez/device-properties.vala new file mode 100644 index 00000000..19d806a5 --- /dev/null +++ b/tests/bluez/device-properties.vala @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2013 Collabora Ltd. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Philip Withnall <philip.withnall@collabora.co.uk> + */ + +using Gee; +using Folks; +using BluezTest; + +public class DevicePropertiesTests : BluezTest.TestCase +{ + public DevicePropertiesTests () + { + base ("DeviceProperties"); + + this.add_test ("device pairing", this.test_device_pairing); + this.add_test ("blocked device", this.test_blocked_device); + this.add_test ("device alias", this.test_device_alias); + } + + /* Start with an unpaired Bluetooth device, and check that it’s not turned + * into a PersonaStore. Then pair the device, and check that it is added as + * a store. */ + public void test_device_pairing () + { + var main_loop = new GLib.MainLoop (null, false); + + /* Set up a simple unpaired device. */ + try + { + this.bluez_backend.mock_bluez.add_adapter ("hci0", "Test System"); + this.bluez_backend.mock_bluez.add_device ("hci0", + this.bluez_backend.primary_device_address, "My Phone"); + } + catch (IOError e1) + { + error ("Error setting up mock BlueZ device: %s", e1.message); + } + + /* Set up its vCard in preparation. */ + this.bluez_backend.set_simple_device_vcard ( + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "N:Jones;Pam;Mrs.\n" + + "FN:Pam Jones\n" + + "TEL:0123456789\n" + + "END:VCARD\n"); + + /* Set up the aggregator and wait until either quiescence, or the test + * times out and fails. Unset the primary store to prevent a warning. */ + Environment.set_variable ("FOLKS_PRIMARY_STORE", "", true); + + var aggregator = IndividualAggregator.dup (); + TestUtils.aggregator_prepare_and_wait_for_quiescence.begin (aggregator, + (o, r) => + { + try + { + TestUtils.aggregator_prepare_and_wait_for_quiescence.end (r); + } + catch (GLib.Error e2) + { + error ("Error preparing aggregator: %s", e2.message); + } + + main_loop.quit (); + }); + + TestUtils.loop_run_with_timeout (main_loop); + + var real_backend = + aggregator.backend_store.dup_backend_by_name ("bluez"); + + /* Check there are no individuals and no persona stores. */ + assert (aggregator.individuals.size == 0); + assert (real_backend.persona_stores.size == 0); + + /* Wait for a signal about an added persona store. */ + TestUtils.aggregator_wait_for_individuals.begin (aggregator, + {"Pam Jones"}, {}, (o, r) => + { + TestUtils.aggregator_wait_for_individuals.end (r); + main_loop.quit (); + }); + + /* Pair the device. */ + try + { + this.bluez_backend.mock_bluez.pair_device ("hci0", + this.bluez_backend.primary_device_address); + } + catch (IOError e4) + { + error ("Error pairing mock BlueZ device: %s", e4.message); + } + + TestUtils.loop_run_with_timeout (main_loop); + } + + /* Start with a blocked Bluetooth device, and check it’s not made into a + * PersonaStore. Then unblock the device and check a PersonaStore is created. + * Then block the device again and check the PersonaStore is removed. */ + public void test_blocked_device () + { + var main_loop = new GLib.MainLoop (null, false); + + /* Set up a simple paired but blocked device. */ + this.bluez_backend.create_simple_device_with_vcard ( + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "N:Jones;Pam;Mrs.\n" + + "FN:Pam Jones\n" + + "TEL:0123456789\n" + + "END:VCARD\n"); + + try + { + this.bluez_backend.mock_bluez.block_device ("hci0", + this.bluez_backend.primary_device_address); + } + catch (IOError e1) + { + error ("Error blocking device: %s", e1.message); + } + + /* Set up the aggregator and wait until either quiescence, or the test + * times out and fails. Unset the primary store to prevent a warning. */ + Environment.set_variable ("FOLKS_PRIMARY_STORE", "", true); + + var aggregator = IndividualAggregator.dup (); + TestUtils.aggregator_prepare_and_wait_for_quiescence.begin (aggregator, + (o, r) => + { + try + { + TestUtils.aggregator_prepare_and_wait_for_quiescence.end (r); + } + catch (GLib.Error e2) + { + error ("Error preparing aggregator: %s", e2.message); + } + + main_loop.quit (); + }); + + TestUtils.loop_run_with_timeout (main_loop); + + var real_backend = + aggregator.backend_store.dup_backend_by_name ("bluez"); + + /* Check there are no individuals and no persona stores. */ + assert (aggregator.individuals.size == 0); + assert (real_backend.persona_stores.size == 0); + + /* Wait for a signal about an added persona store. */ + TestUtils.aggregator_wait_for_individuals.begin (aggregator, + {"Pam Jones"}, {}, (o, r) => + { + TestUtils.aggregator_wait_for_individuals.end (r); + main_loop.quit (); + }); + + /* Unblock the device. */ + try + { + this.bluez_backend.mock_bluez.pair_device ("hci0", + this.bluez_backend.primary_device_address); + } + catch (IOError e4) + { + error ("Error blocking device: %s", e4.message); + } + + TestUtils.loop_run_with_timeout (main_loop); + + /* Wait for a signal about a removed persona store. */ + TestUtils.aggregator_wait_for_individuals.begin (aggregator, + {}, {"Pam Jones"}, (o, r) => + { + TestUtils.aggregator_wait_for_individuals.end (r); + main_loop.quit (); + }); + + /* Block the device again. */ + try + { + this.bluez_backend.mock_bluez.block_device ("hci0", + this.bluez_backend.primary_device_address); + } + catch (IOError e5) + { + error ("Error blocking device again: %s", e5.message); + } + + TestUtils.loop_run_with_timeout (main_loop); + + /* Check there are no individuals and no persona stores. */ + assert (aggregator.individuals.size == 0); + assert (real_backend.persona_stores.size == 0); + } + + /* Test that changes of a device’s Alias property result in the PersonaStore’s + * display-name being updated. */ + public void test_device_alias () + { + /* Set up the backend. */ + string device_path = ""; + this.bluez_backend.create_simple_device_with_vcard ( + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "N:Jones;Pam;Mrs.\n" + + "FN:Pam Jones\n" + + "TEL:0123456789\n" + + "END:VCARD\n", + null, out device_path); + + var aggregator = IndividualAggregator.dup (); + TestUtils.aggregator_prepare_and_wait_for_individuals_sync_with_timeout ( + aggregator, {"Pam Jones"}); + + /* Check the PersonaStore’s alias. */ + var real_backend = + aggregator.backend_store.dup_backend_by_name ("bluez"); + assert (real_backend.persona_stores.size == 1); + + var real_store = + real_backend.persona_stores.get ( + this.bluez_backend.primary_device_address); + + /* FIXME: Have to get the display-name this way because + * Folks.PersonaStore.display_name is not declared as abstract. */ + string display_name = ""; + real_store.get ("display-name", out display_name); + assert (display_name == "My Phone"); + + /* Change the device’s Alias and see if the display-name changes. */ + var main_loop = new GLib.MainLoop (null, false); + real_store.notify["display-name"].connect ((p) => + { + real_store.get ("display-name", out display_name); + assert (display_name == "New Alias!"); + main_loop.quit (); + }); + + try + { + Device mock_device = + Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", device_path); + org.freedesktop.DBus.Mock mock = + Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", device_path); + + var props = new HashTable<string, Variant> (str_hash, str_equal); + props.insert ("Alias", "New Alias!"); + + mock_device.alias = "New Alias!"; + mock.emit_signal ("org.freedesktop.DBus.Properties", + "PropertiesChanged", "sa{sv}as", + { + "org.bluez.Device1", + props, + new Variant.array (VariantType.STRING, {}) + }); + } + catch (IOError e1) + { + error ("Error setting device alias: %s", e1.message); + } + + TestUtils.loop_run_with_timeout (main_loop); + } +} + +/* Mini-copy of the org-bluez.vala file in the BlueZ backend. */ +[DBus (name = "org.bluez.Device1")] +public interface Device : Object + { + [DBus (name = "Alias")] + public abstract string alias { owned get; set; } + } + +public int main (string[] args) +{ + Test.init (ref args); + + var tests = new DevicePropertiesTests (); + tests.register (); + Test.run (); + tests.final_tear_down (); + + return 0; +} diff --git a/tests/bluez/individual-retrieval.vala b/tests/bluez/individual-retrieval.vala new file mode 100644 index 00000000..033821ed --- /dev/null +++ b/tests/bluez/individual-retrieval.vala @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2013 Collabora Ltd. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Philip Withnall <philip.withnall@collabora.co.uk> + */ + +using Gee; +using Folks; +using BluezTest; + +public class IndividualRetrievalTests : BluezTest.TestCase +{ + public IndividualRetrievalTests () + { + base ("IndividualRetrieval"); + + this.add_test ("singleton individuals", this.test_singleton_individuals); + this.add_test ("empty address book", this.test_empty_address_book); + this.add_test ("photos downloaded later", + this.test_photos_downloaded_later); + } + + /* Test that personas on a pre-existing Bluetooth device are successfully + * downloaded and presented as singleton individuals by the aggregator. */ + public void test_singleton_individuals () + { + var main_loop = new GLib.MainLoop (null, false); + + /* Set up the backend. */ + this.bluez_backend.create_simple_device_with_vcard ( + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "N:Gump;Forrest;Mr.\n" + + "FN:Forrest Gump\n" + + "NICKNAME:Fir\n" + + "TEL;TYPE=WORK,VOICE:(111) 555-1212\n" + + "TEL;TYPE=HOME,VOICE:(404) 555-1212\n" + + "EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com\n" + + "URL;TYPE=HOME:http://example.com/\n" + + "END:VCARD\n" + + "\n" + + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "N:Jones;Pam;Mrs.\n" + + "FN:Pam Jones\n" + + "TEL:0123456789\n" + + "END:VCARD\n"); + + /* Set up the aggregator and wait until either the expected persona are + * seen, or the test times out and fails. */ + var aggregator = IndividualAggregator.dup (); + TestUtils.aggregator_prepare_and_wait_for_individuals.begin (aggregator, + {"Forrest Gump", "Pam Jones"}, (o, r) => + { + try + { + TestUtils.aggregator_prepare_and_wait_for_individuals.end (r); + } + catch (GLib.Error e1) + { + error ("Error preparing aggregator: %s", e1.message); + } + + main_loop.quit (); + }); + + TestUtils.loop_run_with_timeout (main_loop); + } + + /* Test that an empty address book is handled correctly. */ + public void test_empty_address_book () + { + var main_loop = new GLib.MainLoop (null, false); + + /* Set up the backend with *no* contacts. */ + this.bluez_backend.create_simple_device_with_vcard (""); + + /* Set up the aggregator and wait until either quiescence, or the test + * times out and fails. */ + var aggregator = IndividualAggregator.dup (); + TestUtils.aggregator_prepare_and_wait_for_quiescence.begin (aggregator, + (o, r) => + { + try + { + TestUtils.aggregator_prepare_and_wait_for_quiescence.end (r); + } + catch (GLib.Error e1) + { + error ("Error preparing aggregator: %s", e1.message); + } + + main_loop.quit (); + }); + + TestUtils.loop_run_with_timeout (main_loop); + + /* Check there are no individuals. */ + assert (aggregator.individuals.size == 0); + } + + /* Test that photos are downloaded in a second sweep of the address book. */ + public void test_photos_downloaded_later () + { + var main_loop = new GLib.MainLoop (null, false); + + /* Set up the backend, at first with a vCard without a photo. */ + var vcard_signal_id = this.bluez_backend.create_simple_device_with_vcard ( + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "N:Gump;Forrest;Mr.\n" + + "FN:Forrest Gump\n" + + "NICKNAME:Fir\n" + + "TEL;TYPE=WORK,VOICE:(111) 555-1212\n" + + "TEL;TYPE=HOME,VOICE:(404) 555-1212\n" + + "EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com\n" + + "URL;TYPE=HOME:http://example.com/\n" + + "END:VCARD\n"); + + /* Set up the aggregator and wait until either the expected persona are + * seen, or the test times out and fails. */ + var aggregator = IndividualAggregator.dup (); + TestUtils.aggregator_prepare_and_wait_for_individuals.begin (aggregator, + {"Forrest Gump"}, (o, r) => + { + try + { + TestUtils.aggregator_prepare_and_wait_for_individuals.end (r); + } + catch (GLib.Error e1) + { + error ("Error preparing aggregator: %s", e1.message); + } + + main_loop.quit (); + }); + + TestUtils.loop_run_with_timeout (main_loop); + + /* Re-set the backend to now return a vCard with a photo (and nothing + * else). */ + this.bluez_backend.mock_obex.disconnect (vcard_signal_id); + this.bluez_backend.set_simple_device_vcard ( + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "N:Gump;Forrest;Mr.\n" + + "FN:Forrest Gump\n" + + "NICKNAME:Fir\n" + + "TEL;TYPE=WORK,VOICE:(111) 555-1212\n" + + "TEL;TYPE=HOME,VOICE:(404) 555-1212\n" + + "EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com\n" + + "URL;TYPE=HOME:http://example.com/\n" + + "PHOTO;TYPE=jpeg;ENCODING=b:" + + "/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsK" + + "CwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQU" + + "FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAAlACADAREA" + + "AhEBAxEB/8QAGgAAAwADAQAAAAAAAAAAAAAABgcIAAMFBP/EABoBAQADAQEBAAAAAAAAAAAAAAAD" + + "BAUCBgf/2gAMAwEAAhADEAAAAapJXNBV5gl8G4uLkNUaUIYew4otQ8+a+gYntscQryguHbZ+pAH2" + + "Y+ZPwzoOv//EAB4QAAICAwADAQAAAAAAAAAAAAMFBAYBAgcAEBUW/9oACAEBAAEFAvOtT230ufOW" + + "qmzepo/tWKyw96ZYgHHKBdX352vVdJrXkd/UBaVXjDrY8F/kTvyDKxMj26aPMTn6QdZJLrwz5FUc" + + "sSyqFDTbKlmkQP8A/8QAHxEAAQQCAwEBAAAAAAAAAAAAAgABAwQREhMgITFR/9oACAEDAQE/Aeta" + + "UInfdlMYmWRbHavTBh2L3KnieE9VUjGWTUvxS0dI8i+XUd6UGx9Vmxz48VabhPbCntHM+PjL/8QA" + + "JxEAAQMDAQcFAAAAAAAAAAAAAQIDBAAFETESICFBUXHwBhMikfH/2gAIAQIBAT8B3bvBenNpSyvG" + + "OXWoEZyKwG3V7R84b12vj5dLLPw2T9480q2zkz44dGvPvV4kriRg82dCPyonqISJYQ4NlB4DvUiw" + + "w5CiviCatltRb0qCTnNXGGmcx7SjioFpjQRlIyrr5pX/xAAuEAACAQIEAwYGAwAAAAAAAAABAgMA" + + "BAUREhMhIjFBUWFxgZEQFDJCUrFD0eH/2gAIAQEABj8CpYbS4eG0gt1ldYpNJJZyufeezy9aiwbE" + + "ZTNHcxtlnNuaWGfbmfxIy+N7dWsC3UdqiWhYj+TnLZeWpQawXHJY12ASjpAv0nMlvcMx9KSaFxJF" + + "INSuvQirq5Vgtww24PFz0/v0q1sgdTqM5G73PE1iO4OaGIzofFRn/nrV5hkj57BEsQPYrdR7/uvl" + + "7m3jeGJzkG48emdK/wBw+oeNNhgmVZ7yN00fdoIIzqXel3p5+Xd09O4UzxTSQyE5/kPajLPid3Fo" + + "5QLJ9nPz6502JWtxcG6HBmuH3NQpXY7sx46yP1X/xAAfEAEAAQUBAAMBAAAAAAAAAAABEQAhQVFh" + + "MRBxkfD/2gAIAQEAAT8hrANf3gCCQckqMY2Pp+fB6xkNfMTQP0gjfHgXeU1IRQE+0Qm17o9OXZUS" + + "I0EKhlJs4GYvDql0TMdx/Zrqhsh1ptBl1SIe6wi4XVeEI3eM/RZfP2hzBYDFFZsCjIkcF/d1Z4w1" + + "CA9H+NUlhU7Su1f8Sr7hPO0xWEeRf2s7OFfF4ZkLzu2iNllBjgxX/9oADAMBAAIAAwAAABASQViS" + + "BhbUn//EACARAQABAwQDAQAAAAAAAAAAAAERACExQVFhwSCBsfH/2gAIAQMBAT8Q8dUAs5T9pPCf" + + "efIvfgyWJ75p28aO5SorS9O9T8Qu6W4KFOAWxp6plOEd0kaUkUkTwHe9f//EACERAQACAQQDAAMA" + + "AAAAAAAAAAERMSEAQVGBIGFxkbHR/9oACAECAQE/EPHLEpZIfSZxxXemy3S7YMFyht+ivKWOXKMs" + + "kE4rsO86wPVHAvps9OocDLrJOe351EQMF5pCsTDXBbyOoSVR3d4Z0yuUmcVPv3pxASM3U/OdCC88" + + "z1/F7uv/xAAdEAEBAAMBAQEBAQAAAAAAAAABEQAhMUFRcWGB/9oACAEBAAE/EPcBt9CLg0mkItkW" + + "bCK+/Mi2KFKVLnuC5jcdY7QomwK5LuBR8HYKQcR1QYytJ8M0iIji8CRilWERrGzK/cZHYHeFgPgW" + + "tVgRTHHylCBCwOKZYo4K7QfGQ+v/AA6JyUCdhZB0LSgxVErXI33xGn7/ABwIkQz6W1i5pB7l1O1Q" + + "UdgKta18AhSHHRqw0Vdfqyk3ggOrmCAjpsQ7XOmIVMFktoFUcCCccJdlLIMWq/ZA/9k=\n" + + "END:VCARD\n"); + + /* The individual should not have a photo to begin with; wait until one + * appears. */ + assert (aggregator.individuals.size == 1); + var iter = aggregator.individuals.map_iterator (); + while (iter.next () == true) + { + var individual = iter.get_value (); + assert (individual.avatar == null); + + /* Wait for it to change. Assert that only the avatar changes. */ + individual.notify.connect ((pspec) => + { + assert (pspec.name == "avatar"); + assert (individual.avatar != null); + main_loop.quit (); + }); + } + + /* There’s normally a 5s wait between poll attempts in the backend, but + * we set the FOLKS_BLUEZ_TIMEOUT_DIVISOR in the TestCase to reduce + * this. */ + TestUtils.loop_run_with_timeout (main_loop); + } +} + +public int main (string[] args) +{ + Test.init (ref args); + + var tests = new IndividualRetrievalTests (); + tests.register (); + Test.run (); + tests.final_tear_down (); + + return 0; +} diff --git a/tests/bluez/vcard-parsing.vala b/tests/bluez/vcard-parsing.vala new file mode 100644 index 00000000..f9e91002 --- /dev/null +++ b/tests/bluez/vcard-parsing.vala @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2013 Collabora Ltd. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Philip Withnall <philip.withnall@collabora.co.uk> + */ + +using Gee; +using Folks; +using BluezTest; + +public class VcardParsingTests : BluezTest.TestCase +{ + public VcardParsingTests () + { + base ("VcardParsing"); + + this.add_test ("multiple attributes", this.test_multiple_attributes); + this.add_test ("name components", this.test_name_components); + this.add_test ("encoding", this.test_encoding); + } + + /* Test that vCards containing multiple attributes with the same name (e.g. + * multiple phone numbers or e-mail addresses) are parsed correctly. */ + public void test_multiple_attributes () + { + /* Set up the backend. */ + this.bluez_backend.create_simple_device_with_vcard ( + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "FN:Forrest Gump\n" + + "TEL;TYPE=WORK,VOICE:(111) 555-1212\n" + + "TEL;TYPE=HOME,VOICE:(404) 555-1212\n" + + "EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com\n" + + "EMAIL:test@example.com\n" + + "URL;TYPE=HOME:http://example.com/\n" + + "URL:http://forest.com/\n" + + "URL:https://test.com/\n" + + "END:VCARD\n"); + + /* Set up the aggregator and wait until either the expected persona are + * seen, or the test times out and fails. */ + var aggregator = IndividualAggregator.dup (); + TestUtils.aggregator_prepare_and_wait_for_individuals_sync_with_timeout ( + aggregator, {"Forrest Gump"}); + + /* Check the properties of our friend Forrest. */ + var ind = TestUtils.get_individual_by_name (aggregator, "Forrest Gump"); + + var expected_phone_numbers = new SmallSet<PhoneFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); + + var expected_phone_fd = new PhoneFieldDetails ("(111) 555-1212"); + expected_phone_fd.add_parameter ("type", "work"); + expected_phone_fd.add_parameter ("type", "voice"); + expected_phone_numbers.add (expected_phone_fd); + + expected_phone_fd = new PhoneFieldDetails ("(404) 555-1212"); + expected_phone_fd.add_parameter ("type", "home"); + expected_phone_fd.add_parameter ("type", "voice"); + expected_phone_numbers.add (expected_phone_fd); + + var expected_email_addresses = new SmallSet<EmailFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); + + var expected_email_fd = new EmailFieldDetails ("forrestgump@example.com"); + expected_email_fd.add_parameter ("type", "pref"); + expected_email_fd.add_parameter ("type", "internet"); + expected_email_addresses.add (expected_email_fd); + + expected_email_fd = new EmailFieldDetails ("test@example.com"); + expected_email_addresses.add (expected_email_fd); + + var expected_uris = new SmallSet<UrlFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); + + var expected_uri_fd = new UrlFieldDetails ("http://example.com/"); + expected_uri_fd.add_parameter ("type", "home"); + expected_uris.add (expected_uri_fd); + + expected_uri_fd = new UrlFieldDetails ("http://forest.com/"); + expected_uris.add (expected_uri_fd); + + expected_uri_fd = new UrlFieldDetails ("https://test.com/"); + expected_uris.add (expected_uri_fd); + + assert (Utils.set_afd_equal (ind.phone_numbers, expected_phone_numbers)); + assert (Utils.set_afd_equal (ind.email_addresses, + expected_email_addresses)); + assert (Utils.set_afd_equal (ind.urls, expected_uris)); + } + + /* Test that vCards with different numbers of values for their N (structured + * name) attribute are parsed correctly. */ + public void test_name_components () + { + /* Set up the backend. */ + this.bluez_backend.create_simple_device_with_vcard ( + /* Valid N attributes. */ + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "FN:John Public\n" + + "N:Public;John;Quinlan;Mr.;Esq.\n" + + "END:VCARD\n" + + "\n" + + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "FN:John Stevenson\n" + + "N:Stevenson;John;Philip,Paul;Dr.;Jr.,M.D.,A.C.P.\n" + + "END:VCARD\n" + + "\n" + + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "FN:Franco Dianno\n" + + "N:Dianno;Franco;;;\n" + + "END:VCARD\n" + + "\n" + + /* Invalid N attributes (but we should handle them anyway). */ + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "FN:Amelia Smith\n" + + "N:Smith;Amelia;David;Dr.\n" + + "END:VCARD\n" + + "\n" + + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "FN:Sadie Jones\n" + + "N:Jones;Sadie;M.\n" + + "END:VCARD\n" + + "\n" + + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "FN:Alex Lawson\n" + + "N:Lawson;Alex\n" + + "END:VCARD\n"); + + /* Set up the aggregator and wait until either the expected persona are + * seen, or the test times out and fails. */ + var aggregator = IndividualAggregator.dup (); + TestUtils.aggregator_prepare_and_wait_for_individuals_sync_with_timeout ( + aggregator, + { + "John Public", + "John Stevenson", + "Franco Dianno", + "Amelia Smith", + "Sadie Jones", + "Alex Lawson" + }); + + /* Check the properties of our individuals. */ + var ind = TestUtils.get_individual_by_name (aggregator, "John Public"); + var expected_name = + new StructuredName ("Public", "John", "Quinlan", "Mr.", "Esq."); + assert (ind.structured_name.equal (expected_name)); + + ind = TestUtils.get_individual_by_name (aggregator, "John Stevenson"); + expected_name = + new StructuredName ("Stevenson", "John", "Philip,Paul", "Dr.", + "Jr.,M.D.,A.C.P."); + assert (ind.structured_name.equal (expected_name)); + + ind = TestUtils.get_individual_by_name (aggregator, "Franco Dianno"); + expected_name = new StructuredName ("Dianno", "Franco", null, null, null); + assert (ind.structured_name.equal (expected_name)); + + ind = TestUtils.get_individual_by_name (aggregator, "Amelia Smith"); + expected_name = + new StructuredName ("Smith", "Amelia", "David", "Dr.", null); + assert (ind.structured_name.equal (expected_name)); + + ind = TestUtils.get_individual_by_name (aggregator, "Sadie Jones"); + expected_name = new StructuredName ("Jones", "Sadie", "M.", null, null); + assert (ind.structured_name.equal (expected_name)); + + ind = TestUtils.get_individual_by_name (aggregator, "Alex Lawson"); + expected_name = new StructuredName ("Lawson", "Alex", null, null, null); + assert (ind.structured_name.equal (expected_name)); + } + + /* Test that vCards with weird encodings are parsed correctly. */ + public void test_encoding () + { + /* Set up the backend. */ + this.bluez_backend.create_simple_device_with_vcard ( + /* From https://bugs.kde.org/show_bug.cgi?id=98790 */ + "BEGIN:VCARD\n" + + "VERSION:2.1\n" + + "FN:Test 1\n" + + "N;CHARSET=UTF-8:溌剌;元気\n" + + "END:VCARD\n" + + "\n" + + /* From https://git.gnome.org/browse/evolution-data-server/tree/tests/ + * libebook-contacts/test-vcard-parsing.c#n360 */ + "BEGIN:VCARD\n" + + "VERSION:2.1\n" + + "FN;ENCODING=quoted-printable:ActualValue=20=C4=9B=C5=A1" + + "=C4=8D=C5=99=C5=BE=C3=BD=C3=A1=C3=AD=C3=A9=C3=BA=C5=AF=C3" + + "=B3=C3=B6=C4=9A=C5=A0=C4=8C=C5=98=C5=BD=C3=9D=C3=81=C3=8D" + + "=C3=89=C3=9A=C5=AE=C3=93=C3=96=C2=A7=201234567890=2012345" + + "67890=201234567890=201234567890=201234567890\n" + + "END:VCARD\n"); + + /* Set up the aggregator and wait until either the expected persona are + * seen, or the test times out and fails. */ + var aggregator = IndividualAggregator.dup (); + TestUtils.aggregator_prepare_and_wait_for_individuals_sync_with_timeout ( + aggregator, + { + "Test 1", + "ActualValue ěščřžýáíéúůóöĚŠČŘŽÝÁÍÉÚŮÓÖ§ " + + "1234567890 1234567890 1234567890 1234567890 1234567890" + }); + + /* Check the properties of our individuals. */ + var ind = TestUtils.get_individual_by_name (aggregator, "Test 1"); + var expected_name = + new StructuredName ("溌剌", "元気", null, null, null); + assert (ind.structured_name.equal (expected_name)); + + ind = + TestUtils.get_individual_by_name (aggregator, + "ActualValue ěščřžýáíéúůóöĚŠČŘŽÝÁÍÉÚŮÓÖ§ " + + "1234567890 1234567890 1234567890 1234567890 1234567890"); + assert (ind.full_name == "ActualValue ěščřžýáíéúůóöĚŠČŘŽÝÁÍÉÚŮÓÖ§ " + + "1234567890 1234567890 1234567890 1234567890 1234567890"); + } +} + +public int main (string[] args) +{ + Test.init (ref args); + + var tests = new VcardParsingTests (); + tests.register (); + Test.run (); + tests.final_tear_down (); + + return 0; +} diff --git a/tests/dummy/Makefile.am b/tests/dummy/Makefile.am index 90fd2d58..668dbe16 100644 --- a/tests/dummy/Makefile.am +++ b/tests/dummy/Makefile.am @@ -24,6 +24,7 @@ LDADD = \ TESTS = \ individual-retrieval \ add-persona \ + linkable-properties \ $(NULL) noinst_PROGRAMS = $(TESTS) @@ -36,6 +37,10 @@ add_persona_SOURCES = \ add-persona.vala \ $(NULL) +linkable_properties_SOURCES = \ + linkable-properties.vala \ + $(NULL) + -include $(top_srcdir)/git.mk -include $(top_srcdir)/valgrind.mk -include $(top_srcdir)/check.mk diff --git a/tests/dummy/linkable-properties.vala b/tests/dummy/linkable-properties.vala new file mode 100644 index 00000000..716feb56 --- /dev/null +++ b/tests/dummy/linkable-properties.vala @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2014 Renato Araujo Oliveira Filho + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Raul Gutierrez Segales <raul.gutierrez.segales@collabora.co.uk> + * Travis Reitter <travis.reitter@collabora.co.uk> + * Renato Araujo Oliveira Filho <renato@canonical.com> + * + */ + +using Folks; +using Gee; + +public class LinkablePropertiesTests : DummyTest.TestCase +{ + private IndividualAggregator _aggregator; + private GLib.MainLoop _main_loop; + private bool _found_before_update; + private bool _found_after_update; + + /* NOTE: each full name must remain unique. Likewise for email. */ + private const string _full_name_1 = "bernie h. innocenti"; + private const string _email_1 = "bernie@example.org"; + private const string _phone_1 = "5551234"; + private const string _full_name_2 = "Clyde McPoyle"; + private const string _email_2 = "clyde@example.org"; + private const string _phone_2 = "987654321"; + private Individual _ind_1; + private Individual _ind_2; + + /* In general, these tests are meant to check basic behavior so we don't need + * to sprinkle that throughout (and potentially revise) within unrelated tests + */ + public LinkablePropertiesTests () + { + base ("LinkableProperties"); + + this.add_test ("correct aggregation after linkable property change", + this.test_linkable_properties_aggregate_after_change); + } + + public override void set_up () + { + base.set_up (); + + this._found_before_update = false; + this._found_after_update = false; + } + + public override void configure_primary_store () + { + base.configure_primary_store (); + this.dummy_persona_store.update_trust_level (PersonaStoreTrust.FULL); + } + + private async void _add_persona (owned Gee.HashMap<string, Value?> c) + { + HashTable<string, Value?> details = new HashTable<string, Value?> + (str_hash, str_equal); + + Value? v1 = Value (typeof (string)); + v1.set_string (c["full_name"].get_string()); + details.insert (Folks.PersonaStore.detail_key (PersonaDetail.FULL_NAME), + (owned) v1); + + Value? v2 = Value (typeof (Set)); + var emails = new HashSet<EmailFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); + var email_1 = new EmailFieldDetails (c["email_1"].get_string()); + email_1.set_parameter (AbstractFieldDetails.PARAM_TYPE, + AbstractFieldDetails.PARAM_TYPE_HOME); + emails.add (email_1); + v2.set_object (emails); + details.insert ( + Folks.PersonaStore.detail_key (PersonaDetail.EMAIL_ADDRESSES), + (owned) v2); + + Value? v5 = Value (typeof (Set)); + var phones = new HashSet<PhoneFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); + + var phone_1 = new PhoneFieldDetails (c["home_phone"].get_string()); + phone_1.set_parameter (AbstractFieldDetails.PARAM_TYPE, + AbstractFieldDetails.PARAM_TYPE_HOME); + phones.add (phone_1); + v5.set_object (phones); + details.insert ( + Folks.PersonaStore.detail_key (PersonaDetail.PHONE_NUMBERS), + (owned) v5); + + try + { + yield this._aggregator.add_persona_from_details (null, + this.dummy_persona_store, details); + } + catch (Folks.IndividualAggregatorError e) + { + GLib.warning ("[AddPersonaError] add_persona_from_details: %s\n", + e.message); + } + } + + + /* Check that two unaggregated Personas get aggregated after one changes its + * linkable property to match the other's (ie, they get linked) + */ + private async void _add_personas () + { + Gee.HashMap<string, Value?> c; + Value? v; + + this._found_before_update = false; + this._found_after_update = false; + + c = new Gee.HashMap<string, Value?> (); + v = Value (typeof (string)); + v.set_string (_full_name_1); + c.set ("full_name", (owned) v); + v = Value (typeof (string)); + v.set_string (_email_1); + c.set ("email_1", (owned) v); + v = Value (typeof (string)); + v.set_string (_phone_1); + c.set ("home_phone", (owned) v); + yield this._add_persona (c); + + c = new Gee.HashMap<string, Value?> (); + v = Value (typeof (string)); + v.set_string (_full_name_2); + c.set ("full_name", (owned) v); + v = Value (typeof (string)); + v.set_string (_email_2); + c.set ("email_1", (owned) v); + v = Value (typeof (string)); + v.set_string (_phone_2); + c.set ("home_phone", (owned) v); + yield this._add_persona (c); + } + + private void test_linkable_properties_aggregate_after_change () + { + this._main_loop = new GLib.MainLoop (null, false); + test_linkable_properties_aggregate_after_change_continue.begin (); + TestUtils.loop_run_with_timeout (this._main_loop); + + assert (this._found_before_update); + assert (this._found_after_update); + } + + private async void test_linkable_properties_aggregate_after_change_continue () + { + this._aggregator = IndividualAggregator.dup (); + this._aggregator.individuals_changed_detailed.connect (this._individuals_changed_aggregate_after_change_cb); + try + { + yield this._aggregator.prepare (); + } + catch (GLib.Error e) + { + GLib.warning ("Error when calling prepare: %s\n", e.message); + } + + yield this._add_personas (); + } + + private void _individuals_changed_aggregate_after_change_cb ( + MultiMap<Individual?, Individual?> changes) + { + var added = changes.get_values (); + + if (!this._found_before_update) + { + foreach (Individual i in added) + { + assert (i != null); + + var name = (Folks.NameDetails) i; + + if (name.full_name == _full_name_1) + { + this._ind_1 = i; + } + /* Change the second Persona's email address to match the first so + * they should get aggregated */ + else if (name.full_name == _full_name_2) + { + this._ind_2 = i; + this._found_before_update = true; + + foreach (var p in i.personas) + { + var emails = new HashSet<EmailFieldDetails> ( + AbstractFieldDetails<string>.hash_static, + AbstractFieldDetails<string>.equal_static); + var email_1 = new EmailFieldDetails (_email_1); + email_1.set_parameter (AbstractFieldDetails.PARAM_TYPE, + AbstractFieldDetails.PARAM_TYPE_OTHER); + emails.add (email_1); + ((EmailDetails) p).email_addresses = emails; + } + } + } + } + else + { + Individual replaced; + + if (changes.contains (this._ind_1)) + { + replaced = this._ind_1; + } + else if (changes.contains (this._ind_2)) + { + replaced = this._ind_2; + } + else + { + return; + } + + var replacements = changes.get (replaced); + foreach (var r in replacements) + { + var phone_fd_1 = new PhoneFieldDetails (_phone_1); + var phone_fd_2 = new PhoneFieldDetails (_phone_1); + var num_equal_1 = false; + var num_equal_2 = false; + + if (r.personas.size == 2) + { + foreach (var num in r.phone_numbers) + { + if (num.values_equal (phone_fd_1)) + num_equal_1 = true; + + if (num.values_equal (phone_fd_2)) + num_equal_2 = true; + } + + if (num_equal_1 && num_equal_2) + { + this._found_after_update = true; + this._main_loop.quit (); + } + } + } + } + } +} + +public int main (string[] args) +{ + Test.init (ref args); + + var tests = new LinkablePropertiesTests (); + tests.register (); + Test.run (); + tests.final_tear_down (); + + return 0; +} diff --git a/tests/eds/Makefile.am b/tests/eds/Makefile.am index 687ebe62..29f7bb33 100644 --- a/tests/eds/Makefile.am +++ b/tests/eds/Makefile.am @@ -77,13 +77,6 @@ TESTS = \ perf \ $(NULL) -RUN_WITH_PRIVATE_BUS = $(top_srcdir)/tests/tools/with-session-bus-eds.sh - -TESTS_ENVIRONMENT = \ - $(RUN_WITH_PRIVATE_BUS) \ - --session \ - -- - noinst_PROGRAMS = \ $(TESTS) \ helper-create-many-contacts \ @@ -239,11 +232,6 @@ helper_prepare_aggregator_SOURCES = \ helper-prepare-aggregator.vala \ $(NULL) -CLEANFILES = \ - *.pid \ - *.address \ - $(NULL) - -include $(top_srcdir)/git.mk -include $(top_srcdir)/check.mk -include $(top_srcdir)/valgrind.mk diff --git a/tests/eds/helper-create-many-contacts.vala b/tests/eds/helper-create-many-contacts.vala index 000348ff..bbeb1847 100644 --- a/tests/eds/helper-create-many-contacts.vala +++ b/tests/eds/helper-create-many-contacts.vala @@ -131,7 +131,7 @@ public class Main { Intl.setlocale (LocaleCategory.ALL, ""); - if (Environment.get_variable ("FOLKS_TESTS_SANDBOXED_DBUS") != "eds") + if (Environment.get_variable ("FOLKS_TESTS_SANDBOXED_DBUS") != "no-services") error ("e-d-s helpers must be run in a private D-Bus session with " + "e-d-s services"); diff --git a/tests/eds/helper-delete-contacts.vala b/tests/eds/helper-delete-contacts.vala index 46d2e35c..816767da 100644 --- a/tests/eds/helper-delete-contacts.vala +++ b/tests/eds/helper-delete-contacts.vala @@ -55,7 +55,7 @@ public class Main { Intl.setlocale (LocaleCategory.ALL, ""); - if (Environment.get_variable ("FOLKS_TESTS_SANDBOXED_DBUS") != "eds") + if (Environment.get_variable ("FOLKS_TESTS_SANDBOXED_DBUS") != "no-services") error ("e-d-s helpers must be run in a private D-Bus session with " + "e-d-s services"); diff --git a/tests/eds/helper-prepare-aggregator.vala b/tests/eds/helper-prepare-aggregator.vala index 1b71a6bb..50bd439f 100644 --- a/tests/eds/helper-prepare-aggregator.vala +++ b/tests/eds/helper-prepare-aggregator.vala @@ -62,7 +62,7 @@ public class Main { Intl.setlocale (LocaleCategory.ALL, ""); - if (Environment.get_variable ("FOLKS_TESTS_SANDBOXED_DBUS") != "eds" || + if (Environment.get_variable ("FOLKS_TESTS_SANDBOXED_DBUS") != "no-services" || Environment.get_variable ("FOLKS_BACKENDS_ALLOWED") != "eds" || Environment.get_variable ("FOLKS_PRIMARY_STORE") == null) error ("e-d-s helpers must be run in a private D-Bus session with " + diff --git a/tests/folks/Makefile.am b/tests/folks/Makefile.am index a04e8461..9fda5745 100644 --- a/tests/folks/Makefile.am +++ b/tests/folks/Makefile.am @@ -54,10 +54,6 @@ noinst_PROGRAMS = \ init \ $(NULL) -TESTS_ENVIRONMENT = \ - $(top_srcdir)/tests/tools/execute-test.sh \ - $(NULL) - TESTS = $(noinst_PROGRAMS) backend_loading_SOURCES = \ diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am index 49dde706..2442d405 100644 --- a/tests/lib/Makefile.am +++ b/tests/lib/Makefile.am @@ -5,6 +5,12 @@ SUBDIRS = \ key-file \ $(NULL) +if ENABLE_BLUEZ +if HAVE_BLUEZ_TESTS +SUBDIRS += bluez +endif +endif + if ENABLE_TELEPATHY # Build the contactlist first because autotools fails to recognize the # dependencies implicitly. There may be a better way to fix this, but then I'd @@ -30,6 +36,7 @@ endif DIST_SUBDIRS = \ dummy \ key-file \ + bluez \ telepathy \ eds \ libsocialweb \ @@ -41,9 +48,13 @@ noinst_LTLIBRARIES = libfolks-test.la libfolks_test_la_SOURCES = \ disconnection-queue.vala \ haze-remove-directory.c \ + gtestdbus.c \ + gtestdbus.h \ + folks-test-dbus.vapi \ test-case.vala \ test-case-helper.c \ test-utils.vala \ + org-freedesktop-dbus-mock.vala \ $(NULL) libfolks_test_la_CFLAGS = \ @@ -81,6 +92,7 @@ libfolks_test_la_VALAFLAGS = \ $(ERROR_VALAFLAGS) \ --vapidir=$(abs_top_srcdir)/folks \ --vapidir=$(abs_top_builddir)/folks \ + --vapidir=$(abs_top_srcdir)/tests/lib \ --pkg gobject-2.0 \ --pkg gio-2.0 \ --pkg gee-0.8 \ diff --git a/tests/lib/bluez/Makefile.am b/tests/lib/bluez/Makefile.am new file mode 100644 index 00000000..a2a382dd --- /dev/null +++ b/tests/lib/bluez/Makefile.am @@ -0,0 +1,51 @@ +noinst_LTLIBRARIES = libbluez-test.la + +libbluez_test_la_VALAFLAGS = \ + $(AM_VALAFLAGS) \ + $(TARGET_VALAFLAGS) \ + $(ERROR_VALAFLAGS) \ + --library bluez-test \ + --vapi bluez-test.vapi \ + --header bluez-test.h \ + --vapidir=$(abs_srcdir) \ + --vapidir=$(abs_builddir) \ + --vapidir=$(abs_top_srcdir)/folks \ + --vapidir=$(abs_top_builddir)/folks \ + --vapidir=$(abs_top_srcdir)/tests/lib \ + --vapidir=$(abs_top_builddir)/tests/lib \ + --pkg folks-test \ + --pkg folks-test-dbus \ + -g \ + $(NULL) + +libbluez_test_la_SOURCES = \ + backend.vala \ + test-case.vala \ + $(NULL) + +libbluez_test_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -include $(top_srcdir)/folks/warnings.h \ + $(NULL) + +libbluez_test_la_CFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/tests/lib \ + $(AM_CFLAGS) \ + $(ERROR_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GEE_CFLAGS) \ + $(NULL) + +libbluez_test_la_LIBADD = \ + $(top_builddir)/tests/lib/libfolks-test.la \ + $(GLIB_LIBS) \ + $(GEE_LIBS) \ + $(NULL) + +EXTRA_DIST = \ + bluez-test.vapi \ + bluez-test.h \ + $(NULL) + +-include $(top_srcdir)/git.mk diff --git a/tests/lib/bluez/backend.vala b/tests/lib/bluez/backend.vala new file mode 100644 index 00000000..1ba34a2a --- /dev/null +++ b/tests/lib/bluez/backend.vala @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2013 Collabora Ltd. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Philip Withnall <philip.withnall@collabora.co.uk> + */ + +using GLib; + +/* Specific mock interfaces for the BlueZ and OBEX services. */ +namespace org + { + namespace bluez + { + /* Interface for the bluez5 python-dbusmock template. */ + [DBus (name = "org.bluez.Mock")] + public interface Mock : Object + { + [DBus (name = "AddAdapter")] + public abstract string add_adapter (string device_name, + string system_name) throws IOError; + + [DBus (name = "AddDevice")] + public abstract string add_device (string adapter_device_name, + string device_address, string alias) throws IOError; + + [DBus (name = "PairDevice")] + public abstract void pair_device (string adapter_device_name, + string device_address) throws IOError; + + [DBus (name = "BlockDevice")] + public abstract void block_device (string adapter_device_name, + string device_address) throws IOError; + } + + namespace obex + { + /* Interface for the bluez5-obex python-dbusmock template. */ + [DBus (name = "org.bluez.obex.Mock")] + public interface Mock : Object + { + [DBus (name = "TransferCreated")] + public abstract signal void transfer_created (string path, + HashTable<string, Variant> filters, + string transfer_filename); + } + + namespace transfer1 + { + [DBus (name = "org.bluez.obex.transfer1.Mock")] + public interface Mock : Object + { + [DBus (name = "UpdateStatus")] + public abstract void update_status (bool is_complete) + throws IOError; + } + } + } + } + } + +/** + * Controller for a mock BlueZ backend. + * + * This contains control methods to instantiate and manipulate a mock BlueZ + * service over D-Bus, for the purposes of testing the folks BlueZ backend. + * + * The mock service uses python-dbusmock, with control messages being sent to + * ``*.Mock`` interfaces on the D-Bus objects. Those control interfaces are + * exposed as {@link Backend.mock_bluez}, {@link Backend.mock_bluez_base}, + * {@link Backend.mock_obex} and {@link Backend.mock_obex_base}. + * + * @since UNRELEASED + */ +public class BluezTest.Backend +{ + private org.bluez.Mock? _mock_bluez = null; + private org.freedesktop.DBus.Mock? _mock_bluez_base = null; + private org.bluez.obex.Mock? _mock_obex = null; + private org.freedesktop.DBus.Mock? _mock_obex_base = null; + + /** + * D-Bus proxy for the BlueZ-specific mock interface on the org.bluez object. + * + * @since UNRELEASED + */ + public org.bluez.Mock? mock_bluez + { + get { return this._mock_bluez; } + } + + /** + * D-Bus proxy for the dbusmock mock interface on the org.bluez object. + * + * @since UNRELEASED + */ + public org.freedesktop.DBus.Mock? mock_bluez_base + { + get { return this._mock_bluez_base; } + } + + /** + * D-Bus proxy for the BlueZ-specific mock interface on the org.bluez.obex + * object. + * + * @since UNRELEASED + */ + public org.bluez.obex.Mock? mock_obex + { + get { return this._mock_obex; } + } + + /** + * D-Bus proxy for the dbusmock mock interface on the org.bluez.obex object. + * + * @since UNRELEASED + */ + public org.freedesktop.DBus.Mock? mock_obex_base + { + get { return this._mock_obex_base; } + } + + /** + * Default Bluetooth address used for the primary adapter. + * + * This is the address used for the primary Bluetooth adapter (``hci0``) + * unless otherwise specified. + * + * @since UNRELEASED + */ + public string primary_device_address + { + get { return "00:00:00:00:00:00"; } + } + + /** + * Set up the mock D-Bus interfaces. + * + * This must be called before every different unit test. It creates D-Bus + * proxies for the dbusmock objects, auto-launching python-dbusmock if + * necessary. + * + * The required D-Bus service files must previously have been set up with the + * buses which are in use. This is done in + * {@link TestCase.create_transient_dir}. + * + * @since UNRELEASED + */ + public void set_up () + { + /* Create proxies for the client code to use. This auto-starts the + * services. Their service files are created in TestCase. */ + try + { + this._mock_bluez = + Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", "/"); + this._mock_bluez_base = + Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", "/"); + + this._mock_obex = + Bus.get_proxy_sync (BusType.SESSION, "org.bluez.obex", "/"); + this._mock_obex_base = + Bus.get_proxy_sync (BusType.SESSION, "org.bluez.obex", "/"); + } + catch (GLib.Error e1) + { + /* Tidy up. */ + this.tear_down (); + + error ("Error connecting to mock object: %s", e1.message); + } + } + + /** + * Tear down the mock D-Bus interfaces. + * + * This must be called after every different unit test. It undoes + * {@link Backend.set_up}, although the python-dbusmock processes are kept + * around and reset, rather than being killed. + * + * @since UNRELEASED + */ + public void tear_down () + { + /* Reset the python-dbusmock state. */ + try + { + this._mock_obex_base.reset (); + this._mock_bluez_base.reset (); + } + catch (IOError e1) + { + error ("Error resetting python-dbusmock state: %s", e1.message); + } + + /* Remove the D-Bus proxies. The python-dbusmock instances will close by + * themselves when the mock D-Bus buses are destroyed in + * final_tear_down(). */ + this._mock_obex_base = null; + this._mock_bluez_base = null; + this._mock_obex = null; + this._mock_bluez = null; + } + + /** + * Create a simple Bluetooth device with the given vCard. + * + * Create a new Bluetooth adapter (``hci0``) and a new Bluetooth device (with + * address {@link Backend.primary_device_address}). Pair with the Bluetooth + * device and simulate it having the given ``vcard`` (potentially containing + * multiple whitespace-separated entries) as its address book. + * + * On error this function will abort the test. + * + * @param vcard series of vCards for the device’s address book + * @param adapter_path optional return location for the adapter’s D-Bus object + * path + * @param device_path optional return location for the device’s D-Bus object + * path + * @return ID of the signal returning the vCard, as per + * {@link Backend.set_simple_device_vcard} + * + * @since UNRELEASED + */ + public ulong create_simple_device_with_vcard (string vcard, + out string? adapter_path = null, out string? device_path = null) + { + try + { + /* Set up a Bluetooth adapter and a single persona store. */ + adapter_path = this.mock_bluez.add_adapter ("hci0", "Test System"); + device_path = + this.mock_bluez.add_device ("hci0", this.primary_device_address, + "My Phone"); + + /* Pair with the phone. */ + this.mock_bluez.pair_device ("hci0", this.primary_device_address); + + /* Set the vCard to be returned for all transfers. */ + return this.set_simple_device_vcard (vcard); + } + catch (IOError e1) + { + error ("Error setting up mock BlueZ device: %s", e1.message); + } + } + + /** + * Set the vCard to be returned by a simple Bluetooth device. + * + * This sets the vCard which will be returned indefinitely. It returns a + * signal ID which may be disconnected with: + * {{{ + * this.mock_obex.disconnect (signal_id); + * }}} + * to prevent the vCard being returned in future. + * + * @param vcard series of vCards for the device’s address book + * @return ID of the signal returning the vCard + * + * @since UNRELEASED + */ + public ulong set_simple_device_vcard (string vcard) + { + /* Wait for a transfer to be created. Skip activating it and go + * straight to completion. */ + return this.mock_obex.transfer_created.connect ((p, f, v) => + { + org.bluez.obex.transfer1.Mock proxy; + + try + { + FileUtils.set_contents (v, vcard); + } + catch (FileError e1) + { + error ("Error writing vCard transfer file ‘%s’: %s", + v, e1.message); + } + + try + { + proxy = + Bus.get_proxy_sync (BusType.SESSION, "org.bluez.obex", p); + proxy.update_status (true); + } + catch (GLib.Error e1) + { + error ("Error activating transfer: %s", e1.message); + } + }); + } +} diff --git a/tests/lib/bluez/test-case.vala b/tests/lib/bluez/test-case.vala new file mode 100644 index 00000000..accaf0b1 --- /dev/null +++ b/tests/lib/bluez/test-case.vala @@ -0,0 +1,127 @@ +/* + * Copyright © 2013 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Philip Withnall <philip.withnall@collabora.co.uk> + */ + +/** + * A test case for the BlueZ backend, whose private D-Bus session contains the + * necessary python-dbusmock instance to mock up BlueZ. + * + * @since UNRELEASED + */ +public class BluezTest.TestCase : Folks.TestCase +{ + /** + * A BlueZ backend, normally non-null between set_up() and tear_down(). + * + * If this is non-null, the subclass is expected to have called + * its set_up() method at some point before tear_down() is reached. + * This usually happens in create_backend(). + */ + public BluezTest.Backend? bluez_backend = null; + + public TestCase (string name) + { + base (name); + + this.bluez_backend = new BluezTest.Backend (); + + Environment.set_variable ("FOLKS_BACKENDS_ALLOWED", "bluez", true); + Environment.set_variable ("FOLKS_PRIMARY_STORE", "bluez", true); + Environment.set_variable ("FOLKS_BLUEZ_TIMEOUT_DIVISOR", "100", true); + } + + /** + * {@inheritDoc} + * + * @since UNRELEASED + */ + public override void set_up () + { + base.set_up (); + this.create_backend (); + this.configure_primary_store (); + } + + /** + * {@inheritDoc} + * + * @since UNRELEASED + */ + public override void private_bus_up () + { + /* Set up service files for the python-dbusmock services. */ + this.create_dbusmock_service (BusType.SYSTEM, "org.bluez", "bluez5"); + this.create_dbusmock_service (BusType.SESSION, "org.bluez.obex", + "bluez5-obex"); + + base.private_bus_up (); + } + + /** + * Virtual method to create and set up the BlueZ backend. + * + * Called from set_up(); may be overridden to not create the backend, + * or to create it but not set it up. + * + * Subclasses may chain up, but are not required to so. + * + * @since UNRELEASED + */ + public virtual void create_backend () + { + this.bluez_backend = new BluezTest.Backend (); + ((!) this.bluez_backend).set_up (); + } + + /** + * Virtual method to configure ``FOLKS_PRIMARY_STORE`` to point to + * our //bluez_backend//. + * + * Subclasses may chain up, but are not required to so. + * + * @since UNRELEASED + */ + public virtual void configure_primary_store () + { + /* By default, configure BlueZ as the primary store. */ + assert (this.bluez_backend != null); + var config_val = + "bluez:" + ((!) this.bluez_backend).primary_device_address; + Environment.set_variable ("FOLKS_PRIMARY_STORE", config_val, true); + } + + /** + * {@inheritDoc} + * + * @since UNRELEASED + */ + public override void tear_down () + { + if (this.bluez_backend != null) + { + ((!) this.bluez_backend).tear_down (); + this.bluez_backend = null; + } + + Environment.unset_variable ("FOLKS_PRIMARY_STORE"); + + base.tear_down (); + } +} diff --git a/tests/lib/dummy/Makefile.am b/tests/lib/dummy/Makefile.am index 11610043..71c4ec80 100644 --- a/tests/lib/dummy/Makefile.am +++ b/tests/lib/dummy/Makefile.am @@ -18,6 +18,7 @@ libdummy_test_la_VALAFLAGS = \ --pkg folks \ --pkg folks-dummy \ --pkg folks-test \ + --pkg folks-test-dbus \ -g \ $(NULL) diff --git a/tests/lib/eds/Makefile.am b/tests/lib/eds/Makefile.am index dddb57f0..ce83750b 100644 --- a/tests/lib/eds/Makefile.am +++ b/tests/lib/eds/Makefile.am @@ -22,6 +22,7 @@ libeds_test_la_VALAFLAGS = \ --pkg libxml-2.0 \ --pkg folks-eds \ --pkg folks-test \ + --pkg folks-test-dbus \ -g \ $(NULL) diff --git a/tests/lib/eds/test-case.vala b/tests/lib/eds/test-case.vala index 456f46f4..bc36d449 100644 --- a/tests/lib/eds/test-case.vala +++ b/tests/lib/eds/test-case.vala @@ -26,8 +26,14 @@ * A test case whose private D-Bus session contains the necessary daemons * for an Evolution address-book. * - * FIXME: For now, this relies on running under with-session-bus-eds.sh - * with FOLKS_BACKEND_PATH set. + * The EDS daemons are started through D-Bus service activation in + * {@link TestCase.private_bus_up}, and should automatically exit when the mock + * D-Bus bus is torn down. All of their configuration and data storage is + * isolated in a temporary directory which is unique per test run. + * + * The EDS daemons are only torn down in {@link TestCase.final_tear_down}, so + * remain running between test cases in the same test binary. Their state is + * soft-reset, but some state may be retained between test cases. */ public class EdsTest.TestCase : Folks.TestCase { @@ -42,14 +48,6 @@ public class EdsTest.TestCase : Folks.TestCase public TestCase (string name) { - /* This variable is set in the same place as the various variables we - * care about for sandboxing purposes, like XDG_CONFIG_HOME and - * DBUS_SESSION_BUS_ADDRESS. */ - if (Environment.get_variable ("FOLKS_TESTS_SANDBOXED_DBUS") - != "eds") - error ("e-d-s tests must be run in a private D-Bus session " + - "with e-d-s services"); - base (name); Environment.set_variable ("FOLKS_BACKENDS_ALLOWED", "eds", true); @@ -57,17 +55,83 @@ public class EdsTest.TestCase : Folks.TestCase true); } - public override string? create_transient_dir () + public override string create_transient_dir () { - /* Don't do anything. We're currently relying on - * being wrapped in with-session-bus-eds.sh. */ - return null; + var transient = base.create_transient_dir (); + + /* Evolution configuration directory. */ + var config_dir = "%s/.config/evolution/sources".printf (transient); + + if (GLib.DirUtils.create_with_parents (config_dir, 0700) != 0) + error ("unable to create '%s': %s", + config_dir, GLib.strerror (GLib.errno)); + + return transient; } public override void private_bus_up () { - /* Don't do anything. We're currently relying on - * being wrapped in with-session-bus-eds.sh. */ + base.private_bus_up (); + + /* Find out the libexec directory to use. */ + int exit_status = -1; + string capture_stdout = null; + + try + { + Process.spawn_sync (null /* cwd */, + { "pkg-config", "--variable=libexecdir", "libedata-book-1.2" }, + null /* envp */, + SpawnFlags.SEARCH_PATH /* flags */, + null /* child setup */, + out capture_stdout, + null /* do not capture stderr */, + out exit_status); + + Process.check_exit_status (exit_status); + } + catch (GLib.Error e1) + { + error ("Error getting libexecdir from pkg-config: %s", e1.message); + } + + var libexec = capture_stdout.strip (); + + /* Create service files for the Evolution binaries. */ + var service_file_name = + Path.build_filename (this.transient_dir, "dbus-1", "services", + "evolution-source-registry.service"); + var service_file = ("[D-BUS Service]\n" + + "Name=org.gnome.evolution.dataserver.Sources3\n" + + "Exec=%s/evolution-source-registry\n").printf (libexec); + + try + { + FileUtils.set_contents (service_file_name, service_file); + } + catch (FileError e2) + { + error ("Error creating D-Bus service file ‘%s’: %s", + service_file_name, e2.message); + } + + /* Address book factory. */ + service_file_name = + Path.build_filename (this.transient_dir, "dbus-1", "services", + "evolution-addressbook-factory.service"); + service_file = ("[D-BUS Service]\n" + + "Name=org.gnome.evolution.dataserver.AddressBook6\n" + + "Exec=%s/evolution-addressbook-factory\n").printf (libexec); + + try + { + FileUtils.set_contents (service_file_name, service_file); + } + catch (FileError e3) + { + error ("Error creating D-Bus service file ‘%s’: %s", + service_file_name, e3.message); + } } public override void set_up () diff --git a/tests/lib/folks-test-dbus.vapi b/tests/lib/folks-test-dbus.vapi new file mode 100644 index 00000000..bc005ebb --- /dev/null +++ b/tests/lib/folks-test-dbus.vapi @@ -0,0 +1,52 @@ +/* + * folks-test-dbus.vapi — a tweaked copy of GTestDBus wrapped in Vala + * + * Copyright © 2014 Philip Withnall + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Authors: + * Philip Withnall <philip@tecnocode.co.uk> + */ + +[CCode (gir_namespace = "Folks", gir_version = "0.6")] +namespace Folks +{ + [CCode (cheader_filename = "gtestdbus.h", cprefix = "FOLKS_TEST_DBUS_")] + [Flags] + public enum TestDBusFlags { + NONE, + SESSION_BUS, + SYSTEM_BUS + } + + [CCode (cheader_filename = "gtestdbus.h")] + public class TestDBus : GLib.Object + { + [CCode (has_construct_function = false)] + public TestDBus (Folks.TestDBusFlags flags); + public void add_service_dir (string path); + public void down (); + public unowned string get_bus_address (); + public Folks.TestDBusFlags get_flags (); + public void stop (); + public static void unset (); + public void up (); + public Folks.TestDBusFlags flags { get; construct; } + } +} + +/* vim:set ft=vala: */ diff --git a/tests/lib/gtestdbus.c b/tests/lib/gtestdbus.c new file mode 100644 index 00000000..cca9435a --- /dev/null +++ b/tests/lib/gtestdbus.c @@ -0,0 +1,941 @@ +/* GIO testing utilities + * + * Copyright (C) 2008-2010 Red Hat, Inc. + * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Authors: David Zeuthen <davidz@redhat.com> + * Xavier Claessens <xavier.claessens@collabora.co.uk> + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <glib/gstdio.h> +#ifdef G_OS_UNIX +#include <unistd.h> +#endif +#ifdef G_OS_WIN32 +#include <io.h> +#endif + +#include <glib.h> +#include <gio/gio.h> + +#include "gtestdbus.h" + +#ifdef G_OS_WIN32 +#include <windows.h> +#endif + +GType +folks_test_dbus_flags_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const GFlagsValue values[] = { + { FOLKS_TEST_DBUS_NONE, "FOLKS_TEST_DBUS_NONE", "none" }, + { FOLKS_TEST_DBUS_SESSION_BUS, "FOLKS_TEST_DBUS_SESSION_BUS", "session-bus" }, + { FOLKS_TEST_DBUS_SYSTEM_BUS, "FOLKS_TEST_DBUS_SYSTEM_BUS", "system-bus" }, + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_flags_register_static (g_intern_static_string ("FolksTestDBusFlags"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +/* -------------------------------------------------------------------------- */ +/* Utility: Wait until object has a single ref */ + +typedef struct +{ + GMainLoop *loop; + gboolean timed_out; +} WeakNotifyData; + +static gboolean +on_weak_notify_timeout (gpointer user_data) +{ + WeakNotifyData *data = user_data; + data->timed_out = TRUE; + g_main_loop_quit (data->loop); + return FALSE; +} + +static gboolean +dispose_on_idle (gpointer object) +{ + g_object_run_dispose (object); + g_object_unref (object); + return FALSE; +} + +static gboolean +_g_object_dispose_and_wait_weak_notify (gpointer object) +{ + WeakNotifyData data; + guint timeout_id; + + data.loop = g_main_loop_new (NULL, FALSE); + data.timed_out = FALSE; + + g_object_weak_ref (object, (GWeakNotify) g_main_loop_quit, data.loop); + + /* Drop the ref in an idle callback, this is to make sure the mainloop + * is already running when weak notify happens */ + g_idle_add (dispose_on_idle, object); + + /* Make sure we don't block forever */ + timeout_id = g_timeout_add (30 * 1000, on_weak_notify_timeout, &data); + + g_main_loop_run (data.loop); + + if (data.timed_out) + { + g_warning ("Weak notify timeout, object ref_count=%d\n", + G_OBJECT (object)->ref_count); + } + else + { + g_source_remove (timeout_id); + } + + g_main_loop_unref (data.loop); + return data.timed_out; +} + +/* -------------------------------------------------------------------------- */ +/* Utilities to cleanup the mess in the case unit test process crash */ + +#ifdef G_OS_WIN32 + +/* This could be interesting to expose in public API */ +static void +_folks_test_watcher_add_pid (GPid pid) +{ + static gsize started = 0; + HANDLE job; + + if (g_once_init_enter (&started)) + { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; + + job = CreateJobObjectW (NULL, NULL); + memset (&info, 0, sizeof (info)); + info.BasicLimitInformation.LimitFlags = 0x2000 /* JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE */; + + if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof (info))) + g_warning ("Can't enable JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: %s", g_win32_error_message (GetLastError())); + + g_once_init_leave (&started,(gsize)job); + } + + job = (HANDLE)started; + + if (!AssignProcessToJobObject(job, pid)) + g_warning ("Can't assign process to job: %s", g_win32_error_message (GetLastError())); +} + +static void +_folks_test_watcher_remove_pid (GPid pid) +{ + /* No need to unassign the process from the job object as the process + will be killed anyway */ +} + +#else + +#define ADD_PID_FORMAT "add pid %d\n" +#define REMOVE_PID_FORMAT "remove pid %d\n" + +static void +watch_parent (gint fd) +{ + GIOChannel *channel; + GPollFD fds[1]; + GArray *pids_to_kill; + + channel = g_io_channel_unix_new (fd); + + fds[0].fd = fd; + fds[0].events = G_IO_HUP | G_IO_IN; + fds[0].revents = 0; + + pids_to_kill = g_array_new (FALSE, FALSE, sizeof (guint)); + + do + { + gint num_events; + gchar *command = NULL; + guint pid; + guint n; + GError *error = NULL; + + num_events = g_poll (fds, 1, -1); + if (num_events == 0) + continue; + + if (fds[0].revents == G_IO_HUP) + { + /* Parent quit, cleanup the mess and exit */ + for (n = 0; n < pids_to_kill->len; n++) + { + pid = g_array_index (pids_to_kill, guint, n); + g_print ("cleaning up pid %d\n", pid); + kill (pid, SIGTERM); + } + + g_array_unref (pids_to_kill); + g_io_channel_shutdown (channel, FALSE, &error); + g_assert_no_error (error); + g_io_channel_unref (channel); + + exit (0); + } + + /* Read the command from the input */ + g_io_channel_read_line (channel, &command, NULL, NULL, &error); + g_assert_no_error (error); + + /* Check for known commands */ + if (sscanf (command, ADD_PID_FORMAT, &pid) == 1) + { + g_array_append_val (pids_to_kill, pid); + } + else if (sscanf (command, REMOVE_PID_FORMAT, &pid) == 1) + { + for (n = 0; n < pids_to_kill->len; n++) + { + if (g_array_index (pids_to_kill, guint, n) == pid) + { + g_array_remove_index (pids_to_kill, n); + pid = 0; + break; + } + } + if (pid != 0) + { + g_warning ("unknown pid %d to remove", pid); + } + } + else + { + g_warning ("unknown command from parent '%s'", command); + } + + g_free (command); + } + while (TRUE); +} + +static GIOChannel * +watcher_init (void) +{ + static gsize started = 0; + static GIOChannel *channel = NULL; + + if (g_once_init_enter (&started)) + { + gint pipe_fds[2]; + + /* fork a child to clean up when we are killed */ + if (pipe (pipe_fds) != 0) + { + g_warning ("pipe() failed: %m"); + g_assert_not_reached (); + } + + switch (fork ()) + { + case -1: + g_warning ("fork() failed: %m"); + g_assert_not_reached (); + break; + + case 0: + /* child */ + close (pipe_fds[1]); + watch_parent (pipe_fds[0]); + break; + + default: + /* parent */ + close (pipe_fds[0]); + channel = g_io_channel_unix_new (pipe_fds[1]); + } + + g_once_init_leave (&started, 1); + } + + return channel; +} + +static void +watcher_send_command (const gchar *command) +{ + GIOChannel *channel; + GError *error = NULL; + + channel = watcher_init (); + + g_io_channel_write_chars (channel, command, -1, NULL, &error); + g_assert_no_error (error); + + g_io_channel_flush (channel, &error); + g_assert_no_error (error); +} + +/* This could be interesting to expose in public API */ +static void +_folks_test_watcher_add_pid (GPid pid) +{ + gchar *command; + + command = g_strdup_printf (ADD_PID_FORMAT, (guint) pid); + watcher_send_command (command); + g_free (command); +} + +static void +_folks_test_watcher_remove_pid (GPid pid) +{ + gchar *command; + + command = g_strdup_printf (REMOVE_PID_FORMAT, (guint) pid); + watcher_send_command (command); + g_free (command); +} + +#endif + +/* -------------------------------------------------------------------------- */ +/* FolksTestDBus object implementation */ + +/** + * SECTION:folkstestdbus + * @short_description: D-Bus testing helper + * @include: gio/gio.h + * + * A helper class for testing code which uses D-Bus without touching the user's + * system or session bus. + * + * Note that #FolksTestDBus modifies the user’s environment, calling setenv(). + * This is not thread-safe, so all #FolksTestDBus calls should be completed before + * threads are spawned, or should have appropriate locking to ensure no access + * conflicts to environment variables shared between #FolksTestDBus and other + * threads. + * + * ## Creating unit tests using FolksTestDBus + * + * Testing of D-Bus services can be tricky because normally we only ever run + * D-Bus services over an existing instance of the D-Bus daemon thus we + * usually don't activate D-Bus services that are not yet installed into the + * target system. The #FolksTestDBus object makes this easier for us by taking care + * of the lower level tasks such as running a private D-Bus daemon and looking + * up uninstalled services in customizable locations, typically in your source + * code tree. + * + * The first thing you will need is a separate service description file for the + * D-Bus daemon. Typically a `services` subdirectory of your `tests` directory + * is a good place to put this file. + * + * The service file should list your service along with an absolute path to the + * uninstalled service executable in your source tree. Using autotools we would + * achieve this by adding a file such as `my-server.service.in` in the services + * directory and have it processed by configure. + * |[ + * [D-BUS Service] + * Name=org.gtk.GDBus.Examples.ObjectManager + * Exec=@abs_top_builddir@/gio/tests/gdbus-example-objectmanager-server + * ]| + * You will also need to indicate this service directory in your test + * fixtures, so you will need to pass the path while compiling your + * test cases. Typically this is done with autotools with an added + * preprocessor flag specified to compile your tests such as: + * |[ + * -DTEST_SERVICES=\""$(abs_top_builddir)/tests/services"\" + * ]| + * Once you have a service definition file which is local to your source tree, + * you can proceed to set up a GTest fixture using the #FolksTestDBus scaffolding. + * + * An example of a test fixture for D-Bus services can be found + * here: + * [gdbus-test-fixture.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-test-fixture.c) + * + * The default behaviour is to create a session bus. The + * %FOLKS_TEST_DBUS_SESSION_BUS flag may be specified to clarify this, but it + * isn’t required. + * + * If your service needs to run on the system bus, rather than the session + * bus, pass the %FOLKS_TEST_DBUS_SYSTEM_BUS flag to folks_test_dbus_new(). This + * will create an isolated system bus. Using two #GTestDBus instances, one + * with this flag set and one without, a unit test can use isolated services + * on both the system and session buses. + * + * Note that these examples only deal with isolating the D-Bus aspect of your + * service. To successfully run isolated unit tests on your service you may need + * some additional modifications to your test case fixture. For example; if your + * service uses GSettings and installs a schema then it is important that your test service + * not load the schema in the ordinary installed location (chances are that your service + * and schema files are not yet installed, or worse; there is an older version of the + * schema file sitting in the install location). + * + * Most of the time we can work around these obstacles using the + * environment. Since the environment is inherited by the D-Bus daemon + * created by #FolksTestDBus and then in turn inherited by any services the + * D-Bus daemon activates, using the setup routine for your fixture is + * a practical place to help sandbox your runtime environment. For the + * rather typical GSettings case we can work around this by setting + * `GSETTINGS_SCHEMA_DIR` to the in tree directory holding your schemas + * in the above fixture_setup() routine. + * + * The GSettings schemas need to be locally pre-compiled for this to work. This can be achieved + * by compiling the schemas locally as a step before running test cases, an autotools setup might + * do the following in the directory holding schemas: + * |[ + * all-am: + * $(GLIB_COMPILE_SCHEMAS) . + * + * CLEANFILES += gschemas.compiled + * ]| + */ + +typedef struct _FolksTestDBusClass FolksTestDBusClass; +typedef struct _FolksTestDBusPrivate FolksTestDBusPrivate; + +/** + * FolksTestDBus: + * + * The #FolksTestDBus structure contains only private data and + * should only be accessed using the provided API. + * + * Since: 2.34 + */ +struct _FolksTestDBus { + GObject parent; + + FolksTestDBusPrivate *priv; +}; + +struct _FolksTestDBusClass { + GObjectClass parent_class; +}; + +struct _FolksTestDBusPrivate +{ + FolksTestDBusFlags flags; + GPtrArray *service_dirs; + GPid bus_pid; + gchar *bus_address; + gboolean up; +}; + +enum +{ + PROP_0, + PROP_FLAGS, +}; + +G_DEFINE_TYPE_WITH_PRIVATE (FolksTestDBus, folks_test_dbus, G_TYPE_OBJECT) + +static void +folks_test_dbus_init (FolksTestDBus *self) +{ + self->priv = folks_test_dbus_get_instance_private (self); + self->priv->service_dirs = g_ptr_array_new_with_free_func (g_free); +} + +static void +folks_test_dbus_dispose (GObject *object) +{ + FolksTestDBus *self = (FolksTestDBus *) object; + + if (self->priv->up) + folks_test_dbus_down (self); + + G_OBJECT_CLASS (folks_test_dbus_parent_class)->dispose (object); +} + +static void +folks_test_dbus_finalize (GObject *object) +{ + FolksTestDBus *self = (FolksTestDBus *) object; + + g_ptr_array_unref (self->priv->service_dirs); + g_free (self->priv->bus_address); + + G_OBJECT_CLASS (folks_test_dbus_parent_class)->finalize (object); +} + +static void +folks_test_dbus_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + FolksTestDBus *self = (FolksTestDBus *) object; + + switch (property_id) + { + case PROP_FLAGS: + g_value_set_flags (value, folks_test_dbus_get_flags (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +folks_test_dbus_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + FolksTestDBus *self = (FolksTestDBus *) object; + + switch (property_id) + { + case PROP_FLAGS: + self->priv->flags = g_value_get_flags (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +folks_test_dbus_class_init (FolksTestDBusClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = folks_test_dbus_dispose; + object_class->finalize = folks_test_dbus_finalize; + object_class->get_property = folks_test_dbus_get_property; + object_class->set_property = folks_test_dbus_set_property; + + /** + * FolksTestDBus:flags: + * + * #FolksTestDBusFlags specifying the behaviour of the D-Bus session. + * + * Since: 2.34 + */ + g_object_class_install_property (object_class, PROP_FLAGS, + g_param_spec_flags ("flags", + "D-Bus session flags", + "Flags specifying the behaviour of the D-Bus session", + FOLKS_TYPE_TEST_DBUS_FLAGS, FOLKS_TEST_DBUS_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + +} + +static gchar * +write_config_file (FolksTestDBus *self) +{ + GString *contents; + gint fd; + guint i; + GError *error = NULL; + gchar *path = NULL; + + fd = g_file_open_tmp ("g-test-dbus-XXXXXX", &path, &error); + g_assert_no_error (error); + + contents = g_string_new (NULL); + g_string_append (contents, + "<busconfig>\n" +#ifdef G_OS_WIN32 + " <listen>nonce-tcp:</listen>\n" +#else + " <listen>unix:tmpdir=/tmp</listen>\n" +#endif + ); + + if (self->priv->flags & FOLKS_TEST_DBUS_SYSTEM_BUS) + { + g_string_append (contents, + " <type>system</type>\n"); + } + else + { + g_string_append (contents, + " <type>session</type>\n"); + } + + for (i = 0; i < self->priv->service_dirs->len; i++) + { + const gchar *dir_path = g_ptr_array_index (self->priv->service_dirs, i); + + g_string_append_printf (contents, + " <servicedir>%s</servicedir>\n", dir_path); + } + + g_string_append (contents, + " <policy context=\"default\">\n" + " <!-- Allow everything to be sent -->\n" + " <allow send_destination=\"*\" eavesdrop=\"true\"/>\n" + " <!-- Allow everything to be received -->\n" + " <allow eavesdrop=\"true\"/>\n" + " <!-- Allow anyone to own anything -->\n" + " <allow own=\"*\"/>\n" + " </policy>\n" + "</busconfig>\n"); + + g_file_set_contents (path, contents->str, contents->len, &error); + g_assert_no_error (error); + + g_string_free (contents, TRUE); + + close (fd); + + return path; +} + +static void +start_daemon (FolksTestDBus *self) +{ + const gchar *argv[] = {"dbus-daemon", "--print-address", "--config-file=foo", NULL}; + gchar *config_path; + gchar *config_arg; + gint stdout_fd; + GIOChannel *channel; + gsize termpos; + GError *error = NULL; + + if (g_getenv ("G_TEST_DBUS_DAEMON") != NULL) + argv[0] = (gchar *)g_getenv ("G_TEST_DBUS_DAEMON"); + + /* Write config file and set its path in argv */ + config_path = write_config_file (self); + config_arg = g_strdup_printf ("--config-file=%s", config_path); + argv[2] = config_arg; + + /* Spawn dbus-daemon */ + g_spawn_async_with_pipes (NULL, + (gchar **) argv, + NULL, +#ifdef G_OS_WIN32 + /* We Need this to get the pid returned on win32 */ + G_SPAWN_DO_NOT_REAP_CHILD | +#endif + G_SPAWN_SEARCH_PATH, + NULL, + NULL, + &self->priv->bus_pid, + NULL, + &stdout_fd, + NULL, + &error); + g_assert_no_error (error); + + _folks_test_watcher_add_pid (self->priv->bus_pid); + + /* Read bus address from daemon' stdout */ + channel = g_io_channel_unix_new (stdout_fd); + g_io_channel_read_line (channel, &self->priv->bus_address, NULL, + &termpos, &error); + g_assert_no_error (error); + self->priv->bus_address[termpos] = '\0'; + + /* start dbus-monitor */ + if (g_getenv ("G_DBUS_MONITOR") != NULL) + { + gchar *command; + + command = g_strdup_printf ("dbus-monitor --address %s", + self->priv->bus_address); + g_spawn_command_line_async (command, NULL); + g_free (command); + + g_usleep (500 * 1000); + } + + /* Cleanup */ + g_io_channel_shutdown (channel, FALSE, &error); + g_assert_no_error (error); + g_io_channel_unref (channel); + + /* Don't use g_file_delete since it calls into gvfs */ + if (g_unlink (config_path) != 0) + g_assert_not_reached (); + + g_free (config_path); + g_free (config_arg); +} + +static void +stop_daemon (FolksTestDBus *self) +{ +#ifdef G_OS_WIN32 + if (!TerminateProcess (self->priv->bus_pid, 0)) + g_warning ("Can't terminate process: %s", g_win32_error_message (GetLastError())); +#else + kill (self->priv->bus_pid, SIGTERM); +#endif + _folks_test_watcher_remove_pid (self->priv->bus_pid); + g_spawn_close_pid (self->priv->bus_pid); + self->priv->bus_pid = 0; + + g_free (self->priv->bus_address); + self->priv->bus_address = NULL; +} + +static void +common_envar_unset (void) +{ + /* Always want to unset the starter address since we don't support simulating + * auto-launched buses */ + g_unsetenv ("DISPLAY"); + g_unsetenv ("DBUS_SESSION_BUS_PID"); + g_unsetenv ("DBUS_SESSION_BUS_WINDOWID"); + g_unsetenv ("DBUS_STARTER_ADDRESS"); + g_unsetenv ("DBUS_STARTER_BUS_TYPE"); +} + +static void +partial_envar_unset (GBusType bus_type) +{ + common_envar_unset (); + + switch (bus_type) + { + case G_BUS_TYPE_SESSION: + g_unsetenv ("DBUS_SESSION_BUS_ADDRESS"); + break; + case G_BUS_TYPE_SYSTEM: + g_unsetenv ("DBUS_SYSTEM_BUS_ADDRESS"); + break; + case G_BUS_TYPE_STARTER: + case G_BUS_TYPE_NONE: + default: + break; + } +} + +/** + * folks_test_dbus_new: + * @flags: a #FolksTestDBusFlags + * + * Create a new #FolksTestDBus object. + * + * Returns: (transfer full): a new #FolksTestDBus. + */ +FolksTestDBus * +folks_test_dbus_new (FolksTestDBusFlags flags) +{ + return g_object_new (FOLKS_TYPE_TEST_DBUS, + "flags", flags, + NULL); +} + +/** + * folks_test_dbus_get_flags: + * @self: a #FolksTestDBus + * + * Get the flags of the #FolksTestDBus object. + * + * Returns: the value of #FolksTestDBus:flags property + */ +FolksTestDBusFlags +folks_test_dbus_get_flags (FolksTestDBus *self) +{ + g_return_val_if_fail (FOLKS_IS_TEST_DBUS (self), FOLKS_TEST_DBUS_NONE); + + return self->priv->flags; +} + +/** + * folks_test_dbus_get_bus_address: + * @self: a #FolksTestDBus + * + * Get the address on which dbus-daemon is running. If folks_test_dbus_up() has not + * been called yet, %NULL is returned. This can be used with + * g_dbus_connection_new_for_address(). + * + * Returns: (allow-none): the address of the bus, or %NULL. + */ +const gchar * +folks_test_dbus_get_bus_address (FolksTestDBus *self) +{ + g_return_val_if_fail (FOLKS_IS_TEST_DBUS (self), NULL); + + return self->priv->bus_address; +} + +/** + * folks_test_dbus_add_service_dir: + * @self: a #FolksTestDBus + * @path: path to a directory containing .service files + * + * Add a path where dbus-daemon will look up .service files. This can't be + * called after folks_test_dbus_up(). + */ +void +folks_test_dbus_add_service_dir (FolksTestDBus *self, + const gchar *path) +{ + g_return_if_fail (FOLKS_IS_TEST_DBUS (self)); + g_return_if_fail (self->priv->bus_address == NULL); + + g_ptr_array_add (self->priv->service_dirs, g_strdup (path)); +} + +/** + * folks_test_dbus_up: + * @self: a #FolksTestDBus + * + * Start a dbus-daemon instance and set <envar>DBUS_SESSION_BUS_ADDRESS</envar> + * or <envar>DBUS_SYSTEM_BUS_ADDRESS</envar> (if the %FOLKS_TEST_DBUS_SYSTEM_BUS + * flag was passed to folks_test_dbus_new()). After this call, it is safe for + * unit tests to start sending messages on the session (or system) bus. + * + * If this function is called from the setup callback of g_test_add(), + * folks_test_dbus_down() must be called in its teardown callback. + * + * If this function is called from unit test's main(), then folks_test_dbus_down() + * must be called after g_test_run(). + * + * As a side-effect, this function unsets the <envar>DISPLAY</envar>, + * <envar>DBUS_STARTER_BUS_ADDRESS</envar> and + * <envar>DBUS_STARTER_BUS_TYPE</envar> environment variables. It does not unset + * <envar>DBUS_SESSION_BUS_ADDRESS</envar> if a system bus is being spawned, + * and similarly for <envar>BUS_SYSTEM_BUS_ADDRESS</envar> with a session bus. + */ +void +folks_test_dbus_up (FolksTestDBus *self) +{ + const gchar *envar; + GBusType bus_type; + + g_return_if_fail (FOLKS_IS_TEST_DBUS (self)); + g_return_if_fail (self->priv->bus_address == NULL); + g_return_if_fail (!self->priv->up); + + start_daemon (self); + + bus_type = (self->priv->flags & FOLKS_TEST_DBUS_SYSTEM_BUS) ? + G_BUS_TYPE_SYSTEM : + G_BUS_TYPE_SESSION; + partial_envar_unset (bus_type); + + envar = (self->priv->flags & FOLKS_TEST_DBUS_SYSTEM_BUS) ? + "DBUS_SYSTEM_BUS_ADDRESS" : + "DBUS_SESSION_BUS_ADDRESS"; + g_setenv (envar, self->priv->bus_address, TRUE); + + self->priv->up = TRUE; +} + + +/** + * folks_test_dbus_stop: + * @self: a #FolksTestDBus + * + * Stop the session (or system) bus started by folks_test_dbus_up(). + * + * Unlike folks_test_dbus_down(), this won't verify the #GDBusConnection + * singleton returned by g_bus_get() or g_bus_get_sync() is destroyed. Unit + * tests wanting to verify behaviour after the bus has been stopped + * can use this function but should still call folks_test_dbus_down() when done. + */ +void +folks_test_dbus_stop (FolksTestDBus *self) +{ + g_return_if_fail (FOLKS_IS_TEST_DBUS (self)); + g_return_if_fail (self->priv->bus_address != NULL); + + stop_daemon (self); +} + +/** + * folks_test_dbus_down: + * @self: a #FolksTestDBus + * + * Stop the session (or system) bus started by folks_test_dbus_up(). + * + * This will wait for the singleton returned by g_bus_get() or g_bus_get_sync() + * is destroyed. This is done to ensure that the next unit test won't get a + * leaked singleton from this test. + * + * As a side-effect, this function unsets the <envar>DISPLAY</envar>, + * <envar>DBUS_STARTER_BUS_ADDRESS</envar> and + * <envar>DBUS_STARTER_BUS_TYPE</envar> environment variables. It does not unset + * <envar>DBUS_SESSION_BUS_ADDRESS</envar> if a system bus is being shut down, + * and similarly for <envar>BUS_SYSTEM_BUS_ADDRESS</envar> with a session bus. + */ +void +folks_test_dbus_down (FolksTestDBus *self) +{ + GBusType bus_type; + GDBusConnection *connection; + + g_return_if_fail (FOLKS_IS_TEST_DBUS (self)); + g_return_if_fail (self->priv->up); + + bus_type = (self->priv->flags & FOLKS_TEST_DBUS_SYSTEM_BUS) ? + G_BUS_TYPE_SYSTEM : + G_BUS_TYPE_SESSION; + + connection = g_bus_get_sync (bus_type, NULL, NULL); + if (connection != NULL) + g_dbus_connection_set_exit_on_close (connection, FALSE); + + if (self->priv->bus_address != NULL) + stop_daemon (self); + + if (connection != NULL) + _g_object_dispose_and_wait_weak_notify (connection); + + partial_envar_unset (bus_type); + self->priv->up = FALSE; +} + +/** + * folks_test_dbus_unset: + * + * Unset various D-Bus environment variables to ensure the test won't use the + * user's session (or system) bus: + * <itemizedlist> + * <listitem><para>DISPLAY</para></listitem> + * <listitem><para>DBUS_SESSION_BUS_ADDRESS</para></listitem> + * <listitem><para>DBUS_SESSION_BUS_PID</para></listitem> + * <listitem><para>DBUS_SESSION_BUS_WINDOWID</para></listitem> + * <listitem><para>DBUS_SYSTEM_BUS_ADDRESS</para></listitem> + * <listitem><para>DBUS_STARTER_ADDRESS</para></listitem> + * <listitem><para>DBUS_STARTER_BUS_TYPE</para></listitem> + * </itemizedlist> + * + * This is useful for unit tests that want to verify behaviour when no session + * (or system) bus is running. It is not necessary to call this if the unit test + * already calls folks_test_dbus_up() before acquiring the bus. + */ +void +folks_test_dbus_unset (void) +{ + /* See also: partial_envar_unset(). */ + common_envar_unset (); + + g_unsetenv ("DBUS_SESSION_BUS_ADDRESS"); + g_unsetenv ("DBUS_SYSTEM_BUS_ADDRESS"); +} diff --git a/tests/lib/gtestdbus.h b/tests/lib/gtestdbus.h new file mode 100644 index 00000000..2c726db7 --- /dev/null +++ b/tests/lib/gtestdbus.h @@ -0,0 +1,90 @@ +/* GIO testing utilities + * + * Copyright (C) 2008-2010 Red Hat, Inc. + * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Authors: David Zeuthen <davidz@redhat.com> + * Xavier Claessens <xavier.claessens@collabora.co.uk> + */ + +#ifndef __FOLKS_TEST_DBUS_H__ +#define __FOLKS_TEST_DBUS_H__ + +#include <gio/gio.h> + +G_BEGIN_DECLS + +/** + * FolksTestDBusFlags: + * @FOLKS_TEST_DBUS_NONE: No flags. + * @FOLKS_TEST_DBUS_SESSION_BUS: Create a session bus (the default). + * @FOLKS_TEST_DBUS_SYSTEM_BUS: Create a system bus instead of a session bus. + * + * Flags to define #FolksTestDBus behaviour. + * + * Since: 2.34 + */ +typedef enum /*< flags >*/ { + FOLKS_TEST_DBUS_NONE = 0, + FOLKS_TEST_DBUS_SESSION_BUS = 0, /* default; same as NONE */ + FOLKS_TEST_DBUS_SYSTEM_BUS = 1 << 0, +} FolksTestDBusFlags; + +#define FOLKS_TYPE_TEST_DBUS_FLAGS (folks_test_dbus_flags_get_type ()) +GType folks_test_dbus_flags_get_type (void) G_GNUC_CONST; + +typedef struct _FolksTestDBus FolksTestDBus; + + +#define FOLKS_TYPE_TEST_DBUS \ + (folks_test_dbus_get_type ()) +#define FOLKS_TEST_DBUS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOLKS_TYPE_TEST_DBUS, \ + FolksTestDBus)) +#define FOLKS_IS_TEST_DBUS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOLKS_TYPE_TEST_DBUS)) + +GLIB_AVAILABLE_IN_2_34 +GType folks_test_dbus_get_type (void) G_GNUC_CONST; + +GLIB_AVAILABLE_IN_2_34 +FolksTestDBus * folks_test_dbus_new (FolksTestDBusFlags flags); + +GLIB_AVAILABLE_IN_2_34 +FolksTestDBusFlags folks_test_dbus_get_flags (FolksTestDBus *self); + +GLIB_AVAILABLE_IN_2_34 +const gchar * folks_test_dbus_get_bus_address (FolksTestDBus *self); + +GLIB_AVAILABLE_IN_2_34 +void folks_test_dbus_add_service_dir (FolksTestDBus *self, + const gchar *path); + +GLIB_AVAILABLE_IN_2_34 +void folks_test_dbus_up (FolksTestDBus *self); + +GLIB_AVAILABLE_IN_2_34 +void folks_test_dbus_stop (FolksTestDBus *self); + +GLIB_AVAILABLE_IN_2_34 +void folks_test_dbus_down (FolksTestDBus *self); + +GLIB_AVAILABLE_IN_2_34 +void folks_test_dbus_unset (void); + +G_END_DECLS + +#endif /* __FOLKS_TEST_DBUS_H__ */ diff --git a/tests/lib/key-file/Makefile.am b/tests/lib/key-file/Makefile.am index ebb067ba..a909d78a 100644 --- a/tests/lib/key-file/Makefile.am +++ b/tests/lib/key-file/Makefile.am @@ -14,6 +14,7 @@ libkf_test_la_VALAFLAGS = \ --vapidir=$(abs_top_srcdir)/tests/lib \ --vapidir=$(abs_top_builddir)/tests/lib \ --pkg folks-test \ + --pkg folks-test-dbus \ -g \ $(NULL) diff --git a/tests/lib/libsocialweb/Makefile.am b/tests/lib/libsocialweb/Makefile.am index f186fe54..252813d7 100644 --- a/tests/lib/libsocialweb/Makefile.am +++ b/tests/lib/libsocialweb/Makefile.am @@ -19,6 +19,7 @@ libsocialweb_test_la_VALAFLAGS = \ --pkg libsocialweb-client \ --pkg folks-libsocialweb \ --pkg folks-test \ + --pkg folks-test-dbus \ -g \ $(NULL) diff --git a/tests/lib/org-freedesktop-dbus-mock.vala b/tests/lib/org-freedesktop-dbus-mock.vala new file mode 100644 index 00000000..386477f0 --- /dev/null +++ b/tests/lib/org-freedesktop-dbus-mock.vala @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2013 Collabora Ltd. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Philip Withnall <philip.withnall@collabora.co.uk> + */ + +using GLib; + +/** + * Vala wrapper for the standard org.freedesktop.DBus.Mock interface. + * + * This is exposed by python-dbusmock as the primary means of controlling a + * mocked up D-Bus service. + * + * @since UNRELEASED + */ + +/* Reference: + * http://bazaar.launchpad.net/~pitti/python-dbusmock/trunk/view/head:/README.rst */ +namespace org + { + namespace freedesktop + { + namespace DBus + { + [DBus (name = "org.freedesktop.DBus.Mock")] + public interface Mock : Object + { + /* Signals. */ + [DBus (name = "MethodCalled")] + public abstract signal void method_called (string method_name, + Variant[] args); + + /* Methods. */ + [DBus (name = "AddMethod")] + public abstract void add_method (string interface_name, + string name, string in_sig, string out_sig, string code) + throws IOError; + + /* Parameter to AddMethods(). */ + public struct Method + { + public string name; + public string in_sig; + public string out_sig; + } + + [DBus (name = "AddMethods")] + public abstract void add_methods (string interface_name, + Method[] methods) throws IOError; + + [DBus (name = "AddObject")] + public abstract void add_object (string path, + string interface_name, + HashTable<string, Variant> properties, Method[] methods) + throws IOError; + + [DBus (name = "AddProperties")] + public abstract void add_properties (string interface_name, + HashTable<string, Variant> properties) throws IOError; + + [DBus (name = "AddProperty")] + public abstract void add_property (string interface_name, + string name, Variant val) throws IOError; + + [DBus (name = "AddTemplate")] + public abstract void add_template (string template_name, + HashTable<string, Variant> template_params) + throws IOError; + + [DBus (name = "ClearCalls")] + public abstract void clear_calls () throws IOError; + + [DBus (name = "EmitSignal")] + public abstract void emit_signal (string interface_name, + string name, string signature, Variant[] args) + throws IOError; + + /* Returned by GetCalls(). */ + public struct Call + { + public uint64 call_time; + public string method_name; + public Variant[] args; + } + + [DBus (name = "GetCalls")] + public abstract Call[] get_calls () throws IOError; + + /* Returned by GetMethodCalls(). */ + public struct MethodCall + { + public uint64 call_time; + public Variant[] args; + } + + [DBus (name = "GetMethodCalls")] + public abstract MethodCall[] get_method_calls (string method) + throws IOError; + + [DBus (name = "RemoveObject")] + public abstract void remove_object (string path) + throws IOError; + + [DBus (name = "Reset")] + public abstract void reset () throws IOError; + } + } + } + } diff --git a/tests/lib/telepathy/Makefile.am b/tests/lib/telepathy/Makefile.am index 159073b0..648249e2 100644 --- a/tests/lib/telepathy/Makefile.am +++ b/tests/lib/telepathy/Makefile.am @@ -21,7 +21,9 @@ libtpf_test_la_VALAFLAGS = \ --vapidir=$(abs_top_builddir)/tests/lib \ --vapidir=$(abs_top_srcdir)/tests/lib/key-file \ --vapidir=$(abs_top_builddir)/tests/lib/key-file \ + --pkg build-conf \ --pkg folks-test \ + --pkg folks-test-dbus \ --pkg kf-test \ --pkg tp-test-contactlist \ -g \ @@ -33,7 +35,14 @@ libtpf_test_la_SOURCES = \ libtpf_test_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/folks \ + -include $(CONFIG_HEADER) \ -include $(top_srcdir)/folks/warnings.h \ + -DABS_TOP_SRCDIR=\"${abs_top_srcdir}\" \ + -DABS_TOP_BUILDDIR=\"${abs_top_builddir}\" \ + -DPKGLIBEXECDIR=\"${pkglibexecdir}\" \ + -DPACKAGE_DATADIR=\"${pkgdatadir}\" \ $(NULL) libtpf_test_la_CFLAGS = \ diff --git a/tests/lib/telepathy/test-case.vala b/tests/lib/telepathy/test-case.vala index 54343c76..28ff908d 100644 --- a/tests/lib/telepathy/test-case.vala +++ b/tests/lib/telepathy/test-case.vala @@ -129,6 +129,11 @@ public class TpfTest.TestCase : Folks.TestCase */ public virtual void create_kf_backend () { + /* Default key-file backend file to load. */ + Environment.set_variable ("FOLKS_BACKEND_KEY_FILE_PATH", + Folks.BuildConf.ABS_TOP_SRCDIR + "/data/relationships-empty.ini", + true); + if (use_keyfile_too) this.kf_backend = new KfTest.Backend (); } diff --git a/tests/lib/test-case.vala b/tests/lib/test-case.vala index a174f647..febc251e 100644 --- a/tests/lib/test-case.vala +++ b/tests/lib/test-case.vala @@ -41,6 +41,13 @@ public abstract class Folks.TestCase : Object { Intl.setlocale (LocaleCategory.ALL, ""); + /* Enable all debug output from libfolks. This is OK, as automake-1.12’s + * parallel test harness will only save the debug output from failed + * tests. If the user’s already set those variables, though, don’t + * overwrite them. */ + Environment.set_variable ("G_MESSAGES_DEBUG", "all", false); + Environment.set_variable ("FOLKS_DEBUG", "all", false); + /* Turn off use of gvfs. If using GTestDBus it's unavailable, * and if not it's pointless: all we need is the local filesystem. */ Environment.set_variable ("GIO_USE_VFS", "local", true); @@ -79,6 +86,9 @@ public abstract class Folks.TestCase : Object if (Folks.BuildConf.HAVE_TRACKER) locations += Folks.BuildConf.ABS_TOP_BUILDDIR + "/backends/tracker/.libs/tracker.so"; + if (Folks.BuildConf.HAVE_BLUEZ) + locations += Folks.BuildConf.ABS_TOP_BUILDDIR + "/backends/bluez/.libs/bluez.so"; + Environment.set_variable ("FOLKS_BACKEND_PATH", string.joinv (":", locations), true); } @@ -113,12 +123,8 @@ public abstract class Folks.TestCase : Object * * Subclasses may override this method to do additional setup * (create more subdirectories or set more environment variables). - * - * FIXME: Subclasses relying on being called by with-session-bus-*.sh - * may override this method to return null, although we should really - * stop doing that. */ - public virtual string? create_transient_dir () + public virtual string create_transient_dir () { unowned string tmp = Environment.get_tmp_dir (); string transient = "%s/folks-test.XXXXXX".printf (tmp); @@ -167,6 +173,19 @@ public abstract class Folks.TestCase : Object error ("unable to create '%s': %s", runtime, GLib.strerror (GLib.errno)); + /* Directories to contain D-Bus service files. */ + var dbus_system = "%s/dbus-1/system-services".printf (transient); + + if (GLib.DirUtils.create_with_parents (dbus_system, 0700) != 0) + error ("unable to create '%s': %s", + local, GLib.strerror (GLib.errno)); + + var dbus_session = "%s/dbus-1/services".printf (transient); + + if (GLib.DirUtils.create_with_parents (dbus_session, 0700) != 0) + error ("unable to create '%s': %s", + local, GLib.strerror (GLib.errno)); + /* Unset some things we don't want to inherit. In particular, * Tracker might try to index XDG_*_DIR, which we don't want. */ Environment.unset_variable ("XDG_DESKTOP_DIR"); @@ -182,6 +201,87 @@ public abstract class Folks.TestCase : Object } /** + * Create a D-Bus service file for a python-dbusmock service. + * + * Create a service file to allow auto-launching a python-dbusmock service + * which uses the given ``dbusmock_template_name`` to mock up the service + * running at ``bus_name`` on the ``bus_type`` bus (which must either be + * {@link BusType.SYSTEM} or {@link BusType.SESSION}. + * + * This requires Python 3 to be installed and available to run as ``python3`` + * somewhere in the system ``PATH``. + * + * It will create a temporary log file which python-dbusmock will log to if + * launched. The name of the log file will be printed to the test logs. + * + * The D-Bus service file itself will be created in a subdirectory of + * {@link TestCase.transient_dir}, which the {@link TestDBus} instance has + * already been configured to use as a service directory. This requires + * {@link TestCase.create_transient_dir} to have been called already. + * + * @param bus_type the bus the service should be auto-launchable from + * @param bus_name the well-known bus name used by the service + * @param dbusmock_template_name name of the python-dbusmock template to use + * + * @since UNRELEASED + */ + public void create_dbusmock_service (BusType bus_type, string bus_name, + string dbusmock_template_name) + { + string service_dir; + switch (bus_type) + { + case BusType.SYSTEM: + service_dir = "system-services"; + break; + case BusType.SESSION: + service_dir = "services"; + break; + case BusType.STARTER: + case BusType.NONE: + default: + assert_not_reached (); + } + + /* Find where the Python 3 executable is (service files require absolute + * paths). */ + var python = Environment.find_program_in_path ("python3"); + if (python == null) + { + error ("Couldn’t find `python3` in $PATH; can’t run " + + "python-dbusmock."); + } + + /* Create a temporary log file for dbusmock to use. This doesn’t need to + * use mkstemp() because it’s already in a unique temporary directory. */ + var log_file_name = + Path.build_filename (this.transient_dir, + "dbusmock-%s-%s-%s.log".printf (service_dir, bus_name, + dbusmock_template_name)); + Test.message ("python-dbusmock service ‘%s’ (template ‘%s’) will log " + + "to ‘%s’.", bus_name, dbusmock_template_name, log_file_name); + + /* Write out the service file for the dbusmock service. */ + var service_file_name = + Path.build_filename (this.transient_dir, "dbus-1", service_dir, + dbusmock_template_name + ".service"); + var service_file = ("[D-BUS Service]\n" + + "Name=%s\n" + + "Exec=%s -m dbusmock --template %s -l %s\n").printf (bus_name, python, + dbusmock_template_name, log_file_name); + + try + { + FileUtils.set_contents (service_file_name, service_file); + } + catch (FileError e2) + { + error ("Error creating D-Bus service file ‘%s’: %s", + service_file_name, e2.message); + } + } + + /** * A private D-Bus session, normally created by private_bus_up() * from the constructor. * @@ -189,7 +289,17 @@ public abstract class Folks.TestCase : Object * address is frequently treated as process-global (for instance, * libdbus will cache a single session bus connection indefinitely). */ - public GLib.TestDBus? test_dbus = null; + public Folks.TestDBus? test_dbus = null; + + /** + * A private D-Bus system bus, normally created by private_bus_up() from the + * constructor. + * + * As with {@link TestCase.test_dbus} this is per-process. + * + * @since UNRELEASED + */ + public Folks.TestDBus? test_system_dbus = null; /** * If true, libraries involved in this test use dbus-1 (or dbus-glib-1) @@ -211,18 +321,40 @@ public abstract class Folks.TestCase : Object * * This is per-process, not per-test, for the reasons mentioned for * //test_dbus//. + * + * By calling {@link TestCase.create_dbusmock_service} in an overridden + * version of this method, python-dbusmock services may be set up. */ public virtual void private_bus_up () { - Environment.unset_variable ("DBUS_SESSION_BUS_ADDRESS"); - Environment.unset_variable ("DBUS_SESSION_BUS_PID"); + /* Clear out existing bus variables. */ + Folks.TestDBus.unset (); + + /* Set up the system bus first, then shimmy its address sideways. */ + this.test_system_dbus = new Folks.TestDBus (Folks.TestDBusFlags.SYSTEM_BUS); + var test_system_dbus = (!) this.test_system_dbus; + test_system_dbus.add_service_dir ( + this.transient_dir + "/dbus-1/system-services"); - this.test_dbus = new GLib.TestDBus (GLib.TestDBusFlags.NONE); + test_system_dbus.up (); + + var system_bus_address = test_system_dbus.get_bus_address (); + + /* Now the session bus. */ + this.test_dbus = new Folks.TestDBus (Folks.TestDBusFlags.NONE); var test_dbus = (!) this.test_dbus; + test_dbus.add_service_dir (this.transient_dir + "/dbus-1/services"); test_dbus.up (); - assert (Environment.get_variable ("DBUS_SESSION_BUS_ADDRESS") != null); + var session_bus_address = test_dbus.get_bus_address (); + + /* Set the bus addresses. We have to do this manually to prevent GTestDBus + * from unsetting the first bus’ address when starting the second. */ + Environment.set_variable ("DBUS_SYSTEM_BUS_ADDRESS", system_bus_address, + true); + Environment.set_variable ("DBUS_SESSION_BUS_ADDRESS", session_bus_address, + true); /* Tell subprocesses that we're running in a private D-Bus * session, so certain operations that would otherwise be dangerous @@ -290,6 +422,12 @@ public abstract class Folks.TestCase : Object this.test_dbus = null; } + if (this.test_system_dbus != null) + { + ((!) this.test_system_dbus).down (); + this.test_system_dbus = null; + } + if (this._transient_dir != null) { unowned string dir = (!) this._transient_dir; diff --git a/tests/lib/test-utils.vala b/tests/lib/test-utils.vala index cbdc4192..67f12481 100644 --- a/tests/lib/test-utils.vala +++ b/tests/lib/test-utils.vala @@ -342,6 +342,98 @@ public class Folks.TestUtils } /** + * Wait for the given personas to be added to or removed from an aggregator. + * + * This will yield until all of the personas listed in + * ``expected_added_persona_names`` are added to the aggregator; or until all + * of the personas listed in ``expected_removed_persona_names`` are removed + * from it. Only one of the two arrays may be non-empty; this method does not + * currently implement checking of complex individual change notifications. + * + * No timeout is used, so if the aggregator never adds or removes all the + * expected personas, this function will never return; callers must add their + * own timeout to avoid this if necessary. On return from this function, all + * of the given names are guaranteed to exist in the aggregator. + * + * The names in ``expected_added_persona_names`` and + * ``expected_removed_persona_names`` must be those appearing in the + * {@link NameDetails.full_name} property of the personas (and hence of the + * individuals). + * + * @param aggregator the aggregator to check + * @param expected_added_persona_names set of full names of the expected + * personas to be added + * @param expected_removed_persona_names set of full names of the expected + * personas to be removed + * + * @since UNRELEASED + */ + public static async void aggregator_wait_for_individuals ( + IndividualAggregator aggregator, string[] expected_added_persona_names, + string[] expected_removed_persona_names) + { + /* Currently only support waiting for all additions or all removals. */ + assert (expected_added_persona_names.length == 0 || + expected_removed_persona_names.length == 0); + + var expected_added = new HashSet<string> (); + var expected_removed = new HashSet<string> (); + + foreach (var name in expected_added_persona_names) + expected_added.add (name); + foreach (var name in expected_removed_persona_names) + expected_removed.add (name); + + /* Set up the aggregator */ + var signal_id = aggregator.individuals_changed_detailed.connect ( + (changes) => + { + var added = changes.get_values (); + var removed = changes.get_keys (); + + foreach (Individual i in added) + { + if (expected_added.size == 0) + { + assert (i == null); + break; + } + + assert (i != null); + + var name_details = i as NameDetails; + assert (name_details != null); + expected_added.remove (name_details.full_name); + } + + foreach (var i in removed) + { + if (expected_removed.size == 0) + { + assert (i == null); + break; + } + + assert (i != null); + + var name_details = i as NameDetails; + assert (name_details != null); + expected_removed.remove (name_details.full_name); + } + + + /* Finished? */ + if (expected_added.size == 0 && expected_removed.size == 0) + TestUtils.aggregator_wait_for_individuals.callback (); + }); + + yield; + + aggregator.disconnect (signal_id); + assert (expected_added.size == 0 && expected_removed.size == 0); + } + + /** * Synchronously prepare an aggregator and wait for the given personas to be * added to it. * diff --git a/tests/lib/tracker/Makefile.am b/tests/lib/tracker/Makefile.am index 02a4c5a5..639efb2e 100644 --- a/tests/lib/tracker/Makefile.am +++ b/tests/lib/tracker/Makefile.am @@ -19,6 +19,7 @@ libtracker_test_la_VALAFLAGS = \ --pkg tracker-sparql-$(TRACKER_SPARQL_MAJOR) \ --pkg folks-tracker \ --pkg folks-test \ + --pkg folks-test-dbus \ -g \ $(NULL) diff --git a/tests/lib/tracker/test-case.vala b/tests/lib/tracker/test-case.vala index 3a1acd37..fd0df80b 100644 --- a/tests/lib/tracker/test-case.vala +++ b/tests/lib/tracker/test-case.vala @@ -26,8 +26,8 @@ * Folks is configured to use the Tracker backend as primary store, * and no other backends. * - * FIXME: For now, this relies on running under with-session-bus-tracker.sh - * with FOLKS_BACKEND_PATH set. + * This uses tracker-control to start and stop Tracker services on a private + * D-Bus bus. */ public class TrackerTest.TestCase : Folks.TestCase { @@ -47,14 +47,6 @@ public class TrackerTest.TestCase : Folks.TestCase */ public TestCase (string name) { - /* This variable is set in the same place as the various variables we - * care about for sandboxing purposes, like XDG_CONFIG_HOME and - * DBUS_SESSION_BUS_ADDRESS. */ - if (Environment.get_variable ("FOLKS_TESTS_SANDBOXED_DBUS") - != "tracker") - error ("Tracker tests must be run in a private D-Bus session " + - "with Tracker services"); - base (name); Environment.set_variable ("FOLKS_BACKENDS_ALLOWED", "tracker", true); @@ -63,17 +55,53 @@ public class TrackerTest.TestCase : Folks.TestCase this.tracker_backend = new TrackerTest.Backend (); } - public override string? create_transient_dir () - { - /* Don't do anything. We're currently relying on - * being wrapped in with-session-bus-tracker.sh. */ - return null; - } - public override void private_bus_up () { - /* Don't do anything. We're currently relying on - * being wrapped in with-session-bus-tracker.sh. */ + base.private_bus_up (); + + /* Find out the libexec directory to use. */ + int exit_status = -1; + string capture_stdout = null; + + try + { + Process.spawn_sync (null /* cwd */, + { "pkg-config", "--variable=prefix", "tracker-miner-1.0" }, + null /* envp */, + SpawnFlags.SEARCH_PATH /* flags */, + null /* child setup */, + out capture_stdout, + null /* do not capture stderr */, + out exit_status); + + Process.check_exit_status (exit_status); + } + catch (GLib.Error e1) + { + error ("Error getting libexecdir from pkg-config: %s", e1.message); + } + + /* FIXME: There really should be a libexec variable in the pkg-config + * file. */ + var libexec = capture_stdout.strip () + "/libexec"; + + /* Create service files for the Tracker binaries. */ + var service_file_name = + Path.build_filename (this.transient_dir, "dbus-1", "services", + "org.freedesktop.Tracker1.service"); + var service_file = ("[D-BUS Service]\n" + + "Name=org.freedesktop.Tracker1\n" + + "Exec=%s/tracker-store\n").printf (libexec); + + try + { + FileUtils.set_contents (service_file_name, service_file); + } + catch (FileError e2) + { + error ("Error creating D-Bus service file ‘%s’: %s", + service_file_name, e2.message); + } } public override void tear_down () diff --git a/tests/libsocialweb/Makefile.am b/tests/libsocialweb/Makefile.am index 02df9eb5..f84c02c1 100644 --- a/tests/libsocialweb/Makefile.am +++ b/tests/libsocialweb/Makefile.am @@ -36,10 +36,6 @@ noinst_PROGRAMS = \ aggregation \ $(NULL) -TESTS_ENVIRONMENT = \ - $(top_srcdir)/tests/tools/execute-test.sh \ - $(NULL) - TESTS = $(noinst_PROGRAMS) dummy_lsw_SOURCES = \ diff --git a/tests/telepathy/Makefile.am b/tests/telepathy/Makefile.am index 645fdcee..b65efd5f 100644 --- a/tests/telepathy/Makefile.am +++ b/tests/telepathy/Makefile.am @@ -43,11 +43,6 @@ LDADD = \ -L$(top_srcdir)/backends/telepathy/lib \ $(NULL) -TESTS_ENVIRONMENT = \ - FOLKS_BACKEND_KEY_FILE_PATH=$(srcdir)/data/relationships-empty.ini \ - $(top_srcdir)/tests/tools/execute-test.sh \ - $(NULL) - TESTS = \ persona-store-capabilities \ individual-retrieval \ diff --git a/tests/test.mk b/tests/test.mk index 0e0eb6bb..801d17ba 100644 --- a/tests/test.mk +++ b/tests/test.mk @@ -31,6 +31,7 @@ test_valaflags = \ --vapidir=$(top_builddir)/backends/dummy/lib \ --pkg folks \ --pkg folks-test \ + --pkg folks-test-dbus \ --pkg folks-dummy \ --pkg gee-0.8 \ --pkg gio-2.0 \ diff --git a/tests/tools/Makefile.am b/tests/tools/Makefile.am index e98f35b0..542e5a28 100644 --- a/tests/tools/Makefile.am +++ b/tests/tools/Makefile.am @@ -1,12 +1,5 @@ EXTRA_DIST = \ - eds.sh \ - execute-test.sh \ - with-session-bus.sh \ - dbus-session.sh \ manager-file.py \ - with-session-bus-eds.sh \ - with-session-bus-tracker.sh \ - tracker.sh \ $(NULL) -include $(top_srcdir)/git.mk diff --git a/tests/tools/dbus-session.sh b/tests/tools/dbus-session.sh deleted file mode 100644 index 35c09d40..00000000 --- a/tests/tools/dbus-session.sh +++ /dev/null @@ -1,119 +0,0 @@ -# -# Helper functions to start your own D-Bus session. -# -# Refactored from with-session-bush.sh (from telepathy-glib). -# -# The canonical location of this program is the telepathy-glib tools/ -# directory, please synchronize any changes with that copy. -# -# Copyright (C) 2007-2008,2011 Collabora Ltd. <http://www.collabora.co.uk/> -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. - - -dbus_daemon_args="--print-address=5 --print-pid=6 --fork" -dbus_verbose=0 -dbus_me=with-session-bus -dbus_sleep=0 -dbus_with_session="" -dbus_config_file="" - -# Params: -# verbose: 0 for off and 1 for on -# -dbus_init () { - unset DBUS_SESSION_BUS_ADDRESS - unset DBUS_SESSION_BUS_PID - unset DBUS_STARTER_ADDRESS - unset DBUS_STARTER_BUS_TYPE - - exec 5> $dbus_me-$$.address - exec 6> $dbus_me-$$.pid - dbus_verbose=$1 -} - -dbus_usage () -{ - echo "usage: $me [options] -- program [program_options]" >&2 - echo "Requires write access to the current directory." >&2 - echo "" >&2 - echo "If \$WITH_SESSION_BUS_FORK_DBUS_MONITOR is set, fork dbus-monitor" >&2 - echo "with the arguments in \$WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT." >&2 - echo "The output of dbus-monitor is saved in $me-<pid>.dbus-monitor-logs" >&2 - exit 2 -} - -dbus_parse_args () { - while test "z$1" != "z--"; do - case "$1" in - --sleep=*) - sleep="$1" - dbus_sleep="${sleep#--sleep=}" - shift - ;; - --session) - dbus_with_session="--session" - shift - ;; - --config-file=*) - # FIXME: assumes config file doesn't contain any special characters - dbus_config_file="$1" - shift - ;; - *) - dbus_usage - ;; - esac - done -} - -dbus_start () { - local args="$dbus_daemon_args $dbus_with_session $dbus_config_file " - - if [ $dbus_verbose -gt 0 ] ; then - echo -n "dbus args $args " - fi - - dbus-daemon $args - - { - if [ $dbus_verbose -gt 0 ] ; then - echo -n "Temporary bus daemon is "; cat $dbus_me-$$.address; - fi - } >&2 - - { - if [ $dbus_verbose -gt 0 ] ; then - echo -n "Temporary bus daemon PID is "; head -n1 $dbus_me-$$.pid; - fi - } >&2 - - DBUS_SESSION_BUS_ADDRESS="`cat $dbus_me-$$.address`" - export DBUS_SESSION_BUS_ADDRESS - - if [ -n "$WITH_SESSION_BUS_FORK_DBUS_MONITOR" ] ; then - if [ $dbus_verbose -gt 0 ] ; then - echo -n "Forking dbus-monitor " \ - "$WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT" >&2 - fi - dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT \ - > $dbus_me-$$.dbus-monitor-logs 2>&1 & - fi -} - -# -# This should be called for INT, HUP and TERM signals -# -dbus_stop () { - pid=`head -n1 $dbus_me-$$.pid` - if test -n "$pid" ; then - if [ $dbus_verbose -gt 0 ] ; then - echo "Killing temporary bus daemon: $pid" >&2 - fi - kill -INT "$pid" - fi - rm -f $dbus_me-$$.address - rm -f $dbus_me-$$.pid -} diff --git a/tests/tools/eds.sh b/tests/tools/eds.sh deleted file mode 100644 index e4821446..00000000 --- a/tests/tools/eds.sh +++ /dev/null @@ -1,35 +0,0 @@ -# -# Helper functions to start your own e-d-s instance. This depends -# on you having your own D-Bus session bus started (first). -# -# -# Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/> -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. - -eds_tmpdir=$(mktemp -d) -libexec=$(pkg-config --variable=libexecdir libedata-book-1.2) - -cur_dir=`dirname $0` - -eds_init_settings () { - export XDG_DATA_HOME=$eds_tmpdir/.local - export XDG_CACHE_HOME=$eds_tmpdir/.cache - export XDG_CONFIG_HOME=$eds_tmpdir/.config - mkdir -p $XDG_CONFIG_HOME/evolution/sources -} - -eds_start () { - $libexec/evolution-source-registry > /dev/null 2>&1 & - $libexec/evolution-addressbook-factory --wait-for-client > /dev/null 2>&1 & - sleep 2 -} - -# This should be called on INT TERM and EXIT -eds_stop () { - rm -rf $eds_tmpdir - rm -rf $eds_tmpdir -} - diff --git a/tests/tools/execute-test.sh b/tests/tools/execute-test.sh deleted file mode 100755 index 54b4e33d..00000000 --- a/tests/tools/execute-test.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -# with-session-bus.sh - run a program with a temporary D-Bus session daemon -# -# interesting bits have been move into dbus to permit reusability -# -# Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/> -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. - -e=0 - -if test -t 1 && test "z$CHECK_VERBOSE" != z; then - "$@" || e=$? -else - "$@" > capture-$$.log 2>&1 || e=$? -fi - -# if exit code is 0, check for skipped tests -if test z$e = z0; then - if test -f capture-$$.log; then - grep -i skipped capture-$$.log || true - fi - rm -f capture-$$.log -# exit code is not 0, so output log and exit -else - cat capture-$$.log - exit $e -fi diff --git a/tests/tools/tracker.sh b/tests/tools/tracker.sh deleted file mode 100644 index dbe91b46..00000000 --- a/tests/tools/tracker.sh +++ /dev/null @@ -1,34 +0,0 @@ -# -# Helper functions to start your own Tracker instance. This depends -# on you having your own D-Bus session bus started (first). -# -# -# Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/> -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. - -tracker_tmpdir=$(mktemp -d) - -tracker_init_settings () { - export XDG_DATA_HOME=$tracker_tmpdir/.local - export XDG_CACHE_HOME=$tracker_tmpdir/.cache - export XDG_CONFIG_HOME=$tracker_tmpdir/.config -} - -# This should be called on INT TERM and EXIT -tracker_cleanup () { - rm -rf $tracker_tmpdir - rm -rf $tracker_tmpdir -} - -tracker_start () { - tracker-control -r > /dev/null 2>&1 -} - -tracker_stop () { - tracker_cleanup - tracker-control -r > /dev/null 2>&1 -} - diff --git a/tests/tools/with-session-bus-eds.sh b/tests/tools/with-session-bus-eds.sh deleted file mode 100755 index 02f50af2..00000000 --- a/tests/tools/with-session-bus-eds.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# with-session-bus-eds.sh - run a program with a temporary D-Bus session daemon -# -# interesting bits have been move into dbus to permit reusability -# -# Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/> -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. - - -cur_dir=`dirname $0` - -. $cur_dir"/dbus-session.sh" -. $cur_dir"/eds.sh" - -dbus_parse_args $@ -while test "z$1" != "z--"; do - shift -done -shift -if test "z$1" = "z"; then dbus_usage; fi - -cleanup () -{ - eds_stop - dbus_stop -} - -trap cleanup INT HUP TERM - -eds_init_settings -dbus_init 0 - -dbus_start -eds_start - -e=0 - -FOLKS_TESTS_SANDBOXED_DBUS=eds -export FOLKS_TESTS_SANDBOXED_DBUS - -$cur_dir"/execute-test.sh" "$@" || e=$? - -trap - INT HUP TERM -cleanup - -exit $e diff --git a/tests/tools/with-session-bus-tracker.sh b/tests/tools/with-session-bus-tracker.sh deleted file mode 100755 index 11ad9c79..00000000 --- a/tests/tools/with-session-bus-tracker.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# with-session-bus.sh - run a program with a temporary D-Bus session daemon -# -# interesting bits have been move into dbus to permit reusability -# -# Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/> -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. - - -cur_dir=`dirname $0` - -. $cur_dir"/dbus-session.sh" -. $cur_dir"/tracker.sh" - -dbus_parse_args $@ -while test "z$1" != "z--"; do - shift -done -shift -if test "z$1" = "z"; then dbus_usage; fi - -cleanup () -{ - tracker_stop - dbus_stop -} - -trap cleanup INT HUP TERM - -tracker_init_settings -dbus_init 0 - -dbus_start -tracker_start - -FOLKS_TESTS_SANDBOXED_DBUS=tracker -export FOLKS_TESTS_SANDBOXED_DBUS - -e=0 -$cur_dir"/execute-test.sh" "$@" || e=$? - -trap - INT HUP TERM -cleanup - -exit $e diff --git a/tests/tools/with-session-bus.sh b/tests/tools/with-session-bus.sh deleted file mode 100755 index d8f8d9b4..00000000 --- a/tests/tools/with-session-bus.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -# with-session-bus.sh - run a program with a temporary D-Bus session daemon -# -# interesting bits have been move into dbus to permit reusability -# -# Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/> -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. - - -cur_dir=`dirname $0` - -. $cur_dir"/dbus-session.sh" - -dbus_parse_args $@ -while test "z$1" != "z--"; do - shift -done -shift -if test "z$1" = "z"; then dbus_usage; fi - -cleanup () -{ - dbus_stop -} - -trap cleanup INT HUP TERM - -dbus_init 0 -dbus_start - -FOLKS_TESTS_SANDBOXED_DBUS=no-services -export FOLKS_TESTS_SANDBOXED_DBUS - -$cur_dir"/execute-test.sh" "$@" || e=$? - -trap - INT HUP TERM -cleanup - -exit $e diff --git a/tests/tracker/Makefile.am b/tests/tracker/Makefile.am index 0882260e..c8d481f7 100644 --- a/tests/tracker/Makefile.am +++ b/tests/tracker/Makefile.am @@ -36,8 +36,6 @@ LDADD = \ -L$(top_srcdir)/backends/tracker/lib \ $(NULL) -RUN_WITH_PRIVATE_BUS = $(top_srcdir)/tests/tools/with-session-bus-tracker.sh - # in order from least to most complex noinst_PROGRAMS = \ individual-retrieval \ @@ -100,10 +98,6 @@ noinst_PROGRAMS = \ set-null-avatar \ $(NULL) -TESTS_ENVIRONMENT = \ - $(RUN_WITH_PRIVATE_BUS) \ - --session \ - -- TESTS = $(noinst_PROGRAMS) individual_retrieval_SOURCES = \ @@ -338,11 +332,6 @@ set_null_avatar_SOURCES = \ set-null-avatar.vala \ $(NULL) -CLEANFILES = \ - *.pid \ - *.address \ - $(NULL) - -include $(top_srcdir)/git.mk -include $(top_srcdir)/check.mk -include $(top_srcdir)/valgrind.mk |