1 /* Ricochet - https://ricochet.im/
2  * Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *    * Redistributions of source code must retain the above copyright
9  *      notice, this list of conditions and the following disclaimer.
10  *
11  *    * Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following disclaimer
13  *      in the documentation and/or other materials provided with the
14  *      distribution.
15  *
16  *    * Neither the names of the copyright owners nor the names of its
17  *      contributors may be used to endorse or promote products derived from
18  *      this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef CONTACTUSER_H
34 #define CONTACTUSER_H
35 
36 #include <QObject>
37 #include <QHash>
38 #include <QMetaType>
39 #include <QVariant>
40 #include <QSharedPointer>
41 #include "utils/Settings.h"
42 #include "protocol/Connection.h"
43 
44 class UserIdentity;
45 class OutgoingContactRequest;
46 class ConversationModel;
47 
48 namespace Protocol
49 {
50     class OutboundConnector;
51 }
52 
53 /* Represents a user on the contact list.
54  * All persistent uses of a ContactUser instance must either connect to the
55  * contactDeleted() signal, or use a QWeakPointer to track deletion. A ContactUser
56  * can be removed at essentially any time. */
57 
58 class ContactUser : public QObject
59 {
60     Q_OBJECT
61     Q_DISABLE_COPY(ContactUser)
62     Q_ENUMS(Status)
63 
64     Q_PROPERTY(int uniqueID READ getUniqueID CONSTANT)
65     Q_PROPERTY(UserIdentity* identity READ getIdentity CONSTANT)
66     Q_PROPERTY(QString nickname READ nickname WRITE setNickname NOTIFY nicknameChanged)
67     Q_PROPERTY(QString contactID READ contactID CONSTANT)
68     Q_PROPERTY(Status status READ status NOTIFY statusChanged)
69     Q_PROPERTY(OutgoingContactRequest *contactRequest READ contactRequest NOTIFY statusChanged)
70     Q_PROPERTY(SettingsObject *settings READ settings CONSTANT)
71     Q_PROPERTY(ConversationModel *conversation READ conversation CONSTANT)
72 
73     friend class ContactsManager;
74     friend class OutgoingContactRequest;
75 
76 public:
77     enum Status
78     {
79         Online,
80         Offline,
81         RequestPending,
82         RequestRejected,
83         Outdated
84     };
85 
86     UserIdentity * const identity;
87     const int uniqueID;
88 
89     explicit ContactUser(UserIdentity *identity, int uniqueID, QObject *parent = 0);
90     virtual ~ContactUser();
91 
connection()92     const QSharedPointer<Protocol::Connection> &connection() { return m_connection; }
isConnected()93     bool isConnected() const { return status() == Online; }
94 
contactRequest()95     OutgoingContactRequest *contactRequest() { return m_contactRequest; }
conversation()96     ConversationModel *conversation() { return m_conversation; }
97 
getIdentity()98     UserIdentity *getIdentity() const { return identity; }
getUniqueID()99     int getUniqueID() const { return uniqueID; }
100 
101     QString nickname() const;
102     /* Hostname is in the onion hostname format, i.e. it ends with .onion */
103     QString hostname() const;
104     quint16 port() const;
105     /* Contact ID in the ricochet: format */
106     QString contactID() const;
107 
status()108     Status status() const { return m_status; }
109 
110     SettingsObject *settings();
111 
112     Q_INVOKABLE void deleteContact();
113 
114 public slots:
115     /* Assign a connection to this user
116      *
117      * The connection must be connected, and the peer must be authenticated and
118      * must match this user. ContactUser will assume ownership of the connection,
119      * and it will be closed and deleted when it's no longer used.
120      *
121      * It is valid to pass an incoming or outgoing connection. If there is already
122      * a connection, protocol-specific rules are applied and the new connection
123      * may be closed to favor the older one.
124      *
125      * If the existing connection is replaced, that is equivalent to disconnecting
126      * and reconnectng immediately - any ongoing operations will fail and need to
127      * be retried at a higher level.
128      */
129     void assignConnection(const QSharedPointer<Protocol::Connection> &connection);
130 
131     void setNickname(const QString &nickname);
132     void setHostname(const QString &hostname);
133 
134     void updateStatus();
135 
136 signals:
137     void statusChanged();
138     void connected();
139     void disconnected();
140     void connectionChanged(const QWeakPointer<Protocol::Connection> &connection);
141 
142     void nicknameChanged();
143     void contactDeleted(ContactUser *user);
144 
145 private slots:
146     void onConnected();
147     void onDisconnected();
148     void requestRemoved();
149     void requestAccepted();
150     void onSettingsModified(const QString &key, const QJsonValue &value);
151 
152 private:
153     QSharedPointer<Protocol::Connection> m_connection;
154     Protocol::OutboundConnector *m_outgoingSocket;
155 
156     Status m_status;
157     quint16 m_lastReceivedChatID;
158     OutgoingContactRequest *m_contactRequest;
159     SettingsObject *m_settings;
160     ConversationModel *m_conversation;
161 
162     /* See ContactsManager::addContact */
163     static ContactUser *addNewContact(UserIdentity *identity, int id);
164 
165     void loadContactRequest();
166     void updateOutgoingSocket();
167 
168     void clearConnection();
169 };
170 
171 Q_DECLARE_METATYPE(ContactUser*)
172 
173 #endif // CONTACTUSER_H
174