summaryrefslogtreecommitdiff
path: root/backends/libsocialweb/lib/swf-persona-store.vala
blob: 0effd7a1a75b9fe1664ccbcf8e22ff6493e454d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/*
 * Copyright (C) 2010 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:
 *       Travis Reitter <travis.reitter@collabora.co.uk>
 *       Philip Withnall <philip.withnall@collabora.co.uk>
 *       Marco Barisione <marco.barisione@collabora.co.uk>
 */

using GLib;
using Folks;
using SocialWebClient;

extern const string BACKEND_NAME;

/**
 * A persona store which is associated with a single libsocialweb service.
 * It will create {@link Persona}s for each of the contacts known to that
 * service.
 */
public class Swf.PersonaStore : Folks.PersonaStore
{
  private HashTable<string, Persona> _personas;
  private bool _is_prepared = false;
  private ClientService _service;
  private ClientContactView _contact_view;

  /**
   * The type of persona store this is.
   *
   * See {@link Folks.PersonaStore.type_id}.
   */
  public override string type_id { get { return BACKEND_NAME; } }

  /**
   * Whether this PersonaStore can add {@link Folks.Persona}s.
   *
   * See {@link Folks.PersonaStore.can_add_personas}.
   *
   * @since 0.5.0
   */
  public override MaybeBool can_add_personas
    {
      get { return MaybeBool.FALSE; }
    }

  /**
   * Whether this PersonaStore can set the alias of {@link Folks.Persona}s.
   *
   * See {@link Folks.PersonaStore.can_alias_personas}.
   *
   * @since 0.5.0
   */
  public override MaybeBool can_alias_personas
    {
      get { return MaybeBool.FALSE; }
    }

  /**
   * Whether this PersonaStore can set the groups of {@link Folks.Persona}s.
   *
   * See {@link Folks.PersonaStore.can_group_personas}.
   *
   * @since 0.5.0
   */
  public override MaybeBool can_group_personas
    {
      get { return MaybeBool.FALSE; }
    }

  /**
   * Whether this PersonaStore can remove {@link Folks.Persona}s.
   *
   * See {@link Folks.PersonaStore.can_remove_personas}.
   *
   * @since 0.5.0
   */
  public override MaybeBool can_remove_personas
    {
      get { return MaybeBool.FALSE; }
    }

  /**
   * Whether this PersonaStore has been prepared.
   *
   * See {@link Folks.PersonaStore.is_prepared}.
   *
   * @since 0.5.0
   */
  public override bool is_prepared
    {
      get { return this._is_prepared; }
    }

  /**
   * The {@link Persona}s exposed by this PersonaStore.
   *
   * See {@link Folks.PersonaStore.personas}.
   */
  public override HashTable<string, Persona> personas
    {
      get { return this._personas; }
    }

  /**
   * Create a new PersonaStore.
   *
   * Create a new persona store to store the {@link Persona}s for the contacts
   * provided by the `service`.
   */
  public PersonaStore (ClientService service)
    {
      Object (display_name: service.get_display_name(),
              id: service.get_name ());

      this.trust_level = PersonaStoreTrust.PARTIAL;
      this._service = service;
      this._personas = new HashTable<string, Persona> (str_hash, str_equal);
    }

  ~PersonaStore ()
    {
      this._contact_view.contacts_added.disconnect (this.contacts_added_cb);
      this._contact_view.contacts_changed.disconnect (this.contacts_changed_cb);
      this._contact_view.contacts_removed.disconnect (this.contacts_removed_cb);
    }

  /**
   * Add a new {@link Persona} to the PersonaStore.
   *
   * See {@link Folks.PersonaStore.add_persona_from_details}.
   */
  public override async Folks.Persona? add_persona_from_details (
      HashTable<string, Value?> details) throws Folks.PersonaStoreError
    {
      throw new PersonaStoreError.READ_ONLY (
          "Personas cannot be added to this store.");
    }

  /**
   * Remove a {@link Persona} from the PersonaStore.
   *
   * See {@link Folks.PersonaStore.remove_persona}.
   */
  public override async void remove_persona (Folks.Persona persona)
      throws Folks.PersonaStoreError
    {
      throw new PersonaStoreError.READ_ONLY (
          "Personas cannot be removed from this store.");
    }

  /**
   * Prepare the PersonaStore for use.
   *
   * See {@link Folks.PersonaStore.prepare}.
   */
  public override async void prepare ()
    {
      lock (this._is_prepared)
        {
          if (!this._is_prepared)
            {
              this._service.get_static_capabilities (
                  (service, caps, error) =>
                    {
                      if (caps == null)
                        return;

                      bool has_contacts = ClientService.has_cap (caps,
                          "has-contacts-query-iface");
                      if (!has_contacts)
                        return;
                      var parameters = new HashTable<weak string, weak string>
                          (str_hash, str_equal);
                      this._service.contacts_query_open_view
                          ("people", parameters, (query, contact_view) =>
                        {
                          /* The D-Bus call could return an error. In this
                           * case, contact_view is null */
                          if (contact_view == null)
                            return;

                          contact_view.contacts_added.connect
                              (this.contacts_added_cb);
                          contact_view.contacts_changed.connect
                              (this.contacts_changed_cb);
                          contact_view.contacts_removed.connect
                              (this.contacts_removed_cb);

                          this._contact_view = contact_view;
                          this._is_prepared = true;
                          this.notify_property ("is-prepared");

                          this._contact_view.start ();
                        });
                    });
            }
        }
    }

  private void contacts_added_cb (List<unowned Contact> contacts)
    {
      var added_personas = new Queue<Persona> ();
      foreach (var contact in contacts)
        {
          var persona = new Persona(this, contact);
          _personas.insert(persona.iid, persona);
          added_personas.push_tail(persona);
        }

      if (added_personas.length > 0)
        this.personas_changed (added_personas.head, null, null, null, 0);
    }

  private void contacts_changed_cb (List<unowned Contact> contacts)
    {
      foreach (var contact in contacts)
        {
          if (this._service.get_name () != contact.service)
            {
              continue;
            }
          var iid = Swf.Persona._build_iid(contact.service, Persona.get_contact_id (contact));
          var persona = _personas.lookup(iid);
          if (persona != null)
            persona.update (contact);
        }
    }

  private void contacts_removed_cb (List<unowned Contact> contacts)
    {
      var removed_personas = new Queue<Persona> ();
      foreach (var contact in contacts)
        {
          if (this._service.get_name () != contact.service)
            {
              continue;
            }
          var iid = Swf.Persona._build_iid(contact.service, Persona.get_contact_id (contact));
          var persona = _personas.lookup(iid);
          if (persona != null)
            {
              removed_personas.push_tail(persona);
              _personas.remove(persona.iid);
            }
        }

      if (removed_personas.length > 0)
        this.personas_changed (null, removed_personas.head, null, null, 0);
    }
}