Welcome Ethumb, it's ready to get out of PROTO.
[framework/uifw/ethumb.git] / src / bin / ethumbd.c
1 /**
2  * @file
3  *
4  * Copyright (C) 2009 by ProFUSION embedded systems
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,  but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  *
21  * @author Rafael Antognolli <antognolli@profusion.mobi>
22  */
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <limits.h>
28 #include <unistd.h>
29 #include <errno.h>
30
31 #include <Ethumb.h>
32 #include <Eina.h>
33 #include <Ecore_Getopt.h>
34 #include <Ecore.h>
35 #include <E_DBus.h>
36
37 #include "ethumbd_private.h"
38
39 #ifndef PATH_MAX
40 #define PATH_MAX 4096
41 #endif
42
43 #define MAX_ID 2000000
44
45 #define DBG(...) EINA_LOG_DBG(__VA_ARGS__)
46 #define INF(...) EINA_LOG_INFO(__VA_ARGS__)
47 #define WRN(...) EINA_LOG_WARN(__VA_ARGS__)
48 #define ERR(...) EINA_LOG_ERR(__VA_ARGS__)
49
50 static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";
51 static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";
52 static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";
53 static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb";
54 static const char fdo_interface[] = "org.freedesktop.DBus";
55 static const char fdo_bus_name[] = "org.freedesktop.DBus";
56 static const char fdo_path[] = "/org/freedesktop/DBus";
57
58 struct _Ethumb_Setup
59 {
60    struct
61    {
62       Eina_Bool fdo : 1;
63       Eina_Bool size : 1;
64       Eina_Bool format : 1;
65       Eina_Bool aspect : 1;
66       Eina_Bool crop : 1;
67       Eina_Bool quality : 1;
68       Eina_Bool compress : 1;
69       Eina_Bool directory : 1;
70       Eina_Bool category : 1;
71       Eina_Bool frame : 1;
72       Eina_Bool video_time : 1;
73       Eina_Bool video_start : 1;
74       Eina_Bool video_interval : 1;
75       Eina_Bool video_ntimes : 1;
76       Eina_Bool video_fps : 1;
77       Eina_Bool document_page : 1;
78    } flags;
79    int fdo;
80    int tw, th;
81    int format;
82    int aspect;
83    float cx, cy;
84    int quality;
85    int compress;
86    const char *directory;
87    const char *category;
88    const char *theme_file;
89    const char *group;
90    const char *swallow;
91    float video_time;
92    float video_start;
93    float video_interval;
94    int video_ntimes;
95    int video_fps;
96    int document_page;
97 };
98
99 struct _Ethumb_Request
100 {
101    int id;
102    const char *file, *key;
103    const char *thumb, *thumb_key;
104    struct _Ethumb_Setup setup;
105 };
106
107 struct _Ethumb_Object
108 {
109    int used;
110    const char *path;
111    const char *client;
112    Eina_List *queue;
113    int nqueue;
114    int id_count;
115    int max_id;
116    int min_id;
117    E_DBus_Object *dbus_obj;
118 };
119
120 struct _Ethumb_Queue
121 {
122    int count;
123    int max_count;
124    int nqueue;
125    int last;
126    int current;
127    struct _Ethumb_Object *table;
128    int *list;
129 };
130
131 struct _Ethumbd
132 {
133    E_DBus_Connection *conn;
134    E_DBus_Signal_Handler *name_owner_changed_handler;
135    E_DBus_Interface *eiface, *objects_iface;
136    E_DBus_Object *dbus_obj;
137    Ecore_Idler *idler;
138    struct _Ethumb_Request *processing;
139    struct _Ethumb_Queue queue;
140    int pipeout;
141    int pipein;
142    Ecore_Fd_Handler *fd_handler;
143    double timeout;
144    Ecore_Timer *timeout_timer;
145 };
146
147 struct _Ethumb_Object_Data
148 {
149    int index;
150    struct _Ethumbd *ed;
151 };
152
153 struct _Ethumb_DBus_Method_Table
154 {
155    const char *name;
156    const char *signature;
157    const char *reply;
158    E_DBus_Method_Cb function;
159 };
160
161 struct _Ethumb_DBus_Signal_Table
162 {
163    const char *name;
164    const char *signature;
165 };
166
167 const Ecore_Getopt optdesc = {
168   "ethumbd",
169   NULL,
170   PACKAGE_VERSION,
171   "(C) 2009 - ProFUSION embedded systems",
172   "LGPL v3 - GNU Lesser General Public License",
173   "Ethumb daemon.\n"
174   "\n"
175   "ethumbd uses the Ethumb library to create thumbnails for any "
176   "program that requests it (now just by dbus).\n",
177   0,
178   {
179     ECORE_GETOPT_STORE_DOUBLE
180     ('t', "timeout", "finish ethumbd after <timeout> seconds of no activity."),
181     ECORE_GETOPT_LICENSE('L', "license"),
182     ECORE_GETOPT_COPYRIGHT('C', "copyright"),
183     ECORE_GETOPT_VERSION('V', "version"),
184     ECORE_GETOPT_HELP('h', "help"),
185     ECORE_GETOPT_SENTINEL
186   }
187 };
188
189 static void _ethumb_dbus_generated_signal(struct _Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success);
190
191 static int
192 _ethumbd_timeout_cb(void *data)
193 {
194    struct _Ethumbd *ed = data;
195
196    ecore_main_loop_quit();
197    ed->timeout_timer = NULL;
198
199    return 0;
200 }
201
202 static void
203 _ethumbd_timeout_start(struct _Ethumbd *ed)
204 {
205    if (ed->timeout < 0)
206      return;
207
208    if (!ed->timeout_timer)
209      ed->timeout_timer = ecore_timer_add(ed->timeout, _ethumbd_timeout_cb, ed);
210 }
211
212 static void
213 _ethumbd_timeout_stop(struct _Ethumbd *ed)
214 {
215    if (!ed->timeout_timer)
216      return;
217
218    ecore_timer_del(ed->timeout_timer);
219    ed->timeout_timer = NULL;
220 }
221
222 static int
223 _ethumb_dbus_check_id(struct _Ethumb_Object *eobject, int id)
224 {
225    if (id < 0 || id > MAX_ID)
226      return 0;
227
228    if (eobject->min_id < eobject->max_id)
229      return id < eobject->min_id || id > eobject->max_id;
230    else if (eobject->min_id > eobject->max_id)
231      return id < eobject->min_id && id > eobject->max_id;
232    else
233      return id != eobject->max_id;
234 }
235
236 static void
237 _ethumb_dbus_inc_max_id(struct _Ethumb_Object *eobject, int id)
238 {
239    if (eobject->min_id < 0 && eobject->max_id < 0)
240      eobject->min_id = id;
241
242    eobject->max_id = id;
243 }
244
245 static void
246 _ethumb_dbus_inc_min_id(struct _Ethumb_Object *eobject)
247 {
248    Eina_List *l;
249
250    l = eobject->queue;
251    while (l)
252      {
253         struct _Ethumb_Request *request = l->data;
254         if (request->id >= 0)
255           {
256              eobject->min_id = request->id;
257              break;
258           }
259
260         l = l->next;
261      }
262
263    if (!l)
264      {
265         eobject->min_id = -1;
266         eobject->max_id = -1;
267      }
268 }
269
270 int
271 _ethumbd_read_safe(int fd, void *buf, ssize_t size)
272 {
273    ssize_t todo;
274    char *p;
275
276    todo = size;
277    p = buf;
278
279    while (todo > 0)
280      {
281         ssize_t r;
282
283         r = read(fd, p, todo);
284         if (r > 0)
285           {
286              todo -= r;
287              p += r;
288           }
289         else if (r == 0)
290           return 0;
291         else
292           {
293              if (errno == EINTR || errno == EAGAIN)
294                continue;
295              else
296                {
297                   ERR("could not read from fd %d: %s",
298                       fd, strerror(errno));
299                   return 0;
300                }
301           }
302      }
303
304    return 1;
305 }
306
307 int
308 _ethumbd_write_safe(int fd, const void *buf, ssize_t size)
309 {
310    ssize_t todo;
311    const char *p;
312
313    todo = size;
314    p = buf;
315
316    while (todo > 0)
317      {
318         ssize_t r;
319
320         r = write(fd, p, todo);
321         if (r > 0)
322           {
323              todo -= r;
324              p += r;
325           }
326         else if (r == 0)
327           return 0;
328         else
329           {
330              if (errno == EINTR || errno == EAGAIN)
331                continue;
332              else
333                {
334                   ERR("could not write to fd %d: %s", fd, strerror(errno));
335                   return 0;
336                }
337           }
338      }
339
340    return 1;
341 }
342
343 static void
344 _ethumbd_child_write_op_new(struct _Ethumbd *ed, int index)
345 {
346    int id = ETHUMBD_OP_NEW;
347    _ethumbd_write_safe(ed->pipeout, &id, sizeof(id));
348    _ethumbd_write_safe(ed->pipeout, &index, sizeof(index));
349 }
350
351 static void
352 _ethumbd_child_write_op_del(struct _Ethumbd *ed, int index)
353 {
354    int id = ETHUMBD_OP_DEL;
355    _ethumbd_write_safe(ed->pipeout, &id, sizeof(id));
356    _ethumbd_write_safe(ed->pipeout, &index, sizeof(index));
357 }
358
359 static void
360 _ethumbd_pipe_str_write(int fd, const char *str)
361 {
362    int len;
363
364    if (str)
365      len = strlen(str) + 1;
366    else
367      len = 0;
368
369    _ethumbd_write_safe(fd, &len, sizeof(len));
370    _ethumbd_write_safe(fd, str, len);
371 }
372
373 static int
374 _ethumbd_pipe_str_read(int fd, char **str)
375 {
376    int size;
377    int r;
378    char buf[PATH_MAX];
379
380    r = _ethumbd_read_safe(fd, &size, sizeof(size));
381    if (!r)
382      {
383         *str = NULL;
384         return 0;
385      }
386
387    if (!size)
388      {
389         *str = NULL;
390         return 1;
391      }
392
393    r = _ethumbd_read_safe(fd, buf, size);
394    if (!r)
395      {
396         *str = NULL;
397         return 0;
398      }
399
400    *str = strdup(buf);
401    return 1;
402 }
403
404 static void
405 _ethumbd_child_write_op_generate(struct _Ethumbd *ed, int index, const char *path, const char *key, const char *thumb_path, const char *thumb_key)
406 {
407    int id = ETHUMBD_OP_GENERATE;
408
409    _ethumbd_write_safe(ed->pipeout, &id, sizeof(id));
410    _ethumbd_write_safe(ed->pipeout, &index, sizeof(index));
411
412    _ethumbd_pipe_str_write(ed->pipeout, path);
413    _ethumbd_pipe_str_write(ed->pipeout, key);
414    _ethumbd_pipe_str_write(ed->pipeout, thumb_path);
415    _ethumbd_pipe_str_write(ed->pipeout, thumb_key);
416 }
417
418 static void
419 _generated_cb(struct _Ethumbd *ed, Eina_Bool success, const char *thumb_path, const char *thumb_key)
420 {
421    int i = ed->queue.current;
422
423    DBG("thumbnail ready at: \"%s:%s\"\n", thumb_path, thumb_key);
424
425    if (ed->queue.table[i].used)
426      _ethumb_dbus_generated_signal
427        (ed, &ed->processing->id, thumb_path, thumb_key, success);
428    eina_stringshare_del(ed->processing->file);
429    eina_stringshare_del(ed->processing->key);
430    eina_stringshare_del(ed->processing->thumb);
431    eina_stringshare_del(ed->processing->thumb_key);
432    free(ed->processing);
433    ed->processing = NULL;
434 }
435
436 static int
437 _ethumbd_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
438 {
439    struct _Ethumbd *ed = data;
440    Eina_Bool success;
441    int r;
442    char *thumb_path, *thumb_key;
443
444    if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
445      {
446         ERR("error on pipein! child exiting...\n");
447         ed->fd_handler = NULL;
448         ecore_main_loop_quit();
449         return 0;
450      }
451
452    r = _ethumbd_read_safe(ed->pipein, &success, sizeof(success));
453    if (!r)
454      {
455         ERR("ethumbd child exited!\n");
456         ed->fd_handler = NULL;
457         return 0;
458      }
459
460    r = _ethumbd_pipe_str_read(ed->pipein, &thumb_path);
461    r = _ethumbd_pipe_str_read(ed->pipein, &thumb_key);
462    _generated_cb(ed, success, thumb_path, thumb_key);
463
464    free(thumb_path);
465    free(thumb_key);
466
467    return 1;
468 }
469
470 static void
471 _ethumbd_pipe_write_setup(int fd, int type, const void *data)
472 {
473    const int *i_value;
474    const float *f_value;
475
476    _ethumbd_write_safe(fd, &type, sizeof(type));
477
478    switch (type)
479      {
480       case ETHUMBD_FDO:
481       case ETHUMBD_FORMAT:
482       case ETHUMBD_ASPECT:
483       case ETHUMBD_QUALITY:
484       case ETHUMBD_COMPRESS:
485       case ETHUMBD_SIZE_W:
486       case ETHUMBD_SIZE_H:
487       case ETHUMBD_DOCUMENT_PAGE:
488       case ETHUMBD_VIDEO_NTIMES:
489       case ETHUMBD_VIDEO_FPS:
490          i_value = data;
491          _ethumbd_write_safe(fd, i_value, sizeof(*i_value));
492          break;
493       case ETHUMBD_CROP_X:
494       case ETHUMBD_CROP_Y:
495       case ETHUMBD_VIDEO_TIME:
496       case ETHUMBD_VIDEO_START:
497       case ETHUMBD_VIDEO_INTERVAL:
498          f_value = data;
499          _ethumbd_write_safe(fd, f_value, sizeof(*f_value));
500          break;
501       case ETHUMBD_DIRECTORY:
502       case ETHUMBD_CATEGORY:
503       case ETHUMBD_FRAME_FILE:
504       case ETHUMBD_FRAME_GROUP:
505       case ETHUMBD_FRAME_SWALLOW:
506          _ethumbd_pipe_str_write(fd, data);
507          break;
508       case ETHUMBD_SETUP_FINISHED:
509          break;
510       default:
511          ERR("wrong ethumb setup parameter.\n");
512      }
513 }
514
515 static void
516 _process_setup(struct _Ethumbd *ed)
517 {
518    int op_id = ETHUMBD_OP_SETUP;
519    int index = ed->queue.current;
520    int fd = ed->pipeout;
521
522    struct _Ethumb_Setup *setup = &ed->processing->setup;
523
524    _ethumbd_write_safe(ed->pipeout, &op_id, sizeof(op_id));
525    _ethumbd_write_safe(ed->pipeout, &index, sizeof(index));
526
527    if (setup->flags.fdo)
528      _ethumbd_pipe_write_setup(fd, ETHUMBD_FDO, &setup->fdo);
529    if (setup->flags.size)
530      {
531         _ethumbd_pipe_write_setup(fd, ETHUMBD_SIZE_W, &setup->tw);
532         _ethumbd_pipe_write_setup(fd, ETHUMBD_SIZE_H, &setup->th);
533      }
534    if (setup->flags.format)
535      _ethumbd_pipe_write_setup(fd, ETHUMBD_FORMAT, &setup->format);
536    if (setup->flags.aspect)
537      _ethumbd_pipe_write_setup(fd, ETHUMBD_ASPECT, &setup->aspect);
538    if (setup->flags.crop)
539      {
540         _ethumbd_pipe_write_setup(fd, ETHUMBD_CROP_X, &setup->cx);
541         _ethumbd_pipe_write_setup(fd, ETHUMBD_CROP_Y, &setup->cy);
542      }
543    if (setup->flags.quality)
544      _ethumbd_pipe_write_setup(fd, ETHUMBD_QUALITY, &setup->quality);
545    if (setup->flags.compress)
546      _ethumbd_pipe_write_setup(fd, ETHUMBD_COMPRESS, &setup->compress);
547    if (setup->flags.directory)
548      _ethumbd_pipe_write_setup(fd, ETHUMBD_DIRECTORY, setup->directory);
549    if (setup->flags.category)
550      _ethumbd_pipe_write_setup(fd, ETHUMBD_CATEGORY, setup->category);
551    if (setup->flags.frame)
552      {
553         _ethumbd_pipe_write_setup(fd, ETHUMBD_FRAME_FILE, setup->theme_file);
554         _ethumbd_pipe_write_setup(fd, ETHUMBD_FRAME_GROUP, setup->group);
555         _ethumbd_pipe_write_setup(fd, ETHUMBD_FRAME_SWALLOW, setup->swallow);
556      }
557    if (setup->flags.video_time)
558      _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_TIME, &setup->video_time);
559    if (setup->flags.video_start)
560      _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_START, &setup->video_start);
561    if (setup->flags.video_interval)
562      _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_INTERVAL,
563                                &setup->video_interval);
564    if (setup->flags.video_ntimes)
565      _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_NTIMES, &setup->video_ntimes);
566    if (setup->flags.video_fps)
567      _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_FPS, &setup->video_fps);
568    if (setup->flags.document_page)
569      _ethumbd_pipe_write_setup(fd, ETHUMBD_DOCUMENT_PAGE,
570                                &setup->document_page);
571    _ethumbd_pipe_write_setup(fd, ETHUMBD_SETUP_FINISHED, NULL);
572
573
574    if (setup->directory) eina_stringshare_del(setup->directory);
575    if (setup->category) eina_stringshare_del(setup->category);
576    if (setup->theme_file) eina_stringshare_del(setup->theme_file);
577    if (setup->group) eina_stringshare_del(setup->group);
578    if (setup->swallow) eina_stringshare_del(setup->swallow);
579
580    free(ed->processing);
581    ed->processing = NULL;
582 }
583
584 static void
585 _process_file(struct _Ethumbd *ed)
586 {
587    _ethumbd_child_write_op_generate
588      (ed, ed->queue.current, ed->processing->file,
589       ed->processing->key, ed->processing->thumb, ed->processing->thumb_key);
590 }
591
592 static int
593 _get_next_on_queue(struct _Ethumb_Queue *queue)
594 {
595    int i, index;
596    struct _Ethumb_Object *eobject;
597
598    i = queue->last;
599    i++;
600    if (i >= queue->count)
601      i = 0;
602
603    index = queue->list[i];
604    eobject = &(queue->table[index]);
605    while (!eobject->nqueue)
606      {
607         i = (i + 1) % queue->count;
608
609         index = queue->list[i];
610         eobject = &(queue->table[index]);
611      }
612
613    return queue->list[i];
614 }
615
616 static int
617 _process_queue_cb(void *data)
618 {
619    struct _Ethumb_Object *eobject;
620    int i;
621    struct _Ethumbd *ed = data;
622    struct _Ethumb_Queue *queue = &ed->queue;
623    struct _Ethumb_Request *request;
624
625    if (ed->processing)
626      return 1;
627
628    if (!queue->nqueue)
629      {
630         ed->idler = NULL;
631         if (!queue->count)
632           _ethumbd_timeout_start(ed);
633         ed->idler = NULL;
634         return 0;
635      }
636
637    i = _get_next_on_queue(queue);
638    eobject = &(queue->table[i]);
639
640    request = eina_list_data_get(eobject->queue);
641    eobject->queue = eina_list_remove_list(eobject->queue, eobject->queue);
642    ed->queue.current = i;
643    DBG("processing file: \"%s:%s\"...\n", request->file,
644        request->key);
645    ed->processing = request;
646
647    if (request->id < 0)
648      _process_setup(ed);
649    else
650      {
651         _process_file(ed);
652         _ethumb_dbus_inc_min_id(eobject);
653      }
654    eobject->nqueue--;
655    queue->nqueue--;
656
657    queue->last = i;
658
659    return 1;
660 }
661
662 static void
663 _process_queue_start(struct _Ethumbd *ed)
664 {
665    if (!ed->idler)
666      ed->idler = ecore_idler_add(_process_queue_cb, ed);
667 }
668
669 static void
670 _process_queue_stop(struct _Ethumbd *ed)
671 {
672    if (ed->idler)
673      {
674         ecore_idler_del(ed->idler);
675         ed->idler = NULL;
676      }
677 }
678
679 static int
680 _ethumb_table_append(struct _Ethumbd *ed)
681 {
682    int i;
683    char buf[1024];
684    struct _Ethumb_Queue *q = &ed->queue;
685
686    if (q->count == q->max_count)
687      {
688         int new_max = q->max_count + 5;
689         int start, size;
690
691         start = q->max_count;
692         size = new_max - q->max_count;
693
694         q->table = realloc(q->table, new_max * sizeof(struct _Ethumb_Object));
695         q->list = realloc(q->list, new_max * sizeof(int));
696         memset(&q->table[start], 0, size * sizeof(struct _Ethumb_Object));
697
698         q->max_count = new_max;
699      }
700
701    for (i = 0; i < q->max_count; i++)
702      {
703         if (!q->table[i].used)
704           break;
705      }
706
707    snprintf(buf, sizeof(buf), "%s/%d", _ethumb_dbus_path, i);
708    q->table[i].used = 1;
709    q->table[i].path = eina_stringshare_add(buf);
710    q->table[i].max_id = -1;
711    q->table[i].min_id = -1;
712    q->list[q->count] = i;
713    q->count++;
714    DBG("new object: %s, index = %d, count = %d\n", buf, i, q->count);
715
716    return i;
717 }
718
719 static inline int
720 _get_index_for_path(const char *path)
721 {
722    int i;
723    int n;
724    n = sscanf(path, "/org/enlightenment/Ethumb/%d", &i);
725    if (!n)
726      return -1;
727    return i;
728 }
729
730 static void
731 _ethumb_table_del(struct _Ethumbd *ed, int i)
732 {
733    int j;
734    Eina_List *l;
735    const Eina_List *il;
736    struct _Ethumb_Queue *q = &ed->queue;
737    struct _Ethumb_Object_Data *odata;
738
739    eina_stringshare_del(q->table[i].path);
740
741    l = q->table[i].queue;
742    while (l)
743      {
744         struct _Ethumb_Request *request = l->data;
745         eina_stringshare_del(request->file);
746         eina_stringshare_del(request->key);
747         eina_stringshare_del(request->thumb);
748         eina_stringshare_del(request->thumb_key);
749         free(request);
750         l = eina_list_remove_list(l, l);
751      }
752    q->nqueue -= q->table[i].nqueue;
753
754    il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
755    while (il)
756      {
757         e_dbus_object_interface_detach(q->table[i].dbus_obj, il->data);
758         il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
759      }
760    odata = e_dbus_object_data_get(q->table[i].dbus_obj);
761    free(odata);
762    e_dbus_object_free(q->table[i].dbus_obj);
763
764    memset(&(q->table[i]), 0, sizeof(struct _Ethumb_Object));
765    for (j = 0; j < q->count; j++)
766      {
767         if (q->list[j] == i)
768           q->list[j] = q->list[q->count - 1];
769      }
770
771    q->count--;
772    _ethumbd_child_write_op_del(ed, i);
773    if (!q->count && !ed->processing)
774      _ethumbd_timeout_start(ed);
775 }
776
777 static void
778 _ethumb_table_clear(struct _Ethumbd *ed)
779 {
780    int i;
781
782    for (i = 0; i < ed->queue.max_count; i++)
783      if (ed->queue.table[i].used)
784        _ethumb_table_del(ed, i);
785 }
786
787 static void
788 _name_owner_changed_cb(void *data, DBusMessage *msg)
789 {
790    DBusError err;
791    struct _Ethumbd *ed = data;
792    struct _Ethumb_Queue *q = &ed->queue;
793    const char *name, *from, *to;
794    int i;
795
796    dbus_error_init(&err);
797    if (!dbus_message_get_args(msg, &err,
798                               DBUS_TYPE_STRING, &name,
799                               DBUS_TYPE_STRING, &from,
800                               DBUS_TYPE_STRING, &to,
801                               DBUS_TYPE_INVALID))
802      {
803         ERR("could not get NameOwnerChanged arguments: %s: %s\n",
804             err.name, err.message);
805         dbus_error_free(&err);
806         return;
807      }
808
809    DBG("NameOwnerChanged: name = %s, from = %s, to = %s\n", name, from, to);
810
811    if (from[0] == '\0' || to[0] != '\0')
812      return;
813
814    from = eina_stringshare_add(from);
815    for (i = 0; i < q->max_count; i++)
816      {
817         if (q->table[i].used && q->table[i].client == from)
818           {
819              _ethumb_table_del(ed, i);
820              DBG("deleting [%d] from queue table.\n", i);
821           }
822      }
823 }
824
825 static void
826 _ethumb_dbus_add_name_owner_changed_cb(struct _Ethumbd *ed)
827 {
828    ed->name_owner_changed_handler = e_dbus_signal_handler_add
829      (ed->conn, fdo_bus_name, fdo_path, fdo_interface, "NameOwnerChanged",
830       _name_owner_changed_cb, ed);
831 }
832
833 DBusMessage *
834 _ethumb_dbus_ethumb_new_cb(E_DBus_Object *object, DBusMessage *msg)
835 {
836    DBusMessage *reply;
837    DBusMessageIter iter;
838    E_DBus_Object *dbus_object;
839    struct _Ethumb_Object_Data *odata;
840    int i;
841    const char *return_path = "";
842    const char *client;
843    struct _Ethumbd *ed;
844
845    ed = e_dbus_object_data_get(object);
846    client = dbus_message_get_sender(msg);
847    if (!client)
848      goto end_new;
849
850    i = _ethumb_table_append(ed);
851
852    odata = calloc(1, sizeof(*odata));
853    odata->index = i;
854    odata->ed = ed;
855
856    ed->queue.table[i].client = eina_stringshare_add(client);
857    return_path = ed->queue.table[i].path;
858
859    dbus_object = e_dbus_object_add(ed->conn, return_path, odata);
860    if (!dbus_object)
861      {
862         ERR("could not create dbus_object.\n");
863         free(odata);
864         return_path = "";
865         goto end_new;
866      }
867
868    e_dbus_object_interface_attach(dbus_object, ed->objects_iface);
869    ed->queue.table[i].dbus_obj = dbus_object;
870
871    _ethumbd_child_write_op_new(ed, i);
872    _ethumbd_timeout_stop(ed);
873
874  end_new:
875    reply = dbus_message_new_method_return(msg);
876    dbus_message_iter_init_append(reply, &iter);
877    dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
878                                   &return_path);
879    return reply;
880 }
881
882 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_methods[] =
883   {
884     {"new", "", "o", _ethumb_dbus_ethumb_new_cb},
885     {NULL, NULL, NULL, NULL}
886   };
887
888 static const char *
889 _ethumb_dbus_get_bytearray(DBusMessageIter *iter)
890 {
891    int el_type;
892    int length;
893    DBusMessageIter riter;
894    const char *result;
895
896    el_type = dbus_message_iter_get_element_type(iter);
897    if (el_type != DBUS_TYPE_BYTE)
898      {
899         ERR("not an byte array element.\n");
900         return NULL;
901      }
902
903    dbus_message_iter_recurse(iter, &riter);
904    dbus_message_iter_get_fixed_array(&riter, &result, &length);
905
906    if (result[0] == '\0')
907      return NULL;
908    else
909      return eina_stringshare_add(result);
910 }
911
912 static void
913 _ethumb_dbus_append_bytearray(DBusMessageIter *iter, const char *string)
914 {
915    DBusMessageIter viter;
916
917    if (!string)
918      string = "";
919
920    dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &viter);
921    dbus_message_iter_append_fixed_array
922      (&viter, DBUS_TYPE_BYTE, &string, strlen(string) + 1);
923    dbus_message_iter_close_container(iter, &viter);
924 }
925
926 DBusMessage *
927 _ethumb_dbus_queue_add_cb(E_DBus_Object *object, DBusMessage *msg)
928 {
929    DBusMessage *reply;
930    DBusMessageIter iter;
931    const char *file, *key;
932    const char *thumb, *thumb_key;
933    struct _Ethumb_Object_Data *odata;
934    struct _Ethumb_Object *eobject;
935    struct _Ethumbd *ed;
936    struct _Ethumb_Request *request;
937    dbus_int32_t id = -1;
938
939    dbus_message_iter_init(msg, &iter);
940    dbus_message_iter_get_basic(&iter, &id);
941    dbus_message_iter_next(&iter);
942    file = _ethumb_dbus_get_bytearray(&iter);
943    dbus_message_iter_next(&iter);
944    key = _ethumb_dbus_get_bytearray(&iter);
945    dbus_message_iter_next(&iter);
946    thumb = _ethumb_dbus_get_bytearray(&iter);
947    dbus_message_iter_next(&iter);
948    thumb_key = _ethumb_dbus_get_bytearray(&iter);
949
950    if (!file)
951      {
952         ERR("no filename given.\n");
953         goto end;
954      }
955
956    odata = e_dbus_object_data_get(object);
957    if (!odata)
958      {
959         ERR("could not get dbus_object data.\n");
960         goto end;
961      }
962
963    ed = odata->ed;
964    eobject = &(ed->queue.table[odata->index]);
965    if (!_ethumb_dbus_check_id(eobject, id))
966      goto end;
967    request = calloc(1, sizeof(*request));
968    request->id = id;
969    request->file = file;
970    request->key = key;
971    request->thumb = thumb;
972    request->thumb_key = thumb_key;
973    eobject->queue = eina_list_append(eobject->queue, request);
974    eobject->nqueue++;
975    ed->queue.nqueue++;
976    _ethumb_dbus_inc_max_id(eobject, id);
977
978    _process_queue_start(ed);
979
980  end:
981    reply = dbus_message_new_method_return(msg);
982    dbus_message_iter_init_append(reply, &iter);
983    dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id);
984    return reply;
985 }
986
987 DBusMessage *
988 _ethumb_dbus_queue_remove_cb(E_DBus_Object *object, DBusMessage *msg)
989 {
990    DBusMessage *reply;
991    DBusMessageIter iter;
992    dbus_int32_t id;
993    struct _Ethumb_Object_Data *odata;
994    struct _Ethumb_Object *eobject;
995    struct _Ethumb_Request *request;
996    struct _Ethumbd *ed;
997    dbus_bool_t r = 0;
998    Eina_List *l;
999
1000    dbus_message_iter_init(msg, &iter);
1001    dbus_message_iter_get_basic(&iter, &id);
1002
1003    odata = e_dbus_object_data_get(object);
1004    if (!odata)
1005      {
1006         ERR("could not get dbus_object data.\n");
1007         goto end;
1008      }
1009
1010    ed = odata->ed;
1011    eobject = &ed->queue.table[odata->index];
1012    l = eobject->queue;
1013    while (l)
1014      {
1015         request = l->data;
1016         if (id == request->id)
1017           break;
1018         l = l->next;
1019      }
1020
1021    if (l)
1022      {
1023         r = 1;
1024         eina_stringshare_del(request->file);
1025         eina_stringshare_del(request->key);
1026         eina_stringshare_del(request->thumb);
1027         eina_stringshare_del(request->thumb_key);
1028         free(request);
1029         eobject->queue = eina_list_remove_list(eobject->queue, l);
1030         eobject->nqueue--;
1031         ed->queue.nqueue--;
1032         _ethumb_dbus_inc_min_id(eobject);
1033      }
1034
1035  end:
1036    reply = dbus_message_new_method_return(msg);
1037    dbus_message_iter_init_append(reply, &iter);
1038    dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1039    return reply;
1040 }
1041
1042 DBusMessage *
1043 _ethumb_dbus_queue_clear_cb(E_DBus_Object *object, DBusMessage *msg)
1044 {
1045    DBusMessage *reply;
1046    struct _Ethumb_Object_Data *odata;
1047    struct _Ethumb_Object *eobject;
1048    struct _Ethumbd *ed;
1049    Eina_List *l;
1050
1051    odata = e_dbus_object_data_get(object);
1052    if (!odata)
1053      {
1054         ERR("could not get dbus_object data.\n");
1055         goto end;
1056      }
1057
1058    ed = odata->ed;
1059    eobject = &ed->queue.table[odata->index];
1060    l = eobject->queue;
1061    while (l)
1062      {
1063         struct _Ethumb_Request *request = l->data;
1064         eina_stringshare_del(request->file);
1065         eina_stringshare_del(request->key);
1066         eina_stringshare_del(request->thumb);
1067         eina_stringshare_del(request->thumb_key);
1068         free(request);
1069         l = eina_list_remove_list(l, l);
1070      }
1071    ed->queue.nqueue -= eobject->nqueue;
1072    eobject->nqueue = 0;
1073
1074  end:
1075    reply = dbus_message_new_method_return(msg);
1076    return reply;
1077 }
1078
1079 DBusMessage *
1080 _ethumb_dbus_delete_cb(E_DBus_Object *object, DBusMessage *msg)
1081 {
1082    DBusMessage *reply;
1083    DBusMessageIter iter;
1084    struct _Ethumb_Object_Data *odata;
1085    struct _Ethumbd *ed;
1086
1087    dbus_message_iter_init(msg, &iter);
1088    reply = dbus_message_new_method_return(msg);
1089
1090    odata = e_dbus_object_data_get(object);
1091    if (!odata)
1092      {
1093         ERR("could not get dbus_object data for del_cb.\n");
1094         return reply;
1095      }
1096    ed = odata->ed;
1097    _ethumb_table_del(ed, odata->index);
1098    free(odata);
1099
1100    return reply;
1101 }
1102
1103 static int
1104 _ethumb_dbus_fdo_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request __UNUSED__)
1105 {
1106    int type;
1107    dbus_int32_t fdo;
1108
1109    type = dbus_message_iter_get_arg_type(iter);
1110    if (type != DBUS_TYPE_INT32)
1111      {
1112         ERR("invalid param for fdo_set.\n");
1113         return 0;
1114      }
1115
1116    dbus_message_iter_get_basic(iter, &fdo);
1117    DBG("setting fdo to: %d\n", fdo);
1118
1119    return 1;
1120 }
1121
1122 static int
1123 _ethumb_dbus_size_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1124 {
1125    DBusMessageIter oiter;
1126    int type;
1127    dbus_int32_t w, h;
1128
1129    type = dbus_message_iter_get_arg_type(iter);
1130    if (type != DBUS_TYPE_STRUCT)
1131      {
1132         ERR("invalid param for size_set.\n");
1133         return 0;
1134      }
1135
1136    dbus_message_iter_recurse(iter, &oiter);
1137    dbus_message_iter_get_basic(&oiter, &w);
1138    dbus_message_iter_next(&oiter);
1139    dbus_message_iter_get_basic(&oiter, &h);
1140    DBG("setting size to: %dx%d\n", w, h);
1141    request->setup.flags.size = 1;
1142    request->setup.tw = w;
1143    request->setup.th = h;
1144
1145    return 1;
1146 }
1147
1148 static int
1149 _ethumb_dbus_format_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1150 {
1151    int type;
1152    dbus_int32_t format;
1153
1154    type = dbus_message_iter_get_arg_type(iter);
1155    if (type != DBUS_TYPE_INT32)
1156      {
1157         ERR("invalid param for format_set.\n");
1158         return 0;
1159      }
1160
1161    dbus_message_iter_get_basic(iter, &format);
1162    DBG("setting format to: %d\n", format);
1163    request->setup.flags.format = 1;
1164    request->setup.format = format;
1165
1166    return 1;
1167 }
1168
1169 static int
1170 _ethumb_dbus_aspect_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1171 {
1172    int type;
1173    dbus_int32_t aspect;
1174
1175    type = dbus_message_iter_get_arg_type(iter);
1176    if (type != DBUS_TYPE_INT32)
1177      {
1178         ERR("invalid param for aspect_set.\n");
1179         return 0;
1180      }
1181
1182    dbus_message_iter_get_basic(iter, &aspect);
1183    DBG("setting aspect to: %d\n", aspect);
1184    request->setup.flags.aspect = 1;
1185    request->setup.aspect = aspect;
1186
1187    return 1;
1188 }
1189
1190 static int
1191 _ethumb_dbus_crop_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1192 {
1193    DBusMessageIter oiter;
1194    int type;
1195    double x, y;
1196
1197    type = dbus_message_iter_get_arg_type(iter);
1198    if (type != DBUS_TYPE_STRUCT)
1199      {
1200         ERR("invalid param for crop_set.\n");
1201         return 0;
1202      }
1203
1204    dbus_message_iter_recurse(iter, &oiter);
1205    dbus_message_iter_get_basic(&oiter, &x);
1206    dbus_message_iter_next(&oiter);
1207    dbus_message_iter_get_basic(&oiter, &y);
1208    DBG("setting crop to: %3.2f,%3.2f\n", x, y);
1209    request->setup.flags.crop = 1;
1210    request->setup.cx = x;
1211    request->setup.cy = y;
1212
1213    return 1;
1214 }
1215
1216 static int
1217 _ethumb_dbus_quality_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1218 {
1219    int type;
1220    dbus_int32_t quality;
1221
1222    type = dbus_message_iter_get_arg_type(iter);
1223    if (type != DBUS_TYPE_INT32)
1224      {
1225         ERR("invalid param for quality_set.\n");
1226         return 0;
1227      }
1228
1229    dbus_message_iter_get_basic(iter, &quality);
1230    DBG("setting quality to: %d\n", quality);
1231    request->setup.flags.quality = 1;
1232    request->setup.quality = quality;
1233
1234    return 1;
1235 }
1236
1237
1238 static int
1239 _ethumb_dbus_compress_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1240 {
1241    int type;
1242    dbus_int32_t compress;
1243
1244    type = dbus_message_iter_get_arg_type(iter);
1245    if (type != DBUS_TYPE_INT32)
1246      {
1247         ERR("invalid param for compress_set.\n");
1248         return 0;
1249      }
1250
1251    dbus_message_iter_get_basic(iter, &compress);
1252    DBG("setting compress to: %d\n", compress);
1253    request->setup.flags.compress = 1;
1254    request->setup.compress = compress;
1255
1256    return 1;
1257 }
1258
1259 static int
1260 _ethumb_dbus_frame_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1261 {
1262    DBusMessageIter oiter;
1263    int type;
1264    const char *file, *group, *swallow;
1265
1266    type = dbus_message_iter_get_arg_type(iter);
1267    if (type != DBUS_TYPE_STRUCT)
1268      {
1269         ERR("invalid param for frame_set.\n");
1270         return 0;
1271      }
1272
1273    dbus_message_iter_recurse(iter, &oiter);
1274    file = _ethumb_dbus_get_bytearray(&oiter);
1275    dbus_message_iter_next(&oiter);
1276    group = _ethumb_dbus_get_bytearray(&oiter);
1277    dbus_message_iter_next(&oiter);
1278    swallow = _ethumb_dbus_get_bytearray(&oiter);
1279    DBG("setting frame to \"%s:%s:%s\"\n", file, group, swallow);
1280    request->setup.flags.frame = 1;
1281    request->setup.theme_file = eina_stringshare_add(file);
1282    request->setup.group = eina_stringshare_add(group);
1283    request->setup.swallow = eina_stringshare_add(swallow);
1284
1285    return 1;
1286 }
1287
1288 static int
1289 _ethumb_dbus_directory_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1290 {
1291    int type;
1292    const char *directory;
1293
1294    type = dbus_message_iter_get_arg_type(iter);
1295    if (type != DBUS_TYPE_ARRAY)
1296      {
1297         ERR("invalid param for dir_path_set.\n");
1298         return 0;
1299      }
1300
1301    directory = _ethumb_dbus_get_bytearray(iter);
1302    DBG("setting directory to: %s\n", directory);
1303    request->setup.flags.directory = 1;
1304    request->setup.directory = eina_stringshare_add(directory);
1305
1306    return 1;
1307 }
1308
1309 static int
1310 _ethumb_dbus_category_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1311 {
1312    int type;
1313    const char *category;
1314
1315    type = dbus_message_iter_get_arg_type(iter);
1316    if (type != DBUS_TYPE_ARRAY)
1317      {
1318         ERR("invalid param for category.\n");
1319         return 0;
1320      }
1321
1322    category = _ethumb_dbus_get_bytearray(iter);
1323    DBG("setting category to: %s\n", category);
1324    request->setup.flags.category = 1;
1325    request->setup.category = eina_stringshare_add(category);
1326
1327    return 1;
1328 }
1329
1330 static int
1331 _ethumb_dbus_video_time_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1332 {
1333    int type;
1334    double video_time;
1335
1336    type = dbus_message_iter_get_arg_type(iter);
1337    if (type != DBUS_TYPE_DOUBLE)
1338      {
1339         ERR("invalid param for video_time_set.\n");
1340         return 0;
1341      }
1342
1343    dbus_message_iter_get_basic(iter, &video_time);
1344    DBG("setting video_time to: %3.2f\n", video_time);
1345    request->setup.flags.video_time = 1;
1346    request->setup.video_time = video_time;
1347
1348    return 1;
1349 }
1350
1351 static int
1352 _ethumb_dbus_video_start_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1353 {
1354    int type;
1355    double video_start;
1356
1357    type = dbus_message_iter_get_arg_type(iter);
1358    if (type != DBUS_TYPE_DOUBLE)
1359      {
1360         ERR("invalid param for video_start_set.\n");
1361         return 0;
1362      }
1363
1364    dbus_message_iter_get_basic(iter, &video_start);
1365    DBG("setting video_start to: %3.2f\n", video_start);
1366    request->setup.flags.video_start = 1;
1367    request->setup.video_start = video_start;
1368
1369    return 1;
1370 }
1371
1372 static int
1373 _ethumb_dbus_video_interval_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1374 {
1375    int type;
1376    double video_interval;
1377
1378    type = dbus_message_iter_get_arg_type(iter);
1379    if (type != DBUS_TYPE_DOUBLE)
1380      {
1381         ERR("invalid param for video_interval_set.\n");
1382         return 0;
1383      }
1384
1385    dbus_message_iter_get_basic(iter, &video_interval);
1386    DBG("setting video_interval to: %3.2f\n", video_interval);
1387    request->setup.flags.video_interval = 1;
1388    request->setup.video_interval = video_interval;
1389
1390    return 1;
1391 }
1392
1393 static int
1394 _ethumb_dbus_video_ntimes_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1395 {
1396    int type;
1397    int video_ntimes;
1398
1399    type = dbus_message_iter_get_arg_type(iter);
1400    if (type != DBUS_TYPE_INT32)
1401      {
1402         ERR("invalid param for video_ntimes_set.\n");
1403         return 0;
1404      }
1405
1406    dbus_message_iter_get_basic(iter, &video_ntimes);
1407    DBG("setting video_ntimes to: %3.2d\n", video_ntimes);
1408    request->setup.flags.video_ntimes = 1;
1409    request->setup.video_ntimes = video_ntimes;
1410
1411    return 1;
1412 }
1413
1414 static int
1415 _ethumb_dbus_video_fps_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1416 {
1417    int type;
1418    int video_fps;
1419
1420    type = dbus_message_iter_get_arg_type(iter);
1421    if (type != DBUS_TYPE_INT32)
1422      {
1423         ERR("invalid param for video_fps_set.\n");
1424         return 0;
1425      }
1426
1427    dbus_message_iter_get_basic(iter, &video_fps);
1428    DBG("setting video_fps to: %3.2d\n", video_fps);
1429    request->setup.flags.video_fps = 1;
1430    request->setup.video_fps = video_fps;
1431
1432    return 1;
1433 }
1434
1435 static int
1436 _ethumb_dbus_document_page_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1437 {
1438    int type;
1439    dbus_int32_t document_page;
1440
1441    type = dbus_message_iter_get_arg_type(iter);
1442    if (type != DBUS_TYPE_INT32)
1443      {
1444         ERR("invalid param for document_page_set.\n");
1445         return 0;
1446      }
1447
1448    dbus_message_iter_get_basic(iter, &document_page);
1449    DBG("setting document_page to: %d\n", document_page);
1450    request->setup.flags.document_page = 1;
1451    request->setup.document_page = document_page;
1452
1453    return 1;
1454 }
1455
1456 static struct
1457 {
1458    const char *option;
1459    int (*setup_func)(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request);
1460 } _option_cbs[] = {
1461   {"fdo", _ethumb_dbus_fdo_set},
1462   {"size", _ethumb_dbus_size_set},
1463   {"format", _ethumb_dbus_format_set},
1464   {"aspect", _ethumb_dbus_aspect_set},
1465   {"crop", _ethumb_dbus_crop_set},
1466   {"quality", _ethumb_dbus_quality_set},
1467   {"compress", _ethumb_dbus_compress_set},
1468   {"frame", _ethumb_dbus_frame_set},
1469   {"directory", _ethumb_dbus_directory_set},
1470   {"category", _ethumb_dbus_category_set},
1471   {"video_time", _ethumb_dbus_video_time_set},
1472   {"video_start", _ethumb_dbus_video_start_set},
1473   {"video_interval", _ethumb_dbus_video_interval_set},
1474   {"video_ntimes", _ethumb_dbus_video_ntimes_set},
1475   {"video_fps", _ethumb_dbus_video_fps_set},
1476   {"document_page", _ethumb_dbus_document_page_set},
1477   {NULL, NULL}
1478 };
1479
1480 static int
1481 _ethumb_dbus_ethumb_setup_parse_element(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request)
1482 {
1483    DBusMessageIter viter, diter;
1484    const char *option;
1485    int i, r;
1486
1487    dbus_message_iter_recurse(iter, &diter);
1488    dbus_message_iter_get_basic(&diter, &option);
1489    dbus_message_iter_next(&diter);
1490
1491    r = 0;
1492    for (i = 0; _option_cbs[i].option; i++)
1493      if (!strcmp(_option_cbs[i].option, option))
1494        {
1495           r = 1;
1496           break;
1497        }
1498
1499    if (!r)
1500      {
1501         ERR("ethumb_setup invalid option: %s\n", option);
1502         return 0;
1503      }
1504
1505    dbus_message_iter_recurse(&diter, &viter);
1506    return _option_cbs[i].setup_func(eobject, &viter, request);
1507 }
1508
1509 DBusMessage *
1510 _ethumb_dbus_ethumb_setup_cb(E_DBus_Object *object, DBusMessage *msg)
1511 {
1512    DBusMessage *reply;
1513    DBusMessageIter iter, aiter;
1514    struct _Ethumb_Object_Data *odata;
1515    struct _Ethumbd *ed;
1516    struct _Ethumb_Object *eobject;
1517    struct _Ethumb_Request *request;
1518    dbus_bool_t r = 0;
1519    int atype;
1520
1521    dbus_message_iter_init(msg, &iter);
1522    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1523      {
1524         ERR("wrong parameters.\n");
1525         goto end;
1526      }
1527
1528    odata = e_dbus_object_data_get(object);
1529    if (!odata)
1530      {
1531         ERR("could not get dbus_object data for setup_cb.\n");
1532         goto end;
1533      }
1534
1535    ed = odata->ed;
1536    eobject = &ed->queue.table[odata->index];
1537
1538    request = calloc(1, sizeof(*request));
1539    request->id = -1;
1540    dbus_message_iter_recurse(&iter, &aiter);
1541    atype = dbus_message_iter_get_arg_type(&aiter);
1542
1543    r = 1;
1544    while (atype != DBUS_TYPE_INVALID)
1545      {
1546         if (!_ethumb_dbus_ethumb_setup_parse_element(eobject, &aiter, request))
1547           r = 0;
1548         dbus_message_iter_next(&aiter);
1549         atype = dbus_message_iter_get_arg_type(&aiter);
1550      }
1551
1552    eobject->queue = eina_list_append(eobject->queue, request);
1553    eobject->nqueue++;
1554    ed->queue.nqueue++;
1555
1556  end:
1557    reply = dbus_message_new_method_return(msg);
1558    dbus_message_iter_init_append(reply, &iter);
1559    dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1560
1561    return reply;
1562 }
1563
1564 static void
1565 _ethumb_dbus_generated_signal(struct _Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success)
1566 {
1567    DBusMessage *signal;
1568    int current;
1569    const char *opath;
1570    DBusMessageIter iter;
1571    dbus_bool_t value;
1572    dbus_int32_t id32;
1573
1574    value = success;
1575    id32 = *id;
1576
1577    current = ed->queue.current;
1578    opath = ed->queue.table[current].path;
1579    signal = dbus_message_new_signal
1580      (opath, _ethumb_dbus_objects_interface, "generated");
1581
1582    dbus_message_iter_init_append(signal, &iter);
1583    dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id32);
1584    _ethumb_dbus_append_bytearray(&iter, thumb_path);
1585    _ethumb_dbus_append_bytearray(&iter, thumb_key);
1586    dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &value);
1587
1588    e_dbus_message_send(ed->conn, signal, NULL, -1, NULL);
1589    dbus_message_unref(signal);
1590 }
1591
1592 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_objects_methods[] = {
1593   {"queue_add", "iayayayay", "i", _ethumb_dbus_queue_add_cb},
1594   {"queue_remove", "i", "b", _ethumb_dbus_queue_remove_cb},
1595   {"clear_queue", "", "", _ethumb_dbus_queue_clear_cb},
1596   {"ethumb_setup", "a{sv}", "b", _ethumb_dbus_ethumb_setup_cb},
1597   {"delete", "", "", _ethumb_dbus_delete_cb},
1598   {NULL, NULL, NULL, NULL}
1599 };
1600
1601 static struct _Ethumb_DBus_Signal_Table _ethumb_dbus_objects_signals[] = {
1602   {"generated", "xayayb"},
1603   {NULL, NULL}
1604 };
1605
1606 static int
1607 _ethumb_dbus_interface_elements_add(E_DBus_Interface *iface, struct _Ethumb_DBus_Method_Table *mtable, struct _Ethumb_DBus_Signal_Table *stable)
1608 {
1609    int i = -1;
1610    while (mtable && mtable[++i].name != NULL)
1611      if (!e_dbus_interface_method_add(iface,
1612                                       mtable[i].name,
1613                                       mtable[i].signature,
1614                                       mtable[i].reply,
1615                                       mtable[i].function))
1616        return 0;
1617
1618    i = -1;
1619    while (stable && stable[++i].name != NULL)
1620      if (!e_dbus_interface_signal_add(iface,
1621                                       stable[i].name,
1622                                       stable[i].signature))
1623        return 0;
1624    return 1;
1625 }
1626
1627 static void
1628 _ethumb_dbus_request_name_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *err)
1629 {
1630    E_DBus_Object *dbus_object;
1631    struct _Ethumbd *ed = data;
1632    int r;
1633
1634    if (dbus_error_is_set(err))
1635      {
1636         ERR("request name error: %s\n", err->message);
1637         dbus_error_free(err);
1638         e_dbus_connection_close(ed->conn);
1639         return;
1640      }
1641
1642    dbus_object = e_dbus_object_add(ed->conn, _ethumb_dbus_path, ed);
1643    if (!dbus_object)
1644      return;
1645    ed->dbus_obj = dbus_object;
1646    ed->eiface = e_dbus_interface_new(_ethumb_dbus_interface);
1647    if (!ed->eiface)
1648      {
1649         ERR("could not create interface.\n");
1650         return;
1651      }
1652    r = _ethumb_dbus_interface_elements_add(ed->eiface,
1653                                            _ethumb_dbus_methods, NULL);
1654    if (!r)
1655      {
1656         ERR("could not add methods to the interface.\n");
1657         e_dbus_interface_unref(ed->eiface);
1658         return;
1659      }
1660    e_dbus_object_interface_attach(dbus_object, ed->eiface);
1661
1662    ed->objects_iface = e_dbus_interface_new(_ethumb_dbus_objects_interface);
1663    if (!ed->objects_iface)
1664      {
1665         ERR("could not create interface.\n");
1666         return;
1667      }
1668
1669    r = _ethumb_dbus_interface_elements_add(ed->objects_iface,
1670                                            _ethumb_dbus_objects_methods,
1671                                            _ethumb_dbus_objects_signals);
1672    if (!r)
1673      {
1674         ERR("ERROR: could not setup objects interface methods.\n");
1675         e_dbus_interface_unref(ed->objects_iface);
1676         return;
1677      }
1678
1679    _ethumb_dbus_add_name_owner_changed_cb(ed);
1680
1681    _ethumbd_timeout_start(ed);
1682 }
1683
1684 static int
1685 _ethumb_dbus_setup(struct _Ethumbd *ed)
1686 {
1687    e_dbus_request_name
1688      (ed->conn, _ethumb_dbus_bus_name, 0, _ethumb_dbus_request_name_cb, ed);
1689
1690    return 1;
1691 }
1692
1693 static void
1694 _ethumb_dbus_finish(struct _Ethumbd *ed)
1695 {
1696    _process_queue_stop(ed);
1697    _ethumb_table_clear(ed);
1698    e_dbus_signal_handler_del(ed->conn, ed->name_owner_changed_handler);
1699    e_dbus_interface_unref(ed->objects_iface);
1700    e_dbus_interface_unref(ed->eiface);
1701    e_dbus_object_free(ed->dbus_obj);
1702    free(ed->queue.table);
1703    free(ed->queue.list);
1704 }
1705
1706 static int
1707 _ethumbd_spawn(struct _Ethumbd *ed)
1708 {
1709    int pparent[2]; // parent writes here
1710    int pchild[2]; // child writes here
1711    int pid;
1712
1713    if (pipe(pparent) == -1)
1714      {
1715         ERR("could not create parent pipe.\n");
1716         return 0;
1717      }
1718
1719    if (pipe(pchild) == -1)
1720      {
1721         ERR("could not create child pipe.\n");
1722         return 0;
1723      }
1724
1725    pid = fork();
1726    if (pid == -1)
1727      {
1728         ERR("fork error.\n");
1729         return 0;
1730      }
1731
1732    if (pid == 0)
1733      {
1734         close(pparent[1]);
1735         close(pchild[0]);
1736         ethumbd_child_start(pparent[0], pchild[1]);
1737         return 2;
1738      }
1739    else
1740      {
1741         close(pparent[0]);
1742         close(pchild[1]);
1743         ed->pipeout = pparent[1];
1744         ed->pipein = pchild[0];
1745         ed->fd_handler = ecore_main_fd_handler_add
1746           (ed->pipein, ECORE_FD_READ | ECORE_FD_ERROR,
1747            _ethumbd_fd_handler, ed, NULL, NULL);
1748         return 1;
1749      }
1750 }
1751
1752 int
1753 main(int argc, char *argv[])
1754 {
1755    Eina_Bool quit_option = 0;
1756    int exit_value = 0;
1757    int arg_index;
1758    struct _Ethumbd ed;
1759    int child;
1760    double timeout = -1;
1761
1762    memset(&ed, 0, sizeof(ed));
1763    ecore_init();
1764    eina_init();
1765
1766    ethumb_init();
1767
1768    child = _ethumbd_spawn(&ed);
1769    if (!child)
1770      {
1771         exit_value = -6;
1772         goto finish;
1773      }
1774
1775    if (child == 2)
1776      {
1777         exit_value = 0;
1778         goto finish;
1779      }
1780
1781    if (!e_dbus_init())
1782      {
1783         ERR("could not init e_dbus.\n");
1784         exit_value = -1;
1785         goto finish;
1786      }
1787
1788    Ecore_Getopt_Value values[] = {
1789      ECORE_GETOPT_VALUE_DOUBLE(timeout),
1790      ECORE_GETOPT_VALUE_BOOL(quit_option),
1791      ECORE_GETOPT_VALUE_BOOL(quit_option),
1792      ECORE_GETOPT_VALUE_BOOL(quit_option),
1793      ECORE_GETOPT_VALUE_BOOL(quit_option),
1794      ECORE_GETOPT_VALUE_NONE
1795    };
1796
1797    arg_index = ecore_getopt_parse(&optdesc, values, argc, argv);
1798    if (arg_index < 0)
1799      {
1800         ERR("Could not parse arguments.\n");
1801         exit_value = -2;
1802         goto finish;
1803      }
1804
1805    if (quit_option)
1806      goto finish;
1807
1808    ed.conn = e_dbus_bus_get(DBUS_BUS_SESSION);
1809    if (!ed.conn)
1810      {
1811         ERR("could not connect to session bus.\n");
1812         exit_value = -3;
1813         goto finish_edbus;
1814      }
1815
1816    ed.timeout = timeout;
1817
1818    if (!_ethumb_dbus_setup(&ed))
1819      {
1820         e_dbus_connection_close(ed.conn);
1821         ERR("could not setup dbus connection.\n");
1822         exit_value = -5;
1823         goto finish_edbus;
1824      }
1825
1826    ecore_main_loop_begin();
1827    _ethumb_dbus_finish(&ed);
1828
1829  finish_edbus:
1830    e_dbus_shutdown();
1831  finish:
1832    ethumb_shutdown();
1833    eina_init();
1834    ecore_shutdown();
1835    return exit_value;
1836 }