Chris@57: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@57: Chris@57: /* Chris@57: EasyMercurial Chris@57: Chris@57: Based on HgExplorer by Jari Korhonen Chris@57: Copyright (c) 2010 Jari Korhonen Chris@644: Copyright (c) 2013 Chris Cannam Chris@644: Copyright (c) 2013 Queen Mary, University of London Chris@57: Chris@57: This program is free software; you can redistribute it and/or Chris@57: modify it under the terms of the GNU General Public License as Chris@57: published by the Free Software Foundation; either version 2 of the Chris@57: License, or (at your option) any later version. See the file Chris@57: COPYING included with this distribution for more information. Chris@57: */ jtkorhonen@0: Chris@62: #include "common.h" Chris@62: #include "debug.h" jtkorhonen@0: Chris@62: #include Chris@62: #include Chris@62: #include Chris@77: #include Chris@172: #include Chris@678: #include Chris@678: #include jtkorhonen@0: Chris@62: #include Chris@76: Chris@76: #ifdef Q_OS_WIN32 Chris@76: #define _WIN32_WINNT 0x0500 Chris@166: #define SECURITY_WIN32 Chris@76: #include Chris@76: #include Chris@455: #include Chris@76: #else Chris@78: #include Chris@62: #include Chris@78: #include Chris@80: #include Chris@80: #include Chris@80: #include Chris@80: #include Chris@105: #include Chris@443: #include Chris@76: #endif Chris@62: Chris@172: QString findInPath(QString name, QString installPath, bool executableRequired) Chris@62: { Chris@77: bool found = false; Chris@62: if (name != "") { Chris@172: if (name[0] != '/' Chris@172: #ifdef Q_OS_WIN32 Chris@178: && (QRegExp("^\\w:").indexIn(name) != 0) Chris@172: #endif Chris@178: ) { Chris@77: #ifdef Q_OS_WIN32 Chris@77: QChar pathSep = ';'; Chris@77: #else Chris@77: QChar pathSep = ':'; Chris@77: #endif Chris@62: name = QFileInfo(name).fileName(); Chris@62: QString path = Chris@62: QProcessEnvironment::systemEnvironment().value("PATH"); Chris@214: DEBUG << "findInPath: seeking location for binary " << name Chris@74: << ": system path is " << path << endl; Chris@172: if (installPath != "") { Chris@214: DEBUG << "findInPath: install path is " << installPath Chris@172: << ", adding to system path" << endl; Chris@172: //!!! path = path + pathSep + installPath; Chris@172: path = installPath + pathSep + path; Chris@172: } Chris@74: #ifndef Q_OS_WIN32 Chris@178: //!!! Chris@74: path = path + ":/usr/local/bin"; Chris@74: DEBUG << "... adding /usr/local/bin just in case (fix and add settings dlg please)" Chris@74: << endl; Chris@74: #endif Chris@62: QStringList elements = path.split(pathSep, QString::SkipEmptyParts); Chris@62: foreach (QString element, elements) { Chris@77: QString full = QDir(element).filePath(name); Chris@62: QFileInfo fi(full); Chris@214: DEBUG << "findInPath: looking at " << full << endl; Chris@172: if (fi.exists() && fi.isFile()) { Chris@214: DEBUG << "findInPath: it's a file" << endl; Chris@172: if (!executableRequired || fi.isExecutable()) { Chris@172: name = full; Chris@214: DEBUG << "findInPath: found at " << name << endl; Chris@172: found = true; Chris@172: break; Chris@172: } Chris@62: } Chris@62: } Chris@214: } else { Chris@214: // absolute path given Chris@214: QFileInfo fi(name); Chris@214: DEBUG << "findInPath: looking at absolute path " << name << endl; Chris@214: if (fi.exists() && fi.isFile()) { Chris@214: DEBUG << "findInPath: it's a file" << endl; Chris@214: if (!executableRequired || fi.isExecutable()) { Chris@214: DEBUG << "findInPath: found at " << name << endl; Chris@214: found = true; Chris@214: } Chris@214: } Chris@62: } Chris@62: } Chris@77: #ifdef Q_OS_WIN32 Chris@77: if (!found) { Chris@77: if (!name.endsWith(".exe")) { Chris@172: return findInPath(name + ".exe", installPath, executableRequired); Chris@77: } Chris@77: } Chris@77: #endif Chris@213: if (found) { Chris@213: return name; Chris@213: } else { Chris@213: return ""; Chris@213: } Chris@62: } jtkorhonen@0: Chris@62: #ifdef Q_OS_WIN32 Chris@62: QString getUserRealName() Chris@62: { Chris@76: TCHAR buf[1024]; Chris@76: long unsigned int maxlen = 1000; Chris@62: LPTSTR info = buf; jtkorhonen@0: Chris@76: if (!GetUserNameEx(NameDisplay, info, &maxlen)) { Chris@76: DEBUG << "GetUserNameEx failed: " << GetLastError() << endl; Chris@62: return ""; Chris@62: } jtkorhonen@0: Chris@76: #ifdef UNICODE Chris@76: return QString::fromUtf16((const unsigned short *)info); Chris@76: #else Chris@76: return QString::fromLocal8Bit(info); Chris@76: #endif Chris@62: } luisf@71: #else luisf@71: #ifdef Q_OS_MAC Chris@62: // Nothing here: definition is in common_osx.mm Chris@62: #else Chris@62: QString getUserRealName() Chris@62: { Chris@62: const int maxlen = 1023; Chris@62: char buf[maxlen + 2]; jtkorhonen@0: Chris@62: if (getlogin_r(buf, maxlen)) return ""; jtkorhonen@0: Chris@62: struct passwd *p = getpwnam(buf); Chris@62: if (!p) return ""; Chris@62: Chris@62: QString s(p->pw_gecos); Chris@62: if (s != "") s = s.split(',')[0]; Chris@62: return s; Chris@62: } Chris@62: #endif luisf@71: #endif jtkorhonen@0: Chris@78: void loseControllingTerminal() Chris@78: { Chris@78: #ifndef Q_OS_WIN32 Chris@80: Chris@80: if (!isatty(0)) { Chris@80: DEBUG << "stdin is not a terminal" << endl; Chris@80: } else { Chris@80: DEBUG << "stdin is a terminal, detaching from it" << endl; Chris@80: if (ioctl(0, TIOCNOTTY, NULL) < 0) { Chris@80: perror("ioctl failed"); Chris@83: DEBUG << "ioctl for TIOCNOTTY on stdin failed (errno = " << errno << ")" << endl; Chris@78: } else { Chris@83: DEBUG << "ioctl for TIOCNOTTY on stdin succeeded" << endl; Chris@83: return; Chris@78: } Chris@80: } Chris@80: Chris@80: int ttyfd = open("/dev/tty", O_RDWR); Chris@80: if (ttyfd < 0) { Chris@80: DEBUG << "failed to open controlling terminal" << endl; Chris@80: } else { Chris@80: if (ioctl(ttyfd, TIOCNOTTY, NULL) < 0) { Chris@80: perror("ioctl failed"); Chris@83: DEBUG << "ioctl for TIOCNOTTY on controlling terminal failed (errno = " << errno << ")" << endl; Chris@80: } else { Chris@83: DEBUG << "ioctl for TIOCNOTTY on controlling terminal succeeded" << endl; Chris@83: return; Chris@78: } Chris@78: } Chris@80: Chris@78: #endif Chris@78: } Chris@79: Chris@105: void installSignalHandlers() Chris@105: { Chris@105: #ifndef Q_OS_WIN32 Chris@105: sigset_t sgnals; Chris@105: sigemptyset (&sgnals); Chris@105: sigaddset(&sgnals, SIGHUP); Chris@105: sigaddset(&sgnals, SIGCONT); Chris@105: pthread_sigmask(SIG_BLOCK, &sgnals, 0); Chris@105: #endif Chris@105: } Chris@105: Chris@455: ProcessStatus Chris@455: GetProcessStatus(int pid) Chris@455: { Chris@455: #ifdef _WIN32 Chris@455: HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); Chris@455: if (!handle) { Chris@455: return ProcessNotRunning; Chris@455: } else { Chris@455: CloseHandle(handle); Chris@455: return ProcessRunning; Chris@455: } Chris@455: #else Chris@455: if (kill(getpid(), 0) == 0) { Chris@455: if (kill(pid, 0) == 0) { Chris@455: return ProcessRunning; Chris@455: } else { Chris@455: return ProcessNotRunning; Chris@455: } Chris@455: } else { Chris@455: return UnknownProcessStatus; Chris@455: } Chris@455: #endif Chris@455: } Chris@455: Chris@79: FolderStatus getFolderStatus(QString path) Chris@79: { Chris@85: if (path != "/" && path.endsWith("/")) { Chris@85: path = path.left(path.length()-1); Chris@85: } Chris@84: DEBUG << "getFolderStatus: " << path << endl; Chris@79: QFileInfo fi(path); Chris@79: if (fi.exists()) { Chris@84: DEBUG << "exists" << endl; Chris@79: QDir dir(path); Chris@79: if (!dir.exists()) { // returns false for files Chris@84: DEBUG << "not directory" << endl; Chris@79: return FolderIsFile; Chris@79: } Chris@79: if (QDir(dir.filePath(".hg")).exists()) { Chris@84: DEBUG << "has repo" << endl; Chris@79: return FolderHasRepo; Chris@79: } Chris@79: return FolderExists; Chris@79: } else { Chris@79: QDir parent = fi.dir(); Chris@79: if (parent.exists()) { Chris@84: DEBUG << "parent exists" << endl; Chris@79: return FolderParentExists; Chris@79: } Chris@79: return FolderUnknown; Chris@79: } Chris@79: } Chris@79: Chris@79: QString getContainingRepoFolder(QString path) Chris@79: { Chris@79: if (getFolderStatus(path) == FolderHasRepo) return ""; Chris@79: Chris@79: QFileInfo me(path); Chris@79: QFileInfo parent(me.dir().absolutePath()); Chris@79: Chris@79: while (me != parent) { Chris@79: QString parentPath = parent.filePath(); Chris@79: if (getFolderStatus(parentPath) == FolderHasRepo) { Chris@79: return parentPath; Chris@79: } Chris@79: me = parent; Chris@79: parent = me.dir().absolutePath(); Chris@79: } Chris@79: Chris@79: return ""; Chris@79: } Chris@79: Chris@79: QString xmlEncode(QString s) Chris@79: { Chris@79: s Chris@79: .replace("&", "&") Chris@79: .replace("<", "<") Chris@79: .replace(">", ">") Chris@79: .replace("\"", """) Chris@79: .replace("'", "'"); Chris@79: Chris@79: return s; Chris@79: } Chris@408: Chris@408: QString uniDecode(QString s) Chris@408: { Chris@408: QString d; Chris@408: for (int i = 0; i < s.length(); ++i) { Chris@412: // backslash escaped with another backslash: replace with a Chris@410: // single backslash and skip on Chris@411: if (i+1 < s.length() && s[i] == '\\' && s[i+1] == '\\') { Chris@411: d += '\\'; Chris@411: i += 1; Chris@410: continue; Chris@410: } Chris@410: // unescaped backslash followed by u and at least four more Chris@410: // chars: replace with Unicode character Chris@408: if (i+5 < s.length() && s[i] == '\\' && s[i+1] == 'u') { Chris@408: QString uni = s.mid(i+2, 4); Chris@663: QByteArray ba = QByteArray::fromHex(uni.toLatin1()); Chris@408: d += QChar(ba[1], ba[0]); Chris@408: i += 5; Chris@410: continue; Chris@408: } Chris@410: // default case: leave alone Chris@410: d += s[i]; Chris@408: } Chris@408: return d; Chris@408: } Chris@443: Chris@443: QByteArray randomKey() Chris@443: { Chris@443: static int len = 16; Chris@443: Chris@443: QByteArray ba; Chris@443: ba.resize(len); Chris@443: char *buffer = ba.data(); Chris@443: Chris@443: #ifdef Q_OS_WIN32 Chris@443: Chris@443: HCRYPTPROV provider = 0; Chris@443: if (!CryptAcquireContextW(&provider, 0, 0, Chris@443: PROV_RSA_FULL, Chris@443: CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { Chris@443: return QByteArray(); Chris@443: } Chris@443: chris@447: if (!CryptGenRandom(provider, len, (BYTE *)buffer)) { Chris@443: CryptReleaseContext(provider, 0); Chris@443: return QByteArray(); Chris@443: } Chris@443: Chris@443: CryptReleaseContext(provider, 0); Chris@443: Chris@443: #else Chris@443: Chris@443: FILE *rf = fopen("/dev/urandom", "r"); Chris@443: if (!rf) { Chris@443: return QByteArray(); Chris@443: } Chris@443: Chris@443: for (int i = 0; i < len; ++i) { Chris@443: buffer[i] = fgetc(rf); Chris@443: } Chris@443: Chris@443: fclose(rf); Chris@443: Chris@443: #endif Chris@443: Chris@443: return ba; Chris@443: } Chris@443: Chris@678: int Chris@678: scalePixelSize(int pixels) Chris@678: { Chris@678: static double ratio = 0.0; Chris@678: if (ratio == 0.0) { Chris@678: double baseEm; Chris@678: #ifdef Q_OS_MAC Chris@678: baseEm = 17.0; Chris@678: #else Chris@678: baseEm = 15.0; Chris@678: #endif Chris@678: double em = QFontMetrics(QFont()).height(); Chris@678: ratio = em / baseEm; Chris@678: } Chris@678: Chris@678: int scaled = int(pixels * ratio + 0.5); Chris@678: if (pixels != 0 && scaled == 0) scaled = 1; Chris@678: return scaled; Chris@678: } Chris@678: