~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to kde/src/lib/phonenumber.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
 *   Copyright (C) 2013-2014 by Savoir-Faire Linux                          *
 
3
 *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
 
4
 *                                                                          *
 
5
 *   This library is free software; you can redistribute it and/or          *
 
6
 *   modify it under the terms of the GNU Lesser General Public             *
 
7
 *   License as published by the Free Software Foundation; either           *
 
8
 *   version 2.1 of the License, or (at your option) any later version.     *
 
9
 *                                                                          *
 
10
 *   This library is distributed in the hope that it will be useful,        *
 
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
 
13
 *   Lesser General Public License for more details.                        *
 
14
 *                                                                          *
 
15
 *   You should have received a copy of the GNU General Public License      *
 
16
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 
17
 ***************************************************************************/
 
18
#include "phonenumber.h"
 
19
#include "phonedirectorymodel.h"
 
20
#include "contact.h"
 
21
#include "account.h"
 
22
#include "call.h"
 
23
#include "dbus/presencemanager.h"
 
24
#include "numbercategorymodel.h"
 
25
#include "numbercategory.h"
 
26
 
 
27
QHash<int,Call*> PhoneNumber::m_shMostUsed = QHash<int,Call*>();
 
28
 
 
29
const PhoneNumber* PhoneNumber::m_spBlank = nullptr;
 
30
const PhoneNumber* PhoneNumber::BLANK()
 
31
{
 
32
   if (!m_spBlank) {
 
33
      m_spBlank = new PhoneNumber("",NumberCategoryModel::other());
 
34
      const_cast<PhoneNumber*>(m_spBlank)->m_Type = PhoneNumber::Type::BLANK;
 
35
   }
 
36
   return m_spBlank;
 
37
}
 
38
 
 
39
///Constructor
 
40
PhoneNumber::PhoneNumber(const QString& number, NumberCategory* cat, Type st) : QObject(PhoneDirectoryModel::instance()),
 
41
   m_Uri(stripUri(number)),m_pCategory(cat),m_Tracked(false),m_Present(false),m_LastUsed(0),
 
42
   m_Type(st),m_PopularityIndex(-1),m_pContact(nullptr),m_pAccount(nullptr),
 
43
   m_LastWeekCount(0),m_LastTrimCount(0),m_HaveCalled(false),m_IsBookmark(false),m_TotalSeconds(0)
 
44
{
 
45
   setObjectName(m_Uri);
 
46
   m_hasType = cat != NumberCategoryModel::other();
 
47
   if (m_hasType) {
 
48
      NumberCategoryModel::instance()->registerNumber(this);
 
49
   }
 
50
}
 
51
 
 
52
PhoneNumber::~PhoneNumber()
 
53
{
 
54
}
 
55
 
 
56
///Return if this number presence is being tracked
 
57
bool PhoneNumber::isTracked() const
 
58
{
 
59
   //If the number doesn't support it, ignore the flag
 
60
   return supportPresence() && m_Tracked;
 
61
}
 
62
 
 
63
///Is this number present
 
64
bool PhoneNumber::isPresent() const
 
65
{
 
66
   return m_Tracked && m_Present;
 
67
}
 
68
 
 
69
///This number presence status string
 
70
QString PhoneNumber::presenceMessage() const
 
71
{
 
72
   return m_PresentMessage;
 
73
}
 
74
 
 
75
///Return the number
 
76
QString PhoneNumber::uri() const {
 
77
   return m_Uri ;
 
78
}
 
79
 
 
80
///Return the phone number type
 
81
NumberCategory* PhoneNumber::category() const {
 
82
   return m_pCategory ;
 
83
}
 
84
 
 
85
///Return this number associated account, if any
 
86
Account* PhoneNumber::account() const
 
87
{
 
88
   return m_pAccount;
 
89
}
 
90
 
 
91
///Return this number associated contact, if any
 
92
Contact* PhoneNumber::contact() const
 
93
{
 
94
   return m_pContact;
 
95
}
 
96
 
 
97
///Return when this number was last used
 
98
time_t PhoneNumber::lastUsed() const
 
99
{
 
100
   return m_LastUsed;
 
101
}
 
102
 
 
103
///Set this number default account
 
104
void PhoneNumber::setAccount(Account* account)
 
105
{
 
106
   m_pAccount = account;
 
107
   if (m_pAccount)
 
108
      connect (m_pAccount,SIGNAL(destroyed(QObject*)),this,SLOT(accountDestroyed(QObject*)));
 
109
   emit changed();
 
110
}
 
111
 
 
112
///Set this number contact
 
113
void PhoneNumber::setContact(Contact* contact)
 
114
{
 
115
   m_pContact = contact;
 
116
   if (contact && m_Type != PhoneNumber::Type::TEMPORARY)
 
117
      PhoneDirectoryModel::instance()->indexNumber(this,m_hNames.keys()+QStringList(contact->formattedName()));
 
118
   emit changed();
 
119
}
 
