d7c5f78f65a66cf07bbdcadb9c97312f7b47fc69
[gnokii.git] / xgnokii / xgnokii_contacts.c
1 /*
2
3   X G N O K I I
4
5   A Linux/Unix GUI for Nokia mobile phones.
6
7   Released under the terms of the GNU GPL, see file COPYING for more details.
8
9   $Id$
10   
11 */
12
13
14 #include "misc.h"
15
16 #include <stdio.h>
17 #include <pthread.h>
18
19 #ifndef WIN32
20 # include <unistd.h>
21 #else
22 # include <windows.h>
23 # define sleep(x) Sleep((x) * 1000)
24 # define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
25 # define index strchr
26 #endif
27
28 #include <stdlib.h>
29 #include <string.h>
30 #if __unices__
31 # include <strings.h>
32 #endif
33 #include <gtk/gtk.h>
34
35 #include "gsm-api.h"
36 #include "gsm-common.h"
37 #include "xgnokii_contacts.h"
38 #include "xgnokii_lowlevel.h"
39 #include "xgnokii.h"
40 #include "xgnokii_common.h"
41 #include "xgnokii_lowlevel.h"
42 #include "xgnokii_sms.h"
43 #include "xpm/Read.xpm"
44 #include "xpm/Send.xpm"
45 #include "xpm/Open.xpm"
46 #include "xpm/Save.xpm"
47 #include "xpm/New.xpm"
48 #include "xpm/Duplicate.xpm"
49 #include "xpm/Edit.xpm"
50 #include "xpm/Delete.xpm"
51 #include "xpm/Dial.xpm"
52 #include "xpm/sim.xpm"
53 #include "xpm/phone.xpm"
54 #include "xpm/quest.xpm"
55
56
57 typedef struct {
58   GtkWidget *dialog;
59   GtkWidget *entry;
60 } DialVoiceDialog;
61
62 typedef struct {
63   GtkWidget *dialog;
64   GtkWidget *entry;
65   gint row;
66   GtkWidget *gbutton;
67   GtkWidget *mbutton;
68   GtkWidget *wbutton;
69   GtkWidget *fbutton;
70   GtkWidget *hbutton;
71   PhonebookEntry *pbEntry;
72 } ExtPbkDialog;
73
74 static GtkWidget *GUI_ContactsWindow;
75 static bool fbus3810;
76 static bool contactsMemoryInitialized;
77 static MemoryStatus memoryStatus;
78 static ContactsMemory contactsMemory;   /* Hold contacts. */
79 static GtkWidget *clist;
80 static StatusInfo statusInfo;
81 static ProgressDialog progressDialog = {NULL, NULL, NULL};
82 static ErrorDialog errorDialog = {NULL, NULL};
83 static FindEntryStruct findEntryStruct = { "", 0};
84 static ExportDialogData exportDialogData = {NULL};
85 static MemoryPixmaps memoryPixmaps;
86 static QuestMark questMark;
87 static EditEntryData newEditEntryData = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
88 static EditEntryData editEditEntryData = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
89 static EditEntryData duplicateEditEntryData = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
90 static EditNumbersData editNumbersData = {NULL, NULL};
91
92 /* return != 0 if user has unsaved changes in contacts memory */
93 inline gint GUI_ContactsIsChanged (void)
94 {
95   return statusInfo.ch_ME | statusInfo.ch_SM;
96 }
97
98
99 /* return TRUE if Contacts memory was read from phone or from file */
100 inline bool GUI_ContactsIsIntialized (void)
101 {
102   return contactsMemoryInitialized;
103 }
104
105
106 static inline void Help1 (GtkWidget *w, gpointer data)
107 {
108   gchar *indx = g_strdup_printf ("/help/%s/windows/contacts/index.html", xgnokiiConfig.locale);
109   Help (w, indx);
110   g_free (indx);
111 }
112
113
114 void RefreshStatusInfo (void)
115 {
116   char p,s;
117   
118   if (statusInfo.ch_ME)
119     p = '*';
120   else
121     p = ' ';
122   
123   if (statusInfo.ch_SM)
124     s = '*';
125   else
126     s = ' ';
127   g_snprintf(statusInfo.text, STATUS_INFO_LENGTH, "SIM: %d/%d%c  Phone: %d/%d%c",
128               memoryStatus.UsedSM, memoryStatus.MaxSM, s,
129               memoryStatus.UsedME, memoryStatus.MaxME, p);
130   gtk_label_set_text(GTK_LABEL (statusInfo.label), statusInfo.text);
131 }
132
133
134 static inline void SetGroup0 (GtkWidget *item, gpointer data)
135 {
136   ((EditEntryData *) data)->newGroup = 0;
137 }
138
139
140 static inline void SetGroup1 (GtkWidget *item, gpointer data)
141 {
142   ((EditEntryData *) data)->newGroup = 1;
143 }
144
145
146 static inline void SetGroup2 (GtkWidget *item, gpointer data)
147 {
148   ((EditEntryData *) data)->newGroup = 2;
149 }
150
151
152 static inline void SetGroup3 (GtkWidget *item, gpointer data)
153 {
154   ((EditEntryData *) data)->newGroup = 3;
155 }
156
157
158 static inline void SetGroup4 (GtkWidget *item, gpointer data)
159 {
160   ((EditEntryData *) data)->newGroup = 4;
161 }
162
163
164 static inline void SetGroup5 (GtkWidget *item, gpointer data)
165 {
166   ((EditEntryData *) data)->newGroup = 5;
167 }
168
169
170 PhonebookEntry *FindFreeEntry (GSM_MemoryType type)
171 {
172   PhonebookEntry *entry;
173   gint start, end;
174   register gint i;
175
176   if (type == GMT_ME)
177   {
178     if (memoryStatus.FreeME == 0)
179       return NULL;
180     start = 0;
181     end = memoryStatus.MaxME;
182   }
183   else
184   {
185     if (memoryStatus.FreeSM == 0)
186       return NULL;
187     start = memoryStatus.MaxME;
188     end = memoryStatus.MaxME + memoryStatus.MaxSM;
189   }
190
191   for(i = start; i < end; i++)
192   {
193     entry = g_ptr_array_index(contactsMemory, i);
194     if (entry->status == E_Empty || entry->status == E_Deleted)
195       return entry;
196   }
197
198   return NULL;
199 }
200
201
202 inline PhonebookEntry *GUI_GetEntry (GSM_MemoryType type, gint nr)
203 {
204   if ((type == GMT_ME && (nr < 1 || nr >= memoryStatus.MaxME)) ||
205       (type == GMT_SM && (nr < 1 || nr >= memoryStatus.MaxSM)))
206     return NULL;
207
208   if (type == GMT_ME)
209     return g_ptr_array_index (contactsMemory, nr - 1);
210   else
211     return g_ptr_array_index (contactsMemory, nr + memoryStatus.MaxME - 1);
212 }
213
214
215 static void CloseContacts (GtkWidget *w, gpointer data)
216 {
217   gtk_widget_hide (GUI_ContactsWindow);
218 }
219
220
221 /* I don't want to allow window to close */
222 static void ProgressDialogDeleteEvent (GtkWidget *w, gpointer data)
223 {
224   return;
225 }
226
227
228 static void CancelEditDialog (GtkWidget *widget, gpointer data )
229 {
230   gtk_widget_hide(GTK_WIDGET(((EditEntryData*) data)->dialog));
231 }
232
233
234
235 static void OkEditEntryDialog (GtkWidget *widget, gpointer data)
236 {
237   gchar *clist_row[4];
238   PhonebookEntry *entry;
239
240   if (GTK_TOGGLE_BUTTON(((EditEntryData*) data)->memoryTypePhone)->active &&
241       ((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_SM)
242   {
243     if ((entry = FindFreeEntry(GMT_ME)) == NULL)
244     {
245       gtk_label_set_text(GTK_LABEL(errorDialog.text), _("Can't change memory type!"));  
246       gtk_widget_show (errorDialog.dialog);
247       return;
248     }
249     strncpy(entry->entry.Name, 
250             gtk_entry_get_text(GTK_ENTRY (((EditEntryData*) data)->name)),
251             max_phonebook_name_length);
252     entry->entry.Name[max_phonebook_name_length] = '\0';
253
254     if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
255     {
256     }
257     else
258     {
259       strncpy(entry->entry.Number,
260               gtk_entry_get_text (GTK_ENTRY(((EditEntryData*) data)->number)),
261               max_phonebook_number_length);
262       entry->entry.Name[max_phonebook_number_length] = '\0';
263     }
264
265     entry->entry.Group = ((EditEntryData*) data)->newGroup;
266
267     entry->status = E_Changed;
268
269     ((EditEntryData*) data)->pbEntry->status = E_Deleted;
270
271     memoryStatus.UsedME++;
272     memoryStatus.FreeME--;
273     memoryStatus.UsedSM--;
274     memoryStatus.FreeSM++;
275     statusInfo.ch_ME = statusInfo.ch_SM = 1;
276
277     ((EditEntryData*) data)->pbEntry = entry;
278   }
279   else if (GTK_TOGGLE_BUTTON(((EditEntryData*) data)->memoryTypeSIM)->active &&
280       ((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_ME)
281   {
282     if ((entry = FindFreeEntry(GMT_SM)) == NULL)
283     {
284       gtk_label_set_text(GTK_LABEL (errorDialog.text), _("Can't change memory type!"));
285       gtk_widget_show (errorDialog.dialog);
286       return;
287     }
288     strncpy(entry->entry.Name, 
289             gtk_entry_get_text(GTK_ENTRY (((EditEntryData*) data)->name)),
290             max_phonebook_sim_name_length);
291     entry->entry.Name[max_phonebook_sim_name_length] = '\0';
292
293     if (strlen(gtk_entry_get_text(GTK_ENTRY (((EditEntryData*) data)->name))) > max_phonebook_sim_name_length)
294     {
295       gtk_label_set_text( GTK_LABEL (errorDialog.text), _("Sorry, phonebook name will be truncated,\n\
296 because you save it into SIM memory!"));
297       gtk_widget_show (errorDialog.dialog);
298     }
299
300     if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
301     {
302     }
303     else
304     {
305       strncpy(entry->entry.Number,
306               gtk_entry_get_text (GTK_ENTRY(((EditEntryData*) data)->number)),
307               max_phonebook_sim_number_length);
308       entry->entry.Name[max_phonebook_sim_number_length] = '\0';
309     }
310
311     entry->entry.Group = ((EditEntryData*) data)->newGroup;
312
313     entry->status = E_Changed;    
314
315     ((EditEntryData*) data)->pbEntry->status = E_Deleted;
316
317     memoryStatus.UsedME--;
318     memoryStatus.FreeME++;
319     memoryStatus.UsedSM++;
320     memoryStatus.FreeSM--;
321     statusInfo.ch_ME = statusInfo.ch_SM = 1;    
322
323     ((EditEntryData*) data)->pbEntry = entry;
324   }
325   else
326   {
327     if (GTK_TOGGLE_BUTTON(((EditEntryData*) data)->memoryTypePhone)->active)
328     {
329       strncpy(((EditEntryData*) data)->pbEntry->entry.Name, 
330               gtk_entry_get_text(GTK_ENTRY (((EditEntryData*) data)->name)),
331               max_phonebook_name_length);
332       ((EditEntryData*) data)->pbEntry->entry.Name[max_phonebook_name_length] = '\0';
333
334       if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
335       {
336       }
337       else
338       {
339         strncpy(((EditEntryData*) data)->pbEntry->entry.Number,
340                 gtk_entry_get_text (GTK_ENTRY(((EditEntryData*) data)->number)),
341                 max_phonebook_number_length);
342         ((EditEntryData*) data)->pbEntry->entry.Name[max_phonebook_number_length] = '\0';
343       }
344     }
345     else
346     {
347       strncpy(((EditEntryData*) data)->pbEntry->entry.Name, 
348               gtk_entry_get_text(GTK_ENTRY (((EditEntryData*) data)->name)),
349               max_phonebook_sim_name_length);
350       ((EditEntryData*) data)->pbEntry->entry.Name[max_phonebook_sim_name_length] = '\0';
351
352       if (strlen(gtk_entry_get_text(GTK_ENTRY (((EditEntryData*) data)->name))) > max_phonebook_sim_name_length)
353       {
354         gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Sorry, phonebook name will be truncated,\n\
355 because you save it into SIM memory!"));
356         gtk_widget_show (errorDialog.dialog);
357       }
358
359       if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
360       {
361       }
362       else
363       {
364         strncpy(((EditEntryData*) data)->pbEntry->entry.Number,
365                 gtk_entry_get_text (GTK_ENTRY(((EditEntryData*) data)->number)),
366                 max_phonebook_sim_number_length);
367         ((EditEntryData*) data)->pbEntry->entry.Name[max_phonebook_sim_number_length] = '\0';
368       }
369     }
370
371     ((EditEntryData*) data)->pbEntry->entry.Group = ((EditEntryData*) data)->newGroup;
372
373     ((EditEntryData*) data)->pbEntry->status = E_Changed;
374
375     if (((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_ME)
376       statusInfo.ch_ME = 1;
377     else
378       statusInfo.ch_SM = 1;
379   }
380
381   gtk_widget_hide (GTK_WIDGET(((EditEntryData*) data)->dialog));
382
383   RefreshStatusInfo ();
384
385   gtk_clist_freeze (GTK_CLIST (clist));
386   gtk_clist_remove (GTK_CLIST (clist), ((EditEntryData*) data)->row);
387
388   clist_row[0] = ((EditEntryData*) data)->pbEntry->entry.Name;
389
390   clist_row[1] = ((EditEntryData*) data)->pbEntry->entry.Number;
391   
392   if( ((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_ME)
393     clist_row[2] = "P";
394   else
395     clist_row[2] = "S";
396   if (GetModelFeature(FN_CALLERGROUPS)!=0)
397     clist_row[3] = xgnokiiConfig.callerGroups[((EditEntryData*) data)->pbEntry->entry.Group];
398   else
399     clist_row[3] = "";
400   gtk_clist_insert(GTK_CLIST (clist), ((EditEntryData*) data)->row, clist_row);
401   if (((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_ME)
402     gtk_clist_set_pixmap( GTK_CLIST (clist), ((EditEntryData*) data)->row, 2,
403                           memoryPixmaps.phoneMemPix, memoryPixmaps.mask);
404   else
405     gtk_clist_set_pixmap( GTK_CLIST (clist), ((EditEntryData*) data)->row, 2,
406                           memoryPixmaps.simMemPix, memoryPixmaps.mask);
407
408   gtk_clist_set_row_data(GTK_CLIST (clist), ((EditEntryData*) data)->row, (gpointer) ((EditEntryData*) data)->pbEntry);
409
410   gtk_clist_sort(GTK_CLIST (clist));
411   gtk_clist_thaw(GTK_CLIST (clist));
412 }
413
414
415 static void OkDeleteEntryDialog(GtkWidget *widget, gpointer data )
416 {
417   PhonebookEntry *pbEntry;
418   GList *sel;
419   gint row;
420
421   sel = GTK_CLIST (clist)->selection;
422
423   gtk_clist_freeze(GTK_CLIST (clist));
424
425   while (sel != NULL)
426   {
427     row = GPOINTER_TO_INT(sel->data); 
428     pbEntry = (PhonebookEntry *) gtk_clist_get_row_data(GTK_CLIST (clist), row);
429     sel = sel->next;
430
431     pbEntry->status = E_Deleted;
432
433     if (pbEntry->entry.MemoryType == GMT_ME)
434     {
435       memoryStatus.UsedME--;
436       memoryStatus.FreeME++;
437       statusInfo.ch_ME = 1;
438     }
439     else
440     {
441       memoryStatus.UsedSM--;
442       memoryStatus.FreeSM++;
443       statusInfo.ch_SM = 1;
444     }
445
446     gtk_clist_remove(GTK_CLIST (clist), row);
447   }
448
449   RefreshStatusInfo ();
450
451   gtk_widget_hide(GTK_WIDGET (data));
452
453   gtk_clist_thaw(GTK_CLIST (clist));
454 }
455
456
457 static void OkNewEntryDialog(GtkWidget *widget, gpointer data )
458 {
459   gchar *clist_row[4];
460   PhonebookEntry *entry;
461
462   if (GTK_TOGGLE_BUTTON(((EditEntryData*) data)->memoryTypePhone)->active &&
463       ((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_SM)
464   {
465     if ((entry = FindFreeEntry (GMT_ME)) == NULL)
466     {
467       gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Can't change memory type!"));
468       gtk_widget_show (errorDialog.dialog);
469       return;
470     }
471     strncpy(entry->entry.Name, 
472             gtk_entry_get_text(GTK_ENTRY (((EditEntryData*) data)->name)),
473             max_phonebook_name_length);
474     entry->entry.Name[max_phonebook_name_length] = '\0';
475
476     if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
477     {
478     }
479     else
480     {
481       strncpy(entry->entry.Number,
482               gtk_entry_get_text (GTK_ENTRY(((EditEntryData*) data)->number)),
483               max_phonebook_number_length);
484       entry->entry.Name[max_phonebook_number_length] = '\0';
485     }
486
487     entry->entry.Group = ((EditEntryData*) data)->newGroup;
488
489     entry->status = E_Changed;
490
491     ((EditEntryData*) data)->pbEntry = entry;
492   }
493   else if (GTK_TOGGLE_BUTTON(((EditEntryData*) data)->memoryTypeSIM)->active &&
494       ((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_ME)
495   {
496     if ((entry = FindFreeEntry (GMT_SM)) == NULL)
497     {
498       gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Can't change memory type!"));
499       gtk_widget_show (errorDialog.dialog);
500       return;
501     }
502     strncpy(entry->entry.Name, 
503             gtk_entry_get_text (GTK_ENTRY (((EditEntryData*) data)->name)),
504             max_phonebook_sim_name_length);
505     entry->entry.Name[max_phonebook_sim_name_length] = '\0';
506
507     if (strlen(gtk_entry_get_text (GTK_ENTRY (((EditEntryData*) data)->name))) > max_phonebook_sim_name_length)
508     {
509       gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Sorry, phonebook name will be truncated\n\
510 because you save it into SIM memory!"));
511       gtk_widget_show (errorDialog.dialog);
512     }
513
514     if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
515     {
516     }
517     else
518     {
519       strncpy(entry->entry.Number,
520               gtk_entry_get_text (GTK_ENTRY(((EditEntryData*) data)->number)),
521               max_phonebook_sim_number_length);
522       entry->entry.Name[max_phonebook_sim_number_length] = '\0';
523     }
524
525     entry->entry.Group = ((EditEntryData*) data)->newGroup;
526
527     entry->status = E_Changed;
528
529     ((EditEntryData*) data)->pbEntry = entry;
530   }
531   else
532   {
533     if (GTK_TOGGLE_BUTTON(((EditEntryData*) data)->memoryTypePhone)->active)
534     {
535       strncpy(((EditEntryData*) data)->pbEntry->entry.Name, 
536               gtk_entry_get_text(GTK_ENTRY (((EditEntryData*) data)->name)),
537               max_phonebook_name_length);
538       ((EditEntryData*) data)->pbEntry->entry.Name[max_phonebook_name_length] = '\0';
539
540       if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
541       {
542       }
543       else
544       {
545         strncpy(((EditEntryData*) data)->pbEntry->entry.Number,
546                 gtk_entry_get_text (GTK_ENTRY(((EditEntryData*) data)->number)),
547                 max_phonebook_number_length);
548         ((EditEntryData*) data)->pbEntry->entry.Name[max_phonebook_number_length] = '\0';
549       }
550     }
551     else
552     {
553       strncpy (((EditEntryData*) data)->pbEntry->entry.Name, 
554               gtk_entry_get_text(GTK_ENTRY (((EditEntryData*) data)->name)),
555               max_phonebook_sim_name_length);
556       ((EditEntryData*) data)->pbEntry->entry.Name[max_phonebook_sim_name_length] = '\0';
557
558       if (strlen(gtk_entry_get_text (GTK_ENTRY (((EditEntryData*) data)->name))) > max_phonebook_sim_name_length)
559       {
560         gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Sorry, phonebook name will be truncated\n\
561 because you save it into SIM memory!"));
562         gtk_widget_show (errorDialog.dialog);
563       }
564
565       if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
566       {
567       }
568       else
569       {
570         strncpy (((EditEntryData*) data)->pbEntry->entry.Number,
571                 gtk_entry_get_text (GTK_ENTRY(((EditEntryData*) data)->number)),
572                 max_phonebook_sim_number_length);
573         ((EditEntryData*) data)->pbEntry->entry.Name[max_phonebook_sim_number_length] = '\0';
574       }
575     }
576
577     ((EditEntryData*) data)->pbEntry->entry.Group = ((EditEntryData*) data)->newGroup;
578
579     ((EditEntryData*) data)->pbEntry->status = E_Changed;
580   }
581
582   if (((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_ME)
583   {
584     memoryStatus.UsedME++;
585     memoryStatus.FreeME--;
586     statusInfo.ch_ME = 1;
587   }
588   else
589   {
590     memoryStatus.UsedSM++;
591     memoryStatus.FreeSM--;
592     statusInfo.ch_SM = 1;
593   }
594
595   gtk_widget_hide(GTK_WIDGET(((EditEntryData*) data)->dialog));
596
597   RefreshStatusInfo ();
598
599   gtk_clist_freeze (GTK_CLIST (clist));
600   clist_row[0] = ((EditEntryData*) data)->pbEntry->entry.Name;
601
602   clist_row[1] = ((EditEntryData*) data)->pbEntry->entry.Number;
603
604   if( ((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_ME)
605     clist_row[2] = "P";
606   else
607     clist_row[2] = "S";
608   if (GetModelFeature(FN_CALLERGROUPS)!=0)
609     clist_row[3] = xgnokiiConfig.callerGroups[((EditEntryData*) data)->pbEntry->entry.Group];
610   else
611     clist_row[3] = "";
612   gtk_clist_insert (GTK_CLIST (clist), 1, clist_row);
613
614   if (((EditEntryData*) data)->pbEntry->entry.MemoryType == GMT_ME)
615     gtk_clist_set_pixmap (GTK_CLIST (clist), 1, 2,
616                           memoryPixmaps.phoneMemPix, memoryPixmaps.mask);
617   else
618     gtk_clist_set_pixmap (GTK_CLIST (clist), 1, 2,
619                           memoryPixmaps.simMemPix, memoryPixmaps.mask);
620
621   gtk_clist_set_row_data (GTK_CLIST (clist), 1, (gpointer) ((EditEntryData*) data)->pbEntry);
622
623   gtk_clist_sort (GTK_CLIST (clist));
624   gtk_clist_thaw (GTK_CLIST (clist));
625 }
626
627
628 static void OkChangeEntryDialog( GtkWidget *widget, gpointer data)
629 {
630   gchar *clist_row[4];
631   gint row;
632   PhonebookEntry *oldPbEntry, *newPbEntry;
633   GList *sel;
634   gchar string[100];
635
636   sel = GTK_CLIST (clist)->selection;
637
638   gtk_widget_hide(GTK_WIDGET (data));
639
640   gtk_clist_freeze(GTK_CLIST (clist));
641
642   while (sel != NULL)
643   {
644     row = GPOINTER_TO_INT (sel->data);
645     oldPbEntry = (PhonebookEntry *) gtk_clist_get_row_data(GTK_CLIST (clist), row);
646
647     sel = sel->next;
648
649     if (oldPbEntry->entry.MemoryType == GMT_SM)
650     {
651       if ((newPbEntry = FindFreeEntry (GMT_ME)) == NULL)
652       {
653         gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Can't change memory type!"));  
654         gtk_widget_show (errorDialog.dialog);
655         return;
656       }
657
658       newPbEntry->entry = oldPbEntry->entry;
659       newPbEntry->entry.MemoryType = GMT_ME;
660
661       newPbEntry->status = E_Changed;
662       oldPbEntry->status = E_Deleted;
663
664       memoryStatus.UsedME++;
665       memoryStatus.FreeME--;
666       memoryStatus.UsedSM--;
667       memoryStatus.FreeSM++;
668       statusInfo.ch_ME = statusInfo.ch_SM = 1;
669
670     }
671     else
672     {
673       if ((newPbEntry = FindFreeEntry(GMT_SM)) == NULL)
674       {
675         gtk_label_set_text(GTK_LABEL (errorDialog.text), _("Can't change memory type!"));
676         gtk_widget_show (errorDialog.dialog);
677         return;
678       }
679
680       newPbEntry->entry = oldPbEntry->entry;
681       newPbEntry->entry.Name[max_phonebook_sim_name_length] = '\0';
682       newPbEntry->entry.MemoryType = GMT_SM;
683
684       newPbEntry->status = E_Changed;
685       oldPbEntry->status = E_Deleted;
686
687       memoryStatus.UsedME--;
688       memoryStatus.FreeME++;
689       memoryStatus.UsedSM++;
690       memoryStatus.FreeSM--;
691       statusInfo.ch_ME = statusInfo.ch_SM = 1;
692     }
693
694     gtk_clist_remove(GTK_CLIST (clist), row);
695
696     clist_row[0] = newPbEntry->entry.Name;
697
698     if (newPbEntry->entry.SubEntriesCount>0) {
699       snprintf(string,100,"%s *",newPbEntry->entry.Number);
700       clist_row[1]=string;
701     } else clist_row[1] = newPbEntry->entry.Number;
702     
703     if( newPbEntry->entry.MemoryType == GMT_ME)
704       clist_row[2] = "P";
705     else
706       clist_row[2] = "S";
707     if (GetModelFeature(FN_CALLERGROUPS)!=0)
708       clist_row[3] = xgnokiiConfig.callerGroups[newPbEntry->entry.Group];
709     else
710       clist_row[3] = "";
711     gtk_clist_insert (GTK_CLIST (clist), row, clist_row);
712     if (newPbEntry->entry.MemoryType == GMT_ME)
713       gtk_clist_set_pixmap (GTK_CLIST (clist), row, 2,
714                             memoryPixmaps.phoneMemPix, memoryPixmaps.mask);
715     else
716       gtk_clist_set_pixmap (GTK_CLIST (clist), row, 2,
717                             memoryPixmaps.simMemPix, memoryPixmaps.mask);
718
719     gtk_clist_set_row_data (GTK_CLIST (clist), row, (gpointer) newPbEntry);
720   }
721
722   RefreshStatusInfo ();  
723   gtk_clist_sort (GTK_CLIST (clist));
724   gtk_clist_thaw (GTK_CLIST (clist));
725 }
726
727
728 static void SearchEntry (void)
729 {
730   gchar *buf;
731   gchar *entry;
732   gint i;
733
734   if (!contactsMemoryInitialized || *findEntryStruct.pattern == '\0')
735     return;
736
737   gtk_clist_unselect_all( GTK_CLIST (clist));
738   g_strup(findEntryStruct.pattern);
739
740   gtk_clist_get_text( GTK_CLIST (clist), findEntryStruct.lastRow,
741                       findEntryStruct.type, &entry);
742   i = (findEntryStruct.lastRow + 1) % (memoryStatus.MaxME + memoryStatus.MaxSM);
743
744   while (findEntryStruct.lastRow != i)
745   {
746     buf = g_strdup (entry);
747     g_strup (buf);
748
749     if (strstr( buf, findEntryStruct.pattern))
750     {
751       g_free(buf);
752       findEntryStruct.lastRow = i;
753       gtk_clist_select_row( GTK_CLIST (clist),
754                             (i + memoryStatus.MaxME + memoryStatus.MaxSM - 1)
755                             % (memoryStatus.MaxME + memoryStatus.MaxSM),
756                             findEntryStruct.type);
757       gtk_clist_moveto( GTK_CLIST (clist),
758                         (i + memoryStatus.MaxME + memoryStatus.MaxSM - 1)
759                         % (memoryStatus.MaxME + memoryStatus.MaxSM),
760                         findEntryStruct.type, 0.5, 0.5);
761       return;
762     }
763     g_free(buf);
764     gtk_clist_get_text (GTK_CLIST (clist), i, findEntryStruct.type, &entry);
765
766     i = (i + 1) % (memoryStatus.MaxME + memoryStatus.MaxSM);
767   }
768
769   gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Can't find pattern!"));
770   gtk_widget_show (errorDialog.dialog);  
771 }
772
773
774 static void OkFindEntryDialog (GtkWidget *widget, gpointer data)
775 {
776   if (GTK_TOGGLE_BUTTON (((FindEntryData*) data)->nameB)->active)
777     findEntryStruct.type = FIND_NAME;
778   else
779     findEntryStruct.type = FIND_NUMBER;
780
781   strncpy(findEntryStruct.pattern, 
782           gtk_entry_get_text (GTK_ENTRY (((FindEntryData*) data)->pattern)),
783           max_phonebook_number_length);
784   findEntryStruct.pattern[max_phonebook_number_length] = '\0';
785
786   findEntryStruct.lastRow = 0;
787
788   gtk_widget_hide( ((FindEntryData*) data)->dialog);
789
790   SearchEntry ();
791 }
792
793
794 void CreateGroupMenu (EditEntryData *data)
795 {
796   GtkWidget *item;
797
798   if (data->groupMenu)
799   {
800     gtk_option_menu_remove_menu (GTK_OPTION_MENU (data->group));
801     if (GTK_IS_WIDGET (data->groupMenu))
802       gtk_widget_destroy (GTK_WIDGET (data->groupMenu));
803     data->groupMenu = NULL;
804   }
805
806   data->groupMenu = gtk_menu_new ();
807
808   item = gtk_menu_item_new_with_label (xgnokiiConfig.callerGroups[0]);
809   gtk_signal_connect (GTK_OBJECT (item), "activate",
810                       GTK_SIGNAL_FUNC (SetGroup0),
811                       (gpointer) data);
812   gtk_widget_show (item);
813   gtk_menu_append (GTK_MENU (data->groupMenu), item);
814
815   item = gtk_menu_item_new_with_label (xgnokiiConfig.callerGroups[1]);
816   gtk_signal_connect (GTK_OBJECT (item), "activate",
817                       GTK_SIGNAL_FUNC (SetGroup1),
818                       (gpointer) data);
819   gtk_widget_show (item);
820   gtk_menu_append (GTK_MENU (data->groupMenu), item);
821
822   item = gtk_menu_item_new_with_label (xgnokiiConfig.callerGroups[2]);
823   gtk_signal_connect (GTK_OBJECT (item), "activate",
824                       GTK_SIGNAL_FUNC (SetGroup2),
825                       (gpointer) data);
826   gtk_widget_show (item);
827   gtk_menu_append (GTK_MENU (data->groupMenu), item);
828
829   item = gtk_menu_item_new_with_label (xgnokiiConfig.callerGroups[3]);
830   gtk_signal_connect (GTK_OBJECT (item), "activate",
831                       GTK_SIGNAL_FUNC (SetGroup3),
832                       (gpointer) data);
833   gtk_widget_show (item);
834   gtk_menu_append (GTK_MENU (data->groupMenu), item);
835
836   item = gtk_menu_item_new_with_label (xgnokiiConfig.callerGroups[4]);
837   gtk_signal_connect (GTK_OBJECT (item), "activate",
838                       GTK_SIGNAL_FUNC (SetGroup4),
839                       (gpointer) data);
840   gtk_widget_show (item);
841   gtk_menu_append (GTK_MENU (data->groupMenu), item);
842
843   item = gtk_menu_item_new_with_label (xgnokiiConfig.callerGroups[5]);
844   gtk_signal_connect (GTK_OBJECT (item), "activate",
845                       GTK_SIGNAL_FUNC (SetGroup5),
846                       (gpointer) data);
847   gtk_widget_show (item);
848   gtk_menu_append (GTK_MENU (data->groupMenu), item);
849
850   gtk_option_menu_set_menu (GTK_OPTION_MENU (data->group), data->groupMenu);
851 }
852
853
854 inline void GUI_RefreshGroupMenu (void)
855 {
856   if (newEditEntryData.group)
857     CreateGroupMenu (&newEditEntryData);
858
859   if (editEditEntryData.group)
860     CreateGroupMenu (&editEditEntryData);
861
862   if (duplicateEditEntryData.group)
863     CreateGroupMenu (&duplicateEditEntryData);
864 }
865
866
867 static void EditSubEntries (GtkWidget      *clist,
868                             gint            row,
869                             gint            column,
870                             GdkEventButton *event,
871                             gpointer        data )
872 {
873   if(event && event->type == GDK_2BUTTON_PRESS)
874 //    EditPbEntry((PhonebookEntry *) gtk_clist_get_row_data(GTK_CLIST (clist), row),
875 //                row);
876   {
877     gchar *buf;
878
879     gtk_clist_get_text (GTK_CLIST (clist), row, 1, &buf);
880     g_print (buf);
881   }
882 }
883
884
885 static void EditNumbers (GtkWidget *widget, void *data)
886 {
887   GtkWidget *button, *clistScrolledWindow;
888   gchar *row[3];
889   register gint i;
890   
891   
892   if (editNumbersData.dialog == NULL)
893   {
894     editNumbersData.dialog = gtk_dialog_new ();
895     gtk_window_set_title (GTK_WINDOW (editNumbersData.dialog), _("Numbers"));
896     gtk_window_set_modal (GTK_WINDOW (editNumbersData.dialog), TRUE);
897     gtk_container_set_border_width (GTK_CONTAINER (editNumbersData.dialog), 10);
898     gtk_signal_connect (GTK_OBJECT (editNumbersData.dialog), "delete_event",
899                         GTK_SIGNAL_FUNC (DeleteEvent), NULL);
900
901     button = gtk_button_new_with_label (_("Ok"));
902     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editNumbersData.dialog)->action_area),
903                         button, TRUE, TRUE, 10);
904 //    gtk_signal_connect (GTK_OBJECT (button), "clicked",
905 //                        GTK_SIGNAL_FUNC (okFunc), (gpointer) editEntryData);
906     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
907     gtk_widget_grab_default (button);
908     gtk_widget_show (button);
909     
910     button = gtk_button_new_with_label (_("New"));
911     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editNumbersData.dialog)->action_area),
912                         button, TRUE, TRUE, 10);
913 //    gtk_signal_connect (GTK_OBJECT (button), "clicked",
914 //                        GTK_SIGNAL_FUNC (okFunc), (gpointer) editEntryData);
915     gtk_widget_show (button);
916     
917     button = gtk_button_new_with_label (_("Cancel"));
918     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editNumbersData.dialog)->action_area),
919                         button, TRUE, TRUE, 10);
920     gtk_signal_connect (GTK_OBJECT (button), "clicked",
921                         GTK_SIGNAL_FUNC (CancelDialog), (gpointer) editNumbersData.dialog);
922     gtk_widget_show (button);
923
924     gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (editNumbersData.dialog)->vbox), 5);
925     
926     editNumbersData.clist = gtk_clist_new (3);
927     gtk_clist_set_shadow_type (GTK_CLIST (editNumbersData.clist), GTK_SHADOW_OUT);
928
929     gtk_clist_set_column_width (GTK_CLIST (editNumbersData.clist), 0, 4);
930     gtk_clist_set_column_width (GTK_CLIST (editNumbersData.clist), 1, 115);
931     gtk_clist_set_column_width (GTK_CLIST (editNumbersData.clist), 2, 10);
932     //gtk_clist_set_column_justification (GTK_CLIST (editNumbersData.clist), 2, GTK_JUSTIFY_CENTER);
933
934     gtk_signal_connect (GTK_OBJECT (editNumbersData.clist), "select_row",
935                         GTK_SIGNAL_FUNC (EditSubEntries), NULL);
936
937     clistScrolledWindow = gtk_scrolled_window_new (NULL, NULL);
938     gtk_container_add (GTK_CONTAINER (clistScrolledWindow), editNumbersData.clist);
939     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (clistScrolledWindow),
940                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
941
942     gtk_container_add (GTK_CONTAINER (GTK_DIALOG (editNumbersData.dialog)->vbox),
943                        clistScrolledWindow);
944                        
945     gtk_widget_show (editNumbersData.clist);
946     gtk_widget_show (clistScrolledWindow);
947   }
948
949   gtk_clist_freeze (GTK_CLIST (editNumbersData.clist));
950   gtk_clist_clear (GTK_CLIST (editNumbersData.clist));
951
952   for(i = 0; i < editNumbersData.pbEntry->entry.SubEntriesCount; i++)
953   {
954     if (strcmp (editNumbersData.pbEntry->entry.Number,
955                 editNumbersData.pbEntry->entry.SubEntries[i].data.Number) == 0)
956       row[0] = "*";
957     else
958       row[0] = "";
959       
960     row[1] = editNumbersData.pbEntry->entry.SubEntries[i].data.Number;
961
962     switch (editNumbersData.pbEntry->entry.SubEntries[i].EntryType)
963     {
964       case GSM_Number:
965         switch (editNumbersData.pbEntry->entry.SubEntries[i].NumberType)
966         {
967           case GSM_General:
968             row[2] = "General";
969             break;
970
971           case GSM_Mobile:
972             row[2] = "Mobile";
973             break;
974
975           case GSM_Work:
976             row[2] = "Work";
977             break;
978
979           case GSM_Fax:
980             row[2] = "Fax";
981             break;
982
983           case GSM_Home:
984             row[2] = "Home";
985             break;
986
987           default:
988             row[2] = "Unknown";
989             break;
990         }
991         break;
992
993       case GSM_Note:
994         row[2] = "Note";
995         break;
996
997       case GSM_Postal:
998         row[2] = "Postal";
999         break;
1000
1001       case GSM_Email:
1002         row[2] = "E-Mail";
1003         break;
1004
1005       case GSM_Name:
1006         row[2] = "Name";
1007         break;
1008
1009       default:
1010         row[2] = "Unknown";
1011         break;
1012     }
1013     
1014     gtk_clist_append (GTK_CLIST (editNumbersData.clist), row);
1015 /*      if (pbEntry->entry.MemoryType == GMT_ME)
1016       gtk_clist_set_pixmap (GTK_CLIST (clist), row_i, 2,
1017                             memoryPixmaps.phoneMemPix, memoryPixmaps.mask);
1018     else
1019       gtk_clist_set_pixmap (GTK_CLIST (clist), row_i, 2,
1020                             memoryPixmaps.simMemPix, memoryPixmaps.mask);
1021 */
1022   }
1023     
1024   gtk_clist_thaw (GTK_CLIST (editNumbersData.clist));
1025   
1026   gtk_widget_show (editNumbersData.dialog);
1027 }
1028
1029
1030 static void CreateEditDialog (EditEntryData *editEntryData, gchar *title,
1031                               GtkSignalFunc okFunc)
1032 {
1033   GtkWidget *button, *label, *hbox;
1034
1035   editEntryData->dialog = gtk_dialog_new ();
1036   gtk_window_set_title (GTK_WINDOW (editEntryData->dialog), title);
1037   gtk_window_set_modal (GTK_WINDOW (editEntryData->dialog), TRUE);
1038   gtk_container_set_border_width (GTK_CONTAINER (editEntryData->dialog), 10);
1039   gtk_signal_connect (GTK_OBJECT (editEntryData->dialog), "delete_event",
1040                       GTK_SIGNAL_FUNC (DeleteEvent), NULL);
1041
1042   button = gtk_button_new_with_label (_("Ok"));
1043   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editEntryData->dialog)->action_area),
1044                       button, TRUE, TRUE, 10);
1045   gtk_signal_connect (GTK_OBJECT (button), "clicked",
1046                       GTK_SIGNAL_FUNC (okFunc), (gpointer) editEntryData);
1047   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1048   gtk_widget_grab_default (button);
1049   gtk_widget_show (button);
1050   button = gtk_button_new_with_label (_("Cancel"));
1051   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editEntryData->dialog)->action_area),
1052                       button, TRUE, TRUE, 10);
1053   gtk_signal_connect (GTK_OBJECT (button), "clicked",
1054                       GTK_SIGNAL_FUNC (CancelEditDialog), (gpointer) editEntryData);
1055   gtk_widget_show (button);
1056
1057   gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (editEntryData->dialog)->vbox), 5);
1058
1059   hbox = gtk_hbox_new (FALSE, 0);
1060   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (editEntryData->dialog)->vbox), hbox);
1061   gtk_widget_show (hbox);
1062
1063   label = gtk_label_new (_("Name:"));
1064   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1065   gtk_widget_show (label);
1066
1067   editEntryData->name = gtk_entry_new_with_max_length (100);
1068
1069   gtk_box_pack_end(GTK_BOX(hbox), editEntryData->name, FALSE, FALSE, 2);
1070   gtk_widget_show (editEntryData->name);
1071
1072   hbox = gtk_hbox_new (FALSE, 0);
1073   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (editEntryData->dialog)->vbox), hbox);
1074   gtk_widget_show (hbox);
1075
1076   label = gtk_label_new (_("Number:"));
1077   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1078   gtk_widget_show (label);
1079
1080   if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
1081   {
1082     button = gtk_button_new ();
1083     editEntryData->number = gtk_label_new ("");
1084
1085     gtk_container_add (GTK_CONTAINER (button), editEntryData->number);
1086
1087     gtk_box_pack_end(GTK_BOX(hbox), button, TRUE, TRUE, 2);
1088
1089     gtk_signal_connect (GTK_OBJECT (button), "clicked",
1090                         GTK_SIGNAL_FUNC (EditNumbers), NULL);
1091     gtk_widget_show_all (button);
1092   }
1093   else
1094   {
1095     editEntryData->number = gtk_entry_new_with_max_length (max_phonebook_number_length);
1096     gtk_box_pack_end(GTK_BOX(hbox), editEntryData->number, FALSE, FALSE, 2);
1097     gtk_widget_show (editEntryData->number);
1098   }
1099
1100 /*  if (GetModelFeature(FN_PHONEBOOK)==F_PBK71) {
1101
1102     hbox = gtk_hbox_new (FALSE, 0);
1103     gtk_container_add (GTK_CONTAINER (GTK_DIALOG (editEntryData->dialog)->vbox), hbox);
1104 //    gtk_widget_show (hbox);
1105
1106     label = gtk_label_new (_("Extended:"));
1107     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1108 //    gtk_widget_show (label);
1109     
1110     editEntryData->extended = gtk_combo_new();
1111     gtk_box_pack_end(GTK_BOX(hbox), editEntryData->extended, FALSE, FALSE, 2);
1112 //    gtk_widget_show (editEntryData->extended);
1113
1114     gtk_signal_connect (GTK_OBJECT (GTK_COMBO(editEntryData->extended)->entry), "activate",
1115                         GTK_SIGNAL_FUNC (ExtPbkChanged), (gpointer) editEntryData);    
1116   }
1117 */
1118     
1119   editEntryData->memoryBox = gtk_hbox_new (FALSE, 0);
1120   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (editEntryData->dialog)->vbox),
1121                      editEntryData->memoryBox);
1122     
1123   label = gtk_label_new (_("Memory:"));
1124   gtk_box_pack_start(GTK_BOX (editEntryData->memoryBox), label, FALSE, FALSE, 2);
1125   gtk_widget_show (label);
1126
1127   editEntryData->memoryTypePhone = gtk_radio_button_new_with_label (NULL, _("phone"));
1128   gtk_box_pack_end (GTK_BOX (editEntryData->memoryBox), editEntryData->memoryTypePhone, TRUE, FALSE, 2);
1129   gtk_widget_show (editEntryData->memoryTypePhone);
1130
1131   editEntryData->memoryTypeSIM = gtk_radio_button_new_with_label( 
1132         gtk_radio_button_group (GTK_RADIO_BUTTON (editEntryData->memoryTypePhone)), "SIM");
1133   gtk_box_pack_end(GTK_BOX (editEntryData->memoryBox), editEntryData->memoryTypeSIM, TRUE, FALSE, 2);
1134   gtk_widget_show (editEntryData->memoryTypeSIM);
1135
1136   hbox = gtk_hbox_new (FALSE, 0);
1137   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (editEntryData->dialog)->vbox), hbox);
1138   gtk_widget_show (hbox);
1139
1140   editEntryData->groupLabel = gtk_label_new (_("Caller group:"));
1141   gtk_box_pack_start (GTK_BOX (hbox), editEntryData->groupLabel, FALSE, FALSE, 2);
1142
1143   editEntryData->group = gtk_option_menu_new ();
1144
1145   CreateGroupMenu (editEntryData);
1146
1147   gtk_box_pack_start (GTK_BOX (hbox), editEntryData->group, TRUE, TRUE, 0);
1148 }
1149
1150
1151 static void EditPbEntry(PhonebookEntry *pbEntry, gint row)
1152 {
1153   if (editEditEntryData.dialog == NULL)
1154     CreateEditDialog(&editEditEntryData, _("Edit entry"), OkEditEntryDialog);
1155
1156   editEditEntryData.pbEntry = pbEntry;
1157   editEditEntryData.newGroup = pbEntry->entry.Group;
1158   editEditEntryData.row = row;
1159   editNumbersData.pbEntry = pbEntry;
1160
1161   gtk_entry_set_text (GTK_ENTRY (editEditEntryData.name), pbEntry->entry.Name);
1162
1163   if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
1164     gtk_label_set_text (GTK_LABEL (editEditEntryData.number), pbEntry->entry.Number);
1165   else
1166     gtk_entry_set_text (GTK_ENTRY (editEditEntryData.number), pbEntry->entry.Number);
1167
1168   if (pbEntry->entry.MemoryType == GMT_ME)
1169     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (editEditEntryData.memoryTypePhone), TRUE);
1170   else
1171     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (editEditEntryData.memoryTypeSIM), TRUE);
1172
1173   gtk_option_menu_set_history( GTK_OPTION_MENU (editEditEntryData.group),
1174                                pbEntry->entry.Group);
1175
1176   if (GetModelFeature(FN_CALLERGROUPS)!=0)
1177   {
1178     gtk_widget_show (editEditEntryData.group);
1179     gtk_widget_show (editEditEntryData.groupLabel);
1180   }
1181   else
1182   {
1183     gtk_widget_hide (editEditEntryData.group);
1184     gtk_widget_hide (editEditEntryData.groupLabel);
1185   }
1186
1187   if (memoryStatus.MaxME > 0)
1188     gtk_widget_show (GTK_WIDGET (editEditEntryData.memoryBox));
1189   else
1190     gtk_widget_hide (GTK_WIDGET (editEditEntryData.memoryBox));
1191
1192   gtk_widget_show (GTK_WIDGET (editEditEntryData.dialog));
1193 }
1194
1195
1196 void DeletePbEntry (void)
1197 {
1198   static GtkWidget *dialog = NULL;
1199   GtkWidget *button, *hbox, *label, *pixmap;
1200
1201   if (dialog == NULL)
1202   {
1203     dialog = gtk_dialog_new ();
1204     gtk_window_set_title (GTK_WINDOW (dialog), _("Delete entries"));
1205     gtk_window_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
1206     gtk_window_set_modal(GTK_WINDOW (dialog), TRUE);
1207     gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
1208     gtk_signal_connect (GTK_OBJECT (dialog), "delete_event",
1209                         GTK_SIGNAL_FUNC (DeleteEvent), NULL);
1210
1211     button = gtk_button_new_with_label (_("Ok"));
1212     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
1213                         button, TRUE, TRUE, 10);
1214     gtk_signal_connect (GTK_OBJECT (button), "clicked",
1215                         GTK_SIGNAL_FUNC (OkDeleteEntryDialog), (gpointer) dialog);
1216     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1217     gtk_widget_grab_default (button);
1218     gtk_widget_show (button);
1219     button = gtk_button_new_with_label (_("Cancel"));
1220     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
1221                         button, TRUE, TRUE, 10);
1222     gtk_signal_connect (GTK_OBJECT (button), "clicked",
1223                         GTK_SIGNAL_FUNC (CancelDialog), (gpointer) dialog);
1224     gtk_widget_show (button);
1225
1226     gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5);
1227
1228     hbox = gtk_hbox_new (FALSE, 0);
1229     gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
1230     gtk_widget_show (hbox);
1231
1232     pixmap = gtk_pixmap_new (questMark.pixmap, questMark.mask);
1233     gtk_box_pack_start(GTK_BOX(hbox), pixmap, FALSE, FALSE, 10);
1234     gtk_widget_show(pixmap);
1235
1236     label = gtk_label_new(_("Do you want to delete selected entries?"));
1237     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
1238     gtk_widget_show(label);
1239   }
1240
1241   gtk_widget_show(GTK_WIDGET (dialog));
1242 }
1243
1244
1245 void NewPbEntry(PhonebookEntry *pbEntry)
1246 {
1247   if (newEditEntryData.dialog == NULL)
1248     CreateEditDialog (&newEditEntryData, _("New entry"), OkNewEntryDialog);
1249
1250   newEditEntryData.pbEntry = pbEntry;
1251   newEditEntryData.newGroup = 5;
1252   editNumbersData.pbEntry = pbEntry;
1253
1254   gtk_entry_set_text (GTK_ENTRY (newEditEntryData.name), "");
1255   
1256   if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
1257     gtk_label_set_text (GTK_LABEL (newEditEntryData.number), "");
1258   else
1259     gtk_entry_set_text (GTK_ENTRY (newEditEntryData.number), "");
1260
1261   if (pbEntry->entry.MemoryType == GMT_ME)
1262     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (newEditEntryData.memoryTypePhone), TRUE);
1263   else
1264     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (newEditEntryData.memoryTypeSIM), TRUE);
1265
1266   gtk_option_menu_set_history( GTK_OPTION_MENU (newEditEntryData.group),
1267                                pbEntry->entry.Group);
1268
1269   if (GetModelFeature(FN_CALLERGROUPS)!=0)
1270   {
1271     gtk_widget_show (newEditEntryData.group);
1272     gtk_widget_show (newEditEntryData.groupLabel);
1273   }
1274   else
1275   {
1276     gtk_widget_hide (newEditEntryData.group);
1277     gtk_widget_hide (newEditEntryData.groupLabel);
1278   }
1279
1280   if (memoryStatus.MaxME > 0)
1281     gtk_widget_show (GTK_WIDGET (newEditEntryData.memoryBox));
1282   else
1283     gtk_widget_hide (GTK_WIDGET (newEditEntryData.memoryBox));
1284
1285   gtk_widget_show(GTK_WIDGET (newEditEntryData.dialog));
1286 }
1287
1288
1289 void DuplicatePbEntry (PhonebookEntry *pbEntry)
1290 {
1291   if (duplicateEditEntryData.dialog == NULL)
1292     CreateEditDialog (&duplicateEditEntryData, _("Duplicate entry"), OkNewEntryDialog);
1293
1294   duplicateEditEntryData.pbEntry = pbEntry;
1295   duplicateEditEntryData.newGroup = pbEntry->entry.Group;
1296   editNumbersData.pbEntry = pbEntry;
1297
1298   gtk_entry_set_text (GTK_ENTRY (duplicateEditEntryData.name), pbEntry->entry.Name);
1299
1300   if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
1301     gtk_label_set_text (GTK_LABEL (duplicateEditEntryData.number), pbEntry->entry.Number);
1302   else
1303     gtk_entry_set_text (GTK_ENTRY (duplicateEditEntryData.number), pbEntry->entry.Number);
1304
1305   if (pbEntry->entry.MemoryType == GMT_ME)
1306     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (duplicateEditEntryData.memoryTypePhone), TRUE);
1307   else
1308     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (duplicateEditEntryData.memoryTypeSIM), TRUE);
1309
1310   gtk_option_menu_set_history( GTK_OPTION_MENU (duplicateEditEntryData.group),
1311                                pbEntry->entry.Group);
1312
1313   if (GetModelFeature(FN_CALLERGROUPS)!=0)
1314   {
1315     gtk_widget_show (duplicateEditEntryData.group);
1316     gtk_widget_show (duplicateEditEntryData.groupLabel);
1317   }
1318   else
1319   {
1320     gtk_widget_hide (duplicateEditEntryData.group);
1321     gtk_widget_hide (duplicateEditEntryData.groupLabel);
1322   }
1323
1324   if (memoryStatus.MaxME > 0)
1325     gtk_widget_show (GTK_WIDGET (duplicateEditEntryData.memoryBox));
1326   else
1327     gtk_widget_hide (GTK_WIDGET (duplicateEditEntryData.memoryBox));
1328
1329   gtk_widget_show(GTK_WIDGET (duplicateEditEntryData.dialog));
1330 }
1331
1332
1333 static void EditEntry (void)
1334 {
1335   if (contactsMemoryInitialized)
1336   {
1337     if (GTK_CLIST (clist)->selection == NULL)
1338       return;
1339
1340     EditPbEntry((PhonebookEntry *) gtk_clist_get_row_data(GTK_CLIST (clist),
1341                 GPOINTER_TO_INT(GTK_CLIST (clist)->selection->data)),
1342                 GPOINTER_TO_INT(GTK_CLIST (clist)->selection->data));
1343   }
1344 }
1345
1346
1347 static void DuplicateEntry (void)
1348 {
1349   PhonebookEntry *new, *old;
1350
1351   if (contactsMemoryInitialized)
1352   {
1353     if (GTK_CLIST (clist)->selection == NULL)
1354       return;
1355
1356     old = (PhonebookEntry *) gtk_clist_get_row_data (GTK_CLIST (clist), GPOINTER_TO_INT(GTK_CLIST (clist)->selection->data));
1357
1358     if ( old->entry.MemoryType == GMT_ME)
1359     {
1360       if ((new = FindFreeEntry (GMT_ME)) == NULL)
1361         if ((new = FindFreeEntry (GMT_SM)) == NULL)
1362         {
1363           gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Can't find free memory."));
1364           gtk_widget_show (errorDialog.dialog);
1365           return;
1366         }
1367     }
1368     else
1369     {
1370       if ((new = FindFreeEntry(GMT_SM)) == NULL)
1371         if ((new = FindFreeEntry(GMT_ME)) == NULL)
1372         {
1373           gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Can't find free memory."));
1374           gtk_widget_show (errorDialog.dialog);
1375           return;
1376         }
1377     }
1378
1379     new->entry = old->entry;
1380
1381     DuplicatePbEntry (new);
1382   }
1383 }
1384
1385
1386 static void NewEntry (void)
1387 {
1388   PhonebookEntry *entry;
1389
1390   if (contactsMemoryInitialized)
1391   {
1392     if ((entry = FindFreeEntry (GMT_SM)) != NULL)
1393       NewPbEntry(entry);
1394     else if ((entry = FindFreeEntry (GMT_ME)) != NULL)
1395       NewPbEntry(entry);
1396     else
1397     {
1398       gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Can't find free memory."));
1399       gtk_widget_show (errorDialog.dialog);
1400     }
1401   }
1402 }
1403
1404
1405 static inline void ClickEntry (GtkWidget      *clist,
1406                  gint            row,
1407                  gint            column,
1408                  GdkEventButton *event,
1409                  gpointer        data )
1410 {
1411   if(event && event->type == GDK_2BUTTON_PRESS)
1412     EditPbEntry((PhonebookEntry *) gtk_clist_get_row_data(GTK_CLIST (clist), row),
1413                 row);
1414 }
1415
1416
1417 static inline void DeleteEntry (void)
1418 {
1419   if (contactsMemoryInitialized)
1420   {
1421     if (GTK_CLIST (clist)->selection == NULL)
1422       return;
1423
1424     DeletePbEntry ();
1425   }
1426 }
1427
1428
1429 static void ChMemType (void)
1430 {
1431   static GtkWidget *dialog = NULL;
1432   GtkWidget *button, *hbox, *label;
1433
1434   if (contactsMemoryInitialized)
1435   {
1436     if (GTK_CLIST (clist)->selection == NULL)
1437       return;
1438
1439     if (dialog == NULL)
1440     {
1441       dialog = gtk_dialog_new ();
1442       gtk_window_set_title (GTK_WINDOW (dialog), _("Changing memory type"));
1443       gtk_window_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
1444       gtk_window_set_modal(GTK_WINDOW (dialog), TRUE);
1445       gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1446       gtk_signal_connect (GTK_OBJECT (dialog), "delete_event",
1447                           GTK_SIGNAL_FUNC (DeleteEvent), NULL);
1448
1449       button = gtk_button_new_with_label (_("Continue"));
1450       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
1451                           button, FALSE, FALSE, 0);
1452       gtk_signal_connect (GTK_OBJECT (button), "clicked",
1453                           GTK_SIGNAL_FUNC (OkChangeEntryDialog), (gpointer) dialog);
1454       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1455       gtk_widget_grab_default (button);
1456       gtk_widget_show (button);
1457
1458       button = gtk_button_new_with_label (_("Cancel"));
1459       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
1460                           button, FALSE, FALSE, 0);
1461       gtk_signal_connect (GTK_OBJECT (button), "clicked",
1462                           GTK_SIGNAL_FUNC (CancelDialog), (gpointer) dialog);
1463       gtk_widget_show (button);
1464
1465       hbox = gtk_hbox_new (FALSE, 0);
1466       gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
1467       gtk_widget_show (hbox);
1468
1469       label = gtk_label_new (_("If you change from phone memory to SIM memory\nsome entries may be truncated."));
1470       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 10);
1471       gtk_widget_show (label);
1472     }
1473
1474     gtk_widget_show (dialog);
1475   }
1476 }
1477
1478
1479 static void FindFirstEntry (void)
1480 {
1481   static FindEntryData findEntryData = { NULL };
1482   GtkWidget *button, *label, *hbox;
1483
1484   if (contactsMemoryInitialized)
1485   {
1486     if (findEntryData.dialog == NULL)
1487     {
1488       findEntryData.dialog = gtk_dialog_new ();
1489       gtk_window_set_title (GTK_WINDOW (findEntryData.dialog), _("Find"));
1490       gtk_window_set_modal (GTK_WINDOW (findEntryData.dialog), TRUE);
1491       gtk_container_set_border_width (GTK_CONTAINER (findEntryData.dialog), 10);
1492       gtk_signal_connect (GTK_OBJECT (findEntryData.dialog), "delete_event",
1493                           GTK_SIGNAL_FUNC (DeleteEvent), NULL);
1494
1495       button = gtk_button_new_with_label (_("Find"));
1496       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (findEntryData.dialog)->action_area),
1497                           button, TRUE, TRUE, 10);
1498       gtk_signal_connect (GTK_OBJECT (button), "clicked",
1499                           GTK_SIGNAL_FUNC (OkFindEntryDialog), (gpointer) &findEntryData);
1500       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1501       gtk_widget_grab_default (button);
1502       gtk_widget_show (button);
1503
1504       button = gtk_button_new_with_label (_("Cancel"));
1505       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (findEntryData.dialog)->action_area),
1506                           button, TRUE, TRUE, 10);
1507       gtk_signal_connect (GTK_OBJECT (button), "clicked",
1508                           GTK_SIGNAL_FUNC (CancelEditDialog), (gpointer) &findEntryData);
1509       gtk_widget_show (button);
1510
1511       gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (findEntryData.dialog)->vbox), 5);
1512
1513       hbox = gtk_hbox_new (FALSE, 0);
1514       gtk_container_add (GTK_CONTAINER (GTK_DIALOG (findEntryData.dialog)->vbox), hbox);
1515       gtk_widget_show (hbox);
1516
1517       label = gtk_label_new (_("Pattern:"));
1518       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
1519       gtk_widget_show (label);
1520
1521       findEntryData.pattern = gtk_entry_new_with_max_length (max_phonebook_name_length);
1522
1523       gtk_box_pack_end (GTK_BOX (hbox), findEntryData.pattern, FALSE, FALSE, 2);
1524       gtk_widget_show (findEntryData.pattern);
1525
1526       hbox = gtk_hbox_new (FALSE, 0);
1527       gtk_container_add (GTK_CONTAINER (GTK_DIALOG (findEntryData.dialog)->vbox), hbox);
1528       gtk_widget_show (hbox);
1529
1530       findEntryData.nameB = gtk_radio_button_new_with_label (NULL, _("Name"));
1531       gtk_box_pack_start (GTK_BOX (hbox), findEntryData.nameB, TRUE, FALSE, 2);
1532       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (findEntryData.nameB), TRUE);
1533       gtk_widget_show (findEntryData.nameB);
1534
1535       findEntryData.numberB = gtk_radio_button_new_with_label ( 
1536         gtk_radio_button_group (GTK_RADIO_BUTTON (findEntryData.nameB)), _("Number"));
1537       gtk_box_pack_start (GTK_BOX(hbox), findEntryData.numberB, TRUE, FALSE, 2);
1538       gtk_widget_show (findEntryData.numberB);
1539     }
1540
1541     gtk_widget_show (findEntryData.dialog);
1542   }
1543 }
1544
1545
1546 static inline void SelectAll (void)
1547 {
1548   gtk_clist_select_all (GTK_CLIST (clist));
1549 }
1550
1551
1552 static inline void OkDialVoiceDialog (GtkWidget *w, gpointer data)
1553 {
1554   PhoneEvent *e;
1555   gchar *buf = g_strdup (gtk_entry_get_text (GTK_ENTRY (((DialVoiceDialog *) data)->entry)));
1556
1557   if (strlen (buf) > 0)
1558   {
1559     e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
1560     e->event = Event_DialVoice;
1561     e->data = buf;
1562     GUI_InsertEvent (e);
1563   }
1564   else
1565     g_free (buf);
1566
1567   gtk_widget_hide (((DialVoiceDialog *) data)->dialog);
1568 }
1569
1570
1571 static void DialVoice (void)
1572 {
1573   static DialVoiceDialog dialVoiceDialog = {NULL, NULL};
1574   GtkWidget *button, *label;
1575   PhonebookEntry *pbEntry;
1576
1577   if (dialVoiceDialog.dialog == NULL)
1578   {
1579     dialVoiceDialog.dialog = gtk_dialog_new ();
1580     gtk_window_set_title (GTK_WINDOW (dialVoiceDialog.dialog), _("Dial voice"));
1581     gtk_window_set_modal(GTK_WINDOW (dialVoiceDialog.dialog), TRUE);
1582     gtk_container_set_border_width (GTK_CONTAINER (dialVoiceDialog.dialog), 10);
1583     gtk_signal_connect (GTK_OBJECT (dialVoiceDialog.dialog), "delete_event",
1584                         GTK_SIGNAL_FUNC (DeleteEvent), NULL);
1585
1586     button = gtk_button_new_with_label (_("Ok"));
1587     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialVoiceDialog.dialog)->action_area),
1588                         button, TRUE, TRUE, 10);
1589     gtk_signal_connect (GTK_OBJECT (button), "clicked",
1590                         GTK_SIGNAL_FUNC (OkDialVoiceDialog), (gpointer) &dialVoiceDialog);
1591     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1592     gtk_widget_grab_default (button);
1593     gtk_widget_show (button);
1594
1595     button = gtk_button_new_with_label (_("Cancel"));
1596     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialVoiceDialog.dialog)->action_area),
1597                         button, TRUE, TRUE, 10);
1598     gtk_signal_connect (GTK_OBJECT (button), "clicked",
1599                         GTK_SIGNAL_FUNC (CancelDialog), (gpointer) dialVoiceDialog.dialog);
1600     gtk_widget_show (button);
1601
1602     gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialVoiceDialog.dialog)->vbox), 5);
1603
1604     label = gtk_label_new (_("Number:"));
1605     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialVoiceDialog.dialog)->vbox), label, FALSE, FALSE, 5);
1606     gtk_widget_show (label);
1607
1608     dialVoiceDialog.entry = gtk_entry_new_with_max_length (GSM_MAX_PHONEBOOK_NUMBER_LENGTH);
1609     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialVoiceDialog.dialog)->vbox), dialVoiceDialog.entry, FALSE, FALSE, 5);
1610     gtk_widget_show (dialVoiceDialog.entry);
1611   }
1612
1613   if (GTK_CLIST (clist)->selection != NULL)
1614   {
1615     pbEntry = (PhonebookEntry *) gtk_clist_get_row_data (GTK_CLIST (clist),
1616                GPOINTER_TO_INT (GTK_CLIST (clist)->selection->data));
1617
1618     gtk_entry_set_text (GTK_ENTRY (dialVoiceDialog.entry), pbEntry->entry.Number);
1619   }
1620
1621   gtk_widget_show (dialVoiceDialog.dialog);  
1622 }
1623
1624
1625 static gint CListCompareFunc (GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
1626 {
1627   static gchar phoneText[] = "B";
1628   static gchar simText[] = "A";
1629   char *text1 = NULL;
1630   char *text2 = NULL;
1631   gint ret;
1632
1633   GtkCListRow *row1 = (GtkCListRow *) ptr1;
1634   GtkCListRow *row2 = (GtkCListRow *) ptr2;
1635
1636   switch (row1->cell[clist->sort_column].type)
1637   {
1638     case GTK_CELL_TEXT:
1639       text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
1640       break;
1641     case GTK_CELL_PIXTEXT:
1642       text1 = GTK_CELL_PIXTEXT (row1->cell[clist->sort_column])->text;
1643       break;
1644     default:
1645       break;
1646   }
1647   switch (row2->cell[clist->sort_column].type)
1648   {
1649     case GTK_CELL_TEXT:
1650       text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
1651       break;
1652     case GTK_CELL_PIXTEXT:
1653       text2 = GTK_CELL_PIXTEXT (row2->cell[clist->sort_column])->text;
1654       break;
1655     default:
1656       break;
1657   }
1658
1659   if (clist->sort_column == 2)
1660   {
1661     if (((PhonebookEntry *) row1->data)->entry.MemoryType == GMT_ME)
1662       text1 = phoneText;
1663     else
1664       text1 = simText;
1665     if (((PhonebookEntry *) row2->data)->entry.MemoryType == GMT_ME)
1666       text2 = phoneText;
1667     else
1668       text2 = simText;
1669   }
1670
1671   if (!text2)
1672     return (text1 != NULL);
1673
1674   if (!text1)
1675     return -1;
1676
1677   if ((ret = g_strcasecmp (text1, text2)) == 0)
1678   {
1679     if (((PhonebookEntry *) row1->data)->entry.MemoryType < ((PhonebookEntry *) row2->data)->entry.MemoryType)
1680       ret = -1;
1681     else if (((PhonebookEntry *) row1->data)->entry.MemoryType > ((PhonebookEntry *) row2->data)->entry.MemoryType)
1682       ret = 1;
1683   }
1684
1685   return ret;      
1686 }
1687
1688
1689 static void CreateProgressDialog (gint maxME, gint maxSM)
1690 {
1691   GtkWidget *vbox, *label;
1692   GtkAdjustment *adj;
1693   
1694   progressDialog.dialog = gtk_window_new (GTK_WINDOW_DIALOG);
1695   gtk_window_position (GTK_WINDOW (progressDialog.dialog), GTK_WIN_POS_MOUSE);
1696   gtk_window_set_modal (GTK_WINDOW (progressDialog.dialog), TRUE);
1697   gtk_signal_connect (GTK_OBJECT (progressDialog.dialog), "delete_event",
1698                       GTK_SIGNAL_FUNC (ProgressDialogDeleteEvent), NULL);
1699
1700   vbox = gtk_vbox_new (FALSE, 10);
1701   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
1702   gtk_container_add (GTK_CONTAINER (progressDialog.dialog), vbox);
1703
1704   gtk_widget_show (vbox);
1705
1706   label = gtk_label_new (_("Phone memory..."));
1707   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
1708
1709   gtk_widget_show (label);
1710
1711   adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, maxME, 0, 0, 0);
1712   progressDialog.pbarME = gtk_progress_bar_new_with_adjustment (adj);
1713
1714   gtk_box_pack_start (GTK_BOX (vbox), progressDialog.pbarME, FALSE, FALSE, 0);
1715   gtk_widget_show (progressDialog.pbarME);
1716
1717   label = gtk_label_new (_("SIM memory..."));
1718   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
1719
1720   gtk_widget_show (label);
1721
1722   adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, maxSM, 0, 0, 0);
1723   progressDialog.pbarSM = gtk_progress_bar_new_with_adjustment (adj);
1724
1725   gtk_box_pack_start (GTK_BOX (vbox), progressDialog.pbarSM, FALSE, FALSE, 0);
1726   gtk_widget_show (progressDialog.pbarSM);
1727 }
1728
1729
1730 static void SaveContacts (void)
1731 {
1732   register gint i;
1733   PhonebookEntry *pbEntry;
1734   PhoneEvent *e;
1735   D_MemoryLocation *ml;
1736
1737   if (progressDialog.dialog == NULL)
1738   {
1739     CreateProgressDialog (memoryStatus.MaxME, memoryStatus.MaxSM);
1740   }
1741
1742   if (contactsMemoryInitialized && progressDialog.dialog)
1743   {
1744     gtk_progress_set_value (GTK_PROGRESS (progressDialog.pbarME), 0);
1745     gtk_progress_set_value (GTK_PROGRESS (progressDialog.pbarSM), 0);
1746     gtk_window_set_title (GTK_WINDOW (progressDialog.dialog), _("Saving entries"));  
1747     gtk_widget_show_now (progressDialog.dialog);
1748
1749     /* Save Phone memory */
1750     for(i = 0; i < memoryStatus.MaxME; i++)
1751     {
1752       pbEntry = g_ptr_array_index(contactsMemory, i);
1753 #ifdef XDEBUG    
1754       g_print ("%d;%s;%s;%d;%d;%d\n", pbEntry->entry.Empty, pbEntry->entry.Name,
1755                pbEntry->entry.Number, (int) pbEntry->entry.MemoryType, pbEntry->entry.Group,
1756                (int) pbEntry->status);
1757 #endif
1758       if (pbEntry->status == E_Changed || pbEntry->status == E_Deleted)
1759       {
1760         if (pbEntry->status == E_Deleted)
1761         {
1762           pbEntry->entry.Name[0] = '\0';
1763           pbEntry->entry.Number[0] = '\0';
1764           pbEntry->entry.Group = 5;
1765         }
1766
1767         pbEntry->entry.Location = i + 1;
1768         ml = (D_MemoryLocation *) g_malloc (sizeof (D_MemoryLocation));
1769         ml->entry = &(pbEntry->entry);
1770         e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
1771         e->event = Event_WriteMemoryLocation;
1772         e->data = ml;
1773         GUI_InsertEvent (e);
1774         pthread_mutex_lock (&memoryMutex);
1775         pthread_cond_wait (&memoryCond, &memoryMutex);
1776         pthread_mutex_unlock (&memoryMutex);
1777
1778         if (ml->status != GE_NONE)
1779         {
1780           g_print (_("%s: line: %d:Can't write ME memory entry number %d! Error: %d\n"),
1781                    __FILE__, __LINE__, i + 1, ml->status);
1782         }
1783         g_free (ml);
1784       }
1785       gtk_progress_set_value (GTK_PROGRESS (progressDialog.pbarME), i + 1);
1786       GUI_Refresh ();
1787     }
1788
1789     /* Save SIM memory */
1790     for (i = memoryStatus.MaxME; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
1791     {
1792       pbEntry = g_ptr_array_index (contactsMemory, i);
1793
1794 #ifdef XDEBUG    
1795       g_print ("%d;%s;%s;%d;%d;%d\n", pbEntry->entry.Empty, pbEntry->entry.Name,
1796                pbEntry->entry.Number, (int) pbEntry->entry.MemoryType, pbEntry->entry.Group,
1797                (int) pbEntry->status);
1798 #endif
1799
1800       if (pbEntry->status == E_Changed || pbEntry->status == E_Deleted)
1801       {
1802         if (pbEntry->status == E_Deleted)
1803         {
1804           pbEntry->entry.Name[0] = '\0';
1805           pbEntry->entry.Number[0] = '\0';
1806           pbEntry->entry.Group = 5;
1807         }
1808
1809         pbEntry->entry.Location = i - memoryStatus.MaxME + 1;
1810         ml = (D_MemoryLocation *) g_malloc (sizeof (D_MemoryLocation));
1811         ml->entry = &(pbEntry->entry);
1812         e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
1813         e->event = Event_WriteMemoryLocation;
1814         e->data = ml;
1815         GUI_InsertEvent (e);
1816         pthread_mutex_lock (&memoryMutex);
1817         pthread_cond_wait (&memoryCond, &memoryMutex);
1818         pthread_mutex_unlock (&memoryMutex);
1819
1820         if (ml->status != GE_NONE)
1821         {
1822           g_print(_("%s: line %d:Can't write SM memory entry number %d! Error: %d\n"),
1823                    __FILE__, __LINE__, i - memoryStatus.MaxME + 1, ml->status);
1824         }
1825         g_free (ml);
1826       }
1827       gtk_progress_set_value (GTK_PROGRESS (progressDialog.pbarSM), i - memoryStatus.MaxME + 1);
1828       GUI_Refresh ();
1829     }
1830
1831     statusInfo.ch_ME = statusInfo.ch_SM = 0;
1832     RefreshStatusInfo ();
1833     gtk_widget_hide (progressDialog.dialog);
1834   }
1835 }
1836
1837
1838 static GtkWidget *CreateSaveQuestionDialog (GtkSignalFunc SaveFunc,
1839                                             GtkSignalFunc DontSaveFunc)
1840 {
1841   GtkWidget *dialog;
1842   GtkWidget *button, *label, *hbox, *pixmap;
1843
1844   dialog = gtk_dialog_new ();
1845   gtk_window_set_title (GTK_WINDOW (dialog), _("Save changes?"));
1846   gtk_window_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
1847   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
1848   gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
1849   gtk_signal_connect (GTK_OBJECT (dialog), "delete_event",
1850                       GTK_SIGNAL_FUNC (DeleteEvent), NULL);
1851
1852   button = gtk_button_new_with_label (_("Save"));
1853   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
1854                       button, TRUE, TRUE, 10);
1855   gtk_signal_connect (GTK_OBJECT (button), "clicked",
1856                       GTK_SIGNAL_FUNC (SaveFunc), (gpointer) dialog);
1857   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1858   gtk_widget_grab_default (button);
1859   gtk_widget_show (button);
1860
1861   button = gtk_button_new_with_label (_("Don't save"));
1862   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
1863                       button, TRUE, TRUE, 10);
1864   gtk_signal_connect (GTK_OBJECT (button), "clicked",
1865                       GTK_SIGNAL_FUNC (DontSaveFunc), (gpointer) dialog);
1866   gtk_widget_show (button);
1867
1868   button = gtk_button_new_with_label (_("Cancel"));
1869   gtk_box_pack_start(GTK_BOX (GTK_DIALOG (dialog)->action_area),
1870                     button, TRUE, TRUE, 10);
1871   gtk_signal_connect(GTK_OBJECT (button), "clicked",
1872                      GTK_SIGNAL_FUNC (CancelDialog), (gpointer) dialog);
1873   gtk_widget_show (button);
1874
1875   gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5);
1876
1877   hbox = gtk_hbox_new (FALSE, 0);
1878   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
1879   gtk_widget_show (hbox);
1880
1881   pixmap = gtk_pixmap_new (questMark.pixmap, questMark.mask);
1882   gtk_box_pack_start (GTK_BOX (hbox), pixmap, FALSE, FALSE, 10);
1883   gtk_widget_show (pixmap);
1884
1885   label = gtk_label_new (_("You have made changes in your\ncontacts directory.\n\
1886 \n\nDo you want save these changes into phone?\n"));
1887   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
1888   gtk_widget_show (label);
1889
1890   return dialog;
1891 }
1892
1893
1894 static void OkExtPbkDialog (GtkWidget *w, gpointer data) {
1895
1896   ExtPbkDialog *d=(ExtPbkDialog*)data;
1897   GSM_NumberType numtype;
1898   gint i, found=999;
1899   gchar *chars;
1900
1901   if (w==d->gbutton) numtype=GSM_General;
1902   else if (w==d->mbutton) numtype=GSM_Mobile;
1903   else if (w==d->wbutton) numtype=GSM_Work;
1904   else if (w==d->fbutton) numtype=GSM_Fax;
1905   else if (w==d->hbutton) numtype=GSM_Home;
1906   else numtype=GSM_General;
1907
1908   /* Search through subentries */
1909
1910   for (i=0;i<d->pbEntry->entry.SubEntriesCount;i++) {
1911      if (d->pbEntry->entry.SubEntries[i].EntryType==GSM_Number)
1912        if (d->pbEntry->entry.SubEntries[i].NumberType==numtype)
1913          found=i;
1914   }
1915
1916   if (found>i) { /* Not found */
1917     found=d->pbEntry->entry.SubEntriesCount;
1918     d->pbEntry->entry.SubEntriesCount++;
1919     d->pbEntry->entry.SubEntries[found].EntryType=GSM_Number;
1920     d->pbEntry->entry.SubEntries[found].NumberType=numtype;
1921   }
1922
1923   chars=gtk_editable_get_chars(GTK_EDITABLE(d->entry),0,-1);
1924   strcpy(d->pbEntry->entry.SubEntries[found].data.Number,chars);
1925   g_free(chars);
1926
1927   /* Update the entry dialog */
1928   EditPbEntry(d->pbEntry,d->row);
1929
1930   gtk_widget_hide (d->dialog);
1931 }
1932
1933
1934 void ExtPbkChanged (GtkWidget *widget, gpointer data )
1935 {
1936   static ExtPbkDialog dialog = {NULL,NULL,0,NULL,NULL,NULL,NULL,NULL};
1937   GtkWidget *button;
1938   static GtkWidget *label;
1939   gchar *chars;
1940
1941
1942   if (dialog.dialog==NULL) {
1943
1944     dialog.dialog=gtk_dialog_new();
1945     
1946     gtk_window_set_title (GTK_WINDOW (dialog.dialog), _("Which Extended Phonebook Entry?"));
1947     gtk_window_set_modal(GTK_WINDOW (dialog.dialog), TRUE);
1948     gtk_container_set_border_width (GTK_CONTAINER (dialog.dialog), 10);
1949     gtk_signal_connect (GTK_OBJECT (dialog.dialog), "delete_event",
1950                         GTK_SIGNAL_FUNC (DeleteEvent), NULL);
1951
1952     dialog.gbutton = gtk_button_new_with_label (_("General"));
1953     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog.dialog)->vbox),
1954                         dialog.gbutton, TRUE, TRUE, 10);
1955     gtk_signal_connect (GTK_OBJECT (dialog.gbutton), "clicked",
1956                         GTK_SIGNAL_FUNC (OkExtPbkDialog), (gpointer)&dialog );
1957     gtk_widget_show (dialog.gbutton);
1958     dialog.mbutton = gtk_button_new_with_label (_("Mobile"));
1959     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog.dialog)->vbox),
1960                         dialog.mbutton, TRUE, TRUE, 10);
1961     gtk_signal_connect (GTK_OBJECT (dialog.mbutton), "clicked",
1962                         GTK_SIGNAL_FUNC (OkExtPbkDialog), (gpointer)&dialog );
1963     gtk_widget_show (dialog.mbutton);
1964     dialog.wbutton = gtk_button_new_with_label (_("Work"));
1965     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog.dialog)->vbox),
1966                         dialog.wbutton, TRUE, TRUE, 10);
1967     gtk_signal_connect (GTK_OBJECT (dialog.wbutton), "clicked",
1968                         GTK_SIGNAL_FUNC (OkExtPbkDialog), (gpointer)&dialog );
1969     gtk_widget_show (dialog.wbutton);
1970     dialog.fbutton = gtk_button_new_with_label (_("Fax"));
1971     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog.dialog)->vbox),
1972                         dialog.fbutton, TRUE, TRUE, 10);
1973     gtk_signal_connect (GTK_OBJECT (dialog.fbutton), "clicked",
1974                         GTK_SIGNAL_FUNC (OkExtPbkDialog), (gpointer)&dialog );
1975     gtk_widget_show (dialog.fbutton);
1976     dialog.hbutton = gtk_button_new_with_label (_("Home"));
1977     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog.dialog)->vbox),
1978                         dialog.hbutton, TRUE, TRUE, 10);
1979     gtk_signal_connect (GTK_OBJECT (dialog.hbutton), "clicked",
1980                         GTK_SIGNAL_FUNC (OkExtPbkDialog), (gpointer)&dialog );
1981     gtk_widget_show (dialog.hbutton);
1982
1983     button = gtk_button_new_with_label (_("Cancel"));
1984     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog.dialog)->action_area),
1985                         button, TRUE, TRUE, 10);
1986     gtk_signal_connect (GTK_OBJECT (button), "clicked",
1987                         GTK_SIGNAL_FUNC (CancelDialog), (gpointer) dialog.dialog);
1988     gtk_widget_show (button);
1989
1990     label = gtk_label_new("");
1991     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog.dialog)->vbox), label, FALSE, FALSE, 5);
1992     gtk_widget_show(label);
1993   }
1994
1995   chars=gtk_editable_get_chars(GTK_EDITABLE(widget),0,-1);
1996   gtk_label_set_text(GTK_LABEL(label),chars);
1997   g_free(chars);
1998   dialog.pbEntry=((EditEntryData*)data)->pbEntry;
1999   dialog.row=((EditEntryData*)data)->row;
2000   dialog.entry=widget;
2001   gtk_widget_show(dialog.dialog);
2002 }
2003
2004
2005
2006 void GUI_RefreshContacts (void)
2007 {
2008   PhonebookEntry *pbEntry;
2009   gint row_i = 0;
2010   register gint i;
2011
2012   if (contactsMemoryInitialized == FALSE)
2013     return;
2014
2015   gtk_clist_freeze (GTK_CLIST (clist));
2016   gtk_clist_clear (GTK_CLIST (clist));
2017
2018   for (i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
2019   {
2020     gchar *row[4];
2021
2022     pbEntry = g_ptr_array_index (contactsMemory, i);
2023     if (pbEntry->status != E_Empty && pbEntry->status != E_Deleted)
2024     {
2025       row[0] = pbEntry->entry.Name;
2026
2027       row[1] = pbEntry->entry.Number;
2028
2029       if (pbEntry->entry.MemoryType == GMT_ME)
2030         row[2] = "P";
2031       else
2032         row[2] = "S";
2033       if (GetModelFeature(FN_CALLERGROUPS)!=0)
2034         row[3] = xgnokiiConfig.callerGroups[pbEntry->entry.Group];
2035       else
2036         row[3] = "";
2037       gtk_clist_append (GTK_CLIST (clist), row);
2038       if (pbEntry->entry.MemoryType == GMT_ME)
2039         gtk_clist_set_pixmap (GTK_CLIST (clist), row_i, 2,
2040                               memoryPixmaps.phoneMemPix, memoryPixmaps.mask);
2041       else
2042         gtk_clist_set_pixmap (GTK_CLIST (clist), row_i, 2,
2043                               memoryPixmaps.simMemPix, memoryPixmaps.mask);
2044
2045       gtk_clist_set_row_data (GTK_CLIST (clist), row_i++, (gpointer) pbEntry);
2046     }
2047 #ifdef XDEBUG    
2048     g_print ("%d;%s;%s;%d;%d;%d\n", pbEntry->entry.Empty, pbEntry->entry.Name,
2049             pbEntry->entry.Number, (int) pbEntry->entry.MemoryType, pbEntry->entry.Group,
2050             (int) pbEntry->status);
2051 #endif
2052   }
2053
2054   gtk_clist_sort (GTK_CLIST (clist));
2055   gtk_clist_thaw (GTK_CLIST (clist));
2056 }
2057
2058
2059 static gint InsertPBEntryME (GSM_PhonebookEntry *entry)
2060 {
2061   PhonebookEntry *pbEntry;
2062
2063   if ((pbEntry = (PhonebookEntry *) g_malloc (sizeof (PhonebookEntry))) == NULL)
2064   {
2065     g_print (_("%s: line %d: Can't allocate memory!\n"), __FILE__, __LINE__);
2066     g_ptr_array_free (contactsMemory, TRUE);
2067     gtk_widget_hide (progressDialog.dialog);
2068     return (-1);
2069   }
2070
2071   pbEntry->entry = *entry;
2072
2073   if (*pbEntry->entry.Name == '\0' && *pbEntry->entry.Number == '\0')
2074     pbEntry->status = E_Empty;
2075   else
2076     pbEntry->status = E_Unchanged;
2077
2078   g_ptr_array_add (contactsMemory, (gpointer) pbEntry);
2079   gtk_progress_set_value (GTK_PROGRESS (progressDialog.pbarME), entry->Location);
2080   GUI_Refresh ();
2081
2082   return (GE_NONE);  
2083 }
2084
2085
2086 static gint InsertPBEntrySM (GSM_PhonebookEntry *entry)
2087 {
2088   PhonebookEntry *pbEntry;
2089
2090   if ((pbEntry = (PhonebookEntry *) g_malloc (sizeof (PhonebookEntry))) == NULL)
2091   {
2092     g_print (_("%s: line %d: Can't allocate memory!\n"), __FILE__, __LINE__);
2093     g_ptr_array_free (contactsMemory, TRUE);
2094     gtk_widget_hide (progressDialog.dialog);
2095     return (-1);
2096   }
2097
2098   pbEntry->entry = *entry;
2099
2100   if (*pbEntry->entry.Name == '\0' && *pbEntry->entry.Number == '\0')
2101     pbEntry->status = E_Empty;
2102   else
2103   {
2104     pbEntry->status = E_Unchanged;
2105     if (fbus3810)
2106     {
2107       memoryStatus.UsedSM++;
2108       memoryStatus.FreeSM--;
2109     }
2110   }
2111
2112   g_ptr_array_add (contactsMemory, (gpointer) pbEntry);
2113   gtk_progress_set_value (GTK_PROGRESS (progressDialog.pbarSM), entry->Location);
2114   GUI_Refresh ();
2115
2116   return (GE_NONE);  
2117 }
2118
2119
2120 static inline gint ReadFailedPBEntry (gint i)
2121 {
2122   g_ptr_array_free (contactsMemory, TRUE);
2123   gtk_widget_hide (progressDialog.dialog);
2124   return (0);
2125 }
2126
2127
2128 static void ReadContactsMain (void)
2129 {
2130   PhoneEvent *e;
2131   D_MemoryStatus *ms;
2132   D_MemoryLocationAll *mla;
2133   PhonebookEntry *pbEntry;
2134   register gint i;
2135
2136   fbus3810 = FALSE;
2137
2138   if (contactsMemoryInitialized == TRUE)
2139   {
2140     for (i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
2141     {
2142       pbEntry = g_ptr_array_index (contactsMemory, i);
2143       g_free (pbEntry);
2144     }
2145     g_ptr_array_free (contactsMemory, TRUE);
2146     contactsMemory = NULL;
2147     gtk_clist_clear (GTK_CLIST (clist));
2148     contactsMemoryInitialized = FALSE;
2149     memoryStatus.MaxME = memoryStatus.UsedME = memoryStatus.FreeME =
2150     memoryStatus.MaxSM = memoryStatus.UsedSM = memoryStatus.FreeSM = 0;
2151     statusInfo.ch_ME = statusInfo.ch_SM = 0;
2152     RefreshStatusInfo ();
2153   }
2154
2155   ms = (D_MemoryStatus *) g_malloc (sizeof (D_MemoryStatus));
2156   ms->memoryStatus.MemoryType = GMT_ME;
2157   e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
2158   e->event = Event_GetMemoryStatus;
2159   e->data = ms;
2160   GUI_InsertEvent (e);
2161   pthread_mutex_lock (&memoryMutex);
2162   pthread_cond_wait (&memoryCond, &memoryMutex);
2163   pthread_mutex_unlock (&memoryMutex);
2164
2165   if (ms->status != GE_NONE)
2166     /* Phone don't support ME (5110) */
2167     memoryStatus.MaxME = memoryStatus.UsedME = memoryStatus.FreeME = 0;
2168   else
2169   {
2170     memoryStatus.MaxME = ms->memoryStatus.Used + ms->memoryStatus.Free;
2171     memoryStatus.UsedME = ms->memoryStatus.Used;
2172     memoryStatus.FreeME = ms->memoryStatus.Free;
2173   }
2174
2175   ms->memoryStatus.MemoryType = GMT_SM;
2176   e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
2177   e->event = Event_GetMemoryStatus;
2178   e->data = ms;
2179   GUI_InsertEvent (e);
2180   pthread_mutex_lock (&memoryMutex);
2181   pthread_cond_wait (&memoryCond, &memoryMutex);
2182   pthread_mutex_unlock (&memoryMutex);
2183
2184   if (ms->status != GE_NONE)
2185   {
2186     fbus3810 = TRUE; /* I try to recognize memoryStatus.UsedSM while reading */
2187     gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Can't get SM memory status!\n\n\
2188 Setting max SIM entries to 100!\n"));
2189     memoryStatus.MaxSM = memoryStatus.FreeSM = 100;
2190     memoryStatus.UsedSM = 0;
2191     gtk_widget_show (errorDialog.dialog);
2192   }
2193   else
2194   {
2195     memoryStatus.MaxSM = ms->memoryStatus.Used + ms->memoryStatus.Free;
2196     memoryStatus.UsedSM = ms->memoryStatus.Used;
2197     memoryStatus.FreeSM = ms->memoryStatus.Free;
2198   }
2199   g_free (ms);
2200
2201   statusInfo.ch_ME = statusInfo.ch_SM = 0;
2202
2203   RefreshStatusInfo ();
2204
2205   if (progressDialog.dialog == NULL)
2206   {
2207     CreateProgressDialog (memoryStatus.MaxME, memoryStatus.MaxSM);
2208   }
2209
2210   gtk_progress_set_value (GTK_PROGRESS (progressDialog.pbarME), 0);
2211   gtk_progress_set_value (GTK_PROGRESS (progressDialog.pbarSM), 0);
2212   gtk_window_set_title (GTK_WINDOW (progressDialog.dialog), _("Getting entries"));
2213   gtk_widget_show_now (progressDialog.dialog);
2214
2215   contactsMemory = g_ptr_array_new ();
2216
2217   mla = (D_MemoryLocationAll *) g_malloc (sizeof (D_MemoryLocationAll));
2218   if (memoryStatus.MaxME > 0)
2219   {
2220     mla->min = 1;
2221     mla->max = memoryStatus.MaxME;
2222     mla->type = GMT_ME;
2223     mla->used = memoryStatus.UsedME; //MW
2224     mla->InsertEntry = InsertPBEntryME;
2225     mla->ReadFailed = ReadFailedPBEntry;
2226
2227     e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
2228     e->event = Event_GetMemoryLocationAll;
2229     e->data = mla;
2230     GUI_InsertEvent (e);
2231     pthread_mutex_lock (&memoryMutex);
2232     pthread_cond_wait (&memoryCond, &memoryMutex);
2233     pthread_mutex_unlock (&memoryMutex);
2234
2235     if (mla->status != GE_NONE)
2236     {
2237       g_free (mla);
2238       gtk_widget_hide (progressDialog.dialog);
2239       return;
2240     }
2241   }
2242
2243   mla->min = 1;
2244   mla->max = memoryStatus.MaxSM;
2245   mla->type = GMT_SM;
2246   mla->used = memoryStatus.UsedSM; //MW
2247   mla->InsertEntry = InsertPBEntrySM;
2248   mla->ReadFailed = ReadFailedPBEntry;
2249
2250   e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
2251   e->event = Event_GetMemoryLocationAll;
2252   e->data = mla;
2253   GUI_InsertEvent (e);
2254   pthread_mutex_lock (&memoryMutex);
2255   pthread_cond_wait (&memoryCond, &memoryMutex);
2256   pthread_mutex_unlock (&memoryMutex);
2257
2258   if (mla->status != GE_NONE)
2259   {
2260     g_free (mla);
2261     gtk_widget_hide (progressDialog.dialog);
2262     return;
2263   }
2264
2265   g_free (mla);
2266
2267   gtk_widget_hide (progressDialog.dialog);
2268
2269   contactsMemoryInitialized = TRUE;
2270   statusInfo.ch_ME = statusInfo.ch_SM = 0;
2271   GUIEventSend (GUI_EVENT_CONTACTS_CHANGED);
2272   GUIEventSend (GUI_EVENT_SMS_NUMBER_CHANGED);
2273 }
2274
2275
2276 static void ReadSaveCallback (GtkWidget *widget, gpointer data)
2277 {
2278   gtk_widget_hide (GTK_WIDGET (data));
2279   SaveContacts ();
2280   ReadContactsMain ();
2281 }
2282
2283
2284 static void ReadDontSaveCallback (GtkWidget *widget, gpointer data)
2285 {
2286   gtk_widget_hide (GTK_WIDGET (data));
2287   ReadContactsMain ();
2288 }
2289
2290
2291 static void ReadSaveContacts (void)
2292 {
2293   static GtkWidget *dialog = NULL;
2294
2295   if (dialog == NULL)
2296     dialog = CreateSaveQuestionDialog (ReadSaveCallback, ReadDontSaveCallback);
2297
2298   gtk_widget_show (dialog);
2299 }
2300
2301
2302 static void ReadContacts (void)
2303 {
2304   if (contactsMemoryInitialized == TRUE && (statusInfo.ch_ME || statusInfo.ch_SM))
2305     ReadSaveContacts ();
2306   else
2307     ReadContactsMain ();
2308 }
2309
2310
2311 inline void GUI_ReadContacts (void)
2312 {
2313   ReadContacts ();
2314 }
2315
2316
2317 inline void GUI_SaveContacts (void)
2318 {
2319   SaveContacts ();
2320 }
2321
2322
2323 inline void GUI_ShowContacts (void)
2324 {
2325   if (xgnokiiConfig.callerGroups[0] == NULL)
2326   {
2327     GUI_Refresh ();
2328     GUI_InitCallerGroupsInf ();
2329   }
2330   gtk_clist_set_column_visibility (GTK_CLIST (clist), 3, (GetModelFeature(FN_CALLERGROUPS)!=0));
2331   GUI_RefreshContacts ();
2332   gtk_widget_show (GUI_ContactsWindow);
2333 //  if (!contactsMemoryInitialized)
2334 //    ReadContacts ();
2335 }
2336
2337 static void ExportVCARD (FILE *f)
2338 {
2339   gchar buf2[10];
2340   register gint i,j;
2341   PhonebookEntry *pbEntry;
2342
2343   for(i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
2344   {
2345     pbEntry = g_ptr_array_index (contactsMemory, i);
2346
2347     if (pbEntry->status == E_Deleted || pbEntry->status == E_Empty)
2348       continue;
2349
2350     fprintf (f, "BEGIN:VCARD\n");
2351     fprintf (f, "VERSION:3.0\n");
2352     fprintf (f, "FN:%s\n", pbEntry->entry.Name);
2353     fprintf (f, "TEL;PREF:%s\n", pbEntry->entry.Number);
2354
2355     if (pbEntry->entry.MemoryType == GMT_ME)
2356       sprintf (buf2, "ME%d", i + 1);
2357     else
2358       sprintf (buf2, "SM%d", i - memoryStatus.MaxME + 1);
2359
2360     fprintf (f, "X_GSM_STORE_AT:%s\n", buf2);
2361     fprintf (f, "X_GSM_CALLERGROUP:%d\n", pbEntry->entry.Group);
2362
2363     /* Add ext. pbk info if required */
2364     if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
2365       for (j = 0; j < pbEntry->entry.SubEntriesCount; j++)
2366       {
2367         if (pbEntry->entry.SubEntries[j].EntryType == GSM_Number)
2368           fprintf (f, "TEL;UNKNOWN_%d:%s\n", pbEntry->entry.SubEntries[j].NumberType,
2369                    pbEntry->entry.SubEntries[j].data.Number);
2370       }
2371
2372     fprintf (f, "END:VCARD\n\n");
2373   }
2374   
2375   fclose (f);
2376 }
2377
2378
2379 static void ExportNative (FILE *f)
2380 {
2381   gchar buf[IO_BUF_LEN], buf2[10];
2382   register gint i,j;
2383   PhonebookEntry *pbEntry;
2384
2385
2386   for(i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
2387   {
2388     pbEntry = g_ptr_array_index (contactsMemory, i);
2389
2390     if (pbEntry->status != E_Deleted && pbEntry->status != E_Empty)
2391     {
2392       if (index (pbEntry->entry.Name, ';') != NULL)
2393       {
2394         strcpy (buf, "\"");
2395         strcat (buf, pbEntry->entry.Name);
2396         strcat (buf, "\";");
2397       }
2398       else
2399       {
2400         strcpy (buf, pbEntry->entry.Name);
2401         strcat (buf, ";");
2402       }
2403       
2404       if (index (pbEntry->entry.Number, ';') != NULL)
2405       {
2406         strcat (buf, "\"");
2407         strcat (buf, pbEntry->entry.Number);
2408         strcat (buf, "\";");
2409       }
2410       else
2411       {
2412         strcat (buf, pbEntry->entry.Number);
2413         strcat (buf, ";");
2414       }
2415
2416       if (pbEntry->entry.MemoryType == GMT_ME)
2417         sprintf (buf2, "B;%d;%d;", i + 1, pbEntry->entry.Group);
2418       else
2419         sprintf (buf2, "A;%d;%d;", i - memoryStatus.MaxME + 1, pbEntry->entry.Group);
2420       strcat (buf, buf2);
2421
2422       /* Add ext. pbk info if required */
2423       if (GetModelFeature(FN_PHONEBOOK)==F_PBK71)
2424       {
2425         for (j = 0; j < pbEntry->entry.SubEntriesCount; j++)
2426           if (pbEntry->entry.SubEntries[j].EntryType==GSM_Number)
2427           {
2428             sprintf(buf2,"%d;",pbEntry->entry.SubEntries[j].NumberType);
2429             strcat(buf,buf2);
2430
2431             if (index (pbEntry->entry.SubEntries[j].data.Number, ';') != NULL)
2432             {
2433               strcat (buf, "\"");
2434               strcat (buf, pbEntry->entry.SubEntries[j].data.Number);
2435               strcat (buf, "\";");
2436             }
2437             else
2438             {
2439               strcat (buf, pbEntry->entry.SubEntries[j].data.Number);
2440               strcat (buf, ";");
2441             }
2442           }
2443       }
2444       fprintf (f, "%s\n", buf);
2445     }
2446   }
2447   
2448   fclose(f);
2449 }
2450
2451
2452 static void ExportContactsMain (gchar *name)
2453 {
2454   FILE *f;
2455   gchar buf[IO_BUF_LEN];
2456
2457   if ((f = fopen (name, "w")) == NULL)
2458   {
2459     g_snprintf (buf, IO_BUF_LEN, _("Can't open file %s for writing!"), name);
2460     gtk_label_set_text (GTK_LABEL (errorDialog.text), buf);
2461     gtk_widget_show (errorDialog.dialog);
2462     return;
2463   }
2464
2465   if (strstr (name, ".vcard") || strstr (name, ".gcrd"))
2466     ExportVCARD (f);
2467   else
2468     ExportNative (f);
2469 }
2470
2471
2472 static void YesExportDialog (GtkWidget *w, gpointer data)
2473 {
2474   gtk_widget_hide (GTK_WIDGET (data));
2475   ExportContactsMain (exportDialogData.fileName);
2476 }
2477
2478
2479 static void OkExportDialog (GtkWidget *w, GtkFileSelection *fs)
2480 {
2481   static YesNoDialog dialog = { NULL, NULL};
2482   FILE *f;
2483   gchar err[80];
2484
2485   exportDialogData.fileName = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
2486   gtk_widget_hide (GTK_WIDGET (fs));
2487
2488   if ((f = fopen (exportDialogData.fileName, "r")) != NULL)
2489   {
2490     fclose (f);
2491     if (dialog.dialog == NULL)
2492     {
2493       CreateYesNoDialog (&dialog, YesExportDialog, CancelDialog, GUI_ContactsWindow);
2494       gtk_window_set_title (GTK_WINDOW (dialog.dialog), _("Overwrite file?"));
2495       g_snprintf ( err, 80, _("File %s already exist.\nOverwrite?"), exportDialogData.fileName); 
2496       gtk_label_set_text (GTK_LABEL(dialog.text), err);
2497     }
2498     gtk_widget_show (dialog.dialog);
2499   }
2500   else
2501     ExportContactsMain (exportDialogData.fileName);
2502 }
2503
2504
2505 static void ExportContacts (void)
2506 {
2507   static GtkWidget *fileDialog = NULL;
2508
2509   if (contactsMemoryInitialized)
2510   {
2511     if (fileDialog == NULL)
2512     {
2513       fileDialog = gtk_file_selection_new (_("Export"));
2514       gtk_signal_connect (GTK_OBJECT (fileDialog), "delete_event",
2515                           GTK_SIGNAL_FUNC (DeleteEvent), NULL);
2516       gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileDialog)->ok_button),
2517                           "clicked", GTK_SIGNAL_FUNC (OkExportDialog), (gpointer) fileDialog);
2518       gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileDialog)->cancel_button),
2519                           "clicked", GTK_SIGNAL_FUNC (CancelDialog), (gpointer) fileDialog);
2520     }
2521
2522     gtk_widget_show (fileDialog);
2523   }
2524 }
2525
2526
2527 static bool ParseLine (GSM_PhonebookEntry *entry, gint *num, gchar *buf)
2528 {
2529   register gint i = 0;
2530   size_t len;
2531   gchar s_num[5];
2532   gchar *endptr;
2533
2534   entry->Empty = FALSE;
2535   entry->SubEntriesCount=0;
2536
2537   len = strlen (buf);
2538   if (buf[i] == '"')
2539   {
2540     i++;
2541     while (i < len && i <= GSM_MAX_PHONEBOOK_NAME_LENGTH && buf[i] != '"')
2542     {
2543       entry->Name[i - 1] = buf[i];
2544       i++;
2545     }
2546     entry->Name[i - 1] = '\0';
2547     if (i >= len)
2548       return FALSE;
2549     if (buf[++i] != ';')
2550       return FALSE;
2551   }
2552   else
2553   {
2554     while (i < len && i < GSM_MAX_PHONEBOOK_NAME_LENGTH && buf[i] != ';')
2555     {
2556       entry->Name[i] = buf[i];
2557       i++;
2558     }
2559     entry->Name[i] = '\0';
2560     if (buf[i] != ';')
2561       return FALSE;
2562     if (i >= len)
2563       return FALSE;
2564   }
2565   buf += (i + 1);
2566   i = 0;
2567
2568   len = strlen (buf);
2569   if (buf[i] == '"')
2570   {
2571     i++;
2572     while (i < len && i <= GSM_MAX_PHONEBOOK_NUMBER_LENGTH && buf[i] != '"')
2573     {
2574       entry->Number[i - 1] = buf[i];
2575       i++;
2576     }
2577     entry->Number[i - 1] = '\0';
2578     if (i >= len)
2579       return FALSE;
2580     if (buf[++i] != ';')
2581       return FALSE;
2582   }
2583   else
2584   {
2585     while (i < len && i < GSM_MAX_PHONEBOOK_NUMBER_LENGTH && buf[i] != ';')
2586     {
2587       entry->Number[i] = buf[i];
2588       i++;
2589     }
2590     entry->Number[i] = '\0';
2591     if (buf[i] != ';')
2592       return FALSE;
2593     if (i >= len)
2594       return FALSE;
2595   }
2596   buf += (i + 1);
2597   i = 0;
2598
2599   if (!strncmp(buf, "B;", 2))
2600   {
2601     entry->MemoryType = GMT_ME;
2602     buf += 2;
2603   }
2604   else
2605   if (!strncmp(buf, "A;", 2))
2606   {
2607     entry->MemoryType = GMT_SM;
2608     buf += 2;
2609   }
2610   else
2611   if (!strncmp(buf, "ME;", 3))
2612   {
2613     entry->MemoryType = GMT_ME;
2614     buf += 3;
2615   }
2616   else
2617   if (!strncmp(buf, "SM;", 3))
2618   {
2619     entry->MemoryType = GMT_SM;
2620     buf += 3;
2621   }
2622   else
2623     return FALSE;
2624
2625   len = strlen (buf);
2626   while (i < len && i < 4 && buf[i] != ';')
2627   {
2628     s_num[i] = buf[i];
2629     i++;
2630   }
2631   s_num[i] = '\0';
2632   if (buf[i] != ';')
2633     return FALSE;
2634   if (i >= len)
2635     return FALSE;
2636   buf += (i + 1);
2637   i = 0;
2638
2639   *num = strtol (s_num, &endptr, 10);
2640   if (s_num == endptr)
2641     return FALSE;
2642   if (*num == LONG_MIN || *num == LONG_MAX)
2643     return FALSE;
2644
2645
2646   if ( *buf == '\n' || *buf == '\r')   /* for compatibility with NCDS */
2647     entry->Group = 5;
2648   else
2649   {
2650     len = strlen (buf);
2651     while (i < len && i < 4 && buf[i] != ';')
2652     {
2653       s_num[i] = buf[i];
2654       i++;
2655     }
2656     s_num[i] = '\0';
2657     if (buf[i] != ';')
2658       return FALSE;
2659     if (i >= len)
2660       return FALSE;
2661     
2662     entry->Group = strtol (s_num, &endptr, 10);
2663     if (s_num == endptr)
2664       return FALSE;
2665     if (entry->Group == LONG_MIN || entry->Group == LONG_MAX)
2666       return FALSE;
2667     if (entry->Group < 0 || entry->Group > 5)
2668       return FALSE;
2669
2670     buf += (i + 1);
2671     i = 0;
2672
2673     /* Ext Pbk Support */
2674     
2675     while (*buf!='\n')
2676     {
2677       entry->SubEntries[entry->SubEntriesCount].EntryType=GSM_Number;
2678       len = strlen (buf);
2679       while (i < len && i < 4 && buf[i] != ';')
2680       {
2681         s_num[i] = buf[i];
2682         i++;
2683       }
2684       s_num[i] = '\0';
2685       if (buf[i] != ';')
2686         return FALSE;
2687       if (i >= len)
2688         return FALSE;
2689       entry->SubEntries[entry->SubEntriesCount].NumberType=(GSM_NumberType)strtol (s_num, &endptr, 10);
2690       if (s_num == endptr)
2691         return FALSE;
2692       buf += (i + 1);
2693       i = 0;
2694       len = strlen (buf);
2695       while (i < len && i < GSM_MAX_PHONEBOOK_TEXT_LENGTH && buf[i] != ';')
2696       {
2697         entry->SubEntries[entry->SubEntriesCount].data.Number[i] = buf[i];
2698         i++;
2699       }
2700       entry->SubEntries[entry->SubEntriesCount].data.Number[i] = '\0';
2701       buf += (i + 1);
2702       i = 0;
2703       if (i >= len)
2704         return FALSE;
2705       entry->SubEntriesCount++;
2706     }
2707   }
2708
2709   return TRUE;
2710 }
2711
2712
2713 static void OkImportDialog (GtkWidget *w, GtkFileSelection *fs)
2714 {
2715   FILE *f;
2716   PhoneEvent *e;
2717   D_MemoryStatus *ms;
2718   PhonebookEntry *pbEntry;
2719   GSM_PhonebookEntry gsmEntry;
2720   gchar buf[IO_BUF_LEN];
2721   gchar *fileName;
2722   gint i;
2723
2724   fileName = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
2725   gtk_widget_hide (GTK_WIDGET (fs));
2726
2727   if ((f = fopen (fileName, "r")) == NULL)
2728   {
2729     g_snprintf (buf, IO_BUF_LEN, _("Can't open file %s for reading!"), fileName);
2730     gtk_label_set_text (GTK_LABEL(errorDialog.text), buf);
2731     gtk_widget_show (errorDialog.dialog);
2732     return;
2733   }
2734
2735   if (contactsMemoryInitialized == TRUE)
2736   {
2737     for(i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
2738     {
2739       pbEntry = g_ptr_array_index(contactsMemory, i);
2740       g_free(pbEntry);
2741     }
2742     g_ptr_array_free (contactsMemory, TRUE);
2743     contactsMemory = NULL;
2744     gtk_clist_clear (GTK_CLIST (clist));
2745     contactsMemoryInitialized = FALSE;
2746     memoryStatus.MaxME = memoryStatus.UsedME = memoryStatus.FreeME =
2747     memoryStatus.MaxSM = memoryStatus.UsedSM = memoryStatus.FreeSM = 0;
2748     statusInfo.ch_ME = statusInfo.ch_SM = 0;
2749     RefreshStatusInfo ();
2750   }
2751
2752   ms = (D_MemoryStatus *) g_malloc (sizeof (D_MemoryStatus));
2753   ms->memoryStatus.MemoryType = GMT_ME;
2754   e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
2755   e->event = Event_GetMemoryStatus;
2756   e->data = ms;
2757   GUI_InsertEvent (e);
2758   pthread_mutex_lock (&memoryMutex);
2759   pthread_cond_wait (&memoryCond, &memoryMutex);
2760   pthread_mutex_unlock (&memoryMutex);
2761
2762   if (ms->status != GE_NONE)
2763     /* Phone don't support ME (5110) */
2764     memoryStatus.MaxME = memoryStatus.UsedME = memoryStatus.FreeME = 0;
2765   else
2766   {
2767     memoryStatus.MaxME = ms->memoryStatus.Used + ms->memoryStatus.Free;
2768     memoryStatus.UsedME = 0;
2769     memoryStatus.FreeME = memoryStatus.MaxME;
2770   }
2771
2772   ms->memoryStatus.MemoryType = GMT_SM;
2773   e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
2774   e->event = Event_GetMemoryStatus;
2775   e->data = ms;
2776   GUI_InsertEvent (e);
2777   pthread_mutex_lock (&memoryMutex);
2778   pthread_cond_wait (&memoryCond, &memoryMutex);
2779   pthread_mutex_unlock (&memoryMutex);
2780
2781   if (ms->status != GE_NONE)
2782   {
2783     gtk_label_set_text (GTK_LABEL (errorDialog.text), _("Can't get SM memory status!\n\n\
2784 Setting max SIM entries set to 100!\n"));
2785     memoryStatus.MaxSM = memoryStatus.FreeSM = 100;
2786     memoryStatus.UsedSM = 0;
2787     gtk_widget_show (errorDialog.dialog);
2788   }
2789   else
2790   {
2791     memoryStatus.MaxSM = ms->memoryStatus.Used + ms->memoryStatus.Free;
2792     memoryStatus.UsedSM = 0;
2793     memoryStatus.FreeSM = memoryStatus.MaxSM;
2794   }
2795   g_free (ms);
2796
2797   statusInfo.ch_ME = statusInfo.ch_SM = 0;
2798
2799   RefreshStatusInfo ();
2800
2801   contactsMemory = g_ptr_array_new ();
2802
2803   for (i = 1; i <= memoryStatus.MaxME; i++)
2804   {
2805     if ((pbEntry = (PhonebookEntry *) g_malloc (sizeof (PhonebookEntry))) == NULL)
2806     {
2807       fclose (f);
2808       g_print (_("%s: line %d: Can't allocate memory!\n"), __FILE__, __LINE__);
2809       g_ptr_array_free (contactsMemory, TRUE);
2810       return;
2811     }
2812
2813     pbEntry->entry.Empty = FALSE;
2814     pbEntry->entry.Name[0] = '\0';
2815     pbEntry->entry.Number[0] = '\0';
2816     pbEntry->entry.MemoryType = GMT_ME;
2817     pbEntry->entry.Group = 5;
2818     pbEntry->status = E_Deleted; /* I must set status to E_Deleted, since I   */
2819                                  /* I want clear empty entries when saving to */
2820                                  /* to phone                                  */
2821     pbEntry->entry.SubEntriesCount=0;
2822
2823     g_ptr_array_add (contactsMemory, (gpointer) pbEntry);
2824     pbEntry = NULL;
2825   }
2826
2827   for (i = 1; i <= memoryStatus.MaxSM; i++)
2828   {
2829     if ((pbEntry = (PhonebookEntry *) g_malloc (sizeof (PhonebookEntry))) == NULL)
2830     {
2831       fclose (f);
2832       g_print (_("%s: line %d: Can't allocate memory!\n"), __FILE__, __LINE__);
2833       g_ptr_array_free (contactsMemory, TRUE);
2834       return;
2835     }
2836
2837     pbEntry->entry.Empty = FALSE;
2838     pbEntry->entry.Name[0] = '\0';
2839     pbEntry->entry.Number[0] = '\0';
2840     pbEntry->entry.MemoryType = GMT_SM;
2841     pbEntry->entry.Group = 5;
2842     pbEntry->status = E_Deleted;
2843     pbEntry->entry.SubEntriesCount=0;
2844
2845     g_ptr_array_add (contactsMemory, (gpointer) pbEntry);
2846     pbEntry = NULL;
2847   }
2848
2849
2850   while (fgets (buf, IO_BUF_LEN, f))
2851   {
2852     if (ParseLine (&gsmEntry, &i, buf))
2853     {
2854       if (gsmEntry.MemoryType == GMT_ME && memoryStatus.FreeME > 0 
2855           && i > 0 && i <= memoryStatus.MaxME)
2856       {
2857         pbEntry = g_ptr_array_index (contactsMemory, i - 1);
2858
2859         if (pbEntry->status == E_Deleted)
2860         {
2861           pbEntry->entry = gsmEntry;
2862           pbEntry->status = E_Changed;
2863           memoryStatus.UsedME++;
2864           memoryStatus.FreeME--;
2865           statusInfo.ch_ME = 1;
2866         }
2867       }
2868       else if (gsmEntry.MemoryType == GMT_SM && memoryStatus.FreeSM > 0
2869                && i > 0 && i <= memoryStatus.MaxSM)
2870       {
2871         pbEntry = g_ptr_array_index (contactsMemory, memoryStatus.MaxME + i - 1);
2872
2873         if (pbEntry->status == E_Deleted)
2874         {
2875           pbEntry->entry = gsmEntry;
2876           pbEntry->status = E_Changed;
2877           memoryStatus.UsedSM++;
2878           memoryStatus.FreeSM--;
2879           statusInfo.ch_SM = 1;
2880         }
2881       }
2882     }
2883   }
2884
2885   contactsMemoryInitialized = TRUE;
2886   RefreshStatusInfo ();
2887   GUIEventSend (GUI_EVENT_CONTACTS_CHANGED);
2888   GUIEventSend (GUI_EVENT_SMS_NUMBER_CHANGED);
2889 }
2890
2891
2892 static void ImportContactsFileDialog ()
2893 {
2894   static GtkWidget *fileDialog = NULL;
2895
2896   if (fileDialog == NULL)
2897   {
2898     fileDialog = gtk_file_selection_new (_("Import"));
2899     gtk_signal_connect (GTK_OBJECT (fileDialog), "delete_event",
2900                         GTK_SIGNAL_FUNC (DeleteEvent), NULL);
2901     gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileDialog)->ok_button),
2902                         "clicked", GTK_SIGNAL_FUNC (OkImportDialog), (gpointer) fileDialog);
2903     gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileDialog)->cancel_button),
2904                         "clicked", GTK_SIGNAL_FUNC (CancelDialog), (gpointer) fileDialog);
2905   }
2906
2907   gtk_widget_show (fileDialog);
2908 }
2909
2910
2911 static void ImportSaveCallback (GtkWidget *widget, gpointer data)
2912 {
2913   gtk_widget_hide (GTK_WIDGET (data));
2914   SaveContacts ();
2915   ImportContactsFileDialog ();
2916 }
2917
2918
2919 static void ImportDontSaveCallback (GtkWidget *widget, gpointer data)
2920 {
2921   gtk_widget_hide (GTK_WIDGET (data));
2922   ImportContactsFileDialog ();
2923 }
2924
2925
2926 void static ImportSaveContacts (void)
2927 {
2928   static GtkWidget *dialog = NULL;
2929
2930   if (dialog == NULL)
2931     dialog = CreateSaveQuestionDialog (ImportSaveCallback, ImportDontSaveCallback);
2932
2933   gtk_widget_show (dialog);
2934 }
2935
2936
2937 static void ImportContacts (void)
2938 {
2939   if (contactsMemoryInitialized == TRUE && (statusInfo.ch_ME || statusInfo.ch_SM))
2940     ImportSaveContacts ();
2941   else
2942     ImportContactsFileDialog ();
2943 }
2944
2945
2946 static void QuitSaveCallback (GtkWidget *widget, gpointer data)
2947 {
2948   PhoneEvent *e;
2949
2950   gtk_widget_hide (GTK_WIDGET (data));
2951   SaveContacts ();
2952   e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
2953   e->event = Event_Exit;
2954   e->data = NULL;
2955   GUI_InsertEvent (e);
2956   pthread_join (monitor_th, NULL); 
2957   gtk_main_quit ();
2958 }
2959
2960
2961 static void QuitDontSaveCallback (GtkWidget *widget, gpointer data)
2962 {
2963   PhoneEvent *e;
2964
2965   gtk_widget_hide (GTK_WIDGET (data));
2966   e = (PhoneEvent *) g_malloc (sizeof (PhoneEvent));
2967   e->event = Event_Exit;
2968   e->data = NULL;
2969   GUI_InsertEvent (e);
2970   pthread_join (monitor_th, NULL); 
2971   gtk_main_quit ();
2972 }
2973
2974
2975 void GUI_QuitSaveContacts (void)
2976 {
2977   static GtkWidget *dialog = NULL;
2978
2979   if (dialog == NULL)
2980     dialog = CreateSaveQuestionDialog (QuitSaveCallback, QuitDontSaveCallback);
2981
2982   gtk_widget_show (dialog);
2983 }
2984
2985
2986 /* Function take number and return name belonged to number.
2987    If no name is found, return NULL;
2988    Do not modify returned name!
2989 */
2990 gchar *GUI_GetName (gchar *number)
2991 {
2992   PhonebookEntry *pbEntry;
2993   register gint i;
2994
2995   if (contactsMemoryInitialized == FALSE || number == NULL)
2996     return (gchar *)NULL;
2997
2998   for(i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
2999   {
3000     pbEntry = g_ptr_array_index (contactsMemory, i);
3001
3002     if (pbEntry->status == E_Empty || pbEntry->status == E_Deleted)
3003       continue;
3004
3005     if (strcmp (pbEntry->entry.Number, number) == 0)
3006       return pbEntry->entry.Name;
3007   }
3008
3009   for (i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
3010   {
3011     pbEntry = g_ptr_array_index (contactsMemory, i);
3012
3013     if (pbEntry->status == E_Empty || pbEntry->status == E_Deleted)
3014       continue;
3015
3016     if (strrncmp (pbEntry->entry.Number, number, 9) == 0)
3017       return pbEntry->entry.Name;
3018   }
3019
3020   return NULL;
3021 }
3022
3023
3024 gchar *GUI_GetNameExact (gchar *number)
3025 {
3026   PhonebookEntry *pbEntry;
3027   register gint i;
3028
3029   if (contactsMemoryInitialized == FALSE || number == NULL)
3030     return (gchar *)NULL;
3031
3032   for(i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
3033   {
3034     pbEntry = g_ptr_array_index (contactsMemory, i);
3035
3036     if (pbEntry->status == E_Empty || pbEntry->status == E_Deleted)
3037       continue;
3038
3039     if (strcmp (pbEntry->entry.Number, number) == 0)
3040       return pbEntry->entry.Name;
3041   }
3042
3043   return NULL;
3044 }
3045
3046
3047 gchar *GUI_GetNumber (gchar *name)
3048 {
3049   PhonebookEntry *pbEntry;
3050   register gint i;
3051
3052   if (contactsMemoryInitialized == FALSE || name == NULL || *name == '\0')
3053     return (gchar *)NULL;
3054
3055   for(i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
3056   {
3057     pbEntry = g_ptr_array_index (contactsMemory, i);
3058
3059     if (pbEntry->status == E_Empty || pbEntry->status == E_Deleted)
3060       continue;
3061
3062     if (strcmp (pbEntry->entry.Name, name) == 0)
3063       return pbEntry->entry.Number;
3064   }
3065
3066   return NULL;
3067 }
3068
3069
3070 static void SelectDialogClickEntry (GtkWidget        *clist,
3071                                     gint              row,
3072                                     gint              column,
3073                                     GdkEventButton   *event,
3074                                     SelectContactData *data )
3075 {
3076   if(event && event->type == GDK_2BUTTON_PRESS)
3077     gtk_signal_emit_by_name(GTK_OBJECT (data->okButton), "clicked");
3078 }
3079
3080
3081 SelectContactData *GUI_SelectContactDialog (void)
3082 {
3083   PhonebookEntry *pbEntry;
3084   static SelectContactData selectContactData;
3085   SortColumn *sColumn;
3086   gchar *titles[4] = { "Name", "Number", "Memory", "Group"};
3087   gint row_i = 0;
3088   register gint i;
3089   gchar string[100];
3090
3091   if (contactsMemoryInitialized == FALSE)
3092     return NULL;
3093
3094   selectContactData.dialog = gtk_dialog_new ();
3095   gtk_widget_set_usize (GTK_WIDGET (selectContactData.dialog), 436, 200);
3096   gtk_window_set_title (GTK_WINDOW (selectContactData.dialog), _("Select contacts"));
3097   gtk_window_set_modal (GTK_WINDOW (selectContactData.dialog), TRUE);
3098
3099   selectContactData.okButton = gtk_button_new_with_label (_("Ok"));
3100   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (selectContactData.dialog)->action_area),
3101                       selectContactData.okButton, TRUE, TRUE, 10);
3102   GTK_WIDGET_SET_FLAGS (selectContactData.okButton, GTK_CAN_DEFAULT);
3103   gtk_widget_grab_default (selectContactData.okButton);
3104   gtk_widget_show (selectContactData.okButton);
3105
3106   selectContactData.cancelButton = gtk_button_new_with_label (_("Cancel"));
3107   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (selectContactData.dialog)->action_area),
3108                       selectContactData.cancelButton, TRUE, TRUE, 10);
3109   gtk_widget_show (selectContactData.cancelButton);
3110
3111   selectContactData.clist = gtk_clist_new_with_titles (4, titles);
3112   gtk_clist_set_shadow_type (GTK_CLIST (selectContactData.clist), GTK_SHADOW_OUT);
3113   gtk_clist_set_compare_func (GTK_CLIST (selectContactData.clist), CListCompareFunc);
3114   gtk_clist_set_sort_column (GTK_CLIST (selectContactData.clist), 0);
3115   gtk_clist_set_sort_type (GTK_CLIST (selectContactData.clist), GTK_SORT_ASCENDING);
3116   gtk_clist_set_auto_sort (GTK_CLIST (selectContactData.clist), FALSE);
3117   gtk_clist_set_selection_mode (GTK_CLIST (selectContactData.clist), GTK_SELECTION_EXTENDED);
3118
3119   gtk_clist_set_column_width (GTK_CLIST(selectContactData.clist), 0, 150);
3120   gtk_clist_set_column_width (GTK_CLIST(selectContactData.clist), 1, 115);
3121   gtk_clist_set_column_width (GTK_CLIST(selectContactData.clist), 3, 70);
3122   gtk_clist_set_column_justification (GTK_CLIST(selectContactData.clist), 2, GTK_JUSTIFY_CENTER);
3123   gtk_clist_set_column_visibility (GTK_CLIST(selectContactData.clist), 3, (GetModelFeature(FN_CALLERGROUPS)!=0));
3124
3125   for (i = 0; i < 4; i++)
3126   {
3127     if ((sColumn = g_malloc (sizeof (SortColumn))) == NULL)
3128     {
3129       g_print (_("Error: %s: line %d: Can't allocate memory!\n"), __FILE__, __LINE__);
3130       return NULL;
3131     }
3132     sColumn->clist = selectContactData.clist;
3133     sColumn->column = i;
3134     gtk_signal_connect (GTK_OBJECT (GTK_CLIST (selectContactData.clist)->column[i].button), "clicked",
3135                         GTK_SIGNAL_FUNC (SetSortColumn), (gpointer) sColumn);
3136   }
3137
3138   gtk_signal_connect (GTK_OBJECT (selectContactData.clist), "select_row",
3139                       GTK_SIGNAL_FUNC (SelectDialogClickEntry),
3140                       (gpointer) &selectContactData);
3141
3142   selectContactData.clistScrolledWindow = gtk_scrolled_window_new (NULL, NULL);
3143   gtk_container_add (GTK_CONTAINER (selectContactData.clistScrolledWindow),
3144                      selectContactData.clist);
3145   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (selectContactData.clistScrolledWindow),
3146                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3147   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (selectContactData.dialog)->vbox),
3148                       selectContactData.clistScrolledWindow, 
3149                       TRUE, TRUE, 0);
3150
3151   gtk_widget_show (selectContactData.clist);
3152   gtk_widget_show (selectContactData.clistScrolledWindow);
3153
3154   if (xgnokiiConfig.callerGroups[0] == NULL)
3155     GUI_InitCallerGroupsInf ();
3156
3157   gtk_clist_freeze (GTK_CLIST (selectContactData.clist));
3158   for (i = 0; i < memoryStatus.MaxME + memoryStatus.MaxSM; i++)
3159   {
3160     gchar *row[4];
3161
3162     pbEntry = g_ptr_array_index (contactsMemory, i);
3163     if (pbEntry->status != E_Empty && pbEntry->status != E_Deleted)
3164     {
3165       row[0] = pbEntry->entry.Name;
3166  
3167       if (pbEntry->entry.SubEntriesCount>0) {
3168         snprintf(string,100,"%s *",pbEntry->entry.Number);
3169         row[1]=string;
3170       } else row[1] = pbEntry->entry.Number;
3171
3172
3173       if (pbEntry->entry.MemoryType == GMT_ME)
3174         row[2] = "P";
3175       else
3176         row[2] = "S";
3177       if (GetModelFeature(FN_CALLERGROUPS)!=0)
3178         row[3] = xgnokiiConfig.callerGroups[pbEntry->entry.Group];
3179       else
3180         row[3] = "";
3181       gtk_clist_append (GTK_CLIST (selectContactData.clist), row);
3182       if (pbEntry->entry.MemoryType == GMT_ME)
3183         gtk_clist_set_pixmap (GTK_CLIST (selectContactData.clist), row_i, 2,
3184                               memoryPixmaps.phoneMemPix, memoryPixmaps.mask);
3185       else
3186         gtk_clist_set_pixmap (GTK_CLIST (selectContactData.clist), row_i, 2,
3187                               memoryPixmaps.simMemPix, memoryPixmaps.mask);
3188
3189      gtk_clist_set_row_data (GTK_CLIST (selectContactData.clist), row_i++, (gpointer) pbEntry);
3190     }
3191   }
3192
3193   gtk_clist_sort (GTK_CLIST (selectContactData.clist));
3194   gtk_clist_thaw (GTK_CLIST (selectContactData.clist));
3195
3196   gtk_widget_show (selectContactData.dialog);
3197
3198   return &selectContactData;
3199 }
3200
3201
3202 static GtkItemFactoryEntry menu_items[] = {
3203   { NULL,               NULL,           NULL, 0, "<Branch>"},
3204   { NULL,               "<control>R",   ReadContacts, 0, NULL},
3205   { NULL,               "<control>S",   SaveContacts, 0, NULL},
3206   { NULL,               NULL,           NULL, 0, "<Separator>"},
3207   { NULL,               "<control>I",   ImportContacts, 0, NULL},
3208   { NULL,               "<control>E",   ExportContacts, 0, NULL},
3209   { NULL,               NULL,           NULL, 0, "<Separator>"},
3210   { NULL,               "<control>W",   CloseContacts, 0, NULL},
3211   { NULL,               NULL,           NULL, 0, "<Branch>"},
3212   { NULL,               "<control>N",   NewEntry, 0, NULL},
3213   { NULL,               "<control>U",   DuplicateEntry, 0, NULL},
3214   { NULL,               NULL,           EditEntry, 0, NULL},
3215   { NULL,               "<control>D",   DeleteEntry, 0, NULL},
3216   { NULL,               NULL,           NULL, 0, "<Separator>"},
3217   { NULL,               "<control>C",   ChMemType, 0, NULL},
3218   { NULL,               NULL,           NULL, 0, "<Separator>"},
3219   { NULL,               "<control>F",   FindFirstEntry, 0, NULL},
3220   { NULL,               "<control>L",   SearchEntry, 0, NULL},
3221   { NULL,               NULL,           NULL, 0, "<Separator>"},
3222   { NULL,               "<control>A",   SelectAll, 0, NULL},
3223   { NULL,               NULL,           NULL, 0, "<Branch>"},
3224   { NULL,               "<control>V",   DialVoice, 0, NULL},
3225   { NULL,               NULL,           NULL, 0, "<LastBranch>"},
3226   { NULL,               NULL,           Help1, 0, NULL},
3227   { NULL,               NULL,           GUI_ShowAbout, 0, NULL},
3228 };
3229
3230
3231 static void InitMainMenu (void)
3232 {
3233   menu_items[0].path = g_strdup (_("/_File"));
3234   menu_items[1].path = g_strdup (_("/File/_Read from phone"));
3235   menu_items[2].path = g_strdup (_("/File/_Save to phone"));
3236   menu_items[3].path = g_strdup (_("/File/Sep1"));
3237   menu_items[4].path = g_strdup (_("/File/_Import from file"));
3238   menu_items[5].path = g_strdup (_("/File/_Export to file"));
3239   menu_items[6].path = g_strdup (_("/File/Sep2"));
3240   menu_items[7].path = g_strdup (_("/File/_Close"));
3241   menu_items[8].path = g_strdup (_("/_Edit"));
3242   menu_items[9].path = g_strdup (_("/Edit/_New"));
3243   menu_items[10].path = g_strdup (_("/Edit/D_uplicate"));
3244   menu_items[11].path = g_strdup (_("/Edit/_Edit"));
3245   menu_items[12].path = g_strdup (_("/Edit/_Delete"));
3246   menu_items[13].path = g_strdup (_("/Edit/Sep3"));
3247   menu_items[14].path = g_strdup (_("/Edit/_Change memory type"));
3248   menu_items[15].path = g_strdup (_("/Edit/Sep4"));
3249   menu_items[16].path = g_strdup (_("/Edit/_Find"));
3250   menu_items[17].path = g_strdup (_("/Edit/Find ne_xt"));
3251   menu_items[18].path = g_strdup (_("/Edit/Sep5"));
3252   menu_items[19].path = g_strdup (_("/Edit/Select _all"));
3253   menu_items[20].path = g_strdup (_("/_Dial"));
3254   menu_items[21].path = g_strdup (_("/Dial/Dial _voice"));
3255   menu_items[22].path = g_strdup (_("/_Help"));
3256   menu_items[23].path = g_strdup (_("/Help/_Help"));
3257   menu_items[24].path = g_strdup (_("/Help/_About"));
3258 }
3259
3260
3261 void GUI_CreateContactsWindow (void)
3262 {
3263   int nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3264   GtkItemFactory *item_factory;
3265   GtkAccelGroup *accel_group;
3266   SortColumn *sColumn;
3267   GtkWidget *menubar;
3268   GtkWidget *main_vbox;
3269   GtkWidget *toolbar;
3270   GtkWidget *clistScrolledWindow;
3271   GtkWidget *status_hbox;
3272   register gint i;
3273   gchar *titles[4] = { _("Name"), _("Number"), _("Memory"), _("Group")};
3274
3275   InitMainMenu ();
3276   contactsMemoryInitialized = FALSE;
3277   GUI_ContactsWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3278   gtk_window_set_title (GTK_WINDOW (GUI_ContactsWindow), _("Contacts"));
3279   gtk_widget_set_usize (GTK_WIDGET (GUI_ContactsWindow), 436, 220);
3280   //gtk_container_set_border_width (GTK_CONTAINER (GUI_ContactsWindow), 10);
3281   gtk_signal_connect (GTK_OBJECT (GUI_ContactsWindow), "delete_event",
3282                       GTK_SIGNAL_FUNC (DeleteEvent), NULL);
3283   gtk_widget_realize (GUI_ContactsWindow);
3284
3285   accel_group = gtk_accel_group_new ();
3286   item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", 
3287                                        accel_group);
3288
3289   gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
3290
3291   gtk_accel_group_attach (accel_group, GTK_OBJECT (GUI_ContactsWindow));
3292
3293   /* Finally, return the actual menu bar created by the item factory. */ 
3294   menubar = gtk_item_factory_get_widget (item_factory, "<main>");
3295
3296   main_vbox = gtk_vbox_new (FALSE, 1);
3297   gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
3298   gtk_container_add (GTK_CONTAINER (GUI_ContactsWindow), main_vbox);
3299   gtk_widget_show (main_vbox);
3300
3301   gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, FALSE, 0);
3302   gtk_widget_show (menubar);
3303
3304   /* Create the toolbar */
3305
3306   toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_ICONS);
3307   gtk_toolbar_set_button_relief (GTK_TOOLBAR (toolbar), GTK_RELIEF_NORMAL);
3308
3309   gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Read from phone"), NULL,
3310                            NewPixmap(Read_xpm, GUI_ContactsWindow->window,
3311                            &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL]),
3312                            (GtkSignalFunc) ReadContacts, NULL);
3313   gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Save to phone"), NULL,
3314                            NewPixmap(Send_xpm, GUI_ContactsWindow->window,
3315                            &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL]),
3316                            (GtkSignalFunc) SaveContacts, NULL);
3317
3318   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
3319
3320   gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Import from file"), NULL,
3321                            NewPixmap(Open_xpm, GUI_ContactsWindow->window,
3322                            &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL]),
3323                            (GtkSignalFunc) ImportContacts, NULL);
3324   gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Export to file"), NULL,
3325                            NewPixmap(Save_xpm, GUI_ContactsWindow->window,
3326                            &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL]),
3327                            (GtkSignalFunc) ExportContacts, NULL);
3328
3329   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
3330
3331   gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("New entry"), NULL,
3332                            NewPixmap(New_xpm, GUI_ContactsWindow->window,
3333                            &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL]),
3334                            (GtkSignalFunc) NewEntry, NULL);
3335   gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Duplicate entry"), NULL,
3336                            NewPixmap(Duplicate_xpm, GUI_ContactsWindow->window,
3337                            &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL]),
3338                            (GtkSignalFunc) DuplicateEntry, NULL);
3339   gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Edit entry"), NULL,
3340                            NewPixmap(Edit_xpm, GUI_ContactsWindow->window,
3341                            &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL]),
3342                            (GtkSignalFunc) EditEntry, NULL);
3343   gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Delete entry"), NULL,
3344                            NewPixmap(Delete_xpm, GUI_ContactsWindow->window,
3345                            &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL]),
3346                            (GtkSignalFunc) DeleteEntry, NULL);
3347
3348   gtk_toolbar_append_space (GTK_TOOLBAR(toolbar));
3349
3350   gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Dial voice"), NULL,
3351                            NewPixmap(Dial_xpm, GUI_ContactsWindow->window,
3352                            &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL]),
3353                            (GtkSignalFunc) DialVoice, NULL);
3354
3355 //  gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
3356
3357   gtk_box_pack_start (GTK_BOX (main_vbox), toolbar, FALSE, FALSE, 0);
3358   gtk_widget_show (toolbar);
3359
3360
3361   clist = gtk_clist_new_with_titles (4, titles);
3362   gtk_clist_set_shadow_type (GTK_CLIST (clist), GTK_SHADOW_OUT);
3363   gtk_clist_set_compare_func (GTK_CLIST (clist), CListCompareFunc);
3364   gtk_clist_set_sort_column (GTK_CLIST (clist), 0);
3365   gtk_clist_set_sort_type (GTK_CLIST (clist), GTK_SORT_ASCENDING);
3366   gtk_clist_set_auto_sort (GTK_CLIST (clist), FALSE);
3367   gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_EXTENDED);
3368
3369   gtk_clist_set_column_width (GTK_CLIST (clist), 0, 150);
3370   gtk_clist_set_column_width (GTK_CLIST (clist), 1, 115);
3371   gtk_clist_set_column_width (GTK_CLIST (clist), 3, 70);
3372   gtk_clist_set_column_justification (GTK_CLIST (clist), 2, GTK_JUSTIFY_CENTER);
3373 //  gtk_clist_set_column_visibility (GTK_CLIST (clist), 3, (GetModelFeature(FN_CALLERGROUPS)!=0));
3374
3375   for (i = 0; i < 4; i++)
3376   {
3377     if ((sColumn = g_malloc (sizeof (SortColumn))) == NULL)
3378     {
3379       g_print (_("Error: %s: line %d: Can't allocate memory!\n"), __FILE__, __LINE__);
3380       gtk_main_quit ();
3381     }
3382     sColumn->clist = clist;
3383     sColumn->column = i;
3384     gtk_signal_connect (GTK_OBJECT (GTK_CLIST (clist)->column[i].button), "clicked",
3385                         GTK_SIGNAL_FUNC (SetSortColumn), (gpointer) sColumn);
3386   }
3387
3388   gtk_signal_connect (GTK_OBJECT (clist), "select_row",
3389                       GTK_SIGNAL_FUNC (ClickEntry), NULL);
3390
3391   clistScrolledWindow = gtk_scrolled_window_new (NULL, NULL);
3392   gtk_container_add (GTK_CONTAINER (clistScrolledWindow), clist);
3393   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (clistScrolledWindow),
3394                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3395   gtk_box_pack_start (GTK_BOX (main_vbox), clistScrolledWindow, 
3396                       TRUE, TRUE, 0);
3397
3398   gtk_widget_show (clist);
3399   gtk_widget_show (clistScrolledWindow);
3400
3401   status_hbox = gtk_hbox_new (FALSE,20);
3402   gtk_box_pack_start (GTK_BOX (main_vbox), status_hbox, FALSE, FALSE, 0);
3403   gtk_widget_show (status_hbox);
3404
3405   memoryStatus.MaxME = memoryStatus.UsedME = memoryStatus.FreeME =
3406   memoryStatus.MaxSM = memoryStatus.UsedSM = memoryStatus.FreeSM = 0;
3407   statusInfo.ch_ME = statusInfo.ch_SM = 0; 
3408
3409   statusInfo.label = gtk_label_new ("");
3410   RefreshStatusInfo ();
3411   gtk_box_pack_start (GTK_BOX (status_hbox), statusInfo.label, FALSE, FALSE, 10);
3412   gtk_widget_show (statusInfo.label);
3413
3414   memoryPixmaps.simMemPix = gdk_pixmap_create_from_xpm_d (GUI_ContactsWindow->window,
3415                                 &memoryPixmaps.mask,
3416                                 &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL],
3417                                 sim_xpm);
3418
3419   memoryPixmaps.phoneMemPix = gdk_pixmap_create_from_xpm_d (GUI_ContactsWindow->window,
3420                                   &memoryPixmaps.mask,
3421                                   &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL],
3422                                   phone_xpm);
3423
3424   questMark.pixmap = gdk_pixmap_create_from_xpm_d (GUI_ContactsWindow->window,
3425                          &questMark.mask,
3426                          &GUI_ContactsWindow->style->bg[GTK_STATE_NORMAL],
3427                          quest_xpm);
3428
3429   CreateErrorDialog (&errorDialog, GUI_ContactsWindow);
3430   GUIEventAdd (GUI_EVENT_CONTACTS_CHANGED, GUI_RefreshContacts);
3431   GUIEventAdd (GUI_EVENT_CALLERS_GROUPS_CHANGED, GUI_RefreshGroupMenu);
3432 }
3433