00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020
00021 #ifdef ENABLE_FILE
00022
00023 #include "FileSyncSource.h"
00024
00025
00026
00027
00028
00029
00030
00031 #include <boost/algorithm/string/case_conv.hpp>
00032
00033 #include <errno.h>
00034 #include <unistd.h>
00035 #include <sys/stat.h>
00036 #include <sys/types.h>
00037
00038 #include <SyncEvolutionUtil.h>
00039
00040 #include <sstream>
00041 #include <fstream>
00042
00043 FileSyncSource::FileSyncSource(const EvolutionSyncSourceParams ¶ms,
00044 const string &dataformat) :
00045 TrackingSyncSource(params),
00046 m_entryCounter(0)
00047 {
00048 if (dataformat.empty()) {
00049 throwError("a data format must be specified");
00050 }
00051 size_t sep = dataformat.find(':');
00052 if (sep == dataformat.npos) {
00053 throwError(string("data format not specified as <mime type>:<mime version>: " + dataformat));
00054 }
00055 m_mimeType.assign(dataformat, 0, sep);
00056 m_mimeVersion = dataformat.substr(sep + 1);
00057 m_supportedTypes = dataformat;
00058 }
00059
00060 string FileSyncSource::fileSuffix() const
00061 {
00062
00063 return
00064 (m_mimeType == "text/vcard" || m_mimeType == "text/x-vcard") ? "vcf" :
00065 (m_mimeType == "text/calendar" || m_mimeType == "text/x-calendar") ? "ics" :
00066 (m_mimeType == "text/plain") ? "txt" :
00067 "dat";
00068 }
00069
00070 const char *FileSyncSource::getMimeType() const
00071 {
00072 return m_mimeType.c_str();
00073 }
00074
00075 const char *FileSyncSource::getMimeVersion() const
00076 {
00077 return m_mimeVersion.c_str();
00078 }
00079
00080 const char *FileSyncSource::getSupportedTypes() const
00081 {
00082
00083 return m_supportedTypes.c_str();
00084 }
00085
00086 void FileSyncSource::open()
00087 {
00088 const string &database = getDatabaseID();
00089 const string prefix("file://");
00090 string basedir;
00091 bool createDir = false;
00092
00093
00094
00095 if (boost::starts_with(database, prefix)) {
00096 basedir = database.substr(prefix.size());
00097 createDir = true;
00098 } else {
00099 basedir = database;
00100 }
00101
00102
00103 if (!isDir(basedir)) {
00104 if (errno == ENOENT && createDir) {
00105 mkdir_p(basedir.c_str());
00106 } else {
00107 throwError(basedir, errno);
00108 }
00109 }
00110
00111
00112 m_basedir = basedir;
00113 }
00114
00115 void FileSyncSource::close()
00116 {
00117
00118
00119
00120
00121
00122 sleepSinceModification(1);
00123
00124 m_basedir.clear();
00125 }
00126
00127 FileSyncSource::Databases FileSyncSource::getDatabases()
00128 {
00129 Databases result;
00130
00131 result.push_back(Database("select database via directory path",
00132 "[file://]<path>"));
00133 return result;
00134 }
00135
00136 void FileSyncSource::listAllItems(RevisionMap_t &revisions)
00137 {
00138 ReadDir dirContent(m_basedir);
00139
00140 BOOST_FOREACH(const string &entry, dirContent) {
00141 string filename = createFilename(entry);
00142 string revision = getATimeString(filename);
00143 long entrynum = atoll(entry.c_str());
00144 if (entrynum >= m_entryCounter) {
00145 m_entryCounter = entrynum + 1;
00146 }
00147 revisions[entry] = revision;
00148 }
00149 }
00150
00151 SyncItem *FileSyncSource::createItem(const string &uid)
00152 {
00153 string filename = createFilename(uid);
00154
00155 ifstream in;
00156 in.open(filename.c_str());
00157 ostringstream out;
00158 char buf[8192];
00159 do {
00160 in.read(buf, sizeof(buf));
00161 out.write(buf, in.gcount());
00162 } while(in);
00163 if (!in.good() && !in.eof()) {
00164 throwError(filename + ": reading failed", errno);
00165 }
00166
00167 string content = out.str();
00168 auto_ptr<SyncItem> item(new SyncItem(uid.c_str()));
00169 item->setData(content.c_str(), content.size());
00170 item->setDataType(getMimeType());
00171
00172 item->setModificationTime(0);
00173
00174 return item.release();
00175 }
00176
00177 TrackingSyncSource::InsertItemResult FileSyncSource::insertItem(const string &uid, const SyncItem &item)
00178 {
00179 string newuid = uid;
00180 string creationTime;
00181 string filename;
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 if (uid.size()) {
00194
00195 filename = createFilename(uid);
00196 } else {
00197
00198 while (true) {
00199 ostringstream buff;
00200 buff << m_entryCounter;
00201 filename = createFilename(buff.str());
00202
00203
00204
00205 struct stat dummy;
00206 if (stat(filename.c_str(), &dummy)) {
00207 if (errno == ENOENT) {
00208 newuid = buff.str();
00209 break;
00210 } else {
00211 throwError(filename, errno);
00212 }
00213 }
00214
00215 m_entryCounter++;
00216 }
00217 }
00218
00219 ofstream out;
00220 out.open(filename.c_str());
00221 out.write((const char *)item.getData(), item.getDataSize());
00222 out.close();
00223 if (!out.good()) {
00224 throwError(filename + ": writing failed", errno);
00225 }
00226
00227 return InsertItemResult(newuid,
00228 getATimeString(filename),
00229 false );
00230 }
00231
00232
00233 void FileSyncSource::deleteItem(const string &uid)
00234 {
00235 string filename = createFilename(uid);
00236
00237 if (unlink(filename.c_str())) {
00238 throwError(filename, errno);
00239 }
00240 }
00241
00242 void FileSyncSource::logItem(const string &uid, const string &info, bool debug)
00243 {
00244 if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 string filename = createFilename(uid);
00260
00261 ifstream in;
00262 in.open(filename.c_str());
00263 ostringstream out;
00264 char buf[8192];
00265 do {
00266 in.read(buf, sizeof(buf));
00267 out.write(buf, in.gcount());
00268 } while(in);
00269 logItemUtil(out.str(),
00270 m_mimeType,
00271 m_mimeVersion,
00272 uid,
00273 info,
00274 debug);
00275 }
00276 }
00277
00278 void FileSyncSource::logItem(const SyncItem &item, const string &info, bool debug)
00279 {
00280 if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
00281 if (!item.getData()) {
00282
00283 logItem(string(item.getKey()), info, debug);
00284 } else {
00285 string data = (const char *)item.getData();
00286
00287 logItemUtil(data,
00288 m_mimeType,
00289 m_mimeVersion,
00290 item.getKey(),
00291 info,
00292 debug);
00293 }
00294 }
00295 }
00296
00297 string FileSyncSource::getATimeString(const string &filename)
00298 {
00299 struct stat buf;
00300 if (stat(filename.c_str(), &buf)) {
00301 throwError(filename, errno);
00302 }
00303 time_t mtime = buf.st_mtime;
00304
00305 ostringstream revision;
00306 revision << mtime;
00307
00308 return revision.str();
00309 }
00310
00311 string FileSyncSource::createFilename(const string &entry)
00312 {
00313 string filename = m_basedir + "/" + entry;
00314 return filename;
00315 }
00316
00317 #endif
00318
00319 #ifdef ENABLE_MODULES
00320 # include "FileSyncSourceRegister.cpp"
00321 #endif