~ubuntu-branches/ubuntu/edgy/digikam/edgy-updates

« back to all changes in this revision

Viewing changes to digikam/kioslave/digikamio.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-08-28
 
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 <klargefile.h>
 
27
#include <kglobal.h>
 
28
#include <kstandarddirs.h>
 
29
#include <kio/global.h>
 
30
 
 
31
#include <qfile.h>
 
32
#include <qfileinfo.h>
 
33
#include <qstring.h>
 
34
#include <qdir.h>
 
35
 
 
36
#include <config.h>
 
37
 
 
38
extern "C" 
 
39
{
 
40
#include <stdlib.h>
 
41
#include <unistd.h>
 
42
#include <stdio.h>
 
43
#include <sys/stat.h>
 
44
#include <sys/types.h>
 
45
#include <sys/time.h>
 
46
#include <time.h>
 
47
#include <utime.h>
 
48
#include <errno.h>
 
49
#include <sqlite.h>
 
50
}
 
51
 
 
52
#include "digikamio.h"
 
53
 
 
54
kio_digikamioProtocol::kio_digikamioProtocol(const QCString &pool_socket,
 
55
                                             const QCString &app_socket)
 
56
    : SlaveBase("kio_digikamio", pool_socket, app_socket)
 
57
{
 
58
    m_db    = 0;
 
59
    m_valid = false;
 
60
    
 
61
    KConfig config("digikamrc");
 
62
    config.setGroup("Album Settings");
 
63
    m_libraryPath = config.readPathEntry("Album Path", QString::null);
 
64
    if (m_libraryPath.isEmpty() || !QFileInfo(m_libraryPath).exists())
 
65
    {
 
66
        error(KIO::ERR_UNKNOWN, i18n("Digikam Library path not set correctly"));
 
67
        return;
 
68
    }
 
69
 
 
70
    m_libraryPath = QDir::cleanDirPath(m_libraryPath);
 
71
    
 
72
    QString dbPath = m_libraryPath + "/digikam.db";
 
73
 
 
74
#ifdef NFS_HACK
 
75
    dbPath = QDir::homeDirPath() + "/.kde/share/apps/digikam/"  +
 
76
             KIO::encodeFileName(QDir::cleanDirPath(dbPath));
 
77
#endif
 
78
    
 
79
    char *errMsg = 0;
 
80
    m_db = sqlite_open(QFile::encodeName(dbPath), 0, &errMsg);
 
81
    if (m_db == 0)
 
82
    {
 
83
        error(KIO::ERR_UNKNOWN, i18n("Failed to open Digikam Database"));
 
84
        free(errMsg);
 
85
        return;
 
86
    }
 
87
 
 
88
    m_valid = true;
 
89
}
 
90
 
 
91
kio_digikamioProtocol::~kio_digikamioProtocol()
 
92
{
 
93
    if (m_db)
 
94
    {
 
95
        sqlite_close(m_db);
 
96
    }
 
97
}
 
98
 
 
99
void kio_digikamioProtocol::copy(const KURL& src, const KURL& dest,
 
100
                                 int permissions, bool overwrite)
 
101
{
 
102
    bool failed = false;
 
103
    copyInternal(src, dest, permissions, overwrite, failed);
 
104
 
 
105
    finished();
 
106
}
 
107
 
 
108
void kio_digikamioProtocol::copyInternal(const KURL& src, const KURL& dest,
 
109
                                         int permissions, bool overwrite,
 
110
                                         bool& failed)
 