120
 
 
121
void PhoneNumber::setCategory(NumberCategory* cat)
 
122
{
 
123
   if (cat == m_pCategory) return;
 
124
   if (m_hasType)
 
125
      NumberCategoryModel::instance()->unregisterNumber(this);
 
126
   m_hasType = cat != NumberCategoryModel::other();
 
127
   m_pCategory = cat;
 
128
   if (m_hasType)
 
129
      NumberCategoryModel::instance()->registerNumber(this);
 
130
   emit changed();
 
131
}
 
132
 
 
133
void PhoneNumber::setBookmarked(bool bookmarked )
 
134
{
 
135
   m_IsBookmark = bookmarked;
 
136
}
 
137
 
 
138
///Force an Uid on this number (instead of hash)
 
139
void PhoneNumber::setUid(const QString& uri)
 
140
{
 
141
   m_Uid = uri;
 
142
}
 
143
 
 
144
///Attempt to change the number type
 
145
bool PhoneNumber::setType(PhoneNumber::Type t)
 
146
{
 
147
   if (m_Type == PhoneNumber::Type::BLANK)
 
148
      return false;
 
149
   if (account() && t == PhoneNumber::Type::ACCOUNT) {
 
150
      if (account()->supportPresenceSubscribe()) {
 
151
         m_Tracked = true; //The daemon will init the tracker itself
 
152
         emit trackedChanged(true);
 
153
      }
 
154
      m_Type = t;
 
155
      return true;
 
156
   }
 
157
   return false;
 
158
}
 
159
 
 
160
///Set if this number is tracking presence information
 
161
void PhoneNumber::setTracked(bool track)
 
162
{
 
163
   if (track != m_Tracked) { //Subscribe only once
 
164
      //You can't subscribe without account
 
165
      if (track && !m_pAccount) return;
 
166
      m_Tracked = track;
 
167
      DBus::PresenceManager::instance().subscribeBuddy(m_pAccount->id(),fullUri(),track);
 
168
      emit changed();
 
169
      emit trackedChanged(track);
 
170
   }
 
171
}
 
172
 
 
173
///Allow phonedirectorymodel to change presence status
 
174
void PhoneNumber::setPresent(bool present)
 
175
{
 
176
   if (m_Present != present) {
 
177
      m_Present = present;
 
178
      emit presentChanged(present);
 
179
   }
 
180
}
 
181
 
 
182
void PhoneNumber::setPresenceMessage(const QString& message)
 
183
{
 
184
   if (m_PresentMessage != message) {
 
185
      m_PresentMessage = message;
 
186
      emit presenceMessageChanged(message);
 
187
   }
 
188
}
 
189
 
 
190
///Return the current type of the number
 
191
PhoneNumber::Type PhoneNumber::type() const
 
192
{
 
193
   return m_Type;
 
194
}
 
195
 
 
196
///Return the number of calls from this number
 
197
int PhoneNumber::callCount() const
 
198
{
 
199
   return m_lCalls.size();
 
200
}
 
201
 
 
202
uint PhoneNumber::weekCount() const
 
203
{
 
204
   return m_LastWeekCount;
 
205
}
 
206
 
 
207
uint PhoneNumber::trimCount() const
 
208
{
 
209
   return m_LastTrimCount;
 
210
}
 
211
 
 
212
bool PhoneNumber::haveCalled() const
 
213
{
 
214
   return m_HaveCalled;
 
215
}
 
216
 
 
217
///Best bet for this person real name
 
218
QString PhoneNumber::primaryName() const
 
219
{
 
220
   if (m_pContact)
 
221
      return m_pContact->formattedName();
 
222
   else if (m_hNames.size() == 1)
 
223
      return m_hNames.constBegin().key();
 
224
   else {
 
225
      QString toReturn = tr("Unknown");
 
226
      QHash<QString,int>::const_iterator i = m_hNames.constBegin();
 
227
      int max = 0;
 
228
      while (i != m_hNames.end()) {
 
229
         if (i.value() > max) {
 
230
            max      = i.value();
 
231
            toReturn = i.key  ();
 
232
         }
 
233
      }
 
234
      return toReturn;
 
235
   }
 
236
}
 
237
 
 
238
///Is this number bookmarked
 
239
bool PhoneNumber::isBookmarked() const
 
240
{
 
241
   return m_IsBookmark;
 
242
}
 
243
 
 
244
///If this number could (theoretically) support presence status
 
245
bool PhoneNumber::supportPresence() const
 
246
{
 
247
   //Without an account, presence is impossible
 
248
   if (!m_pAccount)
 
249
      return false;
 
250
   //The account also have to support it
 
251
   if (!m_pAccount->supportPresenceSubscribe())
 
252
       return false;
 
253
 
 
254
   //In the end, it all come down to this, is the number tracked
 
255
   return true;
 
256
}
 
257
 
 
258
///Proxy accessor to the category icon
 
259
QVariant PhoneNumber::icon() const
 
260
{
 
261
   return category()->icon(isTracked(),isPresent());
 
262
}
 
