2 * This file is part of TpSession
4 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
5 * Contact Kate Alhola kate.alholanokia.com
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "tpsessionaccount.h"
22 #include <TelepathyQt4/Message>
25 * \class TpSessionAccount
26 * \headerfile <tpsessionaccount.h>
28 * TpSessionAccount class represents every account you have. As example account for “Ring” connection manager represents your cellular
29 * account and you may send and receive SMS with it. Gabble represents your GoogleTalk account if you have defined them.
30 * TpSessionAccounts are created by TpSession class,they are not intended to be created stand-alone
34 * \fn void TpSessionAccount::accountReady(TpSessionAccount *);
36 * Emitted when the account becomes ready
38 * \param TpSessionAccount pointer to account become ready
41 * \fn void TpSessionAccount::channelReady(TpSessionAccount *);
43 * Emitted when the account Manager becomes ready
45 * \param TpSession pointer to TpSession class
48 * \fn void TpSessionAccount::messageReceived(const Tp::ReceivedMessage &,TpSessionAccount *);
50 * Emitted when any of Account Managers recived message
52 * \param Tp::ReceivedMessage Message received
53 * \param TpSessionAccount pointer to account received message
57 * \fn void TpSessionAccount::newChannel(TpSessionAccount *,QString CjhannelType,QString peerId,const Tp::ChannelDetails &);
58 * \param TpSession pointer to TpSession class
59 * \param ChannelType type of Channel, TELEPATHY_INTERFACE_CHANNEL_TYPE_TEXT for text channel, TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA for steram media, as exmple for incoming call
60 * \param peedId PeerId, as example caller telephone number
61 * \param channeDetails needed if you would like to create a channel. For text chanels TpSession creates channel automatically. For calls, Maemo Call UI handles callcreation
65 * Construct a new TpSessionAccount object. This constructor is called by TpSession class when new account is created or fetched from account manager. It is not inended to be used stand alone
67 * \param am Telepathy-Qt4 account manager for this account
68 * \param objectPath Dbus object path tonew account
70 TpSessionAccount::TpSessionAccount(Tp::AccountManagerPtr am,const QString &objectPath):
71 mAcc(Tp::Account::create(am->dbusConnection(),am->busName(), objectPath))
74 connect(mAcc->becomeReady(),SIGNAL(finished(Tp::PendingOperation *)),SLOT(onReady(Tp::PendingOperation *)));
76 // qDebug() << "TpSessionAccount::TpSessionAccount objectPath=" << objectPath;
80 void TpSessionAccount::onReady(Tp::PendingOperation *op)
84 // qDebug() << "TpSessionAccount::onReady cmName=" << acc->cmName() << "haveConnection=" <<
85 // (acc->haveConnection()? ( acc->connection()->isReady() ? "Ready":"notReady"):"no");
87 if(acc->haveConnection()) {
89 connect(acc->connection()->becomeReady(Tp::Connection::FeatureRoster | Tp::Connection::FeatureSelfContact ),
90 SIGNAL(finished(Tp::PendingOperation *)),
91 SLOT(onContactsConnectionReady(Tp::PendingOperation *)));
92 if (acc->connection()->isReady() && acc->connection()->interfaces().contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_REQUESTS)) {
93 // qDebug() << "TpSessionAccount::onReady: connecting to Connection.Interface.NewChannels";
94 connect(acc->connection()->requestsInterface(),
95 SIGNAL(NewChannels(const Tp::ChannelDetailsList&)),
96 SLOT(onNewChannels(const Tp::ChannelDetailsList&)));
99 else { // If there is no connection, we are ready now, else we are ready when contacts connection is ready
101 emit accountReady(this);
105 void TpSessionAccount::onContactsConnectionReady(Tp::PendingOperation *op)
108 qWarning() << "Connection cannot become ready" << acc->cmName();
112 if (acc->connection()->interfaces().contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_REQUESTS)) {
113 // // qDebug() << "TpSessionAccount::onContactsConectionReady: connecting to Connection.Interface.NewChannels";
114 connect(acc->connection()->requestsInterface(),
115 SIGNAL(NewChannels(const Tp::ChannelDetailsList&)),
116 SLOT(onNewChannels(const Tp::ChannelDetailsList&)));
117 } else qDebug() << "TpSessionAccount::onContactsConnectionReady: does NO have CONNECTION_INTERFACE_REQUESTS";
118 Tp::PendingReady *pr = qobject_cast<Tp::PendingReady *>(op);
119 contactsConn = Tp::ConnectionPtr(qobject_cast<Tp::Connection *>(pr->object()));
121 connect(contactsConn->contactManager(),
122 SIGNAL(presencePublicationRequested(const Tp::Contacts &)),
123 SLOT(onPresencePublicationRequested(const Tp::Contacts &)));
125 // qDebug() << "TpSessionAccount::onContactsConnectionReady "<< acc->cmName() ;
127 myContacts=contactsConn->contactManager()->allKnownContacts();
128 foreach (const Tp::ContactPtr &contact, myContacts) {
129 // qDebug() << "id=" <<contact->id() << " alias=" << contact->alias() << " presence=" << contact->presenceStatus() ;
130 if(contact->id()==reqContact) {
131 addOutgoingChannel(contact);
135 if(!reqContact.isEmpty() ) makeContactFromAddress(reqContact);
137 emit accountReady(this);
142 * Fetch Tp::ContactPtr for contact with given address. Contact is searched among contacts returned by contact manager for ths account.
143 * All connecions managers does not return contacts, as example Ring telephony contact manager does not. Gabble for Googletalk or Spirit for Skype does
146 * \param id Contact address/id, as example email address, telephone number etc. Only exact matches
147 * \return TpContactPtr, if nontact is not returned TpContactPtr.isNull() is true
150 Tp::ContactPtr TpSessionAccount::getContactFromAddress(QString id)
154 foreach (const Tp::ContactPtr &contact, myContacts) {
155 if(contact->id()==id) return p=contact;
160 * Fetch TpSessionChannel for with given address. Contact is searched among active channels for this account.
163 * \param id Contact address/id, as example email address, telephone number etc. Only exact matches
164 * \return Pointer to TpSessionChannel or NULL if nit found
167 TpSessionChannel* TpSessionAccount::getChannelFromPeerAddress(QString id)
169 TpSessionChannel* p=NULL;
170 foreach (TpSessionChannel* channel, myChannels) {
171 if(channel->peerId()==id) p=channel;
176 * Creates new contact with given address. This function is Acynchronous, it sends request to contact manager for contact creation,
178 * \param address Contact address/id, as example email address, telephone number etc.
179 * \return true in success
181 * \return emits contactRetrieved(Tp:.contactPtr,bool success,bool requested)
184 bool TpSessionAccount::makeContactFromAddress(QString address)
186 if(!contactsConn) return false; // No contacts connection, return fail
187 reqContact=address; // When we get retrieved signal, we check if it is this one
188 Tp::PendingContacts *pc=contactsConn->contactManager()->contactsForIdentifiers(QStringList(address));
189 connect(pc,SIGNAL(finished(Tp::PendingOperation *)),SLOT(onNewContactRetrieved(Tp::PendingOperation *)));
193 void TpSessionAccount::onNewContactRetrieved(Tp::PendingOperation *op)
195 Tp::ContactPtr contact;
196 Tp::PendingContacts *pcontacts = qobject_cast<Tp::PendingContacts *>(op);
197 QList<Tp::ContactPtr> contacts = pcontacts->contacts();
198 QString username = pcontacts->identifiers().first();
199 if (contacts.size() != 1 || !contacts.first()) {
200 qDebug() << "Unable to add contact " <<reqContact;
201 emit contactRetrieved(contact,false,false);
202 if(!reqMessage.isEmpty()) { // If there is requesting messsage, can't queue if contact failed
203 emit messageQueued(this,false);
210 contact = contacts.first();
211 // qDebug() << "TpSessionAccount::onContactRetrieved" << reqContact;
212 if(!reqContact.isEmpty()) {
213 addOutgoingChannel(contacts.first());
214 emit contactRetrieved(contact,true,true);
217 emit contactRetrieved(contact,true,false);
220 * Send message to given address. This function is compled Acynchronous function that may produce multiple state transitions beforecomletion.
221 * If there is already existing TpSessionChannel for this contact, it simply queues message for sending and no forther transitions are needed
222 * If there are no hannel, it first check is there contact for this address, if is, it requests new channel to be created for ths channel and message
223 * is left waiting untill channel is created. If there is no contact, it sends request fr contact creation and when contact is created state machine
224 * proceeds to channel creation.
226 * MessageSent() signal is emitted when completed
228 * \param address Contact address/id, as example email address, telephone number etc.
229 * \param message Message string
232 void TpSessionAccount::sendMessageToAddress(QString address,QString message)
235 TpSessionChannel* channel=getChannelFromPeerAddress(address);
237 // qDebug() << "TpSessionAccount::sendMessageToAddress peer:" << channel->peerId() << "queuing:" << message;
238 channel->sendMessage(message); // We have already channel
239 emit messageQueued(this,true);
243 p=getContactFromAddress(address); // Do we have contact ready ?
244 if(p.isNull()) // If not, create it
245 makeContactFromAddress(address); // Create and after created, send
247 addOutgoingChannel(p); // Create channel and when ready, send
251 void TpSessionAccount::addOutgoingChannel(const Tp::ContactPtr &contact)
255 // qDebug() << "TpSessionAccount::addOutgoingChannel";
257 TpSessionChannel* newChannel=new TpSessionChannel(contact->manager()->connection(),contact);
258 connect(newChannel,SIGNAL(messageReceived(const Tp::ReceivedMessage &,TpSessionChannel *)),
259 SLOT(onMessageReceived(const Tp::ReceivedMessage &,TpSessionChannel *)));
260 connect(newChannel,SIGNAL(messageSent(const Tp::Message &,Tp::MessageSendingFlags, const QString &,TpSessionChannel *)),
261 SLOT(onMessageSent(const Tp::Message &,Tp::MessageSendingFlags, const QString &,TpSessionChannel *)));
262 connect(newChannel,SIGNAL(channelReady(TpSessionChannel *)),
263 SLOT(onOutgoingChannelReady(TpSessionChannel*)));
264 myChannels+=newChannel;
268 void TpSessionAccount::onOutgoingChannelReady(TpSessionChannel *ch)
270 // qDebug() << "TpSessionAccount::onOutgoingChannelReady";
271 emit channelReady(this);
272 if(!reqMessage.isEmpty()) {
273 // qDebug() << "TpSessionAccount::onOutgoingChannelReady peer:" << ch->peerId() << "queuing:" << reqMessage;
274 ch->sendMessage(reqMessage);
275 emit messageQueued(this,true);
281 void TpSessionAccount::onMessageSent(const Tp::Message &msg,Tp::MessageSendingFlags, const QString &flags,TpSessionChannel *ch)
284 // qDebug() << "TpSessionAccount::onMessageSent peer:" << ch->peerId() <<"txt:" << msg.text();
285 emit messageSent(msg,this);
288 void TpSessionAccount::onMessageReceived(const Tp::ReceivedMessage &msg,TpSessionChannel *ch)
291 // qDebug() << "TpSessionAccount::onMessageReceived " << msg.text();
292 emit messageReceived(msg,this);
295 void TpSessionAccount::onNewChannels(const Tp::ChannelDetailsList &channels)
298 Tp::TextChannelPtr myIngoingTextChannel;
299 // qDebug() << "TpSessionAccount::onNewChannels";
300 foreach (const Tp::ChannelDetails &details, channels) {
301 QString channelType = details.properties.value(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".ChannelType")).toString();
302 QString targetId = details.properties.value(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetID")).toString();
303 bool requested = details.properties.value(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".Requested")).toBool();
304 // qDebug() << " channelType:" << channelType <<" requested :" << requested << " targetId" << targetId;
306 emit newChannel(this,channelType,targetId,details);
307 if (channelType == TELEPATHY_INTERFACE_CHANNEL_TYPE_TEXT && !requested) {
309 myIngoingTextChannel = Tp::TextChannel::create(acc->connection(),details.channel.path(),details.properties);
310 // qDebug() << "TpSessionAccount::onNewChannels path=" <<"path " << myIngoingTextChannel->objectPath();
312 TpSessionChannel* newChannel=new TpSessionChannel( myIngoingTextChannel);
313 connect(newChannel,SIGNAL(messageReceived(const Tp::ReceivedMessage &,TpSessionChannel *)),
314 SLOT(onMessageReceived(const Tp::ReceivedMessage &,TpSessionChannel *)));
315 connect(newChannel,SIGNAL(messageSent(const Tp::Message &,Tp::MessageSendingFlags, const QString &,TpSessionChannel *)),
316 SLOT(onMessageSent(const Tp::Message &,Tp::MessageSendingFlags, const QString &,TpSessionChannel *)));
317 myChannels+=newChannel;
319 if (channelType == TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA && !requested) {
320 // qDebug() << "Incoming call" ;