e2cd936bde15b496fefd9b9918f58d0ad0d1d9b3
[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 <QVariantMap>
25 #include <QString>
26
27 #ifdef Q_OS_MAC
28 #  include <CoreServices/CoreServices.h>
29 #  include "mac_utils.h"
30 #endif
31
32 #ifdef Q_OS_UNIX
33 #  include <sys/types.h>
34 #  include <pwd.h>
35 #  include <unistd.h>
36 #endif
37
38 #ifdef Q_OS_WIN
39 #  include <windows.h>
40 #  include <Winbase.h>
41 #  define SECURITY_WIN32
42 #  include <Security.h>
43 #endif
44
45 Identity::Identity(IdentityId id, QObject *parent)
46     : SyncableObject(parent),
47     _identityId(id)
48 {
49     init();
50     setToDefaults();
51 }
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
80 #ifdef Q_OS_WIN
81 #ifdef UNICODE
82 QString tcharToQString(TCHAR *tchar)
83 {
84     return QString::fromUtf16(reinterpret_cast<ushort *>(tchar));
85 }
86
87
88 #else
89 QString tcharToQString(TCHAR *tchar)
90 {
91     return QString::fromLocal8Bit(tchar);
92 }
93
94
95 #endif
96
97 #endif
98 void Identity::init()
99 {
100     setObjectName(QString::number(id().toInt()));
101     setAllowClientUpdates(true);
102 }
103
104
105 QString Identity::defaultNick()
106 {
107     QString nick = QString("quassel%1").arg(qrand() & 0xff); // FIXME provide more sensible default nicks
108
109 #ifdef Q_OS_MAC
110     QString shortUserName = CFStringToQString(CSCopyUserName(true));
111     if (!shortUserName.isEmpty())
112         nick = shortUserName;
113
114 #elif defined(Q_OS_UNIX)
115     QString userName;
116     struct passwd *pwd = getpwuid(getuid());
117     if (pwd)
118         userName = pwd->pw_name;
119     if (!userName.isEmpty())
120         nick = userName;
121
122 #elif defined(Q_OS_WIN)
123     TCHAR infoBuf[128];
124     DWORD bufCharCount = 128;
125     //if(GetUserNameEx(/* NameSamCompatible */ 1, infoBuf, &bufCharCount))
126     if (GetUserNameEx(NameSamCompatible, infoBuf, &bufCharCount)) {
127         QString nickName(tcharToQString(infoBuf));
128         int lastBs = nickName.lastIndexOf('\\');
129         if (lastBs != -1) {
130             nickName = nickName.mid(lastBs + 1);
131         }
132         if (!nickName.isEmpty())
133             nick = nickName;
134     }
135 #endif
136
137     // cleaning forbidden characters from nick
138     QRegExp rx(QString("(^[\\d-]+|[^A-Za-z0-9\x5b-\x60\x7b-\x7d])"));
139     nick.remove(rx);
140     return nick;
141 }
142
143
144 QString Identity::defaultRealName()
145 {
146     QString generalDefault = tr("Quassel IRC User");
147
148 #ifdef Q_OS_MAC
149     return CFStringToQString(CSCopyUserName(false));
150
151 #elif defined(Q_OS_UNIX)
152     QString realName;
153     struct passwd *pwd = getpwuid(getuid());
154     if (pwd)
155         realName = QString::fromUtf8(pwd->pw_gecos);
156     if (!realName.isEmpty())
157         return realName;
158     else
159         return generalDefault;
160
161 #elif defined(Q_OS_WIN)
162     TCHAR infoBuf[128];
163     DWORD bufCharCount = 128;
164     if (GetUserName(infoBuf, &bufCharCount))
165         return tcharToQString(infoBuf);
166     else
167         return generalDefault;
168 #else
169     return generalDefault;
170 #endif
171 }
172
173
174 void Identity::setToDefaults()
175 {
176     setIdentityName(tr("<empty>"));
177     setRealName(defaultRealName());
178     QStringList n = QStringList() << defaultNick();
179     setNicks(n);
180     setAwayNick("");
181     setAwayNickEnabled(false);
182     setAwayReason(tr("Gone fishing."));
183     setAwayReasonEnabled(true);
184     setAutoAwayEnabled(false);
185     setAutoAwayTime(10);
186     setAutoAwayReason(tr("Not here. No, really. not here!"));
187     setAutoAwayReasonEnabled(false);
188     setDetachAwayEnabled(false);
189     setDetachAwayReason(tr("All Quassel clients vanished from the face of the earth..."));
190     setDetachAwayReasonEnabled(false);
191     setIdent("quassel");
192     setKickReason(tr("Kindergarten is elsewhere!"));
193     setPartReason(tr("https://quassel-irc.org - Chat comfortably. Anywhere."));
194     setQuitReason(tr("https://quassel-irc.org - Chat comfortably. Anywhere."));
195 }
196
197
198 /*** setters ***/
199
200 void Identity::setId(IdentityId _id)
201 {
202     _identityId = _id;
203     SYNC(ARG(_id))
204     emit idSet(_id);
205     renameObject(QString::number(id().toInt()));
206 }
207
208
209 void Identity::setIdentityName(const QString &identityName)
210 {
211     _identityName = identityName;
212     SYNC(ARG(identityName))
213 }
214
215
216 void Identity::setRealName(const QString &realName)
217 {
218     _realName = realName;
219     SYNC(ARG(realName))
220 }
221
222
223 void Identity::setNicks(const QStringList &nicks)
224 {
225     _nicks = nicks;
226     SYNC(ARG(nicks))
227     emit nicksSet(nicks);
228 }
229
230
231 void Identity::setAwayNick(const QString &nick)
232 {
233     _awayNick = nick;
234     SYNC(ARG(nick))
235 }
236
237
238 void Identity::setAwayReason(const QString &reason)
239 {
240     _awayReason = reason;
241     SYNC(ARG(reason))
242 }
243
244
245 void Identity::setAwayNickEnabled(bool enabled)
246 {
247     _awayNickEnabled = enabled;
248     SYNC(ARG(enabled))
249 }
250
251
252 void Identity::setAwayReasonEnabled(bool enabled)
253 {
254     _awayReasonEnabled = enabled;
255     SYNC(ARG(enabled))
256 }
257
258
259 void Identity::setAutoAwayEnabled(bool enabled)
260 {
261     _autoAwayEnabled = enabled;
262     SYNC(ARG(enabled))
263 }
264
265
266 void Identity::setAutoAwayTime(int time)
267 {
268     _autoAwayTime = time;
269     SYNC(ARG(time))
270 }
271
272
273 void Identity::setAutoAwayReason(const QString &reason)
274 {
275     _autoAwayReason = reason;
276     SYNC(ARG(reason))
277 }
278
279
280 void Identity::setAutoAwayReasonEnabled(bool enabled)
281 {
282     _autoAwayReasonEnabled = enabled;
283     SYNC(ARG(enabled))
284 }
285
286
287 void Identity::setDetachAwayEnabled(bool enabled)
288 {
289     _detachAwayEnabled = enabled;
290     SYNC(ARG(enabled))
291 }
292
293
294 void Identity::setDetachAwayReason(const QString &reason)
295 {
296     _detachAwayReason = reason;
297     SYNC(ARG(reason))
298 }
299
300
301 void Identity::setDetachAwayReasonEnabled(bool enabled)
302 {
303     _detachAwayReasonEnabled = enabled;
304     SYNC(ARG(enabled))
305 }
306
307
308 void Identity::setIdent(const QString &ident)
309 {
310     _ident = ident;
311     SYNC(ARG(ident))
312 }
313
314
315 void Identity::setKickReason(const QString &reason)
316 {
317     _kickReason = reason;
318     SYNC(ARG(reason))
319 }
320
321
322 void Identity::setPartReason(const QString &reason)
323 {
324     _partReason = reason;
325     SYNC(ARG(reason))
326 }
327
328
329 void Identity::setQuitReason(const QString &reason)
330 {
331     _quitReason = reason;
332     SYNC(ARG(reason))
333 }
334
335
336 /***  ***/
337
338 void Identity::copyFrom(const Identity &other)
339 {
340     for (int idx = staticMetaObject.propertyOffset(); idx < staticMetaObject.propertyCount(); idx++) {
341         QMetaProperty metaProp = staticMetaObject.property(idx);
342         Q_ASSERT(metaProp.isValid());
343         if (this->property(metaProp.name()) != other.property(metaProp.name())) {
344             setProperty(metaProp.name(), other.property(metaProp.name()));
345         }
346     }
347 }
348
349
350 bool Identity::operator==(const Identity &other) const
351 {
352     for (int idx = staticMetaObject.propertyOffset(); idx < staticMetaObject.propertyCount(); idx++) {
353         QMetaProperty metaProp = staticMetaObject.property(idx);
354         Q_ASSERT(metaProp.isValid());
355         QVariant v1 = this->property(metaProp.name());
356         QVariant v2 = other.property(metaProp.name()); // qDebug() << v1 << v2;
357         // QVariant cannot compare custom types, so we need to check for this special case
358         if (QString(v1.typeName()) == "IdentityId") {
359             if (v1.value<IdentityId>() != v2.value<IdentityId>()) return false;
360         }
361         else {
362             if (v1 != v2) return false;
363         }
364     }
365     return true;
366 }
367
368
369 bool Identity::operator!=(const Identity &other) const
370 {
371     return !(*this == other);
372 }
373
374
375 ///////////////////////////////
376
377 QDataStream &operator<<(QDataStream &out, Identity id)
378 {
379     out << id.toVariantMap();
380     return out;
381 }
382
383
384 QDataStream &operator>>(QDataStream &in, Identity &id)
385 {
386     QVariantMap i;
387     in >> i;
388     id.fromVariantMap(i);
389     return in;
390 }