111
{
 
112
    if (failed)
 
113
        return;
 
114
    
 
115
    QCString _src(  QFile::encodeName(src.path())  );
 
116
    QCString _dest( QFile::encodeName(dest.path()) );
 
117
 
 
118
    bool srcIsDir      = false;
 
119
    bool srcInLibrary  = true;
 
120
    bool destInLibrary = true;
 
121
    
 
122
    KDE_struct_stat buff_src;
 
123
    if ( KDE_stat( _src.data(), &buff_src ) == -1 )
 
124
    {
 
125
        if ( errno == EACCES )
 
126
            error( KIO::ERR_ACCESS_DENIED, src.path() );
 
127
        else
 
128
            error( KIO::ERR_DOES_NOT_EXIST, src.path() );
 
129
        failed = true;
 
130
        return;
 
131
    }
 
132
 
 
133
    // Is src a directory
 
134
    srcIsDir = S_ISDIR(buff_src.st_mode);
 
135
 
 
136
    // Is src and dest in library
 
137
    KURL libURL(m_libraryPath);
 
138
    libURL.setProtocol("digikamio");
 
139
    srcInLibrary  = libURL.isParentOf(src);
 
140
    destInLibrary = libURL.isParentOf(dest);
 
141
 
 
142
    if (!destInLibrary)
 
143
    {
 
144
        kdWarning() << "This should not happen. "
 
145
                    << "Destination URL not in album library Path. "
 
146
                    << dest.prettyURL() << endl;
 
147
        error(KIO::ERR_UNKNOWN, i18n("Destination URL not in album library Path."));
 
148
        failed = true;
 
149
        return;
 
150
    }
 
151
 
 
152
    KDE_struct_stat buff_dest;
 
153
    bool dest_exists = ( KDE_stat( _dest.data(), &buff_dest ) != -1 );
 
154
    if ( dest_exists )
 
155
    {
 
156
        if (S_ISDIR(buff_dest.st_mode))
 
157
        {
 
158
            error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
 
159
            failed = true;
 
160
            return;
 
161
        }
 
162
 
 
163
        if (!overwrite)
 
164
        {
 
165
            error( KIO::ERR_FILE_ALREADY_EXIST, dest.path() );
 
166
            failed = true;
 
167
            return;
 
168
        }
 
169
    }
 
170
 
 
171
    // Four possible scenarios:
 
172
    // a. dir in library being copied to another location
 
173
    // b. external dir being copied into library
 
174
    // c. file from one album being copied to another album
 
175
    // d. external file being copied into an album 
 
176
    
 
177
    
 
178
    if (srcIsDir && srcInLibrary)
 
179
    {
 
180
        // a. dir in library being copied to another location
 
181
 
 
182
        infoMessage(i18n("Copying folder\n%1")
 
183
                    .arg(src.path()));
 
184
        
 
185
        // lock the database
 
186
        execSql( "BEGIN TRANSACTION;" );
 
187
 
 
188
        bool success = true;
 
189
        
 
190
        // first make the directory
 
191
        if (::mkdir(_dest.data(), buff_src.st_mode))
 
192
        {
 
193
            if (( errno == EACCES ) || (errno == EPERM) || (errno == EROFS)) 
 
194
                error( KIO::ERR_ACCESS_DENIED, dest.path() );
 
195
            else if (errno == EEXIST)
 
196
                error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
 
197
            else if (errno == ENOSPC)
 
198
                error( KIO::ERR_DISK_FULL, dest.path() );
 
199
            else 
 
200
                error( KIO::ERR_COULD_NOT_MKDIR, dest.path() );
 
201
 
 
202
            success = false;
 
203
            failed  = true;
 
204
        }            
 
205
 
 
206
        if ( success )
 
207
        {
 
208
            QString oldURL = escapeString( albumURLFromKURL(src)  );
 
209
            QString newURL = escapeString( albumURLFromKURL(dest) );
 
210
            
 
211
            // delete any stale album
 
212
            removeDirFromDB( newURL );
 
213
 
 
214
            // copy the attributes of the original album to this
 
215
            execSql( QString("INSERT INTO Albums (url, date, caption, collection) "
 
216
                             "SELECT '%1',date,caption,collection FROM Albums "
 
217
                             "WHERE url='%2';")
 
218
                     .arg(escapeString(newURL))
 
219
                     .arg(escapeString(oldURL)) );
 
220
 
 
221
        }
 
222
 
 
223
        // unlock the database
 
224
        execSql( "COMMIT TRANSACTION;" );
 
225
 
 
226
        if ( !success )
 
227
        {
 
228
            failed = true;
 
229
            return;
 
230
        }
 
231
        
 
232
        // now read the old directory and start copying each of entries
 
233
        QDir dir( src.path(-1) );
 
234
        dir.setFilter( QDir::Dirs | QDir::Files | QDir::NoSymLinks );
 
235
        dir.setSorting( QDir::DirsFirst | QDir::Name );
 
236
        
 
237
        const QFileInfoList *infoList = dir.entryInfoList();
 
238
        if ( infoList )
 
239
        {
 
240
            QFileInfoListIterator it( *infoList );
 
241
            QFileInfo *fi;
 
242
            
 
243
            while ( (fi = it.current()) != 0 )
 
244
            {
 
245
                ++it;
 
246
                if (fi->fileName().startsWith("."))
 
247
                    continue;
 
248
                    
 
249
                KURL surl( src );
 
250
                surl.addPath( fi->fileName() );
 
251
                    
 
252
                KURL durl( dest );
 
253
                durl.addPath( fi->fileName() );
 
254
                    
 
255
                copyInternal( surl, durl, permissions, overwrite, failed );
 
256
                if ( failed )
 
257
                    return;
 
258
            }
 
259
        }
 
260
 
 
261
        return;
 
262
 
 
263
    }
 
264
    else if (srcIsDir)
 
265
    {
 
266
        // b. external dir being copied into library
 
267
 
 
268
        infoMessage(i18n("Copying folder\n%1")
 
269
                    .arg(src.path()));
 
270
        
 
271
        bool success = true;
 
272
        
 
273
        // first make the directory
 
274
        if (::mkdir(_dest.data(), buff_src.st_mode))
 
275
        {
 
276
            if (( errno == EACCES ) || (errno == EPERM) || (errno == EROFS)) 
 
277
                error( KIO::ERR_ACCESS_DENIED, dest.path() );
 
278
            else if (errno == EEXIST)
 
279
                error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
 
280
            else if (errno == ENOSPC)
 
281
                error( KIO::ERR_DISK_FULL, dest.path() );
 
282
            else 
 
283
                error( KIO::ERR_COULD_NOT_MKDIR, dest.path() );
 
284
 
 
285
            success = false;
 
286
            failed  = true;
 
287
        }            
 
288
 
 
289
        if ( !success )
 
290
        {
 
291
            failed = true;
 
292
            return;
 
293
        }
 
294
        
 
295
        // now read the old directory and start copying each of entries
 
296
        QDir dir( src.path(-1) );
 
297
        dir.setFilter( QDir::Dirs | QDir::Files | QDir::NoSymLinks );
 
298
        dir.setSorting( QDir::DirsFirst | QDir::Name );
 
299
        
 
300
        const QFileInfoList *infoList = dir.entryInfoList();
 
301
        if ( infoList )
 
302
        {
 
303
            QFileInfoListIterator it( *infoList );
 
304
            QFileInfo *fi;
 
305
            while ( (fi = it.current()) != 0 )
 
306
            {
 
307
                ++it;
 
308
                if (fi->fileName().startsWith("."))
 
309
                    continue;
 
310
 
 
311
                KURL surl( src );
 
312
                surl.addPath( fi->fileName() );
 
313
                
 
314
                KURL durl( dest );
 
315
                durl.addPath( fi->fileName() );
 
316
                
 
317
                copyInternal( surl, durl, permissions, overwrite, failed );
 
318
                if ( failed )
 
319
                    return;
 
320
 
 
321
            }
 
322
        }
 
323
    }
 
324
    else if (srcInLibrary)
 
325
    {
 
326
        // c. file from one album being copied to another album
 
327
 
 
328
        infoMessage(i18n("Copying file\n%1")
 
329
                    .arg(src.path()));
 
330
        
 
331
        // find the parent albums
 
332
        QString oldParentURL(albumURLFromKURL(src.upURL()));
 
333
        QString newParentURL(albumURLFromKURL(dest.upURL()));
 
334
 
 
335
        // find the album ids
 
336
        int oldDirID;
 
337
        int newDirID;
 
338
 
 
339
        QStringList vals;
 
340
        
 
341
        execSql( QString("SELECT id FROM Albums WHERE url = '%1'")
 
342
                 .arg(escapeString(oldParentURL)), &vals );
 
343
        if (vals.isEmpty())
 
344
        {
 
345
            error(KIO::ERR_UNKNOWN,
 
346
                  i18n("Could not find source parent album for %1")
 
347
                  .arg(src.path()));
 
348
            failed = true;
 
349
            return;
 
350
        }
 
351
        oldDirID = vals.first().toInt();
 
352
 
 
353
        vals.clear();
 
354
        execSql( QString("SELECT id FROM Albums WHERE url = '%1'")
 
355
                 .arg(escapeString(newParentURL)), &vals );
 
356
        if (vals.isEmpty())
 
357
        {
 
358
            error(KIO::ERR_UNKNOWN,
 
359
                  i18n("Could not find destination parent album for %1")
 
360
                  .arg(dest.prettyURL()));
 
361
            failed = true;
 
362
            return;
 
363
        }
 
364
        newDirID = vals.first().toInt();
 
365
        
 
366
        // first copy to a tmp file
 
367
        KURL destDirURL(dest.upURL());
 
368
        destDirURL.addPath(QString(".digikamio-%1")
 
369
                           .arg(getpid()));
 
370
 
 
371
        QString tmpFile(destDirURL.path());
 
372
 
 
373
        if (!copyFile(src.path(), tmpFile))
 
374
        {
 
375
            error(KIO::ERR_COULD_NOT_WRITE, dest.prettyURL());
 
376
            kdWarning() << k_funcinfo << "Failed to copy file to temporary file. "
 
377
                        << "src: " << _src << ", temp: " << tmpFile <<  endl;
 
378
            failed = true;
 
379
            return;
 
380
        }
 
381
 
 
382
        // now rename to dest file
 
383
        execSql( "BEGIN TRANSACTION;" );
 
384
 
 
385
        if (::rename( QFile::encodeName(tmpFile), _dest.data()))
 
386
        {
 
387
            unlink( QFile::encodeName(tmpFile) );
 
388
            error(KIO::ERR_COULD_NOT_WRITE, dest.prettyURL());
 
389
            kdWarning() << k_funcinfo << "Failed to rename temporary file to destination file: "
 
390
                        << _dest <<  endl;
 
391
            failed = true;
 
392
        }
 
393
        else
 
394
        {
 
395
            // successful copy: now copy the file metadata
 
396
 
 
397
            // first delete any stale database entries if any
 
398
            removeFileFromDB(newDirID, dest.fileName());
 
399
    
 
400
            execSql( QString("INSERT INTO Images (dirid, name, caption, datetime) "
 
401
                             "SELECT %1, '%2', caption, datetime FROM Images "
 
402
                             "WHERE dirid=%3 AND name='%4';")
 
403
                     .arg(newDirID)
 
404
                     .arg(escapeString(dest.fileName()))
 
405
                     .arg(oldDirID)
 
406
                     .arg(escapeString(src.fileName())) );
 
407
 
 
408
            execSql( QString("INSERT INTO ImageTags (dirid, name, tagid) "
 
409
                             "SELECT %1, '%2', tagid FROM ImageTags "
 
410
                             "WHERE dirid=%3 AND name='%4';")
 
411
                     .arg(newDirID)
 
412
                     .arg(escapeString(dest.fileName()))
 
413
                     .arg(oldDirID)
 
414
                     .arg(escapeString(src.fileName())) );
 
415
 
 
416
            // also set the filetime to that of the original file
 
417
            struct utimbuf t;
 
418
            t.actime  = buff_src.st_atime;
 
419
            t.modtime = buff_src.st_mtime;
 
420
 
 
421
            if ( ::utime( _dest.data(), &t ) != 0 )
 
422
            {
 
423
                kdWarning() << k_funcinfo
 
424
                            << "Failed to set datetime of destination file "
 
425
                            << "to that of of original file" << endl;
 
426
            }
 
427
        }
 
428
 
 
429
        execSql( "COMMIT TRANSACTION;");
 
430
 
 
431
        return;
 
432
    }
 
433
    else
 
434
    {
 
435
        // d. external file being copied into an album
 
436
 
 
437
        infoMessage(i18n("Copying file\n%1")
 
438
                    .arg(src.path()));
 
439
 
 
440
        // first copy to a tmp file
 
441
        KURL destDirURL(dest.upURL());
 
442
        destDirURL.addPath(QString(".digikamio-%1")
 
443
                           .arg(getpid()));
 
444
 
 
445
        QString tmpFile(destDirURL.path());
 
446
 
 
447
        if (!copyFile(src.path(), tmpFile))
 
448
        {
 
449
            error(KIO::ERR_COULD_NOT_WRITE, dest.prettyURL());
 
450
            failed = true;
 
451
            return;
 
452
        }
 
453
 
 
454
        // now rename to the dest file
 
455
        if (::rename( QFile::encodeName(tmpFile), _dest.data()))
 
456
        {
 
457
            unlink( QFile::encodeName(tmpFile) );
 
458
            error(KIO::ERR_COULD_NOT_WRITE, dest.prettyURL());
 
459
            failed = true;
 
460
            return;
 
461
        }
 
462
 
 
463
        // also set the filetime to that of the original file
 
464
        struct utimbuf t;
 
465
        t.actime  = buff_src.st_atime;
 
466
        t.modtime = buff_src.st_mtime;
 
467
 
 
468
        if ( ::utime( _dest.data(), &t ) != 0 )
 
469
        {
 
470
            kdWarning() << k_funcinfo
 
471
                        << "Failed to set datetime of destination file "
 
472
                        << "to that of of original file" << endl;
 
473
        }
 
474
    }
 
475
}
 
