do not pass a non-zero offset to plugins AFTER the first call to connect_and_run...
[ardour.git] / libs / fst / vstwin.c
1 #include <stdio.h>
2 #include <jack/jack.h>
3 #include <jack/thread.h>
4 #include <libgen.h>
5 #include <windows.h>
6 #include <winnt.h>
7 #include <wine/exception.h>
8 #include <pthread.h>
9 #include <signal.h>
10 #include <glib.h>
11
12 #include "fst.h"
13
14 #include <X11/X.h>
15 #include <X11/Xlib.h>
16
17 struct ERect{
18     short top;
19     short left;
20     short bottom;
21     short right;
22 };
23
24 static pthread_mutex_t plugin_mutex;
25 static FST* fst_first = NULL;
26 const char magic[] = "FST Plugin State v002";
27
28 DWORD  gui_thread_id = 0;
29 static int gui_quit = 0;
30
31 #define DELAYED_WINDOW 1
32
33
34 static LRESULT WINAPI 
35 my_window_proc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
36 {
37 #if 0
38         if (msg != WM_TIMER) {
39                 fst_error ("window callback handler, msg = 0x%x win=%p\n", msg, w);
40         }
41 #endif
42
43         switch (msg) {
44         case WM_KEYUP:
45         case WM_KEYDOWN:
46                 break;
47
48         case WM_CLOSE:
49                 /* we don't care about windows closing ... */
50                 return 0;
51                 break;
52
53         case WM_DESTROY:
54         case WM_NCDESTROY:
55                 /* we don't care about windows being destroyed ... */
56                 return 0;
57                 break;
58
59         default:
60                 break;
61         }
62
63         return DefWindowProcA (w, msg, wp, lp );
64 }
65
66 static FST* 
67 fst_new ()
68 {
69         FST* fst = (FST*) calloc (1, sizeof (FST));
70         pthread_mutex_init (&fst->lock, NULL);
71         pthread_cond_init (&fst->window_status_change, NULL);
72         pthread_cond_init (&fst->plugin_dispatcher_called, NULL);
73         fst->want_program = -1;
74         return fst;
75 }
76
77 static FSTHandle* 
78 fst_handle_new ()
79 {
80         FSTHandle* fst = (FSTHandle*) calloc (1, sizeof (FSTHandle));
81         return fst;
82 }
83
84 DWORD WINAPI gui_event_loop (LPVOID param)
85 {
86         MSG msg;
87         FST* fst;
88         HMODULE hInst;
89         HWND window;
90
91         gui_thread_id = GetCurrentThreadId ();
92
93         /* create a dummy window for timer events */
94
95         if ((hInst = GetModuleHandleA (NULL)) == NULL) {
96                 fst_error ("can't get module handle");
97                 return 1;
98         }
99         
100         if ((window = CreateWindowExA (0, "FST", "dummy",
101                                        WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
102                                        9999, 9999,
103                                        1, 1,
104                                        NULL, NULL,
105                                        hInst,
106                                        NULL )) == NULL) {
107                 fst_error ("cannot create dummy timer window");
108         }
109
110         if (!SetTimer (window, 1000, 20, NULL)) {
111                 fst_error ("cannot set timer on dummy window");
112         }
113
114         while (!gui_quit) {
115
116                 if (!GetMessageA (&msg, NULL, 0,0)) {
117                         if (!gui_quit) {
118                                 fprintf (stderr, "QUIT message received by Windows GUI thread - ignored\n");
119                                 continue;
120                         } else {
121                                 break;
122                         }
123                 }
124
125                 TranslateMessage( &msg );
126                 DispatchMessageA (&msg);
127
128                 /* handle window creation requests, destroy requests, 
129                    and run idle callbacks 
130                 */
131
132                 if (msg.message == WM_TIMER) {
133                         pthread_mutex_lock (&plugin_mutex);
134                     
135 again:
136                         for (fst = fst_first; fst; fst = fst->next) {
137                                 
138                                 pthread_mutex_lock (&fst->lock);
139
140                                 if (fst->destroy) {
141                                         fprintf (stderr, "%s scheduled for destroy\n", fst->handle->name);
142                                         if (fst->window) {
143                                                 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
144                                                 CloseWindow (fst->window);
145                                                 fst->window = NULL;
146                                                 fst->destroy = FALSE;
147                                         }
148                                         fst_event_loop_remove_plugin (fst);
149                                         fst->been_activated = FALSE;
150                                         pthread_cond_signal (&fst->window_status_change);
151                                         pthread_mutex_unlock (&fst->lock);
152                                         goto again;
153                                 } 
154                                 
155                                 if (fst->window == NULL) {
156                                         if (fst_create_editor (fst)) {
157                                                 fst_error ("cannot create editor for plugin %s", fst->handle->name);
158                                                 fst_event_loop_remove_plugin (fst);
159                                                 pthread_cond_signal (&fst->window_status_change);
160                                                 pthread_mutex_unlock (&fst->lock);
161                                                 goto again;
162                                         } else {
163                                                 /* condition/unlock: it was signalled & unlocked in fst_create_editor()   */
164                                         }
165                                 }
166
167                                 if (fst->want_program != -1 ) {
168                                         fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
169                                         fst->want_program = -1; 
170                                 }
171                                 
172                                 if(fst->dispatcher_wantcall) {
173                                         fst->dispatcher_retval = fst->plugin->dispatcher( fst->plugin, 
174                                                                                           fst->dispatcher_opcode,
175                                                                                           fst->dispatcher_index,
176                                                                                           fst->dispatcher_val,
177                                                                                           fst->dispatcher_ptr,
178                                                                                           fst->dispatcher_opt );
179                                         fst->dispatcher_wantcall = 0;
180                                         pthread_cond_signal (&fst->plugin_dispatcher_called);
181                                 }
182                                 
183                                 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
184
185                                 if( fst->wantIdle ) {
186                                         fst->plugin->dispatcher (fst->plugin, 53, 0, 0, NULL, 0);
187                                 }
188
189                                 pthread_mutex_unlock (&fst->lock);
190                         }
191                         pthread_mutex_unlock (&plugin_mutex);
192                         
193                 }
194         }
195
196         return 0;
197 }
198
199 int
200 fst_init (void* possible_hmodule)
201 {
202         WNDCLASSEX wclass;
203         HMODULE hInst;
204         
205         if (possible_hmodule) {
206                 hInst = (HMODULE) possible_hmodule;
207         } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
208                 fst_error ("can't get module handle");
209                 return -1;
210         }
211
212         wclass.cbSize = sizeof(WNDCLASSEX);
213         wclass.style = 0;
214         wclass.lpfnWndProc = my_window_proc;
215         wclass.cbClsExtra = 0;
216         wclass.cbWndExtra = 0;
217         wclass.hInstance = hInst;
218         wclass.hIcon = LoadIcon(hInst, "FST");
219         wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
220 //    wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
221         wclass.lpszMenuName = "MENU_FST";
222         wclass.lpszClassName = "FST";
223         wclass.hIconSm = 0;
224
225
226         if (!RegisterClassExA(&wclass)){
227                 printf( "Class register failed :(\n" );
228                 return -1;
229         }
230
231         fst_error ("Startup win32 GUI thread\n");
232
233         if (CreateThread (NULL, 0, gui_event_loop, NULL, 0, NULL) == NULL) {
234                 fst_error ("could not create new thread proxy");
235                 return -1;
236         }
237
238 #ifdef HAVE_JACK_SET_THREAD_CREATOR
239         jack_set_thread_creator (wine_pthread_create);
240 #endif
241
242         return 0;
243 }
244
245 void
246 fst_exit ()
247 {
248         gui_quit = 1;
249         PostQuitMessage (0);
250 }
251
252 int
253 fst_run_editor (FST* fst)
254 {
255         pthread_mutex_lock (&plugin_mutex);
256
257         if (fst_first == NULL) {
258                 fst_first = fst;
259         } else {
260                 FST* p = fst_first;
261                 while (p->next) {
262                         p = p->next;
263                 }
264                 p->next = fst;
265         }
266
267         pthread_mutex_unlock (&plugin_mutex);
268
269         /* wait for the plugin editor window to be created (or not) */
270
271         pthread_mutex_lock (&fst->lock);
272         if (!fst->window) {
273                 pthread_cond_wait (&fst->window_status_change, &fst->lock);
274         } 
275         pthread_mutex_unlock (&fst->lock);
276
277         if (!fst->window) {
278                 return -1;
279         }
280
281         return 0;
282 }
283
284 int
285 fst_call_dispatcher (FST *fst, int opcode, int index, int val, void *ptr, float opt) 
286 {
287         pthread_mutex_lock (&fst->lock);
288         fst->dispatcher_opcode = opcode;
289         fst->dispatcher_index = index;
290         fst->dispatcher_val = val;
291         fst->dispatcher_ptr = ptr;
292         fst->dispatcher_opt = opt;
293         fst->dispatcher_wantcall = 1;
294
295         pthread_cond_wait (&fst->plugin_dispatcher_called, &fst->lock);
296         pthread_mutex_unlock (&fst->lock);
297
298         return fst->dispatcher_retval;
299 }
300
301 int
302 fst_create_editor (FST* fst)
303 {
304         HMODULE hInst;
305         HWND window;
306         struct ERect* er;
307
308         /* "guard point" to trap errors that occur during plugin loading */
309
310         /* Note: fst->lock is held while this function is called */
311
312         if (!(fst->plugin->flags & effFlagsHasEditor)) {
313                 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
314                 return -1;
315         }
316
317         if ((hInst = GetModuleHandleA (NULL)) == NULL) {
318                 fst_error ("can't get module handle");
319                 return 1;
320         }
321         
322 //      if ((window = CreateWindowExA (WS_EX_TOOLWINDOW | WS_EX_TRAYWINDOW, "FST", fst->handle->name,
323         if ((window = CreateWindowExA (0, "FST", fst->handle->name,
324                                        (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
325 //                                     (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
326                                        9999,9999,1,1,
327 //                                     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
328                                        NULL, NULL,
329                                        hInst,
330                                        NULL)) == NULL) {
331                 fst_error ("cannot create editor window");
332                 return 1;
333         }
334
335         if (!SetPropA (window, "fst_ptr", fst)) {
336                 fst_error ("cannot set fst_ptr on window");
337         }
338
339         fst->window = window;
340 //      fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
341
342
343         //printf( "effEditOpen......\n" );
344         fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->window, 0 );
345         fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
346
347         fst->width =  er->right-er->left;
348         fst->height =  er->bottom-er->top;
349         //printf( "get rect ses... %d,%d\n", fst->width, fst->height );
350
351         //SetWindowPos (fst->window, 0, 9999, 9999, er->right-er->left+8, er->bottom-er->top+26, 0);
352         SetWindowPos (fst->window, 0, 9999, 9999, 2, 2, 0);
353         ShowWindow (fst->window, SW_SHOWNA);
354         //SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_NOMOVE|SWP_NOZORDER);
355         
356         fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
357         fst->been_activated = TRUE;
358         pthread_cond_signal (&fst->window_status_change);
359         pthread_mutex_unlock (&fst->lock);
360
361         return 0;
362 }
363
364 void
365 fst_move_window_into_view (FST* fst)
366 {
367         if (fst->window) {
368                 SetWindowPos (fst->window, 0, 0, 0, fst->width, fst->height+24, 0);
369                 ShowWindow (fst->window, SW_SHOWNA);
370         }
371 }
372
373 void
374 fst_destroy_editor (FST* fst)
375 {
376         pthread_mutex_lock (&fst->lock);
377         if (fst->window) {
378                 fprintf (stderr, "mark %s for destroy\n", fst->handle->name);
379                 fst->destroy = TRUE;
380                 //if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
381                 //if (!PostThreadMessageA (gui_thread_id, WM_QUIT, 0, 0)) {
382                 //      fst_error ("could not post message to gui thread");
383                 //}
384                 pthread_cond_wait (&fst->window_status_change, &fst->lock);
385                 fprintf (stderr, "%s editor destroyed\n", fst->handle->name);
386
387         }
388         pthread_mutex_unlock (&fst->lock);
389 }
390
391 void
392 fst_event_loop_remove_plugin (FST* fst)
393 {
394         FST* p;
395         FST* prev;
396
397         for (p = fst_first, prev = NULL; p->next; prev = p, p = p->next) {
398                 if (p == fst) {
399                         if (prev) {
400                                 prev->next = p->next;
401                         }
402                 }
403         }
404
405         if (fst_first == fst) {
406                 fst_first = fst_first->next;
407         }
408
409 }
410
411 HMODULE
412 fst_load_vst_library(const char * path)
413 {
414         HMODULE dll;
415         char * full_path;
416         char * envdup;
417         char * vst_path;
418         size_t len1;
419         size_t len2;
420
421         if ((dll = LoadLibraryA (path)) != NULL) {
422                 return dll;
423         }
424
425         envdup = getenv ("VST_PATH");
426         if (envdup == NULL) {
427                 return NULL;
428         }
429
430         envdup = strdup (envdup);
431         if (envdup == NULL) {
432                 fst_error ("strdup failed");
433                 return NULL;
434         }
435
436         len2 = strlen(path);
437
438         vst_path = strtok (envdup, ":");
439         while (vst_path != NULL) {
440                 fst_error ("\"%s\"", vst_path);
441                 len1 = strlen(vst_path);
442                 full_path = malloc (len1 + 1 + len2 + 1);
443                 memcpy(full_path, vst_path, len1);
444                 full_path[len1] = '/';
445                 memcpy(full_path + len1 + 1, path, len2);
446                 full_path[len1 + 1 + len2] = '\0';
447
448                 if ((dll = LoadLibraryA (full_path)) != NULL) {
449                         break;
450                 }
451
452                 vst_path = strtok (NULL, ":");
453         }
454
455         free(envdup);
456
457         return dll;
458 }
459
460 FSTHandle*
461 fst_load (const char *path)
462 {
463         char* buf;
464         FSTHandle* fhandle;
465         char* period;
466
467         fhandle = fst_handle_new ();
468         
469         // XXX: Would be nice to find the correct call for this.
470         //      if the user does not configure Z: to be / we are doomed :(
471
472         if (strstr (path, ".dll") == NULL) {
473
474                 buf = (char *) malloc (strlen (path) + 7);
475
476                 if( path[0] == '/' ) {
477                     sprintf (buf, "Z:%s.dll", path);
478                 } else {
479                     sprintf (buf, "%s.dll", path);
480                 }
481
482                 fhandle->nameptr = strdup (path);
483
484         } else {
485
486                 buf = (char *) malloc (strlen (path) + 3);
487
488                 if( path[0] == '/' ) {
489                     sprintf (buf, "Z:%s", path);
490                 } else {
491                     sprintf (buf, "%s", path);
492                 }
493
494                 fhandle->nameptr = strdup (path);
495         }
496         
497         fhandle->name = basename (fhandle->nameptr);
498
499         /* strip off .dll */
500
501         if ((period = strrchr (fhandle->name, '.')) != NULL) {
502                 *period = '\0';
503         }
504
505         if ((fhandle->dll = fst_load_vst_library (buf)) == NULL) {
506                 fst_unload (fhandle);
507                 return NULL;
508         }
509
510         if ((fhandle->main_entry = (main_entry_t) GetProcAddress (fhandle->dll, "main")) == NULL) {
511                 fst_unload (fhandle);
512                 return NULL;
513         }
514
515         return fhandle;
516 }
517
518 int
519 fst_unload (FSTHandle* fhandle)
520 {
521         if (fhandle->plugincnt) {
522                 return -1;
523         }
524
525         if (fhandle->dll) {
526                 FreeLibrary (fhandle->dll);
527                 fhandle->dll = NULL;
528         }
529
530         if (fhandle->nameptr) {
531                 free (fhandle->nameptr);
532                 fhandle->name = NULL;
533         }
534         
535         free (fhandle);
536         return 0;
537 }
538
539 FST*
540 fst_instantiate (FSTHandle* fhandle, audioMasterCallback amc, void* userptr)
541 {
542         FST* fst = fst_new ();
543
544         if( fhandle == NULL ) {
545             fst_error( "the handle was NULL\n" );
546             return NULL;
547         }
548
549         if ((fst->plugin = fhandle->main_entry (amc)) == NULL)  {
550                 fst_error ("%s could not be instantiated\n", fhandle->name);
551                 free (fst);
552                 return NULL;
553         }
554         
555         fst->handle = fhandle;
556         fst->plugin->user = userptr;
557                 
558         if (fst->plugin->magic != kEffectMagic) {
559                 fst_error ("%s is not a VST plugin\n", fhandle->name);
560                 free (fst);
561                 return NULL;
562         }
563         
564         fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
565         //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
566
567         fst->handle->plugincnt++;
568         fst->wantIdle = 0;
569
570         return fst;
571 }
572
573 void
574 fst_close (FST* fst)
575 {
576         fst_destroy_editor (fst);
577
578         fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
579         fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
580
581         if (fst->handle->plugincnt) {
582                 --fst->handle->plugincnt;
583         }
584 }
585
586 int
587 fst_get_XID (FST* fst)
588 {
589         return fst->xid;
590 }
591
592 float htonf (float v)
593 {
594       float result;
595       char * fin = (char*)&v;
596       char * fout = (char*)&result;
597       fout[0] = fin[3];
598       fout[1] = fin[2];
599       fout[2] = fin[1];
600       fout[3] = fin[0];
601       return result;
602 }
603
604 #if 0
605 int fst_load_state (FST * fst, char * filename)
606 {
607         FILE * f = fopen (filename, "rb");
608         if (f) {
609                 char testMagic[sizeof (magic)];
610                 fread (&testMagic, sizeof (magic), 1, f);
611                 if (strcmp (testMagic, magic)) {
612                         printf ("File corrupt\n");
613                         return FALSE;
614                 }
615
616                 char productString[64];
617                 char vendorString[64];
618                 char effectName[64];
619                 char testString[64];
620                 unsigned length;
621                 int success;
622
623                 fread (&length, sizeof (unsigned), 1, f);
624                 length = htonl (length);
625                 fread (productString, length, 1, f);
626                 productString[length] = 0;
627                 printf ("Product string: %s\n", productString);
628
629                 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, testString, 0 );
630                 if (success == 1) {
631                         if (strcmp (testString, productString) != 0) {
632                                 printf ("Product string mismatch! Plugin has: %s\n", testString);
633                                 fclose (f);
634                                 return FALSE;
635                         }
636                 } else if (length != 0) {
637                         printf ("Product string mismatch! Plugin has none.\n", testString);
638                         fclose (f);
639                         return FALSE;
640                 }
641
642                 fread (&length, sizeof (unsigned), 1, f);
643                 length = htonl (length);
644                 fread (effectName, length, 1, f);
645                 effectName[length] = 0;
646                 printf ("Effect name: %s\n", effectName);
647
648                 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, testString, 0 );
649                 if (success == 1) {
650                         if (strcmp (testString, effectName) != 0) {
651                                 printf ("Effect name mismatch! Plugin has: %s\n", testString);
652                                 fclose (f);
653                                 return FALSE;
654                         }
655                 } else if (length != 0) {
656                         printf ("Effect name mismatch! Plugin has none.\n", testString);
657                         fclose (f);
658                         return FALSE;
659                 }
660
661                 fread (&length, sizeof (unsigned), 1, f);
662                 length = htonl (length);
663                 fread (vendorString, length, 1, f);
664                 vendorString[length] = 0;
665                 printf ("Vendor string: %s\n", vendorString);
666
667                 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, testString, 0 );
668                 if (success == 1) {
669                         if (strcmp (testString, vendorString) != 0) {
670                                 printf ("Vendor string mismatch! Plugin has: %s\n", testString);
671                                 fclose (f);
672                                 return FALSE;
673                         }
674                 } else if (length != 0) {
675                         printf ("Vendor string mismatch! Plugin has none.\n", testString);
676                         fclose (f);
677                         return FALSE;
678                 }
679
680                 int numParam;
681                 unsigned i;
682                 fread (&numParam, sizeof (int), 1, f);
683                 numParam = htonl (numParam);
684                 for (i = 0; i < numParam; ++i) {
685                         float val;
686                         fread (&val, sizeof (float), 1, f);
687                         val = htonf (val);
688
689                         pthread_mutex_lock( &fst->lock );
690                         fst->plugin->setParameter( fst->plugin, i, val );
691                         pthread_mutex_unlock( &fst->lock );
692                 }
693
694                 int bytelen;
695                 fread (&bytelen, sizeof (int), 1, f);
696                 bytelen = htonl (bytelen);
697                 if (bytelen) {
698                         char * buf = malloc (bytelen);
699                         fread (buf, bytelen, 1, f);
700
701                         fst_call_dispatcher( fst, 24, 0, bytelen, buf, 0 );
702                         free (buf);
703                 }
704         } else {
705                 printf ("Could not open state file\n");
706                 return FALSE;
707         }
708         return TRUE;
709
710 }
711 #endif
712
713 int fst_save_state (FST * fst, char * filename)
714 {
715         FILE * f = fopen (filename, "wb");
716         if (f) {
717                 int bytelen;
718                 int numParams = fst->plugin->numParams;
719                 unsigned i;
720                 char productString[64];
721                 char effectName[64];
722                 char vendorString[64];
723                 int success;
724
725                 // write header
726                 fprintf( f, "<plugin_state>\n" );
727
728                 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, productString, 0 );
729                 if( success == 1 ) {
730                         fprintf (f, "  <check field=\"productString\" value=\"%s\"/>\n", productString);
731                 } else {
732                         printf ("No product string\n");
733                 }
734
735                 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, effectName, 0 );
736                 if( success == 1 ) {
737                         fprintf (f, "  <check field=\"effectName\" value=\"%s\"/>\n", effectName);
738                         printf ("Effect name: %s\n", effectName);
739                 } else {
740                         printf ("No effect name\n");
741                 }
742
743                 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, vendorString, 0 );
744                 if( success == 1 ) {
745                         fprintf (f, "  <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
746                         printf ("Vendor string: %s\n", vendorString);
747                 } else {
748                         printf ("No vendor string\n");
749                 }
750
751
752                 if( fst->plugin->flags & 32 ) {
753                         numParams = 0;
754                 }
755
756                 for( i=0; i<numParams; i++ ) {
757                         float val;
758                         
759                         pthread_mutex_lock( &fst->lock );
760                         val = fst->plugin->getParameter( fst->plugin, i );
761                         pthread_mutex_unlock( &fst->lock );
762                         fprintf( f, "  <param index=\"%d\" value=\"%f\"/>\n", i, val );
763                 }
764
765                 if( fst->plugin->flags & 32 ) {
766                         printf( "getting chunk...\n" );
767                         void * chunk;
768                         bytelen = fst_call_dispatcher( fst, 23, 0, 0, &chunk, 0 );
769                         printf( "got tha chunk..\n" );
770                         if( bytelen ) {
771                                 if( bytelen < 0 ) {
772                                         printf( "Chunke len < 0 !!! Not saving chunk.\n" );
773                                 } else {
774                                         char *encoded = g_base64_encode( chunk, bytelen );
775                                         fprintf( f, "  <chunk size=\"%d\">\n    %s\n  </chunk>\n", bytelen, encoded );
776                                         g_free( encoded );
777                                 }
778                         }
779                 } 
780
781                 fprintf( f, "</plugin_state>\n" );
782                 fclose( f );
783         } else {
784                 printf ("Could not open state file\n");
785                 return FALSE;
786         }
787         return TRUE;
788 }
789