|
|
|
/*
|
|
|
|
* Copyright (C) 1999-2002 Bernd Gehrmann
|
|
|
|
* bernd@mail.berlios.de
|
|
|
|
* Copyright (c) 2003 Christian Loose <christian.loose@hamburg.de>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "misc.h"
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqfileinfo.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
#include <tdeconfig.h>
|
|
|
|
#include <tdeemailsettings.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <kprocess.h>
|
|
|
|
#include <tdetempfile.h>
|
|
|
|
#include <kuser.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include "cvsservice_stub.h"
|
|
|
|
#include "progressdlg.h"
|
|
|
|
|
|
|
|
// These regular expression parts aren't useful to check the validity of the
|
|
|
|
// CVSROOT specification. They are just used to extract the different parts of it.
|
|
|
|
static const TQString userNameRegExp("([a-z0-9_][a-z0-9_-.]*)?");
|
|
|
|
static const TQString passwordRegExp("(:[^@]+)?");
|
|
|
|
static const TQString hostNameRegExp("([^:/@]+)");
|
|
|
|
static const TQString portRegExp("(:(\\d*))?");
|
|
|
|
static const TQString pathRegExp("(/.*)");
|
|
|
|
|
|
|
|
|
|
|
|
static int FindWhiteSpace(const TQString& str, int index)
|
|
|
|
{
|
|
|
|
const int length = str.length();
|
|
|
|
|
|
|
|
if( index < 0 )
|
|
|
|
index += length;
|
|
|
|
|
|
|
|
if( index < 0 || index >= length )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
const TQChar* const startPos = str.unicode();
|
|
|
|
const TQChar* const endPos = startPos + length;
|
|
|
|
|
|
|
|
const TQChar* pos = startPos + index;
|
|
|
|
while( pos < endPos && !pos->isSpace() )
|
|
|
|
++pos;
|
|
|
|
|
|
|
|
const int foundIndex = pos - startPos;
|
|
|
|
return (foundIndex < length ? foundIndex : -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const TQStringList FetchBranchesAndTags(const TQString& searchedType,
|
|
|
|
CvsService_stub* cvsService,
|
|
|
|
TQWidget* parent)
|
|
|
|
{
|
|
|
|
TQStringList branchOrTagList;
|
|
|
|
|
|
|
|
DCOPRef job = cvsService->status(TQStringList(), true, true);
|
|
|
|
if( !cvsService->ok() )
|
|
|
|
return branchOrTagList;
|
|
|
|
|
|
|
|
ProgressDialog dlg(parent, "Status", job, TQString(), i18n("CVS Status"));
|
|
|
|
|
|
|
|
if( dlg.execute() )
|
|
|
|
{
|
|
|
|
TQString line;
|
|
|
|
while( dlg.getLine(line) )
|
|
|
|
{
|
|
|
|
int wsPos, bracketPos, colonPos;
|
|
|
|
|
|
|
|
if( line.isEmpty() || line[0] != '\t' )
|
|
|
|
continue;
|
|
|
|
if( (wsPos = FindWhiteSpace(line, 2)) < 0 )
|
|
|
|
continue;
|
|
|
|
if( (bracketPos = line.find('(', wsPos + 1)) < 0 )
|
|
|
|
continue;
|
|
|
|
if( (colonPos = line.find(':', bracketPos + 1)) < 0 )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const TQString tag = line.mid(1, wsPos - 1);
|
|
|
|
const TQString type = line.mid(bracketPos + 1, colonPos - bracketPos - 1);
|
|
|
|
if( type == searchedType && !branchOrTagList.contains(tag) )
|
|
|
|
branchOrTagList.push_back(tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
branchOrTagList.sort();
|
|
|
|
}
|
|
|
|
|
|
|
|
return branchOrTagList;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Cervisia::IsValidTag(const TQString& tag)
|
|
|
|
{
|
|
|
|
static const TQString prohibitedChars("$,.:;@");
|
|
|
|
|
|
|
|
if( !isalpha(tag[0].latin1()) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for( uint i = 1; i < tag.length(); ++i )
|
|
|
|
{
|
|
|
|
if( !isgraph(tag[i].latin1()) || prohibitedChars.contains(tag[i]) )
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString Cervisia::UserName()
|
|
|
|
{
|
|
|
|
// 1. Try to retrieve the information from the control center settings
|
|
|
|
KEMailSettings settings;
|
|
|
|
TQString name = settings.getSetting(KEMailSettings::RealName);
|
|
|
|
TQString email = settings.getSetting(KEMailSettings::EmailAddress);
|
|
|
|
|
|
|
|
if( name.isEmpty() || email.isEmpty() )
|
|
|
|
{
|
|
|
|
// 2. Try to retrieve the information from the system
|
|
|
|
struct passwd* pw = getpwuid(getuid());
|
|
|
|
if( !pw )
|
|
|
|
return TQString();
|
|
|
|
|
|
|
|
char hostname[512];
|
|
|
|
hostname[0] = '\0';
|
|
|
|
|
|
|
|
if( !gethostname(hostname, sizeof(hostname)) )
|
|
|
|
hostname[sizeof(hostname)-1] = '0';
|
|
|
|
|
|
|
|
name = TQString::fromLocal8Bit(pw->pw_gecos);
|
|
|
|
email = TQString::fromLocal8Bit(pw->pw_name) + "@" +
|
|
|
|
TQString::fromLocal8Bit(hostname);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString result = name;
|
|
|
|
result += " <";
|
|
|
|
result += email;
|
|
|
|
result += ">";
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString Cervisia::NormalizeRepository(const TQString& repository)
|
|
|
|
{
|
|
|
|
// only :pserver: repositories
|
|
|
|
if( !repository.startsWith(":pserver:") )
|
|
|
|
return repository;
|
|
|
|
|
|
|
|
TQRegExp rx(":pserver:(" + userNameRegExp + passwordRegExp + "@)?" +
|
|
|
|
hostNameRegExp + portRegExp + pathRegExp);
|
|
|
|
|
|
|
|
// extract username, hostname, port and path from CVSROOT
|
|
|
|
TQString userName, hostName, port, path;
|
|
|
|
if( rx.search(repository) != -1 )
|
|
|
|
{
|
|
|
|
userName = rx.cap(2);
|
|
|
|
hostName = rx.cap(4);
|
|
|
|
port = rx.cap(6);
|
|
|
|
path = rx.cap(7);
|
|
|
|
|
|
|
|
kdDebug() << "NormalizeRepository(): username=" << userName << endl;
|
|
|
|
kdDebug() << "NormalizeRepository(): hostname=" << hostName << endl;
|
|
|
|
kdDebug() << "NormalizeRepository(): port =" << port << endl;
|
|
|
|
kdDebug() << "NormalizeRepository(): path =" << path << endl;
|
|
|
|
|
|
|
|
if( port.isEmpty() )
|
|
|
|
port = "2401";
|
|
|
|
|
|
|
|
if( userName.isEmpty() )
|
|
|
|
userName = KUser().loginName();
|
|
|
|
|
|
|
|
TQString canonicalForm = ":pserver:" + userName + "@" + hostName +
|
|
|
|
":" + port + path;
|
|
|
|
|
|
|
|
kdDebug() << "NormalizeRepository(): canonicalForm=" << canonicalForm
|
|
|
|
<< endl;
|
|
|
|
return canonicalForm;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return repository;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Cervisia::CheckOverwrite(const TQString& fileName, TQWidget* parent)
|
|
|
|
{
|
|
|
|
bool result = true;
|
|
|
|
|
|
|
|
TQFileInfo fi(fileName);
|
|
|
|
|
|
|
|
// does the file already exist?
|
|
|
|
if( fi.exists() )
|
|
|
|
{
|
|
|
|
result = (KMessageBox::warningContinueCancel(parent,
|
|
|
|
i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(fileName),
|
|
|
|
i18n("Overwrite File?"),
|
Bring filenew, fileopen, fileprint, filequickprint, filesave, filesaveas, fileclose, editclear, editcopy, editcut, editdelete, editpaste, folder_new, and gohome icons into XDG compliance
10 years ago
|
|
|
KGuiItem(i18n("&Overwrite"), "document-save", i18n("Overwrite the file"))) == KMessageBox::Continue);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString joinLine(const TQStringList &list)
|
|
|
|
{
|
|
|
|
TQString line;
|
|
|
|
for ( TQStringList::ConstIterator it = list.begin();
|
|
|
|
it != list.end(); ++it )
|
|
|
|
{
|
|
|
|
line += KShellProcess::quote(*it);
|
|
|
|
line += " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (line.length() > 0)
|
|
|
|
line.truncate(line.length()-1);
|
|
|
|
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Should be replaceable by TQStringList::split
|
|
|
|
TQStringList splitLine(TQString line, char delim)
|
|
|
|
{
|
|
|
|
int pos;
|
|
|
|
TQStringList list;
|
|
|
|
|
|
|
|
line = line.simplifyWhiteSpace();
|
|
|
|
while ((pos = line.find(delim)) != -1)
|
|
|
|
{
|
|
|
|
list.append(line.left(pos));
|
|
|
|
line = line.mid(pos+1, line.length()-pos-1);
|
|
|
|
}
|
|
|
|
if (!line.isEmpty())
|
|
|
|
list.append(line);
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const TQStringList fetchBranches(CvsService_stub* cvsService, TQWidget* parent)
|
|
|
|
{
|
|
|
|
return FetchBranchesAndTags(TQString::fromLatin1("branch"), cvsService,
|
|
|
|
parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const TQStringList fetchTags(CvsService_stub* cvsService, TQWidget* parent)
|
|
|
|
{
|
|
|
|
return FetchBranchesAndTags(TQString::fromLatin1("revision"), cvsService,
|
|
|
|
parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static TQStringList *tempFiles = 0;
|
|
|
|
|
|
|
|
void cleanupTempFiles()
|
|
|
|
{
|
|
|
|
if (tempFiles)
|
|
|
|
{
|
|
|
|
TQStringList::Iterator it;
|
|
|
|
for (it = tempFiles->begin(); it != tempFiles->end(); ++it)
|
|
|
|
TQFile::remove(*it);
|
|
|
|
delete tempFiles;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString tempFileName(const TQString& suffix)
|
|
|
|
{
|
|
|
|
if (!tempFiles)
|
|
|
|
tempFiles = new TQStringList;
|
|
|
|
|
|
|
|
KTempFile f(TQString(), suffix);
|
|
|
|
tempFiles->append(f.name());
|
|
|
|
return f.name();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int compareRevisions(const TQString& rev1, const TQString& rev2)
|
|
|
|
{
|
|
|
|
const int length1(rev1.length());
|
|
|
|
const int length2(rev2.length());
|
|
|
|
|
|
|
|
// compare all parts of the revision
|
|
|
|
|
|
|
|
int startPos1(0);
|
|
|
|
int startPos2(0);
|
|
|
|
while (startPos1 < length1 && startPos2 < length2)
|
|
|
|
{
|
|
|
|
int pos1(rev1.find('.', startPos1));
|
|
|
|
if (pos1 < 0)
|
|
|
|
pos1 = length1;
|
|
|
|
const int partLength1(pos1 - startPos1);
|
|
|
|
|
|
|
|
int pos2(rev2.find('.', startPos2));
|
|
|
|
if (pos2 < 0)
|
|
|
|
pos2 = length2;
|
|
|
|
const int partLength2(pos2 - startPos2);
|
|
|
|
|
|
|
|
// if the number of digits in both parts is not equal we are ready
|
|
|
|
if (const int comp = ::compare(partLength1, partLength2))
|
|
|
|
return comp;
|
|
|
|
|
|
|
|
// if the parts are not equal we are ready
|
|
|
|
if (const int comp = ::compare(rev1.mid(startPos1, partLength1),
|
|
|
|
rev2.mid(startPos2, partLength2)))
|
|
|
|
return comp;
|
|
|
|
|
|
|
|
// continue with next part
|
|
|
|
startPos1 = pos1 + 1;
|
|
|
|
startPos2 = pos2 + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// rev1 has more parts than rev2: rev2 < rev1
|
|
|
|
if (startPos1 < length1)
|
|
|
|
return 1;
|
|
|
|
// rev2 has more parts than rev1: rev1 < rev2
|
|
|
|
else if (startPos2 < length2)
|
|
|
|
return -1;
|
|
|
|
// all parts of rev1 and rev2 were compared (the number of parts is equal): rev1 == rev2
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|