~ubuntu-branches/ubuntu/feisty/digikam/feisty

« back to all changes in this revision

Viewing changes to digikam/kioslave/digikamtags.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Achim Bohnet
  • Date: 2005-03-10 02:39:02 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 hoary)
  • Revision ID: james.westby@ubuntu.com-20050310023902-023nymfst5mg696c
Tags: 0.7.2-2
* debian/TODO: clean
* digikam manpage: better --detect-camera description

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ============================================================
 
2
 * Author: Renchi Raju <renchi@pooh.tam.uiuc.edu>
 
3
 * Date  : 2004-07-09
 
4
 * Description : 
 
5
 * 
 
6
 * Copyright 2004 by Renchi Raju
 
7
 
 
8
 * This program is free software; you can redistribute it
 
9
 * and/or modify it under the terms of the GNU General
 
10
 * Public License as published by the Free Software Foundation;
 
11
 * either version 2, or (at your option)
 
12
 * any later version.
 
13
 * 
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 * 
 
19
 * ============================================================ */
 
20
 
 
21
#include <kinstance.h>
 
22
#include <kdebug.h>
 
23
#include <kconfig.h>
 
24
#include <kurl.h>
 
25
#include <klocale.h>
 
26
#include <kglobal.h>
 
27
#include <kstandarddirs.h>
 
28
#include <kio/global.h>
 
29
 
 
30
#include <qfile.h>
 
31
#include <qfileinfo.h>
 
32
#include <qstring.h>
 
33
#include <qdir.h>
 
34
 
 
35
#include <config.h>
 
36
 
 
37
extern "C" 
 
38
{
 
39
#include <stdlib.h>
 
40
#include <unistd.h>
 
41
#include <stdio.h>
 
42
#include <sys/stat.h>
 
43
#include <sys/types.h>
 
44
#include <sqlite.h>
 
45
#include <sys/time.h>
 
46
#include <time.h>
 
47
}
 
48
 
 
49
#include "digikamtags.h"
 
50
 
 
51
kio_digikamtagsProtocol::kio_digikamtagsProtocol(const QCString &pool_socket,
 
52
                                               const QCString &app_socket)
 
53
    : SlaveBase("kio_digikamtags", pool_socket, app_socket)
 
54
{
 
55
    m_db    = 0;
 
56
    m_valid = false;
 
57
    
 
58
    KConfig config("digikamrc");
 
59
    config.setGroup("Album Settings");
 
60
    m_libraryPath = config.readPathEntry("Album Path", QString::null);
 
61
    if (m_libraryPath.isEmpty() || !QFileInfo(m_libraryPath).exists())
 
62
    {
 
63
        error(KIO::ERR_UNKNOWN, i18n("Digikam library path not set correctly."));
 
64
        return;
 
65
    }
 
66
 
 
67
    QString dbPath = m_libraryPath + "/digikam.db";
 
68
 
 
69
 
 
70
#ifdef NFS_HACK
 
71
    dbPath = QDir::homeDirPath() + "/.kde/share/apps/digikam/"  +
 
72
             KIO::encodeFileName(QDir::cleanDirPath(dbPath));
 
73
#endif
 
74
 
 
75
    char *errMsg = 0;
 
76
    m_db = sqlite_open(QFile::encodeName(dbPath), 0, &errMsg);
 
77
    if (m_db == 0)
 
78
    {
 
79
        error(KIO::ERR_UNKNOWN, i18n("Failed to open Digikam database."));
 
80
        free(errMsg);
 
81
        return;
 
82
    }
 
83
 
 
84
    m_valid = true;
 
85
}
 
86
 
 
87
kio_digikamtagsProtocol::~kio_digikamtagsProtocol()
 
88
{
 
89
    if (m_db)
 
90
    {
 
91
        sqlite_close(m_db);
 
92
    }
 
93
}
 
94
 
 
95
void kio_digikamtagsProtocol::stat(const KURL& url)
 
96
{
 
97
    if (url.equals(KURL("digikamtags:/")))
 
98
    {
 
99
        statRoot();
 
100
    }
 
101
    else
 
102
    {
 
103
        // TODO: provide some protection here against rogue apps
 
104
        statTag(url);
 
105
    }
 
106
}
 
107
 
 
108
void kio_digikamtagsProtocol::statRoot()
 