476
 
 
477
void kio_digikamioProtocol::rename(const KURL &src, const KURL &dest,
 
478
                                   bool overwrite)
 
479
{
 
480
    QCString _src(  QFile::encodeName(src.path())  );
 
481
    QCString _dest( QFile::encodeName(dest.path()) );
 
482
 
 
483
    bool srcIsDir      = false;
 
484
    bool srcInLibrary  = true;
 
485
    bool destInLibrary = true;
 
486
    
 
487
    KDE_struct_stat buff_src;
 
488
    if ( KDE_stat( _src.data(), &buff_src ) == -1 )
 
489
    {
 
490
        if ( errno == EACCES )
 
491
            error( KIO::ERR_ACCESS_DENIED, src.path() );
 
492
        else
 
493
            error( KIO::ERR_DOES_NOT_EXIST, src.path() );
 
494
        finished();
 
495
        return;
 
496
    }
 
497
 
 
498
    // Is src a directory
 
499
    srcIsDir = S_ISDIR(buff_src.st_mode);
 
500
 
 
501
    // Is src and dest in library
 
502
    KURL libURL(m_libraryPath);
 
503
    libURL.setProtocol("digikamio");
 
504
    srcInLibrary  = libURL.isParentOf(src);
 
505
    destInLibrary = libURL.isParentOf(dest);
 
506
 
 
507
    if (!destInLibrary)
 
508
    {
 
509
        kdWarning() << "This should not happen. "
 
510
                    << "Destination URL not in album library Path. "
 
511
                    << dest.prettyURL() << endl;
 
512
        error(KIO::ERR_UNKNOWN, i18n("Destination URL not in album library Path."));
 
513
        finished();
 
514
        return;
 
515
    }
 
516
 
 
517
    KDE_struct_stat buff_dest;
 
518
    bool dest_exists = ( KDE_stat( _dest.data(), &buff_dest ) != -1 );
 
519
    if ( dest_exists )
 
520
    {
 
521
        if (S_ISDIR(buff_dest.st_mode))
 
522
        {
 
523
            error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
 
524
            finished();
 
525
            return;
 
526
        }
 
527
 
 
528
        if (!overwrite)
 
529
        {
 
530
            error( KIO::ERR_FILE_ALREADY_EXIST, dest.path() );
 
531
            finished();
 
532
            return;
 
533
        }
 
534
    }
 
535
 
 
536
    if (srcIsDir && srcInLibrary)
 
537
    {
 
538
        // moving or renaming an album;
 
539
 
 
540
        infoMessage(i18n("Moving folder\n%1")
 
541
                    .arg(src.path()));
 
542
 
 
543
        // lock the database
 
544
        execSql( "BEGIN TRANSACTION;" );
 
545
 
 
546
        bool success = true;
 
547
        
 
548
        if (::rename( _src.data(), _dest.data()))
 
549
        {
 
550
            if (( errno == EACCES ) || (errno == EPERM)) 
 
551
                error( KIO::ERR_ACCESS_DENIED, dest.path() );
 
552
            else if (errno == EXDEV) 
 
553
                error( KIO::ERR_UNSUPPORTED_ACTION, QString::fromLatin1("rename"));
 
554
            else if (errno == EROFS)  // The file is on a read-only filesystem
 
555
                error( KIO::ERR_CANNOT_DELETE, src.path() );
 
556
            else 
 
557
                error( KIO::ERR_CANNOT_RENAME, src.path() );
 
558
 
 
559
            success = false;
 
560
        }
 
561
 
 
562
        if (success)
 
563
        {
 
564
            // first rename the album in the database
 
565
 
 
566
            QString oldURL = escapeString( albumURLFromKURL(src)  );
 
567
            QString newURL = escapeString( albumURLFromKURL(dest) );
 
568
 
 
569
            // delete any stale albums left behind
 
570
            removeDirFromDB( newURL );
 
571
 
 
572
            // update album url
 
573
            execSql( QString("UPDATE Albums SET url = '%1' WHERE url = '%2';")
 
574
                     .arg(escapeString(newURL))
 
575
                     .arg(escapeString(oldURL)) );
 
576
 
 
577
            // Now rename all the subalbums
 
578
 
 
579
            QStringList suburls;
 
580
            
 
581
            execSql( QString("SELECT url FROM Albums WHERE url LIKE '%1/%'")
 
582
                     .arg(escapeString(oldURL)), &suburls );
 
583
            for (QStringList::iterator it = suburls.begin(); it != suburls.end();
 
584
                 ++it)
 
585
            {
 
586
                QString url(*it);
 
587
                url.remove(0,oldURL.length());
 
588
                url.prepend(newURL);
 
589
 
 
590
                url = escapeString(url);
 
591
                
 
592
                // delete any stale albums left behind
 
593
                execSql( QString("DELETE FROM Albums WHERE url = '%1'")
 
594
                         .arg(escapeString(url)) );
 
595
 
 
596
                // update album url
 
597
                execSql( QString("UPDATE Albums SET url = '%1' WHERE url = '%2';")
 
598
                         .arg(escapeString(url))
 
599
                         .arg(escapeString(*it)) );
 
600
            }
 
601
        }
 
602
        
 
603
        // unlock the database
 
604
        execSql( "COMMIT TRANSACTION;" );
 
605
 
 
606
        finished();
 
607
        return;
 
608
    }
 
609
    else if (srcIsDir)
 
610
    {
 
611
        // moving an external folder into album library
 
612
        // nothing to do here. just rename the folder
 
613
 
 
614
        infoMessage(i18n("Moving folder\n%1")
 
615
                    .arg(src.path()));
 
616
        
 
617
        if (::rename( _src.data(), _dest.data()))
 
618
        {
 
619
            if (( errno == EACCES ) || (errno == EPERM)) 
 
620
                error( KIO::ERR_ACCESS_DENIED, dest.path() );
 
621
            else if (errno == EXDEV) 
 
622
                error( KIO::ERR_UNSUPPORTED_ACTION, QString::fromLatin1("rename"));
 
623
            else if (errno == EROFS)  // The file is on a read-only filesystem
 
624
                error( KIO::ERR_CANNOT_DELETE, src.path() );
 
625
            else 
 
626
                error( KIO::ERR_CANNOT_RENAME, src.path() );
 
627
            finished();
 
628
        }
 
629
 
 
630
        finished();
 
631
        return;
 
632
    }
 
633
    else if (srcInLibrary)
 
634
    {
 
635
        // moving a file within the album library
 
636
 
 
637
        infoMessage(i18n("Moving file\n%1")
 
638
                    .arg(src.path()));
 
639
 
 
640
        // find the parent albums
 
641
        QString oldParentURL(albumURLFromKURL(src.upURL()));
 
642
        QString newParentURL(albumURLFromKURL(dest.upURL()));
 
643
 
 
644
        // find the album ids
 
645
        int oldDirID;
 
646
        int newDirID;
 
647
 
 
648
        QStringList vals;
 
649
        
 
650
        execSql( QString("SELECT id FROM Albums WHERE url = '%1'")
 
651
                 .arg(escapeString(oldParentURL)), &vals );
 
652
        if (vals.isEmpty())
 
653
        {
 
654
            error(KIO::ERR_UNKNOWN,
 
655
                  i18n("Could not find source parent album for %1")
 
656
                  .arg(src.path()));
 
657
            finished();
 
658
            return;
 
659
        }
 
660
        oldDirID = vals.first().toInt();
 
661
 
 
662
        vals.clear();
 
663
        execSql( QString("SELECT id FROM Albums WHERE url = '%1'")
 
664
                 .arg(escapeString(newParentURL)), &vals );
 
665
        if (vals.isEmpty())
 
666
        {
 
667
            error(KIO::ERR_UNKNOWN,
 
668
                  i18n("Could not find destination parent album for %1")
 
669
                  .arg(dest.prettyURL()));
 
670
            finished();
 
671
            return;
 
672
        }
 
673
        newDirID = vals.first().toInt();
 
674
 
 
675
        // lock the database
 
676
        execSql( "BEGIN TRANSACTION;" );
 
677
 
 
678
        bool success = true;
 
679
        
 
680
        if (::rename( _src.data(), _dest.data()))
 
681
        {
 
682
            if (( errno == EACCES ) || (errno == EPERM)) 
 
683
                error( KIO::ERR_ACCESS_DENIED, dest.path() );
 
684
            else if (errno == EXDEV) 
 
685
                error( KIO::ERR_UNSUPPORTED_ACTION, QString::fromLatin1("rename"));
 
686
            else if (errno == EROFS)  // The file is on a read-only filesystem
 
687
                error( KIO::ERR_CANNOT_DELETE, src.path() );
 
688
            else 
 
689
                error( KIO::ERR_CANNOT_RENAME, src.path() );
 
690
 
 
691
            success = false;
 
692
        }
 
693
 
 
694
        QString oldFileName(src.fileName());
 
695
        QString newFileName(dest.fileName());
 
696
        
 
697
        if (success)
 
698
        {
 
699
            // delete stale items
 
700
            removeFileFromDB(newDirID, newFileName);
 
701
            
 
702
            execSql( QString("UPDATE Images SET dirid=%1, name='%2' "
 
703
                             "WHERE dirid=%3 AND name='%4';")
 
704
                     .arg(newDirID)
 
705
                     .arg(escapeString(newFileName))
 
706
                     .arg(oldDirID)
 
707
                     .arg(escapeString(oldFileName)) );
 
708
 
 
709
            execSql( QString("UPDATE ImageTags SET dirid=%1, name='%2' "
 
710
                             "WHERE dirid=%3 AND name='%4';")
 
711
                     .arg(newDirID)
 
712
                     .arg(escapeString(newFileName))
 
713
                     .arg(oldDirID)
 
714
                     .arg(escapeString(oldFileName)) );
 
715
 
 
716
            // if the image is used for the tag icon, the tags.icon column
 
717
            // has to be updated
 
718
 
 
719
            execSql( QString("UPDATE Tags SET icon='%1' "
 
720
                             "WHERE icon='%2';")
 
721
                     .arg(escapeString(QDir::cleanDirPath(dest.path())))
 
722
                     .arg(escapeString(QDir::cleanDirPath(src.path()))) );
 
723
        }
 
724
        
 
725
        // unlock the database
 
726
        execSql( "COMMIT TRANSACTION;" );
 
727
 
 
728
        finished();
 
729
        return;
 
730
    }
 
731
    else
 
732
    {
 
733
        // external file being moved into album library 
 
734
        // nothing to do here. just rename the file
 
735
 
 
736
        infoMessage(i18n("Moving file\n%1")
 
737
                    .arg(src.path()));
 
738
 
 
739
        if ( ::rename( _src.data(), _dest.data()))
 
740
        {
 
741
            if (( errno == EACCES ) || (errno == EPERM)) 
 
742
                error( KIO::ERR_ACCESS_DENIED, dest.path() );
 
743
            else if (errno == EXDEV) 
 
744
                error( KIO::ERR_UNSUPPORTED_ACTION, QString::fromLatin1("rename"));
 
745
            else if (errno == EROFS)  // The file is on a read-only filesystem
 
746
                error( KIO::ERR_CANNOT_DELETE, src.path() );
 
747
            else 
 
748
                error( KIO::ERR_CANNOT_RENAME, src.path() );
 
749
            finished();
 
750
            return;
 
751
        }
 
752
 
 
753
        finished();
 
754
        return;
 
755
    }
 
756
}
 
