1 /***************************************************************************
2 * Copyright (C) 2005-08 by the Quassel IRC Team *
3 * devel@quassel-irc.org *
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. *
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. *
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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
25 #include <QCoreApplication>
33 #include "bufferinfo.h"
35 #include "syncableobject.h"
37 #if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC)
38 # define BUILD_CRASHHANDLER
39 # include <execinfo.h>
44 Quassel::BuildInfo Quassel::_buildInfo;
45 CliParser *Quassel::_cliParser = 0;
46 Quassel::RunMode Quassel::_runMode;
47 bool Quassel::_initialized = false;
48 bool Quassel::DEBUG = false;
51 Q_INIT_RESOURCE(i18n);
53 // We catch SIGTERM and SIGINT (caused by Ctrl+C) to graceful shutdown Quassel.
54 signal(SIGTERM, handleSignal);
55 signal(SIGINT, handleSignal);
57 #ifdef BUILD_CRASHHANDLER
58 signal(SIGABRT, handleSignal);
59 signal(SIGBUS, handleSignal);
60 signal(SIGSEGV, handleSignal);
61 #endif // #if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC)
63 _cliParser = new CliParser();
65 // put shared client&core arguments here
66 cliParser()->addSwitch("debug",'d', tr("Enable debug output"));
67 cliParser()->addSwitch("help",'h', tr("Display this help and exit"));
74 bool Quassel::init() {
76 return true; // allow multiple invocations because of MonolithicApplication
79 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
84 QCoreApplication::setApplicationName(buildInfo().applicationName);
85 QCoreApplication::setOrganizationName(buildInfo().organizationName);
86 QCoreApplication::setOrganizationDomain(buildInfo().organizationDomain);
88 Network::setDefaultCodecForServer("ISO-8859-1");
89 Network::setDefaultCodecForEncoding("UTF-8");
90 Network::setDefaultCodecForDecoding("ISO-8859-15");
92 if(!cliParser()->parse(QCoreApplication::arguments()) || isOptionSet("help")) {
96 DEBUG = isOptionSet("debug");
100 //! Register our custom types with Qt's Meta Object System.
101 /** This makes them available for QVariant and in signals/slots, among other things.
104 void Quassel::registerMetaTypes() {
106 qRegisterMetaType<QVariant>("QVariant");
107 qRegisterMetaType<Message>("Message");
108 qRegisterMetaType<BufferInfo>("BufferInfo");
109 qRegisterMetaType<NetworkInfo>("NetworkInfo");
110 qRegisterMetaType<Identity>("Identity");
111 qRegisterMetaType<Network::ConnectionState>("Network::ConnectionState");
113 qRegisterMetaTypeStreamOperators<QVariant>("QVariant");
114 qRegisterMetaTypeStreamOperators<Message>("Message");
115 qRegisterMetaTypeStreamOperators<BufferInfo>("BufferInfo");
116 qRegisterMetaTypeStreamOperators<NetworkInfo>("NetworkInfo");
117 qRegisterMetaTypeStreamOperators<Identity>("Identity");
118 qRegisterMetaTypeStreamOperators<qint8>("Network::ConnectionState");
120 qRegisterMetaType<IdentityId>("IdentityId");
121 qRegisterMetaType<BufferId>("BufferId");
122 qRegisterMetaType<NetworkId>("NetworkId");
123 qRegisterMetaType<UserId>("UserId");
124 qRegisterMetaType<AccountId>("AccountId");
125 qRegisterMetaType<MsgId>("MsgId");
127 qRegisterMetaTypeStreamOperators<IdentityId>("IdentityId");
128 qRegisterMetaTypeStreamOperators<BufferId>("BufferId");
129 qRegisterMetaTypeStreamOperators<NetworkId>("NetworkId");
130 qRegisterMetaTypeStreamOperators<UserId>("UserId");
131 qRegisterMetaTypeStreamOperators<AccountId>("AccountId");
132 qRegisterMetaTypeStreamOperators<MsgId>("MsgId");
135 void Quassel::setupTranslations() {
136 // Set up i18n support
137 QLocale locale = QLocale::system();
139 QTranslator *qtTranslator = new QTranslator(qApp);
140 qtTranslator->setObjectName("QtTr");
141 qtTranslator->load(QString(":i18n/qt_%1").arg(locale.name()));
142 qApp->installTranslator(qtTranslator);
144 QTranslator *quasselTranslator = new QTranslator(qApp);
145 quasselTranslator->setObjectName("QuasselTr");
146 quasselTranslator->load(QString(":i18n/quassel_%1").arg(locale.name()));
147 qApp->installTranslator(quasselTranslator);
150 void Quassel::setupBuildInfo(const QString &generated) {
151 _buildInfo.applicationName = "Quassel IRC";
152 _buildInfo.coreApplicationName = "Quassel Core";
153 _buildInfo.clientApplicationName = "Quassel Client";
154 _buildInfo.organizationName = "Quassel Project";
155 _buildInfo.organizationDomain = "quassel-irc.org";
157 QStringList gen = generated.split(',');
158 Q_ASSERT(gen.count() == 10);
159 _buildInfo.baseVersion = gen[0];
160 _buildInfo.generatedVersion = gen[1];
161 _buildInfo.isSourceDirty = !gen[2].isEmpty();
162 _buildInfo.commitHash = gen[3];
163 _buildInfo.commitDate = gen[4].toUInt();
164 _buildInfo.protocolVersion = gen[5].toUInt();
165 _buildInfo.clientNeedsProtocol = gen[6].toUInt();
166 _buildInfo.coreNeedsProtocol = gen[7].toUInt();
167 _buildInfo.buildDate = QString("%1 %2").arg(gen[8], gen[9]);
168 // create a nice version string
169 if(_buildInfo.generatedVersion.isEmpty()) {
170 if(!_buildInfo.commitHash.isEmpty()) {
172 _buildInfo.plainVersionString = QString("v%1 (dist-%2)")
173 .arg(_buildInfo.baseVersion)
174 .arg(_buildInfo.commitHash.left(7));
175 _buildInfo.fancyVersionString
176 = QString("v%1 (dist-<a href=\"http://git.quassel-irc.org/?p=quassel.git;a=commit;h=%3\">%2</a>)")
177 .arg(_buildInfo.baseVersion)
178 .arg(_buildInfo.commitHash.left(7))
179 .arg(_buildInfo.commitHash);
181 // we only have a base version :(
182 _buildInfo.plainVersionString = QString("v%1 (unknown rev)").arg(_buildInfo.baseVersion);
185 // analyze what we got from git-describe
186 QRegExp rx("(.*)-(\\d+)-g([0-9a-f]+)$");
187 if(rx.exactMatch(_buildInfo.generatedVersion)) {
188 QString distance = rx.cap(2) == "0" ? QString() : QString(" [+%1]").arg(rx.cap(2));
189 _buildInfo.plainVersionString = QString("v%1%2 (git-%3%4)")
190 .arg(rx.cap(1), distance, rx.cap(3))
191 .arg(_buildInfo.isSourceDirty ? "*" : "");
192 if(!_buildInfo.commitHash.isEmpty()) {
193 _buildInfo.fancyVersionString = QString("v%1%2 (git-<a href=\"http://git.quassel-irc.org/?p=quassel.git;a=commit;h=%5\">%3</a>%4)")
194 .arg(rx.cap(1), distance, rx.cap(3))
195 .arg(_buildInfo.isSourceDirty ? "*" : "")
196 .arg(_buildInfo.commitHash);
199 _buildInfo.plainVersionString = QString("v%1 (invalid rev)").arg(_buildInfo.baseVersion);
202 if(_buildInfo.fancyVersionString.isEmpty())
203 _buildInfo.fancyVersionString = _buildInfo.plainVersionString;
206 //! Signal handler for graceful shutdown.
207 void Quassel::handleSignal(int sig) {
211 qWarning("%s", qPrintable(QString("Caught signal %1 - exiting.").arg(sig)));
212 QCoreApplication::quit();
215 #ifdef BUILD_CRASHHANDLER
227 void Quassel::handleCrash() {
228 #ifdef BUILD_CRASHHANDLER
229 void* callstack[128];
230 int i, frames = backtrace(callstack, 128);
232 QFile dumpFile(QString("Quassel-Crash-%1").arg(QDateTime::currentDateTime().toString("yyyyMMdd-hhmm.log")));
233 dumpFile.open(QIODevice::WriteOnly);
234 QTextStream dumpStream(&dumpFile);
236 for (i = 0; i < frames; ++i) {
238 dladdr (callstack[i], &info);
242 // __const char *dli_fname; /* File name of defining object. */
243 // void *dli_fbase; /* Load address of that object. */
244 // __const char *dli_sname; /* Name of nearest symbol. */
245 // void *dli_saddr; /* Exact value of nearest symbol. */
256 char *func = abi::__cxa_demangle(info.dli_sname, 0, 0, 0);
258 funcName = QString(func);
261 funcName = QString(info.dli_sname);
264 funcName = QString("0x%1").arg((long)info.dli_saddr, addrSize, QLatin1Char('0'));
267 // prettificating the filename
268 QString fileName("???");
270 fileName = QString(info.dli_fname);
271 int slashPos = fileName.lastIndexOf('/');
273 fileName = fileName.mid(slashPos + 1);
274 if(fileName.count() < 20)
275 fileName += QString(20 - fileName.count(), ' ');
278 QString debugLine = QString("#%1 %2 0x%3 %4").arg(i, 3, 10)
280 .arg((long)(callstack[i]), addrSize, 16, QLatin1Char('0'))
283 dumpStream << debugLine << "\n";
284 qDebug() << qPrintable(debugLine);
288 #endif /* BUILD_CRASHHANDLER */