sigproxy: Modernize RPC calls (remote signals)
[quassel.git] / src / common / identity.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program 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         *
13  *   GNU 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, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "identity.h"
22
23 #include <QMetaProperty>
24 #include <QString>
25 #include <QVariantMap>
26
27 #ifdef Q_OS_MAC
28 #    include <CoreServices/CoreServices.h>
29
30 #    include "mac_utils.h"
31 #endif
32
33 #ifdef Q_OS_UNIX
34 #    include <pwd.h>
35 #    include <sys/types.h>
36 #    include <unistd.h>
37 #endif
38
39 #ifdef Q_OS_WIN
40 #    include <windows.h>
41 #    include <Winbase.h>
42 #    define SECURITY_WIN32
43 #    include <Security.h>
44 #endif
45
46 Identity::Identity(IdentityId id, QObject* parent)
47     : SyncableObject(parent)
48     , _identityId(id)
49 {
50     init();
51     setToDefaults();
52 }
53
54 Identity::Identity(const Identity& other, QObject* parent)
55     : SyncableObject(parent)
56     , _identityId(other.id())
57     , _identityName(other.identityName())
58     , _realName(other.realName())
59     , _nicks(other.nicks())
60     , _awayNick(other.awayNick())
61     , _awayNickEnabled(other.awayNickEnabled())
62     , _awayReason(other.awayReason())
63     , _awayReasonEnabled(other.awayReasonEnabled())
64     , _autoAwayEnabled(other.autoAwayEnabled())
65     , _autoAwayTime(other.autoAwayTime())
66     , _autoAwayReason(other.autoAwayReason())
67     , _autoAwayReasonEnabled(other.autoAwayReasonEnabled())
68     , _detachAwayEnabled(other.detachAwayEnabled())
69     , _detachAwayReason(other.detachAwayReason())
70     , _detachAwayReasonEnabled(other.detachAwayReasonEnabled())
71     , _ident(other.ident())
72     , _kickReason(other.kickReason())
73     , _partReason(other.partReason())
74     , _quitReason(other.quitReason())
75 {
76     init();
77 }
78
79 #ifdef Q_OS_WIN
80 #    ifdef UNICODE
81 QString tcharToQString(TCHAR* tchar)
82 {
83     return QString::fromUtf16(reinterpret_cast<ushort*>(tchar));
84 }
85
86 #    else
87 QString tcharToQString(TCHAR* tchar)
88 {
89     return QString::fromLocal8Bit(tchar);
90 }
91
92 #    endif
93
94 #endif
95 void Identity::init()
96 {
97     setObjectName(QString::number(id().toInt()));
98     setAllowClientUpdates(true);
99 }
100
101 QString Identity::defaultNick()
102 {
103     QString nick = QString("quassel%1").arg(qrand() & 0xff);  // FIXME provide more sensible default nicks
104
105 #ifdef Q_OS_MAC
106     QString shortUserName = CFStringToQString(CSCopyUserName(true));
107     if (!shortUserName.isEmpty())
108         nick = shortUserName;
109
110 #elif defined(Q_OS_UNIX)
111     QString userName;
112     struct passwd* pwd = getpwuid(getuid());
113     if (pwd)
114         userName = pwd->pw_name;
115     if (!userName.isEmpty())
116         nick = userName;
117
118 #elif defined(Q_OS_WIN)
119     TCHAR infoBuf[128];
120     DWORD bufCharCount = 128;
121     // if(GetUserNameEx(/* NameSamCompatible */ 1, infoBuf, &bufCharCount))
122     if (GetUserNameEx(NameSamCompatible, infoBuf, &bufCharCount)) {
123         QString nickName(tcharToQString(infoBuf));
124         int lastBs = nickName.lastIndexOf('\\');
125         if (lastBs != -1) {
126             nickName = nickName.mid(lastBs + 1);
127         }
128         if (!nickName.isEmpty())
129             nick = nickName;
130     }
131 #endif
132
133     // cleaning forbidden characters from nick
134     QRegExp rx(QString("(^[\\d-]+|[^A-Za-z0-9\x5b-\x60\x7b-\x7d])"));  // NOLINT(modernize-raw-string-literal)
135     nick.remove(rx);
136     return nick;
137 }
138
139 QString Identity::defaultRealName()
140 {
141     QString generalDefault = tr("Quassel IRC User");
142
143 #ifdef Q_OS_MAC
144     return CFStringToQString(CSCopyUserName(false));
145
146 #elif defined(Q_OS_UNIX)
147     QString realName;
148     struct passwd* pwd = getpwuid(getuid());
149     if (pwd)
150         realName = QString::fromUtf8(pwd->pw_gecos);
151     if (!realName.isEmpty())
152         return realName;
153     else
154         return generalDefault;
155
156 #elif defined(Q_OS_WIN)
157     TCHAR infoBuf[128];
158     DWORD bufCharCount = 128;
159     if (GetUserName(infoBuf, &bufCharCount))
160         return tcharToQString(infoBuf);
161     else
162         return generalDefault;
163 #else
164     return generalDefault;
165 #endif
166 }
167
168 void Identity::setToDefaults()
169 {
170     setIdentityName(tr("<empty>"));
171     setRealName(defaultRealName());
172     QStringList n = QStringList() << defaultNick();
173     setNicks(n);
174     setAwayNick("");
175     setAwayNickEnabled(false);
176     setAwayReason(tr("Gone fishing."));
177     setAwayReasonEnabled(true);
178     setAutoAwayEnabled(false);
179     setAutoAwayTime(10);
180     setAutoAwayReason(tr("Not here. No, really. not here!"));
181     setAutoAwayReasonEnabled(false);
182     setDetachAwayEnabled(false);
183     setDetachAwayReason(tr("All Quassel clients vanished from the face of the earth..."));
184     setDetachAwayReasonEnabled(false);
185     setIdent("quassel");
186     setKickReason(tr("Kindergarten is elsewhere!"));
187     setPartReason(tr("https://quassel-irc.org - Chat comfortably. Anywhere."));
188     setQuitReason(tr("https://quassel-irc.org - Chat comfortably. Anywhere."));
189 }
190
191 /*** setters ***/
192
193 void Identity::setId(IdentityId _id)
194 {
195     _identityId = _id;
196     SYNC(ARG(_id))
197     emit idSet(_id);
198     setObjectName(QString::number(id().toInt()));
199 }
200
201 void Identity::setIdentityName(const QString& identityName)
202 {
203     _identityName = identityName;
204     SYNC(ARG(identityName))
205 }
206
207 void Identity::setRealName(const QString& realName)
208 {
209     _realName = realName;
210     SYNC(ARG(realName))
211 }
212
213 void Identity::setNicks(const QStringList& nicks)
214 {
215     _nicks = nicks;
216     SYNC(ARG(nicks))
217     emit nicksSet(nicks);
218 }
219
220 void Identity::setAwayNick(const QString& nick)
221 {
222     _awayNick = nick;
223     SYNC(ARG(nick))
224 }
225
226 void Identity::setAwayReason(const QString& reason)
227 {
228     _awayReason = reason;
229     SYNC(ARG(reason))
230 }
231
232 void Identity::setAwayNickEnabled(bool enabled)
233 {
234     _awayNickEnabled = enabled;
235     SYNC(ARG(enabled))
236 }
237
238 void Identity::setAwayReasonEnabled(bool enabled)
239 {
240     _awayReasonEnabled = enabled;
241     SYNC(ARG(enabled))
242 }
243
244 void Identity::setAutoAwayEnabled(bool enabled)
245 {
246     _autoAwayEnabled = enabled;
247     SYNC(ARG(enabled))
248 }
249
250 void Identity::setAutoAwayTime(int time)
251 {
252     _autoAwayTime = time;
253     SYNC(ARG(time))
254 }
255
256 void Identity::setAutoAwayReason(const QString& reason)
257 {
258     _autoAwayReason = reason;
259     SYNC(ARG(reason))
260 }
261
262 void Identity::setAutoAwayReasonEnabled(bool enabled)
263 {
264     _autoAwayReasonEnabled = enabled;
265     SYNC(ARG(enabled))
266 }
267
268 void Identity::setDetachAwayEnabled(bool enabled)
269 {
270     _detachAwayEnabled = enabled;
271     SYNC(ARG(enabled))
272 }
273
274 void Identity::setDetachAwayReason(const QString& reason)
275 {
276     _detachAwayReason = reason;
277     SYNC(ARG(reason))
278 }
279
280 void Identity::setDetachAwayReasonEnabled(bool enabled)
281 {
282     _detachAwayReasonEnabled = enabled;
283     SYNC(ARG(enabled))
284 }
285
286 void Identity::setIdent(const QString& ident)
287 {
288     _ident = ident;
289     SYNC(ARG(ident))
290 }
291
292 void Identity::setKickReason(const QString& reason)
293 {
294     _kickReason = reason;
295     SYNC(ARG(reason))
296 }
297
298 void Identity::setPartReason(const QString& reason)
299 {
300     _partReason = reason;
301     SYNC(ARG(reason))
302 }
303
304 void Identity::setQuitReason(const QString& reason)
305 {
306     _quitReason = reason;
307     SYNC(ARG(reason))
308 }
309
310 /***  ***/
311
312 void Identity::copyFrom(const Identity& other)
313 {
314     for (int idx = staticMetaObject.propertyOffset(); idx < staticMetaObject.propertyCount(); idx++) {
315         QMetaProperty metaProp = staticMetaObject.property(idx);
316         Q_ASSERT(metaProp.isValid());
317         if (this->property(metaProp.name()) != other.property(metaProp.name())) {
318             setProperty(metaProp.name(), other.property(metaProp.name()));
319         }
320     }
321 }
322
323 bool Identity::operator==(const Identity& other) const
324 {
325     for (int idx = staticMetaObject.propertyOffset(); idx < staticMetaObject.propertyCount(); idx++) {
326         QMetaProperty metaProp = staticMetaObject.property(idx);
327         Q_ASSERT(metaProp.isValid());
328         QVariant v1 = this->property(metaProp.name());
329         QVariant v2 = other.property(metaProp.name());  // qDebug() << v1 << v2;
330         // QVariant cannot compare custom types, so we need to check for this special case
331         if (QString(v1.typeName()) == "IdentityId") {
332             if (v1.value<IdentityId>() != v2.value<IdentityId>())
333                 return false;
334         }
335         else {
336             if (v1 != v2)
337                 return false;
338         }
339     }
340     return true;
341 }
342
343 bool Identity::operator!=(const Identity& other) const
344 {
345     return !(*this == other);
346 }
347
348 ///////////////////////////////
349
350 QDataStream& operator<<(QDataStream& out, Identity id)
351 {
352     out << id.toVariantMap();
353     return out;
354 }
355
356 QDataStream& operator>>(QDataStream& in, Identity& id)
357 {
358     QVariantMap i;
359     in >> i;
360     id.fromVariantMap(i);
361     return in;
362 }