757
 
 
758
void kio_digikamioProtocol::del(const KURL& url, bool isfile)
 
759
{
 
760
    QCString path( QFile::encodeName(url.path()));
 
761
 
 
762
    if (isfile)
 
763
    {
 
764
        kdDebug() <<  "Deleting file "<< url.url() << endl;
 
765
 
 
766
        // find the parent album
 
767
        QString parentURL(albumURLFromKURL(url.upURL()));
 
768
 
 
769
        // find the album id
 
770
        int dirID;
 
771
 
 
772
        QStringList vals;
 
773
        
 
774
        execSql( QString("SELECT id FROM Albums WHERE url = '%1'")
 
775
                 .arg(escapeString(parentURL)), &vals );
 
776
        if (vals.isEmpty())
 
777
        {
 
778
            error(KIO::ERR_UNKNOWN,
 
779
                  i18n("Could not find source parent album for %1")
 
780
                  .arg(url.path()));
 
781
            return;
 
782
        }
 
783
        dirID = vals.first().toInt();
 
784
 
 
785
        execSql( "BEGIN TRANSACTION;" );
 
786
        
 
787
        if (::unlink(path.data()) == 0)
 
788
        {
 
789
            // delete the item from the database
 
790
            execSql( QString("DELETE FROM Images "
 
791
                             "WHERE dirid=%1 AND name='%2';")
 
792
                     .arg(dirID)
 
793
                     .arg(escapeString(url.fileName())) );
 
794
            
 
795
            execSql( QString("DELETE FROM ImageTags "
 
796
                             "WHERE dirid=%1 AND name='%2';")
 
797
                     .arg(dirID)
 
798
                     .arg(escapeString(url.fileName())) );
 
799
        }
 
800
        else
 
801
        {
 
802
            if ((errno == EACCES) || (errno == EPERM))
 
803
                error( KIO::ERR_ACCESS_DENIED, url.path());
 
804
            else if (errno == EISDIR)
 
805
                error( KIO::ERR_IS_DIRECTORY, url.path());
 
806
            else
 
807
                error( KIO::ERR_CANNOT_DELETE, url.path() );
 
808
        }
 
809
 
 
810
        execSql( "COMMIT TRANSACTION;" );
 
811
    }
 
812
    else
 
813
    {
 
814
        kdDebug() << "Deleting folder not supported yet" << endl;
 
815
        
 
816
        error( KIO::ERR_COULD_NOT_RMDIR, url.path() );
 
817
    }
 
818
 
 
819
    finished();
 
820
}
 
