Added 'services' and 'metadata' tags for specific constants.
[LibTracker-Client-Perl.git] / Client.xs
blob8c9fd394495f4a9d2f5609428ab6b48830c5dbb0
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
5 #include "ppport.h"
7 #include <tracker.h>
10 /* SERVICE_ definitions */
11 #define  SERVICE_MIN                    0
12 #define  SERVICE_FILES                  0
13 #define  SERVICE_FOLDERS                1
14 #define  SERVICE_DOCUMENTS              2
15 #define  SERVICE_IMAGES                 3
16 #define  SERVICE_MUSIC                  4
17 #define  SERVICE_VIDEOS                 5
18 #define  SERVICE_TEXT_FILES             6
19 #define  SERVICE_DEVELOPMENT_FILES      7
20 #define  SERVICE_OTHER_FILES            8
21 #define  SERVICE_VFS_FILES              9
22 #define  SERVICE_VFS_FOLDERS           10
23 #define  SERVICE_VFS_DOCUMENTS         11
24 #define  SERVICE_VFS_IMAGES            12
25 #define  SERVICE_VFS_MUSIC             13
26 #define  SERVICE_VFS_VIDEOS            14
27 #define  SERVICE_VFS_TEXT_FILES        15
28 #define  SERVICE_VFS_DEVELOPMENT_FILES 16
29 #define  SERVICE_VFS_OTHER_FILES       17
30 #define  SERVICE_CONVERSATIONS         18
31 #define  SERVICE_PLAYLISTS             19
32 #define  SERVICE_APPLICATIONS          20
33 #define  SERVICE_CONTACTS              21
34 #define  SERVICE_EMAILS                22
35 #define  SERVICE_EMAILATTACHMENTS      23
36 #define  SERVICE_APPOINTMENTS          24
37 #define  SERVICE_TASKS                 25
38 #define  SERVICE_BOOKMARKS             26
39 #define  SERVICE_HISTORY               27
40 #define  SERVICE_PROJECTS              28
41 #define  SERVICE_MAX                   28
43 /* MetasataTypes definitions */
44 #define DATA_MIN                        0
45 #define DATA_STRING_INDEXABLE           0
46 #define DATA_STRING                     1
47 #define DATA_NUMERIC                    2
48 #define DATA_DATE                       3
49 #define DATA_MAX                        4
51 #include "const-c.inc"
53 SV* get_instance(char* class)
55         TrackerClient*  client = NULL;
56         SV*             obj_ref = newSViv(0);
57         SV*             obj = newSVrv(obj_ref, class);
59         client = tracker_connect(FALSE);
60         if(!client)
61                 return &PL_sv_undef;
63         sv_setiv(obj, (IV)client);
64         SvREADONLY_on(obj);
65         return obj_ref;
69 void assert_valid_servicetype(int servicetype)
71         if( (servicetype < SERVICE_MIN) || (servicetype > SERVICE_MAX) )
72                 croak("Invalid service type : %d\n", servicetype);
76 void assert_valid_mdtype(int mdtype)
78         if( (mdtype < DATA_MIN) || (mdtype > DATA_MAX) )
79                 croak("Invalid metadata type : %d\n", mdtype);
83 char* service_name(char* class, int type)
85         assert_valid_servicetype(type);
86         return tracker_type_to_service_name(type);
90 int service_type(char* class, const char* name)
92         return tracker_service_name_to_type(name);
96 void store_in_hash_and_free(gpointer key, gpointer value, gpointer perlhash)
98         hv_store(perlhash, key, strlen(key), newSVpvn(value, strlen(value)), 0);
99         free(key);
100         free(value);
103 void store_in_array(gpointer data, gpointer perlarray)
105         /* inspired from tracker-tag.c's get_meta_table_data */
106         char **meta, **meta_p;
107         int i = 0;
109         meta = (char **) data;
110         for(meta_p = meta; *meta_p; meta_p++) {
111                 if( i == 0 )
112                         av_push((AV *)perlarray, newSVpv(*meta_p, 0));
113                 i++;
114         }
117 void DESTROY(SV* obj) {
118         TrackerClient* client = (TrackerClient*) SvIV(SvRV(obj));
119         tracker_disconnect(client);
123 MODULE = LibTracker::Client             PACKAGE = LibTracker::Client            
124 PROTOTYPES: DISABLE
126 INCLUDE: const-xs.inc
129 get_instance (class)
130         char* class
133 char*
134 service_name (class, type)
135         char* class;
136         int type;
140 service_type (class, name)
141         char* class;
142         const char* name;
146 get_version (obj)
147                 SV* obj;
148         PREINIT:
149                 int ret;
150                 GError *error = NULL;
151                 TrackerClient* client;
152         CODE:
153                 client = (TrackerClient*) SvIV(SvRV(obj));
154                 ST(0) = sv_newmortal();
155                 ret = tracker_get_version(client, &error);
156                 if(error)
157                         ST(0) = &PL_sv_undef;
158                 else
159                         sv_setiv( ST(0), ret );
163 get_status (obj)
164                 SV* obj;
165         PREINIT:
166                 char* ret;
167                 GError *error = NULL;
168                 TrackerClient* client;
169         CODE:
170                 client = (TrackerClient*) SvIV(SvRV(obj));
171                 ST(0) = sv_newmortal();
172                 ret = tracker_get_status(client, &error);
173                 if(error)
174                         ST(0) = &PL_sv_undef;
175                 else
176                         sv_setpv( ST(0), ret );
177                 free(ret);
181 get_services (obj, main_only)
182                 SV* obj;
183                 bool main_only;
184         PREINIT:
185                 GHashTable* ret;
186                 GError *error = NULL;
187                 TrackerClient* client;
188         INIT:
189                 HV* rh;
190         CODE:
191                 main_only = (!!main_only);      /* either 0 or 1 */
192                 client = (TrackerClient*) SvIV(SvRV(obj));
193                 ret = tracker_get_services(client, main_only, &error);
194                 rh = (HV *) sv_2mortal( (SV *) newHV() );
195                 if(error)
196                         RETVAL = &PL_sv_undef;
197                 else {
198                         g_hash_table_foreach( ret, store_in_hash_and_free, (gpointer) rh );
199                         RETVAL = newRV( (SV *) rh);
200                 }
201         OUTPUT:
202                 RETVAL
206 get_metadata (obj, servicetype, id, keys)
207                 SV* obj;
208                 int servicetype;
209                 const char* id;
210                 SV* keys;
211         PREINIT:
212                 char** ret;
213                 char** _keys;
214                 char* placeholder;
215                 STRLEN length;
216                 GError *error = NULL;
217                 TrackerClient* client;
218         INIT:
219                 HV* rh;
220                 I32 numkeys = 0;
221                 int i;
222                 SV **current_val;
223                 if( (!SvROK(keys))
224                         || ( SvTYPE( SvRV(keys) ) != SVt_PVAV )
225                         || ( (numkeys = av_len( (AV *) SvRV(keys))) < 0 ) ) {
226                         XSRETURN_UNDEF;
227                 }
228                 assert_valid_servicetype(servicetype);
229                 /* convert keys to a char** - this is inspired from the
230                  * avref2charptrptr function from perldap
231                  */
232                 Newxz(_keys, numkeys + 2, char *);
233                 for (i = 0; i <= numkeys; i++) {
234                         current_val = av_fetch( (AV *) SvRV(keys), i, 0 );
235                         placeholder = SvPV(*current_val, length);
236                         /* store a copy in _keys */
237                         Newxz(_keys[i], length+1, char);
238                         Copy(placeholder, _keys[i], length+1, char);
239                 }
240                 _keys[i] = NULL;
241         CODE:
242                 client = (TrackerClient*) SvIV(SvRV(obj));
243                 ret = tracker_metadata_get(client, servicetype, id, _keys, &error);
244                 rh = (HV *) sv_2mortal( (SV *) newHV() );
245                 if(error)
246                         RETVAL = &PL_sv_undef;
247                 else {
248                         for(i = 0; _keys[i] && ret[i]; i++)
249                                 hv_store(rh, _keys[i], strlen(_keys[i]), newSVpv(ret[i], 0), 0);
250                         g_strfreev(ret);        /* don't leak anything */
251                         RETVAL = newRV( (SV *) rh);
252                 }
253         OUTPUT:
254                 RETVAL
258 set_metadata (obj, servicetype, id, data)
259                 SV* obj;
260                 int servicetype;
261                 const char* id;
262                 SV* data;
263         PREINIT:
264                 char** _keys;
265                 char** _values;
266                 char* placeholder;
267                 STRLEN length;
268                 I32 keylen;
269                 GError *error = NULL;
270                 TrackerClient* client;
271         INIT:
272                 I32 numkeys = 0;
273                 int i;
274                 SV* current_val;
275                 HV* datahash;
276                 /* the iter_init prepares the hash iterator and gives us
277                  * the number of keys in the hash
278                  */
279                 if( (!SvROK(data))
280                         || ( SvTYPE( SvRV(data) ) != SVt_PVHV )
281                         || ( (numkeys = hv_iterinit((HV *)SvRV(data))) < 1 ) ) {
282                         XSRETURN_UNDEF;
283                 }
284                 else {
285                         datahash = (HV *) SvRV(data);
286                 }
287                 assert_valid_servicetype(servicetype);
288                 /* convert keys to a char** - this is inspired from the
289                  * avref2charptrptr function from perldap
290                  */
291                 Newxz(_keys, numkeys + 1, char *);
292                 Newxz(_values, numkeys + 1, char *);
293                 for (i = 0; i < numkeys; i++) {
294                         current_val = hv_iternextsv(datahash, &placeholder, &keylen);
295                         /* store the copy of the key in _keys */
296                         Newxz(_keys[i], keylen + 1, char);
297                         Copy(placeholder, _keys[i], keylen + 1, char);
298                         /* store the copy of the value in _values */
299                         placeholder = SvPV(current_val, length);
300                         Newxz(_values[i], length + 1, char);
301                         Copy(placeholder, _values[i], length + 1, char);
302                 }
303                 _keys[i] = NULL;
304                 _values[i] = NULL;
305         CODE:
306                 client = (TrackerClient*) SvIV(SvRV(obj));
307                 tracker_metadata_set(client, servicetype, id, _keys, _values, &error);
308                 ST(0) = sv_newmortal();
309                 if(error)
310                         ST(0) = &PL_sv_undef;
311                 else
312                         sv_setiv( ST(0), numkeys );
315 void
316 register_metadata_type (obj, name, type)
317                 SV* obj;
318                 const char* name;
319                 int type;
320         PREINIT:
321                 GError *error = NULL;
322                 TrackerClient* client;
323         CODE:
324                 assert_valid_mdtype(type);
325                 client = (TrackerClient*) SvIV(SvRV(obj));
326                 tracker_metadata_register_type(client, name, type, &error);
327                 if(error)
328                         croak("tracker_metadata_register_type failed with code %d (%s)", error->code, error->message);
332 get_metadata_type_details (obj, name)
333                 SV* obj;
334                 const char* name;
335         PREINIT:
336                 HV* args;
337                 I32 count;
338                 MetaDataTypeDetails* ret;
339                 GError *error = NULL;
340                 TrackerClient* client;
341         CODE:
342                 client = (TrackerClient*) SvIV(SvRV(obj));
343                 ret = tracker_metadata_get_type_details(client, name, &error);
344                 if(error)
345                         RETVAL = &PL_sv_undef;
346                 else {
347                         ENTER;
348                         SAVETMPS;
349                         /* set up a hashref for args to "new" */
350                         args = (HV *) sv_2mortal( (SV *) newHV() );
351                         hv_store(args, "type", 4, newSVpv(ret->type, 0), 0);
352                         hv_store(args, "is_embedded", 11, newSViv(ret->is_embedded), 0);
353                         hv_store(args, "is_writeable", 12, newSViv(ret->is_writeable), 0);
354                         free(ret);
355                         /* instantiate new MetadataTypeDetails object */
356                         PUSHMARK(SP);
357                         XPUSHs(sv_2mortal(newSVpv("LibTracker::Client::MetaDataTypeDetails", 0)));
358                         XPUSHs(sv_2mortal(newRV((SV*)args)));
359                         PUTBACK;
360                         count = call_method("new", G_SCALAR);
361                         SPAGAIN;
362                         if(count != 1)
363                                 croak("LibTracker::Client::MetaDataTypeDetails->new returned unexpected number of args. Expected 1, got %d", count);
364                         RETVAL = newSVsv((SV *)POPs);
365                         PUTBACK;
366                         FREETMPS;
367                         LEAVE;
368                 }
369         OUTPUT:
370                 RETVAL
374 get_registered_metadata_classes (obj)
375                 SV* obj;
376         PREINIT:
377                 char** ret;
378                 I32 i;
379                 GError *error = NULL;
380                 TrackerClient* client;
381                 AV* ra;
382         CODE:
383                 client = (TrackerClient*) SvIV(SvRV(obj));
384                 ret = tracker_metadata_get_registered_classes(client, &error);
385                 ra = (AV *) sv_2mortal( (SV *) newAV() );
386                 if(error)
387                         RETVAL = &PL_sv_undef;
388                 else {
389                         for(i = 0; ret[i]; i++)
390                                 av_push(ra, newSVpv(ret[i], 0));
391                         RETVAL = newRV( (SV *) ra);
392                         g_strfreev(ret);        /* don't leak */
393                 }
394         OUTPUT:
395                 RETVAL
399 get_registered_metadata_types (obj, classname)
400                 SV* obj;
401                 const char* classname;
402         PREINIT:
403                 char** ret;
404                 I32 i;
405                 GError *error = NULL;
406                 TrackerClient* client;
407                 AV* ra;
408         CODE:
409                 client = (TrackerClient*) SvIV(SvRV(obj));
410                 ret = tracker_metadata_get_registered_types(client, classname, &error);
411                 ra = (AV *) sv_2mortal( (SV *) newAV() );
412                 if(error)
413                         RETVAL = &PL_sv_undef;
414                 else {
415                         for(i = 0; ret[i]; i++)
416                                 av_push(ra, newSVpv(ret[i], 0));
417                         RETVAL = newRV( (SV *) ra);
418                         g_strfreev(ret);        /* don't leak */
419                 }
420         OUTPUT:
421                 RETVAL
425 get_writeable_metadata_types (obj, classname)
426                 SV* obj;
427                 const char* classname;
428         PREINIT:
429                 char** ret;
430                 I32 i;
431                 GError *error = NULL;
432                 TrackerClient* client;
433                 AV* ra;
434         CODE:
435                 client = (TrackerClient*) SvIV(SvRV(obj));
436                 ret = tracker_metadata_get_writeable_types(client, classname, &error);
437                 ra = (AV *) sv_2mortal( (SV *) newAV() );
438                 if(error)
439                         RETVAL = &PL_sv_undef;
440                 else {
441                         for(i = 0; ret[i]; i++)
442                                 av_push(ra, newSVpv(ret[i], 0));
443                         RETVAL = newRV( (SV *) ra);
444                         g_strfreev(ret);        /* don't leak */
445                 }
446         OUTPUT:
447                 RETVAL
451 get_all_keywords (obj, servicetype)
452                 SV* obj;
453                 int servicetype;
454         PREINIT:
455                 GPtrArray* ret;
456                 GError *error = NULL;
457                 TrackerClient* client;
458                 AV* ra;
459         CODE:
460                 assert_valid_servicetype(servicetype);
461                 client = (TrackerClient*) SvIV(SvRV(obj));
462                 ret = tracker_keywords_get_list(client, servicetype, &error);
463                 ra = (AV *) sv_2mortal( (SV *) newAV() );
464                 if(error)
465                         RETVAL = &PL_sv_undef;
466                 else {
467                         g_ptr_array_foreach(ret, store_in_array, (gpointer)ra);
468                         RETVAL = newRV( (SV *) ra);
469                         g_ptr_array_free(ret, TRUE);    /* don't leak */
470                 }
471         OUTPUT:
472                 RETVAL
476 get_keywords (obj, servicetype, id)
477                 SV* obj;
478                 int servicetype;
479                 const char* id;
480         PREINIT:
481                 char** ret;
482                 I32 i;
483                 GError *error = NULL;
484                 TrackerClient* client;
485                 AV* ra;
486         CODE:
487                 assert_valid_servicetype(servicetype);
488                 client = (TrackerClient*) SvIV(SvRV(obj));
489                 ret = tracker_keywords_get(client, servicetype, id, &error);
490                 ra = (AV *) sv_2mortal( (SV *) newAV() );
491                 if(error)
492                         RETVAL = &PL_sv_undef;
493                 else {
494                         for(i = 0; ret[i]; i++)
495                                 av_push(ra, newSVpv(ret[i], 0));
496                         RETVAL = newRV( (SV *) ra);
497                         g_strfreev(ret);        /* don't leak */
498                 }
499         OUTPUT:
500                 RETVAL
504 add_keywords (obj, servicetype, id, values)
505                 SV* obj;
506                 int servicetype;
507                 const char* id;
508                 SV* values;
509         PREINIT:
510                 char** _values;
511                 char* placeholder;
512                 STRLEN length;
513                 GError *error = NULL;
514                 TrackerClient* client;
515         INIT:
516                 I32 num = 0;
517                 I32 i;
518                 SV **current_val;
519                 if( (!SvROK(values))
520                         || ( SvTYPE( SvRV(values) ) != SVt_PVAV )
521                         || ( (num = av_len( (AV *) SvRV(values))) < 0 ) ) {
522                         XSRETURN_UNDEF;
523                 }
524                 assert_valid_servicetype(servicetype);
525                 /* convert keys to a char** - this is inspired from the
526                  * avref2charptrptr function from perldap
527                  */
528                 Newxz(_values, num + 2, char *); /* av_len returns elem-1 */
529                 for (i = 0; i <= num; i++) {
530                         current_val = av_fetch( (AV *) SvRV(values), i, 0 );
531                         placeholder = SvPV(*current_val, length);
532                         /* store a copy in _values */
533                         Newxz(_values[i], length+1, char);
534                         Copy(placeholder, _values[i], length+1, char);
535                 }
536                 _values[i] = NULL;
537         CODE:
538                 client = (TrackerClient*) SvIV(SvRV(obj));
539                 tracker_keywords_add(client, servicetype, id, _values, &error);
540                 ST(0) = sv_newmortal();
541                 if(error)
542                         ST(0) = &PL_sv_undef;
543                 else
544                         sv_setiv( ST(0), num + 1);
548 remove_keywords (obj, servicetype, id, values)
549                 SV* obj;
550                 int servicetype;
551                 const char* id;
552                 SV* values;
553         PREINIT:
554                 char** _values;
555                 char* placeholder;
556                 STRLEN length;
557                 GError *error = NULL;
558                 TrackerClient* client;
559         INIT:
560                 I32 num = 0;
561                 I32 i;
562                 SV **current_val;
563                 if( (!SvROK(values))
564                         || ( SvTYPE( SvRV(values) ) != SVt_PVAV )
565                         || ( (num = av_len( (AV *) SvRV(values))) < 0 ) ) {
566                         XSRETURN_UNDEF;
567                 }
568                 assert_valid_servicetype(servicetype);
569                 /* convert keys to a char** - this is inspired from the
570                  * avref2charptrptr function from perldap
571                  */
572                 Newxz(_values, num + 2, char *); /* av_len returns elem+1 */
573                 for (i = 0; i <= num; i++) {
574                         current_val = av_fetch( (AV *) SvRV(values), i, 0 );
575                         placeholder = SvPV(*current_val, length);
576                         /* store a copy in _values */
577                         Newxz(_values[i], length+1, char);
578                         Copy(placeholder, _values[i], length+1, char);
579                 }
580                 _values[i] = NULL;
581         CODE:
582                 client = (TrackerClient*) SvIV(SvRV(obj));
583                 tracker_keywords_remove(client, servicetype, id, _values, &error);
584                 ST(0) = sv_newmortal();
585                 if(error)
586                         ST(0) = &PL_sv_undef;
587                 else
588                         sv_setiv( ST(0), num + 1);
592 remove_all_keywords (obj, servicetype, id)
593                 SV* obj;
594                 int servicetype;
595                 const char* id;
596         PREINIT:
597                 GError *error = NULL;
598                 TrackerClient* client;
599         CODE:
600                 assert_valid_servicetype(servicetype);
601                 client = (TrackerClient*) SvIV(SvRV(obj));
602                 tracker_keywords_remove_all(client, servicetype, id, &error);
603                 ST(0) = sv_newmortal();
604                 if(error)
605                         ST(0) = &PL_sv_undef;
606                 else
607                         ST(0) = &PL_sv_yes;
611 search_keywords (obj, lqi, servicetype, keywords, offset, maxhits)
612                 SV* obj;
613                 int lqi;
614                 int servicetype;
615                 SV* keywords;
616                 int offset;
617                 int maxhits;
618         PREINIT:
619                 char** ret;
620                 char** _keywords;
621                 char* placeholder;
622                 STRLEN length;
623                 GError *error = NULL;
624                 TrackerClient* client;
625                 AV* ra;
626         INIT:
627                 I32 num = 0;
628                 I32 i;
629                 SV **current_val;
630                 if( (!SvROK(keywords))
631                         || ( SvTYPE( SvRV(keywords) ) != SVt_PVAV )
632                         || ( (num = av_len( (AV *) SvRV(keywords))) < 0 ) ) {
633                         XSRETURN_UNDEF;
634                 }
635                 assert_valid_servicetype(servicetype);
636                 /* convert keywords to a char** - this is inspired from the
637                  * avref2charptrptr function from perldap
638                  */
639                 Newxz(_keywords, num + 2, char *);
640                 for (i = 0; i <= num; i++) {
641                         current_val = av_fetch( (AV *) SvRV(keywords), i, 0 );
642                         placeholder = SvPV(*current_val, length);
643                         /* store a copy in _keywords */
644                         Newxz(_keywords[i], length+1, char);
645                         Copy(placeholder, _keywords[i], length+1, char);
646                 }
647                 _keywords[i] = NULL;
648         CODE:
649                 client = (TrackerClient*) SvIV(SvRV(obj));
650                 ret = tracker_keywords_search(client, lqi, servicetype, _keywords, offset, maxhits, &error);
651                 ra = (AV *) sv_2mortal( (SV *) newAV() );
652                 if(error)
653                         RETVAL = &PL_sv_undef;
654                 else {
655                         for(i = 0; ret[i]; i++)
656                                 av_push(ra, newSVpv(ret[i], 0));
657                         RETVAL = newRV( (SV *) ra);
658                         g_strfreev(ret);        /* don't leak */
659                 }
660         OUTPUT:
661                 RETVAL
665 search_text (obj, lqi, servicetype, searchtext, offset, maxhits)
666                 SV* obj;
667                 int lqi;
668                 int servicetype;
669                 const char* searchtext;
670                 int offset;
671                 int maxhits;
672         PREINIT:
673                 I32 i;
674                 char** ret;
675                 GError *error = NULL;
676                 TrackerClient* client;
677                 AV* ra;
678         CODE:
679                 assert_valid_servicetype(servicetype);
680                 client = (TrackerClient*) SvIV(SvRV(obj));
681                 ret = tracker_search_text(client, lqi, servicetype, searchtext, offset, maxhits, &error);
682                 ra = (AV *) sv_2mortal( (SV *) newAV() );
683                 if(error)
684                         RETVAL = &PL_sv_undef;
685                 else {
686                         for(i = 0; ret[i]; i++)
687                                 av_push(ra, newSVpv(ret[i], 0));
688                         RETVAL = newRV( (SV *) ra);
689                         g_strfreev(ret);        /* don't leak */
690                 }
691         OUTPUT:
692                 RETVAL
696 get_snippet (obj, servicetype, path, searchtext)
697                 SV* obj;
698                 int servicetype;
699                 const char* path;
700                 const char* searchtext;
701         PREINIT:
702                 char* ret;
703                 GError *error = NULL;
704                 TrackerClient* client;
705         CODE:
706                 assert_valid_servicetype(servicetype);
707                 client = (TrackerClient*) SvIV(SvRV(obj));
708                 ST(0) = sv_newmortal();
709                 ret = tracker_search_get_snippet(client, servicetype, path, searchtext, &error);
710                 if(error)
711                         ST(0) = &PL_sv_undef;
712                 else
713                         sv_setpv( ST(0), ret );
714                 free(ret);
718 search_metadata (obj, servicetype, field, searchtext, offset, maxhits)
719                 SV* obj;
720                 int servicetype;
721                 const char* field;
722                 const char* searchtext;
723                 int offset;
724                 int maxhits;
725         PREINIT:
726                 I32 i;
727                 char** ret;
728                 GError *error = NULL;
729                 TrackerClient* client;
730                 AV* ra;
731         CODE:
732                 assert_valid_servicetype(servicetype);
733                 client = (TrackerClient*) SvIV(SvRV(obj));
734                 ret = tracker_search_metadata(client, servicetype, field, searchtext, offset, maxhits, &error);
735                 ra = (AV *) sv_2mortal( (SV *) newAV() );
736                 if(error)
737                         RETVAL = &PL_sv_undef;
738                 else {
739                         for(i = 0; ret[i]; i++)
740                                 av_push(ra, newSVpv(ret[i], 0));
741                         RETVAL = newRV( (SV *) ra);
742                         g_strfreev(ret);        /* don't leak */
743                 }
744         OUTPUT:
745                 RETVAL
749 get_suggestion (obj, searchtext, maxdist)
750                 SV* obj;
751                 const char* searchtext;
752                 int maxdist;
753         PREINIT:
754                 char* ret;
755                 GError *error = NULL;
756                 TrackerClient* client;
757         CODE:
758                 client = (TrackerClient*) SvIV(SvRV(obj));
759                 ST(0) = sv_newmortal();
760                 ret = tracker_search_suggest(client,searchtext, maxdist, &error);
761                 if(error)
762                         ST(0) = &PL_sv_undef;
763                 else
764                         sv_setpv( ST(0), ret );
765                 free(ret);
769 get_files_by_service (obj, lqi, servicetype, offset, maxhits)
770                 SV* obj;
771                 int lqi;
772                 int servicetype;
773                 int offset;
774                 int maxhits;
775         PREINIT:
776                 I32 i;
777                 char** ret;
778                 GError *error = NULL;
779                 TrackerClient* client;
780                 AV* ra;
781         CODE:
782                 assert_valid_servicetype(servicetype);
783                 client = (TrackerClient*) SvIV(SvRV(obj));
784                 ret = tracker_files_get_by_service_type(client, lqi, servicetype, offset, maxhits, &error);
785                 ra = (AV *) sv_2mortal( (SV *) newAV() );
786                 if(error)
787                         RETVAL = &PL_sv_undef;
788                 else {
789                         for(i = 0; ret[i]; i++)
790                                 av_push(ra, newSVpv(ret[i], 0));
791                         RETVAL = newRV( (SV *) ra);
792                         g_strfreev(ret);        /* don't leak */
793                 }
794         OUTPUT:
795                 RETVAL
798 void
799 DESTROY (obj)
800                 SV* obj
801         PREINIT:
802                 I32* temp;
803         PPCODE:
804                 /* this is stolen from Inline::C documentation */
805                 temp = PL_markstack_ptr++;
806                 DESTROY(obj);
807                 if(PL_markstack_ptr != temp) {
808                         /* truly void, because dXSARGS not invoked */
809                         PL_markstack_ptr = temp;
810                         XSRETURN_EMPTY;
811                 }
812                 /* must have used dXSARGS; list context implied */
813                 return; /* assume stack size is correct */