File indexing completed on 2025-01-12 04:19:47
0001 /* 0002 * Copyright (C) 2003-2008 Justin Karneges <justin@affinix.com> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public 0015 * License along with this library; if not, write to the Free Software 0016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 0017 */ 0018 0019 // since keyring files are often modified by creating a new copy and 0020 // overwriting the original file, this messes up Qt's file watching 0021 // capability since the original file goes away. to work around this 0022 // problem, we'll watch the directories containing the keyring files 0023 // instead of watching the actual files themselves. 0024 // 0025 // FIXME: qca 2.0.1 FileWatch has this logic already, so we can probably 0026 // simplify this class. 0027 0028 #include "ringwatch.h" 0029 #include "qca_safetimer.h" 0030 #include "qca_support.h" 0031 #include <QFileInfo> 0032 0033 using namespace QCA; 0034 0035 namespace gpgQCAPlugin { 0036 0037 RingWatch::RingWatch(QObject *parent) 0038 : QObject(parent) 0039 { 0040 } 0041 0042 RingWatch::~RingWatch() 0043 { 0044 clear(); 0045 } 0046 0047 void RingWatch::add(const QString &filePath) 0048 { 0049 QFileInfo fi(filePath); 0050 // Try to avoid symbolic links 0051 QString path = fi.canonicalPath(); 0052 if (path.isEmpty()) 0053 path = fi.absolutePath(); 0054 0055 // watching this path already? 0056 DirWatch *dirWatch = nullptr; 0057 foreach (const DirItem &di, dirs) { 0058 if (di.dirWatch->dirName() == path) { 0059 dirWatch = di.dirWatch; 0060 break; 0061 } 0062 } 0063 0064 // if not, make a watcher 0065 if (!dirWatch) { 0066 // printf("creating dirwatch for [%s]\n", qPrintable(path)); 0067 0068 DirItem di; 0069 di.dirWatch = new DirWatch(path, this); 0070 connect(di.dirWatch, &DirWatch::changed, this, &RingWatch::dirChanged); 0071 0072 di.changeTimer = new SafeTimer(this); 0073 di.changeTimer->setSingleShot(true); 0074 connect(di.changeTimer, &SafeTimer::timeout, this, &RingWatch::handleChanged); 0075 0076 dirWatch = di.dirWatch; 0077 dirs += di; 0078 } 0079 0080 FileItem i; 0081 i.dirWatch = dirWatch; 0082 i.fileName = fi.fileName(); 0083 i.exists = fi.exists(); 0084 if (i.exists) { 0085 i.size = fi.size(); 0086 i.lastModified = fi.lastModified(); 0087 } 0088 files += i; 0089 0090 // printf("watching [%s] in [%s]\n", qPrintable(fi.fileName()), qPrintable(i.dirWatch->dirName())); 0091 } 0092 0093 void RingWatch::clear() 0094 { 0095 files.clear(); 0096 0097 foreach (const DirItem &di, dirs) { 0098 delete di.changeTimer; 0099 delete di.dirWatch; 0100 } 0101 0102 dirs.clear(); 0103 } 0104 0105 void RingWatch::dirChanged() 0106 { 0107 DirWatch *dirWatch = (DirWatch *)sender(); 0108 0109 int at = -1; 0110 for (int n = 0; n < dirs.count(); ++n) { 0111 if (dirs[n].dirWatch == dirWatch) { 0112 at = n; 0113 break; 0114 } 0115 } 0116 if (at == -1) 0117 return; 0118 0119 // we get a ton of change notifications for the dir when 0120 // something happens.. let's collect them and only 0121 // report after 100ms 0122 0123 if (!dirs[at].changeTimer->isActive()) 0124 dirs[at].changeTimer->start(100); 0125 } 0126 0127 void RingWatch::handleChanged() 0128 { 0129 SafeTimer *t = (SafeTimer *)sender(); 0130 0131 int at = -1; 0132 for (int n = 0; n < dirs.count(); ++n) { 0133 if (dirs[n].changeTimer == t) { 0134 at = n; 0135 break; 0136 } 0137 } 0138 if (at == -1) 0139 return; 0140 0141 DirWatch *dirWatch = dirs[at].dirWatch; 0142 const QString dir = dirWatch->dirName(); 0143 0144 // see which files changed 0145 QStringList changeList; 0146 for (int n = 0; n < files.count(); ++n) { 0147 FileItem &i = files[n]; 0148 QString filePath = dir + QLatin1Char('/') + i.fileName; 0149 QFileInfo fi(filePath); 0150 0151 // if the file didn't exist, and still doesn't, skip 0152 if (!i.exists && !fi.exists()) 0153 continue; 0154 0155 // size/lastModified should only get checked here if 0156 // the file existed and still exists 0157 if (fi.exists() != i.exists || fi.size() != i.size || fi.lastModified() != i.lastModified) { 0158 changeList += filePath; 0159 0160 i.exists = fi.exists(); 0161 if (i.exists) { 0162 i.size = fi.size(); 0163 i.lastModified = fi.lastModified(); 0164 } 0165 } 0166 } 0167 0168 foreach (const QString &s, changeList) 0169 emit changed(s); 0170 } 0171 0172 } // end namespace gpgQCAPlugin