821
 
 
822
void kio_digikamioProtocol::stat(const KURL& url)
 
823
{
 
824
    QCString path( QFile::encodeName(url.path(-1)));
 
825
    KIO::UDSEntry entry;
 
826
 
 
827
    KIO::UDSAtom atom;
 
828
    atom.m_uds = KIO::UDS_NAME;
 
829
    atom.m_str = url.fileName();
 
830
    entry.append( atom );
 
831
 
 
832
    mode_t type;
 
833
    mode_t access;
 
834
    KDE_struct_stat buff;
 
835
 
 
836
    if (KDE_stat( path.data(), &buff ))
 
837
    {
 
838
        error( KIO::ERR_DOES_NOT_EXIST, url.path(-1) );
 
839
        return;
 
840
    }
 
841
 
 
842
    type = buff.st_mode & S_IFMT; // extract file type
 
843
    access = buff.st_mode & 07777; // extract permissions
 
844
 
 
845
    atom.m_uds = KIO::UDS_FILE_TYPE;
 
846
    atom.m_long = type;
 
847
    entry.append( atom );
 
848
 
 
849
    atom.m_uds = KIO::UDS_ACCESS;
 
850
    atom.m_long = access;
 
851
    entry.append( atom );
 
852
 
 
853
    atom.m_uds = KIO::UDS_SIZE;
 
854
    atom.m_long = buff.st_size;
 
855
    entry.append( atom );
 
856
 
 
857
    atom.m_uds = KIO::UDS_MODIFICATION_TIME;
 
858
    atom.m_long = buff.st_mtime;
 
859
    entry.append( atom );
 
860
 
 
861
    atom.m_uds = KIO::UDS_ACCESS_TIME;
 
862
    atom.m_long = buff.st_atime;
 
863
    entry.append( atom );
 
864
    
 
865
    statEntry(entry);
 
866
    
 
867
    finished();
 
868
}
 