109
{
 
110
    KIO::UDSEntry entry;
 
111
    KIO::UDSAtom  atom;
 
112
 
 
113
    atom.m_uds = KIO::UDS_NAME;
 
114
    atom.m_str = "/";
 
115
    entry.append(atom);
 
116
 
 
117
    atom.m_uds  = KIO::UDS_FILE_TYPE;
 
118
    atom.m_long = S_IFDIR;
 
119
    entry.append(atom);
 
120
 
 
121
    atom.m_uds = KIO::UDS_ACCESS;
 
122
    atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
 
123
                  S_IWUSR | S_IWGRP | S_IWOTH;
 
124
    entry.append(atom);
 
125
 
 
126
    statEntry(entry);
 
127
    
 
128
    finished();
 
129
}
 
130
 
 
131
void kio_digikamtagsProtocol::statTag(const KURL &url)
 
132
{
 
133
    KIO::UDSEntry entry;
 
134
    KIO::UDSAtom  atom;
 
135
 
 
136
    atom.m_uds = KIO::UDS_NAME;
 
137
    atom.m_str = url.fileName();
 
138
    entry.append(atom);
 
139
 
 
140
    atom.m_uds  = KIO::UDS_FILE_TYPE;
 
141
    atom.m_long = S_IFDIR;
 
142
    entry.append(atom);
 
143
 
 
144
    atom.m_uds = KIO::UDS_ACCESS;
 
145
    atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
 
146
                  S_IWUSR | S_IWGRP | S_IWOTH;
 
147
    entry.append(atom);
 
148
 
 
149
    statEntry(entry);
 
150
    finished();
 
151
}
 
152
 
 
153
void kio_digikamtagsProtocol::listDir(const KURL& url)
 
154
{
 
155
    kdDebug() << k_funcinfo << url.url() << endl;
 
156
 
 
157
    if (QDir::cleanDirPath(url.path()) == "/")
 
158
    {
 
159
        kdDebug() << "Listing root " << url.url() << endl;
 
160
        
 
161
        QStringList values;
 
162
        
 
163
        execSql( QString("SELECT id, name "
 
164
                         "FROM Tags where pid=0 ORDER by name;"),
 
165
                 &values );
 
166
 
 
167
        int     id;
 
168
        QString name;
 
169
 
 
170
        KURL xurl;
 
171
        
 
172
        for (QStringList::iterator it = values.begin(); it != values.end(); )
 
173
        {
 
174
            id   = (*it++).toInt();
 
175
            name =  *it++;
 
176
 
 
177
            KIO::UDSEntry entry;
 
178
            KIO::UDSAtom  atom;
 
179
 
 
180
            atom.m_uds = KIO::UDS_NAME;
 
181
            atom.m_str = name;
 
182
            entry.append(atom);
 
183
 
 
184
            atom.m_uds  = KIO::UDS_FILE_TYPE;
 
185
            atom.m_long = S_IFDIR;
 
186
            entry.append(atom);
 
187
 
 
188
            atom.m_uds  = KIO::UDS_ACCESS;
 
189
            atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
 
190
                          S_IWUSR | S_IWGRP | S_IWOTH;
 
191
            entry.append(atom);
 
192
 
 
193
            atom.m_uds = KIO::UDS_URL;
 
194
            xurl.setProtocol("digikamtags");
 
195
            xurl.setPath(QString("/%1").arg(id));
 
196
            atom.m_str = xurl.url();
 
197
            entry.append(atom);
 
198
 
 
199
            listEntry(entry, false);
 
200
        }
 
201
    }
 
202
    else if (url.protocol() == "digikamtags")
 
203
    {
 
204
        kdDebug() << "Listing child " << url.url() << endl;
 
205
 
 
206
        int id = url.fileName().toInt();
 
207
        if (id == 0)
 
208
        {
 
209
            KIO::UDSEntry entry;
 
210
            listEntry(entry, true);
 
211
            finished();
 
212
            return;
 
213
        }
 
214
        
 
215
        // list directories first
 
216
 
 
217
        QStringList values;
 
218
        execSql( QString("SELECT id, name "
 
219
                         "FROM Tags where pid=%1 ORDER by name;")
 
220
                 .arg(QString::number(id)),
 
221
                 &values );
 
222
 
 
223
        QString name, path;
 
224
        KURL xurl;
 
225
 
 
226
        KIO::UDSEntry entry;
 
227
        KIO::UDSAtom  atom;
 
228
        
 
229
        int childid;
 
230
        for (QStringList::iterator it = values.begin(); it != values.end(); )
 
231
        {
 
232
            childid  = (*it++).toInt();
 
233
            name     =  *it++;
 
234
 
 
235
            entry.clear();
 
236
 
 
237
            atom.m_uds = KIO::UDS_NAME;
 
238
            atom.m_str = name;
 
239
            entry.append(atom);
 
240
 
 
241
            atom.m_uds  = KIO::UDS_FILE_TYPE;
 
242
            atom.m_long = S_IFDIR;
 
243
            entry.append(atom);
 
244
 
 
245
            atom.m_uds  = KIO::UDS_ACCESS;
 
246
            atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
 
247
                          S_IWUSR | S_IWGRP | S_IWOTH;
 
248
            entry.append(atom);
 
249
 
 
250
            atom.m_uds = KIO::UDS_URL;
 
251
            xurl.setProtocol("digikamtags");
 
252
            xurl.setPath(url.path(1) + QString::number(childid));
 
253
            atom.m_str = xurl.url();
 
254
            entry.append(atom);
 
255
 
 
256
            listEntry(entry, false);
 
257
        }
 
258
 
 
259
        // if host app told us to recursively get items from
 
260
        // sub tags, do so.
 
261
        bool recurse = false;
 
262
        if (url.queryItem("recurse") == "yes")
 
263
        {
 
264
            recurse = true;
 
265
        }
 
266
        
 
267
        // now list files
 
268
        buildAlbumMap();
 
269
        listDir(url, id, recurse);
 
270
 
 
271
        m_items.clear();
 
272
    }
 
273
        
 
274
        
 
275
    KIO::UDSEntry entry;
 
276
    listEntry(entry, true);
 
277
    
 
278
    finished();
 
279
}
 
