fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / kio / kio / authinfo.cpp
blobb0d6cdc1f282173cce9e65ecc0a50577d1c20009
1 /*
2 * This file is part of the KDE libraries
3 * Copyright (C) 2000-2001 Dawit Alemayehu <adawit@kde.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library 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 GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
21 #include "authinfo.h"
23 #include <config.h>
25 #include <sys/stat.h> // don't move it down the include order, it breaks compilation on MSVC
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <sys/types.h>
31 #include <QtCore/QByteArray>
32 #include <QtCore/QDir>
33 #include <QtCore/QFile>
34 #include <kde_file.h>
36 #include <kdebug.h>
37 #include <kstandarddirs.h>
38 #include <ksavefile.h>
40 #define NETRC_READ_BUF_SIZE 4096
42 using namespace KIO;
44 //////
46 class ExtraField
48 public:
49 QString customTitle; // reserved for future use
50 AuthInfo::FieldFlags flags;
51 QVariant value;
53 ExtraField() : flags(AuthInfo::ExtraFieldNoFlags) {}
56 QDataStream& operator<< (QDataStream& s, const ExtraField& extraField)
58 s << extraField.customTitle;
59 s << (int)extraField.flags;
60 s << extraField.value;
61 return s;
64 QDataStream& operator>> (QDataStream& s, ExtraField& extraField)
66 s >> extraField.customTitle ;
67 int i;
68 s >> i;
69 extraField.flags = (AuthInfo::FieldFlags)i;
70 s >> extraField.value ;
71 return s;
75 class KIO::AuthInfoPrivate
77 public:
78 AuthInfoPrivate()
81 QMap<QString, ExtraField> extraFields;
85 //////
87 AuthInfo::AuthInfo() : d(new AuthInfoPrivate())
89 modified = false;
90 readOnly = false;
91 verifyPath = false;
92 keepPassword = false;
95 AuthInfo::AuthInfo( const AuthInfo& info ) : d(new AuthInfoPrivate())
97 (*this) = info;
100 AuthInfo::~AuthInfo()
102 delete d;
105 AuthInfo& AuthInfo::operator= ( const AuthInfo& info )
107 url = info.url;
108 username = info.username;
109 password = info.password;
110 prompt = info.prompt;
111 caption = info.caption;
112 comment = info.comment;
113 commentLabel = info.commentLabel;
114 realmValue = info.realmValue;
115 digestInfo = info.digestInfo;
116 verifyPath = info.verifyPath;
117 readOnly = info.readOnly;
118 keepPassword = info.keepPassword;
119 modified = info.modified;
120 d->extraFields = info.d->extraFields;
121 return *this;
124 bool AuthInfo::isModified() const
126 return modified;
129 void AuthInfo::setModified( bool flag )
131 modified = flag;
134 /////
136 void AuthInfo::setExtraField(const QString &fieldName, const QVariant & value)
138 d->extraFields[fieldName].value = value;
141 void AuthInfo::setExtraFieldFlags(const QString &fieldName, const FieldFlags flags)
143 d->extraFields[fieldName].flags = flags;
146 QVariant AuthInfo::getExtraField(const QString &fieldName) const
148 if (!d->extraFields.contains(fieldName)) return QVariant();
149 return d->extraFields[fieldName].value;
152 AuthInfo::FieldFlags AuthInfo::getExtraFieldFlags(const QString &fieldName) const
154 if (!d->extraFields.contains(fieldName)) return AuthInfo::ExtraFieldNoFlags;
155 return d->extraFields[fieldName].flags;
158 /////
160 QDataStream& KIO::operator<< (QDataStream& s, const AuthInfo& a)
162 s << (quint8)1
163 << a.url << a.username << a.password << a.prompt << a.caption
164 << a.comment << a.commentLabel << a.realmValue << a.digestInfo
165 << a.verifyPath << a.readOnly << a.keepPassword << a.modified
166 << a.d->extraFields;
167 return s;
170 QDataStream& KIO::operator>> (QDataStream& s, AuthInfo& a)
172 quint8 version;
173 s >> version
174 >> a.url >> a.username >> a.password >> a.prompt >> a.caption
175 >> a.comment >> a.commentLabel >> a.realmValue >> a.digestInfo
176 >> a.verifyPath >> a.readOnly >> a.keepPassword >> a.modified
177 >> a.d->extraFields;
178 return s;
182 typedef QList<NetRC::AutoLogin> LoginList;
183 typedef QMap<QString, LoginList> LoginMap;
185 class NetRC::NetRCPrivate
187 public:
188 NetRCPrivate()
189 : isDirty(false)
191 bool isDirty;
192 LoginMap loginMap;
195 NetRC* NetRC::instance = 0L;
197 NetRC::NetRC()
198 : d( new NetRCPrivate )
202 NetRC::~NetRC()
204 delete instance;
205 instance = 0L;
206 delete d;
209 NetRC* NetRC::self()
211 if ( !instance )
212 instance = new NetRC;
213 return instance;
216 bool NetRC::lookup( const KUrl& url, AutoLogin& login, bool userealnetrc,
217 const QString &_type, LookUpMode mode )
219 // kDebug() << "AutoLogin lookup for: " << url.host();
220 if ( !url.isValid() )
221 return false;
223 QString type = _type;
224 if ( type.isEmpty() )
225 type = url.protocol();
227 if ( d->loginMap.isEmpty() || d->isDirty )
229 d->loginMap.clear();
231 QString filename = KStandardDirs::locateLocal("config", QLatin1String("kionetrc"));
232 bool status = parse (openf (filename));
234 if ( userealnetrc )
236 filename = QDir::homePath() + QDir::separator() + QLatin1String(".netrc");
237 status |= parse (openf(filename));
240 if ( !status )
241 return false;
244 if ( !d->loginMap.contains( type ) )
245 return false;
247 const LoginList& l = d->loginMap[type];
248 if ( l.isEmpty() )
249 return false;
251 for (LoginList::ConstIterator it = l.begin(); it != l.end(); ++it)
253 const AutoLogin &log = *it;
255 if ( (mode & defaultOnly) == defaultOnly &&
256 log.machine == QLatin1String("default") &&
257 (login.login.isEmpty() || login.login == log.login) )
259 login.type = log.type;
260 login.machine = log.machine;
261 login.login = log.login;
262 login.password = log.password;
263 login.macdef = log.macdef;
266 if ( (mode & presetOnly) == presetOnly &&
267 log.machine == QLatin1String("preset") &&
268 (login.login.isEmpty() || login.login == log.login) )
270 login.type = log.type;
271 login.machine = log.machine;
272 login.login = log.login;
273 login.password = log.password;
274 login.macdef = log.macdef;
277 if ( (mode & exactOnly) == exactOnly &&
278 log.machine == url.host() &&
279 (login.login.isEmpty() || login.login == log.login) )
281 login.type = log.type;
282 login.machine = log.machine;
283 login.login = log.login;
284 login.password = log.password;
285 login.macdef = log.macdef;
286 break;
290 return true;
293 void NetRC::reload()
295 d->isDirty = true;
298 int NetRC::openf( const QString& f )
300 KDE_struct_stat sbuff;
301 if ( KDE::stat(f, &sbuff) != 0 )
302 return -1;
304 // Security check!!
305 if ( sbuff.st_mode != (S_IFREG|S_IRUSR|S_IWUSR) ||
306 sbuff.st_uid != geteuid() )
307 return -1;
309 return KDE::open( f, O_RDONLY );
312 QString NetRC::extract( const char* buf, const char* key, int& pos )
314 int idx = pos;
315 int m_len = strlen(key);
316 int b_len = strlen(buf);
318 while( idx < b_len )
320 while( buf[idx] == ' ' || buf[idx] == '\t' )
321 idx++;
323 if ( strncasecmp( buf+idx, key, m_len ) != 0 )
324 idx++;
325 else
327 idx += m_len;
328 while( buf[idx] == ' ' || buf[idx] == '\t' )
329 idx++;
331 int start = idx;
332 while( buf[idx] != ' ' && buf[idx] != '\t' &&
333 buf[idx] != '\n' && buf[idx] != '\r' )
334 idx++;
336 if ( idx > start )
338 pos = idx;
339 return QString::fromLatin1( buf+start, idx-start);
344 return QString();
347 bool NetRC::parse( int fd )
349 if (fd == -1)
350 return false;
352 QString type;
353 QString macro;
355 uint index = 0;
356 bool isMacro = false;
357 char* buf = new char[NETRC_READ_BUF_SIZE];
358 FILE* fstream = KDE_fdopen( fd,"rb" );
360 while ( fgets (buf, NETRC_READ_BUF_SIZE, fstream) != 0L )
362 int pos = 0;
364 while ( buf[pos] == ' ' || buf[pos] == '\t' )
365 pos++;
367 if ( buf[pos] == '#' || buf[pos] == '\n' ||
368 buf[pos] == '\r' || buf[pos] == '\0' )
370 if ( buf[pos] != '#' && isMacro )
371 isMacro = false;
373 continue;
376 if ( isMacro )
378 int tail = strlen(buf);
379 while( buf[tail-1] == '\n' || buf[tail-1] =='\r' )
380 tail--;
382 QString mac = QString::fromLatin1(buf, tail).trimmed();
383 if ( !mac.isEmpty() )
384 d->loginMap[type][index].macdef[macro].append( mac );
386 continue;
389 AutoLogin l;
390 l.machine = extract( buf, "machine", pos );
391 if ( l.machine.isEmpty() )
393 if (strncasecmp(buf+pos, "default", 7) == 0 )
395 pos += 7;
396 l.machine = QLatin1String("default");
398 else if (strncasecmp(buf+pos, "preset", 6) == 0 )
400 pos += 6;
401 l.machine = QLatin1String("preset");
404 // kDebug() << "Machine: " << l.machine;
406 l.login = extract( buf, "login", pos );
407 // kDebug() << "Login: " << l.login;
409 l.password = extract( buf, "password", pos );
410 if ( l.password.isEmpty() )
411 l.password = extract( buf, "account", pos );
412 // kDebug() << "Password: " << l.password;
414 type = l.type = extract( buf, "type", pos );
415 if ( l.type.isEmpty() && !l.machine.isEmpty() )
416 type = l.type = QLatin1String("ftp");
417 // kDebug() << "Type: " << l.type;
419 macro = extract( buf, "macdef", pos );
420 isMacro = !macro.isEmpty();
421 // kDebug() << "Macro: " << macro;
423 d->loginMap[l.type].append(l);
424 index = d->loginMap[l.type].count()-1;
427 delete [] buf;
428 fclose (fstream);
429 close (fd);
430 return true;