869
 
 
870
QString kio_digikamioProtocol::albumURLFromKURL(const KURL& kurl)
 
871
{
 
872
    QString url(kurl.path(-1));
 
873
    url = QDir::cleanDirPath(url);
 
874
 
 
875
    url.remove(0,m_libraryPath.length());
 
876
 
 
877
    if (!url.startsWith("/"))
 
878
        url.prepend("/");
 
879
 
 
880
    return url;
 
881
}
 
882
 
 
883
void kio_digikamioProtocol::removeDirFromDB(const QString& url)
 
884
{
 
885
    execSql( QString("DELETE FROM Albums WHERE url = '%1'")
 
886
             .arg(escapeString(url)) );
 
887
}
 
888
 
 
889
void kio_digikamioProtocol::removeFileFromDB(int dirid, const QString& name)
 
890
{
 
891
    execSql( QString("DELETE FROM Images "
 
892
                     "WHERE dirid=%1 AND name='%2';")
 
893
             .arg(dirid)
 
894
             .arg(escapeString(name)) );
 
895
 
 
896
    execSql( QString("DELETE FROM ImageTags "
 
897
                     "WHERE dirid=%1 AND name='%2';")
 
898
             .arg(dirid)
 
899
             .arg(escapeString(name)) );
 
900
}
 