280
 
 
281
void kio_digikamtagsProtocol::listDir(const KURL& url, int tagid, bool recurse)
 
282
{
 
283
    QStringList values;
 
284
 
 
285
    static const QString sqlStr = "SELECT dirid, name "
 
286
                                  "FROM ImageTags "
 
287
                                  "WHERE tagid=%1  "
 
288
                                  "ORDER BY name;";
 
289
 
 
290
    execSql( sqlStr.arg(tagid), &values );
 
291
 
 
292
    QString path;
 
293
    KURL    xurl;
 
294
    int     dirid;
 
295
    QString name;
 
296
 
 
297
    KIO::UDSEntry entry;
 
298
    KIO::UDSAtom  atom;
 
299
    
 
300
    for (QStringList::iterator it = values.begin(); it != values.end(); )
 
301
    {
 
302
        dirid = (*(it++)).toInt();
 
303
        name  =  *it++;
 
304
        path  = QDir::cleanDirPath( m_libraryPath + QString("/") +
 
305
                                    m_albumMap[dirid] + "/" + name );
 
306
 
 
307
        // check if this item is already between listed to avoid duplicate items
 
308
        // (this problem arises when you have same item under different subtags)
 
309
        if (std::binary_search(m_items.begin(), m_items.end(), path))
 
310
        {
 
311
            continue;
 
312
        }
 
313
        m_items.push_back(path);
 
314
        
 
315
        struct stat st;
 
316
        if (::stat(QFile::encodeName(path), &st) != 0)
 
317
            continue;
 
318
 
 
319
        entry.clear();
 
320
 
 
321
        atom.m_uds  = KIO::UDS_FILE_TYPE;
 
322
        atom.m_long = S_IFREG;
 
323
        entry.append(atom);
 
324
 
 
325
        atom.m_uds  = KIO::UDS_ACCESS;
 
326
        atom.m_long = st.st_mode & 07777;
 
327
        entry.append(atom);
 
328
 
 
329
        atom.m_uds  = KIO::UDS_SIZE;
 
330
        atom.m_long = st.st_size;
 
331
        entry.append( atom );
 
332
 
 
333
        atom.m_uds = KIO::UDS_MODIFICATION_TIME;
 
334
        atom.m_long = st.st_mtime;
 
335
        entry.append( atom );
 
336
 
 
337
        atom.m_uds  = KIO::UDS_ACCESS_TIME;
 
338
        atom.m_long = st.st_atime;
 
339
        entry.append( atom );
 
340
 
 
341
        atom.m_uds = KIO::UDS_URL;
 
342
        xurl.setProtocol("file");
 
343
        xurl.setPath(path);
 
344
        atom.m_str = xurl.url();
 
345
        entry.append(atom);
 
346
 
 
347
        atom.m_uds = KIO::UDS_NAME;
 
348
        atom.m_str = xurl.fileName();
 
349
        entry.append( atom );
 
350
        
 
351
        // TODO: for now we pass the dirid for this item
 
352
        // as the xml_properties. once kde 3.2 becomes a
 
353
        // requirement for kde, change this to UDS_EXTRA
 
354
        atom.m_uds = KIO::UDS_XML_PROPERTIES;
 
355
        atom.m_str = QString::number(dirid);
 
356
        entry.append( atom );
 
357
        
 
358
        listEntry(entry, false);
 
359
    }
 
360
 
 
361
    m_items.sort();
 
362
 
 
363
    if (!recurse)
 
364
        return;
 
365
 
 
366
    // recursively list files in subtags
 
367
    values.clear();
 
368
    execSql( QString("SELECT id, name FROM Tags where pid=%1;")
 
369
             .arg(QString::number(tagid)),
 
370
             &values );
 
371
 
 
372
    if (values.isEmpty())
 
373
        return;
 
374
 
 
375
    int childid;
 
376
    for (QStringList::iterator it = values.begin(); it != values.end(); )
 
377
    {
 
378
        childid  = (*it++).toInt();
 
379
        
 
380
        xurl.setProtocol("digikamtags");
 
381
        xurl.setPath(url.path(1) + (*it++));
 
382
        listDir(xurl, childid, recurse);
 
383
    }
 
384
}
 
