Fixes: NB#300219 - Transfer consisting of multiple files in same upload does not...
[meego-sharing-framework:webupload-engine.git] / webupload-engine / src / uploadengine.cpp
1 /*
2  * Web Upload Engine -- MeeGo social networking uploads
3  * Copyright (c) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
4  * Contact: Jukka Tiihonen <jukka.t.tiihonen@nokia.com>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU Lesser General Public License,
8  * version 2.1, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT ANY
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20
21 #include "uploadengine.h"
22 #include "uploaditem.h"
23 #include "uploadqueue.h"
24 #include "logger.h"
25 #include <stdlib.h>
26
27 /*****************************************************************
28  * UploadEngine class function definitions
29  *****************************************************************/
30
31 UploadEngine::UploadEngine(int argc, char **argv) :
32     QCoreApplication(argc, argv), connection (this), uploadProcess (this),
33     tuiClient (new TransferUI::Client (this)), shutdownWhenEmptyQueue (true),
34     state (IDLE), processThread (0), usbModeDetector (this) {
35     
36     // Parse input parameters
37     for (int i = 1; i < argc; ++i) {
38         QString param = argv[i];
39     
40         if (param == "--immortal") {
41             shutdownWhenEmptyQueue = false;
42         }
43     }
44     
45     // Init TUI connection
46     if (!tuiClient->init ()) {
47         WARNSTREAM << "Failed to open TUI connection. Upload engine will"
48             << "run without TUI communication.";
49         delete tuiClient;
50         tuiClient = 0;
51     }
52
53     connect (this, SIGNAL (uploadReceived(QString)), this,
54         SLOT (newUploadReceived(QString)), Qt::QueuedConnection);
55     
56     // - Queue signals ---
57     // Connect queue done signal
58     connect (&queue, SIGNAL(done()), this, SLOT(queueDone()));   
59     // Connect queue top signal
60     connect (&queue, SIGNAL(topItem(UploadItem*)), this,
61         SLOT(queueTop(UploadItem*)));    
62     // Connect queue reorder top signal
63     connect (&queue, SIGNAL(replacedTopItem(UploadItem*,UploadItem*)),
64         this, SLOT(queueChangeTop(UploadItem*,UploadItem*)));
65     // Connect remove signal to queue
66     connect (this, SIGNAL(removeUpload(UploadItem*)),
67         &queue, SLOT(removeItem(UploadItem*))); 
68         
69     connect (&connection, SIGNAL (connected()), this, SLOT (connected()));
70     connect (&connection, SIGNAL (disconnected()), this, SLOT (disconnected()));
71
72     connect (this, SIGNAL (startUpload(UploadItem*)), &uploadProcess,
73         SLOT (startUpload(UploadItem*)));
74     connect (this, SIGNAL (stopUpload(UploadItem*)), &uploadProcess,
75         SLOT (stopUpload(UploadItem*)));
76
77     connect (&uploadProcess, SIGNAL (uploadDone(UploadItem*)), this,
78         SLOT (uploadDone(UploadItem*)), Qt::QueuedConnection);
79     connect (&uploadProcess, SIGNAL (uploadStopped(UploadItem*)), this,
80         SLOT (uploadStopped(UploadItem*)), Qt::QueuedConnection);
81     connect (&uploadProcess,
82         SIGNAL (uploadFailed(UploadItem*,WebUpload::Error)), this,
83         SLOT (uploadFailed(UploadItem*,WebUpload::Error)), 
84         Qt::QueuedConnection);
85
86     connect (&usbModeDetector, SIGNAL(modeChanged(MeeGo::QmUSBMode::Mode)),
87         this, SLOT(usbModeChanged(MeeGo::QmUSBMode::Mode)));
88     connect (&usbModeDetector, 
89         SIGNAL(fileSystemWillUnmount(MeeGo::QmUSBMode::MountPath)),
90         this, SLOT(fileSystemWillUnmount(MeeGo::QmUSBMode::MountPath)));
91     currentUSBMode = usbModeDetector.getMode ();
92 }
93
94
95 UploadEngine::~UploadEngine() {
96     connection.disconnect (this);
97     uploadProcess.disconnect (this);
98     usbModeDetector.disconnect (this);
99 }
100
101 bool UploadEngine::newUpload (const QString &path) {
102     DBGSTREAM << "New upload task received:" << path;
103
104     Q_EMIT (uploadReceived(path));
105     return true;
106 }
107
108     
109 void UploadEngine::newUploadReceived (const QString &path) {
110
111     // Safety check for duplicate adding
112     if ((queue.itemForEntryPath (path) != 0) || queue.isEntryInit (path))  {
113         WARNSTREAM << "Entry" << path << "received multiple times. Ignored";
114         return;
115     }
116
117     queue.initing (path);
118     UploadItem * item = new UploadItem();
119     
120     if (!item->init (path, tuiClient)) {
121         WARNSTREAM << "Invalid upload request with" << path;
122         delete item;
123         queue.initFailed (path);
124         return;
125     }
126     
127     // Connect user input signals
128     connect (item, SIGNAL(cancel()), this, SLOT(cancelItem()));
129     connect (item, SIGNAL(repairError()), this, SLOT(repairError()));
130     
131     queue.push (item);
132     
133     // Mark item to be in queue
134     if (queue.size() > 1) {
135         item->markPending (UploadItem::PENDING_QUEUED);
136
137         // Handle the case where the new transfer pushed is not the top of the
138         // queue, and the process thread is not already running. Only in this
139         // case do we need to restart the process thread and send this item for
140         // processing. 
141         // If the item is the top item, it will get sent to the process thread
142         // as a part of the processing of the top item. 
143         // If the process thread is running, then this item will get picked up
144         // at some point of time when the item before it is finished being
145         // processed.
146         if (processThread == 0) {
147             startProcessThread ();
148             item->setOwner (UploadItem::OWNER_PROCESS_THREAD);
149             // Mark item as pending processing only if it is the top of the
150             // queue
151             Q_EMIT (startProcess (item));
152         }
153     }
154 }
155
156 void UploadEngine::shutdown() {
157
158     setState (SHUTTING_DOWN);
159     
160     // Disconnect and don't recieve any more signals from any other object
161     queue.disconnect (this);
162     
163     connection.disconnect (this);
164
165     if (uploadProcess.processCount () > 0) {
166         uploadProcess.killAll ();
167     }
168
169     if (processThread != 0) {
170         DBGSTREAM << "Process thread pointer is non-NULL. It is probably "
171             "running. Stop it ...";
172         stopProcessThread ();
173     } else {
174         DBGSTREAM << "Shutdown upload engine ...";
175         quit();
176     }
177 }
178
179 void UploadEngine::queueDone () {
180
181     DBGSTREAM << "Queue done";
182
183     setState (IDLE);
184     connection.releaseConnection();
185
186     if (shutdownWhenEmptyQueue) {
187         DBGSTREAM << "Queue done. Shutdown upload engine...";    
188         shutdown();
189     } else {
190         DBGSTREAM << "Queue done. Move to idle state.";       
191     }
192 }
193
194 void UploadEngine::queueTop (UploadItem * item) {
195     if (item == 0) {
196         DBGSTREAM << "Queue is empty, ignoring queueTop call";
197         return;
198     }
199
200     DBGSTREAM << "New top in queue"; 
201
202     if (currentUSBMode == MeeGo::QmUSBMode::MassStorage) {
203         usbModeChanged (currentUSBMode);
204         return;
205     } 
206     
207     if (item->getOwner () == UploadItem::OWNER_PROCESS_THREAD) {
208         DBGSTREAM << "Process thread is owner";
209         item->markPending (UploadItem::PENDING_PROCESSING);
210     } else if (item->isCancelled ()) {
211         DBGSTREAM << "Item was marked cancelled - remove it";
212         tuiClient->removeTransfer (item->getTransferId ());
213         Q_EMIT (removeUpload (item)); 
214     } else if (!item->isProcessed ()) {
215         if (processThread == 0) {
216             startProcessThread ();
217         }
218         item->setOwner (UploadItem::OWNER_PROCESS_THREAD);
219         item->markPending (UploadItem::PENDING_PROCESSING);
220         Q_EMIT (startProcess (item));
221     } else {
222         if (item->getOwner () == UploadItem::OWNER_UPLOAD_THREAD) {
223             // This can only happen if the previous upload attempt for the item
224             // was asked to be stopped, but plugin has not stopped - perhaps
225             // because it is stuck somewhere. In this case, we should
226             // explicitly kill the plugin
227             Q_ASSERT (uploadProcess.isProcessStopping() == true);
228             processStopped (item);
229         } else {
230             // Should never try to upload an item which is still being
231             // processed
232             Q_ASSERT (item->getOwner() == UploadItem::OWNER_QUEUE);
233         }
234
235         DBGSTREAM << "Now checking for connection";
236         // If we don't have connection ask for it
237         if (connection.isConnected() == false) {
238             item->markPending (UploadItem::PENDING_CONNECTIVITY);    
239             setState (OFFLINE);
240             return;
241         } else {
242             DBGSTREAM << "Can finally send item";
243             setState (SENDING);
244         }
245         
246         item->setOwner (UploadItem::OWNER_UPLOAD_THREAD);
247         Q_EMIT (startUpload (item));
248     }
249 }
250
251 void UploadEngine::queueChangeTop (UploadItem * down, UploadItem * top) {
252     Q_UNUSED (down);
253
254     DBGSTREAM << "New top in queue (old one moved down)";    
255
256     if (top->getOwner () != UploadItem::OWNER_QUEUE) {
257         DBGSTREAM << "New top is already being handled by one of the queues";
258     } else {
259         if (!top->isProcessed()) {
260             
261             // ProcessThread should be actively processing something at this
262             // point because otherwise this item would have been processed 
263             Q_ASSERT (processThread != 0);
264
265             // Stop processing of whatever is being processed currently.
266             // We can come back to that later. We should not hold up the upload
267             // queue right now
268             Q_EMIT (stopProcess (0));
269         }
270
271         queueTop (top);
272     }
273 }
274
275 void UploadEngine::startProcessThread() {
276
277     if (getState() == SHUTTING_DOWN) {
278         DBGSTREAM << "Shutting down - should not start thread here";
279         return;
280     }
281
282     if (processThread == 0) {
283         processThread = new ProcessThread (this);
284         DBGSTREAM << "ProcessThread initialized";
285     }
286
287     if (processThread->isRunning()) {
288         DBGSTREAM << "Process Thread already running";
289     } else {
290         DBGSTREAM << "Connecting signals and starting the process thread";
291         // Connect signals
292         connect (this, SIGNAL (startProcess(UploadItem*)), processThread,
293             SIGNAL (startProcess(UploadItem*)));
294         connect (this, SIGNAL (stopProcess(UploadItem*)), processThread,
295             SIGNAL (stopProcess(UploadItem*)));
296                 
297         connect (processThread, SIGNAL(processDone(UploadItem*)), this,
298             SLOT(processDone(UploadItem*)));
299         connect (processThread, SIGNAL(processStopped(UploadItem*)), this,
300             SLOT(processStopped(UploadItem*)));    
301         connect (processThread, SIGNAL (processFailed(UploadItem*,int)), this,
302             SLOT (processThreadFailed(UploadItem*,int)));
303         connect (processThread, SIGNAL(finished()), this,
304                 SLOT(processThreadFinished()));    
305     
306         processThread->start();
307     }
308 }
309
310 void UploadEngine::stopProcessThread () {
311     if (processThread && processThread->isRunning ()) {
312         DBGSTREAM << "Ask process thread to stop";
313         processThread->stop ();
314     } else {
315         processThreadFinished ();
316     }
317 }
318
319 void UploadEngine::processThreadFinished () {
320     if (processThread != 0) {
321         DBGSTREAM << "Process Thread finished";
322         this->disconnect (processThread);
323         delete processThread;
324         processThread = 0;
325     }
326         
327     if (getState() == SHUTTING_DOWN) {
328         DBGSTREAM << "Shutdown upload engine.";
329         quit();
330     }
331 }
332
333 void UploadEngine::processDone (UploadItem * item) {
334
335     DBGSTREAM << "Process done signal recieved";
336     item->setOwner (UploadItem::OWNER_QUEUE);
337     UploadItem *next = queue.getNextItem (item);
338
339     if (next) {
340         next->setOwner (UploadItem::OWNER_PROCESS_THREAD);
341         Q_EMIT (startProcess (next));
342     } else {
343         DBGSTREAM << "No more items to process. Stopping thread";
344         // No more items to process
345         stopProcessThread ();
346     }
347
348     if (item->isCancelled()) {
349         tuiClient->removeTransfer (item->getTransferId ());
350         // We could alternately wait for the item to become top of the queue
351         // and then get cancelled, but that does not make sense from UI
352         // perspective
353         Q_EMIT (removeUpload (item));
354         return;
355     }
356
357     if (item == queue.getTop ()) {
358         DBGSTREAM << "Item was at the top of the queue";
359         queueTop (item);
360     }
361 }
362
363 void UploadEngine::processStopped (UploadItem *item) {
364     DBGSTREAM << "Process stopped signal recieved";
365     if (item) {
366         item->setOwner (UploadItem::OWNER_QUEUE);
367
368         if (item->isCancelled ()) {
369             tuiClient->removeTransfer (item->getTransferId ());
370             Q_EMIT (removeUpload (item));
371         } else if (getState () == MASS_STORAGE) {
372             item->markPending (UploadItem::PENDING_MSM);
373         }
374     }
375
376     return;
377 }
378
379 void UploadEngine::processThreadFailed (UploadItem *item,
380     int processErrorCode) {
381     
382     Q_ASSERT (item != 0);
383     item->setOwner (UploadItem::OWNER_QUEUE);
384
385     if (getState () == MASS_STORAGE) {
386         DBGSTREAM << "Mass storage is enabled. Error might have been"
387             "because of that";
388         item->markPending (UploadItem::PENDING_MSM);
389         return;
390     }
391
392     UploadItem::ProcessError processError =
393         (UploadItem::ProcessError)processErrorCode;
394     
395     DBGSTREAM << "Handle process failed reponse" << processError;
396
397     WebUpload::Error itemError;
398     switch (processError) {
399         case UploadItem::PROCESS_ERROR_STORAGE_MEMORY_FULL:
400         case UploadItem::PROCESS_ERROR_OUT_OF_MEMORY:
401         {
402             itemError = WebUpload::Error::outOfMemory ();
403             break;
404         }
405
406         case UploadItem::PROCESS_ERROR_FILE_NOT_FOUND:
407         {
408             itemError = WebUpload::Error::missingFiles();
409             break;
410         }
411
412         default:
413             itemError = WebUpload::Error::transferFailed();
414             break;
415     }
416
417     WebUpload::Entry * entry = item->getEntry();
418     unsigned int notSent = entry->mediaCount() - entry->mediaSentCount();
419     itemError.setFailedCount (notSent);
420
421     if (!item->markFailed (itemError)) {
422         item->setCancelled ();
423     } 
424
425     if (item->isCancelled()) {
426         tuiClient->removeTransfer (item->getTransferId ());
427         Q_EMIT (removeUpload (item));
428     }
429
430 }
431
432 void UploadEngine::uploadDone (UploadItem * item) {
433     DBGSTREAM << "Upload done signal from thread";
434     item->markDone(); 
435     item->setOwner (UploadItem::OWNER_QUEUE);
436     tuiClient->removeTransfer (item->getTransferId ());
437     Q_EMIT (removeUpload (item));
438 }
439
440 void UploadEngine::uploadStopped (UploadItem * item) {
441     DBGSTREAM << "Upload stopped signal from thread";
442     
443     if (item == 0) {
444         WARNSTREAM << "Upload stopped called without item";
445         return;
446     }
447
448     if (m_stoppingItems.contains(item)) {
449         m_stoppingItems.removeAll(item);
450         item->setCancelled();
451     }
452     
453     item->setOwner (UploadItem::OWNER_QUEUE);
454     if (item->isCancelled ()) {
455         tuiClient->removeTransfer (item->getTransferId ());
456         Q_EMIT (removeUpload (item));
457     } else if (getState () == MASS_STORAGE) {
458         item->markPending (UploadItem::PENDING_MSM);
459     } else if (getState () == OFFLINE) {
460         item->markPending (UploadItem::PENDING_CONNECTIVITY);
461
462         // Reopen session if device is still online. This happens when
463         // connection changes to another network.
464         if (connection.isOnline()) {
465             connection.isConnected();
466         }
467     } else {
468         WARNSTREAM << "Stop called after stop";
469     }
470 }
471
472 void UploadEngine::uploadFailed (UploadItem * item, WebUpload::Error error) {
473     DBGSTREAM << "Upload failed signal" << error.code();
474
475     Q_ASSERT (item != 0);
476
477     if (m_stoppingItems.contains(item)) {
478         DBGSTREAM << "Fail: Marked to be cancelled";
479         m_stoppingItems.removeAll(item);
480         item->setCancelled();
481     }
482
483     if (item->isCancelled() == false) {
484         item->setOwner (UploadItem::OWNER_QUEUE);
485
486         if (getState () == MASS_STORAGE) {
487             DBGSTREAM << "Fail: Mass storage is enabled.";
488             item->markPending (UploadItem::PENDING_MSM);
489         } else if (error.code() == WebUpload::Error::CODE_NO_CONNECTION || 
490             getState () == OFFLINE) {
491             
492             DBGSTREAM << "Fail: Connection lost";
493
494             setState (OFFLINE);
495             item->markPending (UploadItem::PENDING_CONNECTIVITY);
496
497             // Reopen session if device is still online. This happens when
498             // connection changes to another network.
499             if (connection.isOnline()) {
500                 connection.isConnected();
501             }
502         } else {
503         
504             DBGSTREAM << "Fail: Code:" << error.code();
505         
506             // Try to mark failed (cancel if failing)
507             if (item->markFailed (error) == false) {
508                 WARNSTREAM << "Fail: No TUI: Cancel";
509                 item->setCancelled ();
510             }
511         }
512     }
513
514     // Handling two cases here:
515     // (1) Cancel was requested by the user. At that time, the item was being
516     // processed. But by the time the cancel request reaches UploadHandler, the
517     // item has returned an error, and the thread no longer owns it. So, the
518     // uploadFailed in the engine should check the cancelled flag as well.
519     // (2) UploadEngine is not connected with the Transfer UI. In this case,
520     // rather than letting a failed item stay in the queue, we should remove it
521     if (item->isCancelled()) {
522         DBGSTREAM << "Fail: Removing from queue";
523         tuiClient->removeTransfer (item->getTransferId ());
524         Q_EMIT (removeUpload (item));
525     }
526 }
527
528 void UploadEngine::repairError () {
529
530     UploadItem * item = qobject_cast<UploadItem *>(QObject::sender());
531     
532     if (item == 0) {
533         WARNSTREAM << "Repair: Slot repairError called wrongly. Sender:"
534             << QObject::sender();
535         return;
536     }
537
538     if (item->getOwner () == UploadItem::OWNER_UPLOAD_THREAD) {
539         DBGSTREAM << "Repair: Ignoring repair (already uploading)";
540         return;
541     }
542
543     if (item->isProcessed ()) {
544         DBGSTREAM << "Repair: Item is processed";
545         item->setOwner (UploadItem::OWNER_QUEUE);
546         if (item == queue.getTop ()) {
547             DBGSTREAM << "Repair: Item is the top item";
548             queueTop (item);
549         } else {
550             item->markPending (UploadItem::PENDING_QUEUED);
551         }
552     } else {
553         if (processThread) {
554
555             if (item->getOwner () == UploadItem::OWNER_PROCESS_THREAD) {
556                 DBGSTREAM << "Repair: Item is already being processed";
557                 return;
558             }
559
560             // Stop whatever is being processed right now, so we can get back
561             // to processing this item
562             Q_EMIT (stopProcess (0));
563         } else {
564             // Process thread is not running. Start it
565             startProcessThread ();
566         }
567
568         item->setOwner (UploadItem::OWNER_PROCESS_THREAD);
569         if (item == queue.getTop ()) {
570             item->markPending (UploadItem::PENDING_PROCESSING);
571         } else {
572             item->markPending (UploadItem::PENDING_QUEUED);
573         }
574         Q_EMIT (startProcess (item));
575     }
576 }
577
578 void UploadEngine::cancelItem () {
579
580     UploadItem * item = qobject_cast<UploadItem *>(QObject::sender());
581     
582     if (item == 0) {
583         WARNSTREAM << "Slot cancelItem called wrongly. QObject::sender() = "
584             << QObject::sender();
585         return;
586     }
587
588     if (item->isCancelled ()) {
589         WARNSTREAM << "Cancel called on already cancelled item " << 
590             item->toString();
591         return;
592     }
593     
594     DBGSTREAM << "Cancel item" << item->toString() << ", owner"
595         << item->getOwner();
596     
597     // TODO: What to do first if item is processed
598     switch (item->getOwner()) {
599         case UploadItem::OWNER_QUEUE:
600         {
601             item->setCancelled();
602             tuiClient->removeTransfer (item->getTransferId ());
603             Q_EMIT (removeUpload (item));
604             break;
605         }
606
607         case UploadItem::OWNER_UPLOAD_THREAD:
608         {
609             DBGSTREAM << "Cancel with item that is being uploaded";
610             m_stoppingItems.append(item);
611             Q_EMIT (stopUpload (item));
612             break;
613         }
614
615         case UploadItem::OWNER_PROCESS_THREAD:
616         {
617             Q_ASSERT (processThread != 0);
618             item->setCancelled();
619             DBGSTREAM << "Cancel with item that is being processed";
620             break;
621         }
622         
623         default:
624             CRITSTREAM << "Cancel with invalid owner";
625             break;
626     }
627 }
628
629 UploadEngine::State UploadEngine::getState () const {
630     return state;
631 }
632
633 void UploadEngine::setState (State newState) {
634     if (state != newState) {
635         DBGSTREAM << "Engine state" << newState;
636         state = newState;
637         Q_EMIT (stateChanged (state));
638     }
639 }
640
641 void UploadEngine::connected () {
642     if (getState () != SENDING) {
643         setState (IDLE);
644         DBGSTREAM << "Continue uploading after offline mode";
645         queueTop (queue.getTop());
646     } else {
647         DBGSTREAM << "Engine ignoring connected signal";
648     }
649 }
650
651 void UploadEngine::disconnected () {
652     if (getState() == SENDING) {
653         DBGSTREAM << "Entering to offline mode. Stop sending.";
654         setState (OFFLINE);
655         Q_EMIT (stopUpload(0));
656     } else {
657         DBGSTREAM << "Engine ignoring disconnected signal";    
658     }
659 }
660
661
662 void UploadEngine::usbModeChanged (MeeGo::QmUSBMode::Mode mode) {
663
664     DBGSTREAM << "USB Mode:" << (int)currentUSBMode << "-->" << (int)mode;
665
666     currentUSBMode = mode;
667     
668     // Handle only the MassStorage and Disconnected modes. Can ignore all the 
669     // other mode changes
670     if (mode == MeeGo::QmUSBMode::MassStorage) {
671         if (state == IDLE || state == MASS_STORAGE) {
672             UploadItem * top = queue.getTop ();
673             if (top != 0) {
674                 top->markPending (UploadItem::PENDING_MSM);
675             }
676         }
677
678         if (state == MASS_STORAGE || state == OFFLINE || 
679             state == SHUTTING_DOWN) {
680             return;
681         }
682
683         setState (MASS_STORAGE);
684         if (processThread) {
685             processThread->stop ();
686         }
687
688         UploadItem *nowSending = uploadProcess.currentlySendingMedia ();
689         if (nowSending != 0) {
690             Q_EMIT (stopUpload(nowSending));
691         } 
692     } else if (mode == MeeGo::QmUSBMode::Disconnected) {
693         if (getState () != MASS_STORAGE) {
694             return;
695         }
696         
697         DBGSTREAM << "Entering USB disconnected mode";
698         setState (IDLE);
699
700         // First continue processing from where it was stopped
701         UploadItem *item = 0; 
702         for (item = queue.getTop (); item != 0 && item->isProcessed (); 
703             item = queue.getNextItem (item));
704         if (item != 0) {
705             if (processThread == 0) {
706                 startProcessThread ();
707             }
708             item->setOwner (UploadItem::OWNER_PROCESS_THREAD);
709             if (item == queue.getTop ()) {
710                 item->markPending (UploadItem::PENDING_PROCESSING);
711             } else {
712                 item->markPending (UploadItem::PENDING_QUEUED);
713             }
714             Q_EMIT (startProcess (item));
715         }
716
717         // Now handle the queue top element as it should be handled
718         queueTop (queue.getTop ());
719     }
720 }
721
722
723 void UploadEngine::fileSystemWillUnmount (MeeGo::QmUSBMode::MountPath path) {
724
725     Q_UNUSED (path)
726
727     setState (MASS_STORAGE);
728     UploadItem *nowSending = uploadProcess.currentlySendingMedia ();
729     if (nowSending != 0) {
730         Q_EMIT (stopUpload(nowSending));
731     }
732 }
733
734