901
 
 
902
bool kio_digikamioProtocol::copyFile(const QString& src, const QString& dest)
 
903
{
 
904
    QFile sFile(src);
 
905
    QFile dFile(dest);
 
906
 
 
907
    if ( !sFile.open(IO_ReadOnly) )
 
908
    {
 
909
        kdWarning() << k_funcinfo << "Failed to open source file for reading: "
 
910
                    << src << endl;
 
911
        return false;
 
912
    }
 
913
    
 
914
    if ( !dFile.open(IO_WriteOnly) )
 
915
    {
 
916
        sFile.close();
 
917
        kdWarning() << k_funcinfo << "Failed to open dest file for writing: "
 
918
                    << src << endl;
 
919
        return false;
 
920
    }
 
921
 
 
922
    const int MAX_IPC_SIZE = (1024*32);
 
923
    char buffer[MAX_IPC_SIZE];
 
924
 
 
925
    Q_LONG len;
 
926
    while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0)
 
927
    {
 
928
        if (len == -1 || dFile.writeBlock(buffer, (Q_ULONG)len) == -1)
 
929
        {
 
930
            sFile.close();
 
931
            dFile.close();
 
932
            return false;
 
933
        }
 
934
    }
 
935
 
 
936
    sFile.close();
 
937
    dFile.close();
 