385
 
 
386
void kio_digikamtagsProtocol::buildAlbumMap()
 
387
{
 
388
    m_albumMap.clear();
 
389
 
 
390
    static const QString sqlStr = "SELECT id, url FROM Albums;";
 
391
 
 
392
    QStringList values;
 
393
    execSql(sqlStr, &values);
 
394
 
 
395
    int     id;
 
396
    QString url;
 
397
    for (QStringList::iterator it = values.begin(); it != values.end(); )
 
398
    {
 
399
        id  = (*it++).toInt();
 
400
        url = *it++;
 
401
        m_albumMap.insert(id, url);
 
402
    }
 
403
}
 
404
 
 
405
bool kio_digikamtagsProtocol::execSql(const QString& sql,
 
406
                                      QStringList* const values, 
 
407
                                      const bool debug)
 
408
{
 
409
    if ( debug )
 
410
        kdDebug() << "SQL-query: " << sql << endl;
 
411
 
 
412
    if ( !m_db ) {
 
413
        kdWarning() << k_funcinfo << "SQLite pointer == NULL"
 
414
                    << endl;
 
415
        return false;
 
416
    }
 
417
 
 
418
    const char* tail;
 
419
    sqlite_vm* vm;
 
420
    char* errorStr;
 
421
    int error;
 
422
    
 
423
    //compile SQL program to virtual machine
 
424
    error = sqlite_compile( m_db, sql.local8Bit(), &tail, &vm, &errorStr );
 
425
 
 
426
    if ( error != SQLITE_OK ) {
 
427
        kdWarning() << k_funcinfo << "sqlite_compile error: "
 
428
                    << errorStr 
 
429
                    << " on query: " << sql << endl;
 
430
        sqlite_freemem( errorStr );
 
431
        return false;
 
432
    }
 
433
 
 
434
    int number;
 
435
    const char** value;
 
436
    const char** colName;
 
437
    //execute virtual machine by iterating over rows
 
438
    while ( true ) {
 
439
        error = sqlite_step( vm, &number, &value, &colName );
 
440
        if ( error == SQLITE_DONE || error == SQLITE_ERROR )
 
441
            break;
 
442
        //iterate over columns
 
443
        for ( int i = 0; values && i < number; i++ ) {
 
444
            *values << QString::fromLocal8Bit( value [i] );
 
445
        }
 
446
    }
 
447
    
 
448
    //deallocate vm resources
 
449
    sqlite_finalize( vm, &errorStr );
 
450
 
 
451
    if ( error != SQLITE_DONE ) {
 
452
        kdWarning() << k_funcinfo << "sqlite_step error: "
 
453
                    << errorStr
 
454
                    << " on query: " << sql << endl;
 
455
        return false;
 
456
    }
 
457
 
 
458
    return true;
 
459
}
 
460
 
 
461
/* KIO slave registration */
 
462
 
 
463
extern "C"
 
464
{
 
465
    int kdemain(int argc, char **argv)
 
466
    {
 
467
        KLocale::setMainCatalogue("digikam");
 
468
        KInstance instance( "kio_digikamtags" );
 
469
        ( void ) KGlobal::locale();
 
470
        
 
471
        kdDebug() << "*** kio_digikamtag started ***" << endl;
 
472
        
 
473
        if (argc != 4) {
 
474
            kdDebug() << "Usage: kio_digikamtags  protocol domain-socket1 domain-socket2"
 
475
                      << endl;
 
476
            exit(-1);
 
477
        }
 
478
 
 
479
        kio_digikamtagsProtocol slave(argv[2], argv[3]);
 
480
        slave.dispatchLoop();
 
481
        
 
482
        kdDebug() << "*** kio_digikamtags finished ***" << endl;
 
483
        return 0;
 
484
    }
 
485
}
 
486