263
 
 
264
///The number of seconds spent with the URI (from history)
 
265
int PhoneNumber::totalSpentTime() const
 
266
{
 
267
   return m_TotalSeconds;
 
268
}
 
269
 
 
270
///Return this number unique identifier (hash)
 
271
QString PhoneNumber::uid() const
 
272
{
 
273
   return m_Uid.isEmpty()?toHash():m_Uid;
 
274
}
 
275
 
 
276
///Return all calls from this number
 
277
QList<Call*> PhoneNumber::calls() const
 
278
{
 
279
   return m_lCalls;
 
280
}
 
281
 
 
282
///Return the phonenumber position in the popularity index
 
283
int PhoneNumber::popularityIndex() const
 
284
{
 
285
   return m_PopularityIndex;
 
286
}
 
287
 
 
288
QHash<QString,int> PhoneNumber::alternativeNames() const
 
289
{
 
290
   return m_hNames;
 
291
}
 
292
 
 
293
///Add a call to the call list, notify listener
 
294
void PhoneNumber::addCall(Call* call)
 
295
{
 
296
   if (!call) return;
 
297
   m_Type = PhoneNumber::Type::USED;
 
298
   m_lCalls << call;
 
299
   m_TotalSeconds += call->stopTimeStamp() - call->startTimeStamp();
 
300
   time_t now;
 
301
   ::time ( &now );
 
302
   if (now - 3600*24*7 < call->stopTimeStamp())
 
303
      m_LastWeekCount++;
 
304
   if (now - 3600*24*7*15 < call->stopTimeStamp())
 
305
      m_LastTrimCount++;
 
306
 
 
307
   if (call->historyState() == Call::LegacyHistoryState::OUTGOING || call->direction() == Call::Direction::OUTGOING)
 
308
      m_HaveCalled = true;
 
309
 
 
310
   emit callAdded(call);
 
311
   if (call->startTimeStamp() > m_LastUsed)
 
312
      m_LastUsed = call->startTimeStamp();
 
313
   emit changed();
 
314
}
 
315
 
 
316
///Generate an unique representation of this number
 
317
QString PhoneNumber::toHash() const
 
318
{
 
319
   return QString("%1///%2///%3").arg(uri()).arg(account()?account()->id():QString()).arg(contact()?contact()->uid():QString());
 
320
}
 
321
 
 
322
 
 
323
///Return the domaine of an URI (<sip:12345@exemple.com>)
 
324
QString PhoneNumber::hostname() const
 
325
{
 
326
   if (m_Uri.indexOf('@') != -1) {
 
327
      return m_Uri.split('@')[1].left(m_Uri.split('@')[1].size());
 
328
   }
 
329
   return QString();
 
330
}
 
331
 
 
332
QString PhoneNumber::fullUri() const
 
333
{
 
334
   return QString("<sip:%1>").arg(m_Uri);
 
335
}
 
336
 
 
337
 
 
338
///Strip out <sip:****> from the URI
 
339
QString PhoneNumber::stripUri(const QString& uri)
 
340
{
 
341
   int start(0),end(uri.size()-1); //Other type of comparaisons were too slow
 
342
   if (uri.size() > 0 && uri[0] == '<' && uri[4] == ':')
 
343
      start = 5;
 
344
   if (end && uri[end] == '>')
 
345
      end--;
 
346
   return uri.mid(start,end-start+1);
 
347
}
 
348
 
 
349
///Increment name counter and update indexes
 
350
void PhoneNumber::incrementAlternativeName(const QString& name)
 
351
{
 
352
   const bool needReIndexing = !m_hNames[name];
 
353
   m_hNames[name]++;
 
354
   if (needReIndexing && m_Type != PhoneNumber::Type::TEMPORARY)
 
355
      PhoneDirectoryModel::instance()->indexNumber(this,m_hNames.keys()+(m_pContact?(QStringList(m_pContact->formattedName())):QStringList()));
 
356
}
 
357
 
 
358
void PhoneNumber::accountDestroyed(QObject* o)
 
359
{
 
360
   if (o == m_pAccount)
 
361
      m_pAccount = nullptr;
 
362
}
 
363
 
 
364
/************************************************************************************
 
365
 *                                                                                  *
 
366
 *                             Temporary phone number                               *
 
367
 *                                                                                  *
 
368
 ***********************************************************************************/
 
369
 
 
370
void TemporaryPhoneNumber::setUri(const QString& uri)
 
371
{
 
372
   m_Uri = uri;
 
373
   emit changed();
 
374
}
 
375
 
 
376
///Constructor
 
377
TemporaryPhoneNumber::TemporaryPhoneNumber(const PhoneNumber* number) :
 
378
   PhoneNumber(QString(),NumberCategoryModel::other(),PhoneNumber::Type::TEMPORARY)
 
379
{
 
380
   if (number) {
 
381
      setContact(number->contact());
 
382
      setAccount(number->account());
 
383
   }
 
384
}