938
    
 
939
    return true;
 
940
}
 
941
 
 
942
bool kio_digikamioProtocol::execSql(const QString& sql, QStringList* const values, 
 
943
                                    const bool debug )
 
944
{
 
945
    if ( debug )
 
946
        kdDebug() << "SQL-query: " << sql << endl;
 
947
 
 
948
    if ( !m_db ) {
 
949
        kdWarning() << k_funcinfo << "SQLite pointer == NULL"
 
950
                    << endl;
 
951
        return false;
 
952
    }
 
953
 
 
954
    const char* tail;
 
955
    sqlite_vm* vm;
 
956
    char* errorStr;
 
957
    int error;
 
958
    
 
959
    //compile SQL program to virtual machine
 
960
    error = sqlite_compile( m_db, sql.local8Bit(), &tail, &vm, &errorStr );
 
961
 
 
962
    if ( error != SQLITE_OK ) {
 
963
        kdWarning() << k_funcinfo << "sqlite_compile error: "
 
964
                    << errorStr 
 
965
                    << " on query: " << sql << endl;
 
966
        sqlite_freemem( errorStr );
 
967
        return false;
 
968
    }
 
969
 
 
970
    int number;
 
971
    const char** value;
 
972
    const char** colName;
 
973
    //execute virtual machine by iterating over rows
 
974
    while ( true ) {
 
975
        error = sqlite_step( vm, &number, &value, &colName );
 
976
        if ( error == SQLITE_DONE || error == SQLITE_ERROR )
 
977
            break;
 
978
        //iterate over columns
 
979
        for ( int i = 0; values && i < number; i++ ) {
 
980
            *values << QString::fromLocal8Bit( value [i] );
 
981
        }
 
982
    }
 
983
    
 
984
    //deallocate vm resources
 
985
    sqlite_finalize( vm, &errorStr );
 
986
 
 
987
    if ( error != SQLITE_DONE ) {
 
988
        kdWarning() << k_funcinfo << "sqlite_step error: "
 
989
                    << errorStr
 
990
                    << " on query: " << sql << endl;
 
991
        return false;
 
992
    }
 
993
 
 
994
    return true;
 
995
}
 
996
 
 
997
QString kio_digikamioProtocol::escapeString(QString str) const
 
998
{
 
999
    str.replace( "'", "''" );
 
1000
    return str;
 
1001
}
 
1002
 
 
1003
/* KIO slave registration */
 
1004
 
 
1005
extern "C"
 
1006
{
 
1007
    int kdemain(int argc, char **argv)
 
1008
    {
 
1009
        KLocale::setMainCatalogue("digikam");
 
1010
        KInstance instance( "kio_digikamio" );
 
1011
        ( void ) KGlobal::locale();
 
1012
        
 
1013
        kdDebug() << "*** kio_digikamio started ***" << endl;
 
1014
        
 
1015
        if (argc != 4) {
 
1016
            kdDebug() << "Usage: kio_digikamio  protocol domain-socket1 domain-socket2"
 
1017
                      << endl;
 
1018
            exit(-1);
 
1019
        }
 
1020
 
 
1021
        kio_digikamioProtocol slave(argv[2], argv[3]);
 
1022
        slave.dispatchLoop();
 
1023
        
 
1024
        kdDebug() << "*** kio_digikamio finished ***" << endl;
 
1025
        return 0;
 
1026
    }
 
1027
}