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