This commit was manufactured by cvs2svn to create tag 'bp_uc'.
[gnokii.git] / common / files / gsm-filetypes.c
1 /*
2
3   G N O K I I
4
5   A Linux/Unix toolset and driver for Nokia mobile phones.
6
7   Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml. 
8
9   Released under the terms of the GNU GPL, see file COPYING for more details.
10         
11   Functions to read and write common file types.
12  
13 */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <sys/stat.h>
20 #ifndef VC6
21 #include <unistd.h>
22 #endif
23
24 #include "gsm-common.h"
25 #include "gsm-ringtones.h"
26 #include "gsm-bitmaps.h"
27 #include "files/gsm-filetypes.h"
28 #include "files/midifile.h"
29 #include "gsm-coding.h"
30 #include "misc.h"
31 #include "newmodules/n7110.h"
32 #include "newmodules/n6110.h"
33
34 #ifdef XPM
35   #include <X11/xpm.h>
36 #endif
37
38 /**
39 * GetvCalTime
40 *
41 * Fills vCalendar time string into GSM_DateTime structure
42 *
43 * in:
44 *   dt:  datetime structure
45 *   time:  string in format yyyymmddThhmmss
46 * out:
47 *   <>0 if error
48 */
49 int GetvCalTime(GSM_DateTime *dt, char *time)
50 {
51   char year[5]="", month[3]="", day[3]="", hour[3]="", minute[3]="", second[3]="";
52   dt->Year=dt->Month=dt->Day=dt->Hour=dt->Minute=dt->Second=dt->Timezone=0;
53
54   strncpy(year, time, 4);
55   strncpy(month, time+4, 2);
56   strncpy(day, time+6, 2);
57   strncpy(hour, time+9, 2);
58   strncpy(minute, time+11, 2);
59   strncpy(second, time+13, 2);
60
61 /* FIXME: Should check ranges... */
62   dt->Year=atoi(year);
63   dt->Month=atoi(month);
64   dt->Day=atoi(day);
65   dt->Hour=atoi(hour);
66   dt->Minute=atoi(minute);
67   dt->Second=atoi(second);
68 /* FIXME */
69   dt->Timezone=0;
70
71   return 0;
72 }
73
74 /**
75 * FillCalendarNote
76 *
77 * Fills calendar data from strings into calendar note
78 *
79 * in:
80 *   note:  calendar note structure
81 *   type:  type of calendar note
82 *   text:  text or phonenumber
83 *   time:  string in format yyyymmddThhmmss
84 *   alarm: dito
85 * out:
86 *   <>0 if error
87 */
88 int FillCalendarNote(GSM_CalendarNote *note, char *type,
89                        char *text, char *time, char *alarm)
90 {
91   GetvCalTime(&note->Time, time);
92   GetvCalTime(&note->Alarm, alarm);
93
94   note->Location=0; 
95
96   strncpy(note->Text, text, MAX_CALENDAR_TEXT_LENGTH);
97   strcpy(note->Phone, ""); /* correct in most cases */
98
99   /* FIXME: Handle additional strings, maybe from configuration file */
100
101   if(!strcmp(type, "PHONE CALL"))
102   {
103     strncpy(note->Phone, text, MAX_CALENDAR_PHONE_LENGTH);
104     note->Type=GCN_CALL;
105   }
106   else if(!strcmp(type, "MEETING"))
107       note->Type=GCN_MEETING;
108   else if(!strcmp(type, "SPECIAL OCCASION"))
109       note->Type=GCN_BIRTHDAY;
110   else
111       note->Type=GCN_REMINDER;
112
113   return 0;
114 }
115
116 /**
117 * GSM_ReadVCalendarFile
118 *
119 * Reads vCalendar file
120 *
121 * in:
122 *   FileName: name of vCalendar file 
123 *   cnote:  pointer to calendar note
124 *   number:  number in file of calendar note to read
125 * out:
126 *   <>0 if error
127 */
128 GSM_Error GSM_ReadVCalendarFile(char *FileName, GSM_CalendarNote *cnote, int *number)
129 {
130   FILE *file;
131   char type[21]="", text[40]="", time[16]="", alarm[16]="";
132         char phone[40]="";
133         long recurr=0L;
134         char altype=0x00;
135
136   int veventcounter=0;
137   int isOK=0;
138   
139   bool NoteOK=false;
140
141   char *Line, OLine[1024], BackLine[1024];
142
143   Line = OLine;
144
145   file=fopen(FileName, "r");    
146   if (!file) {
147 #ifdef DEBUG
148     fprintf(stderr, _("File cannot be opened!\n"));
149 #endif
150     return GE_CANTOPENFILE;
151   }
152
153   /* Go through data from file. */
154   while (GetLine(file, Line, sizeof(OLine))!=-1) {
155
156     strcpy(BackLine, Line);
157
158     switch (isOK) {
159       case 0:
160         if (!strcmp(Line,"BEGIN:VCALENDAR"))
161           isOK++;
162         break;
163       case 1:
164         if (!strcmp(Line,"BEGIN:VEVENT")) {
165           isOK++;
166           veventcounter++;
167         }
168         if (!strcmp(Line,"END:VCALENDAR"))
169           isOK--;       
170         break;
171       case 2:
172         if (veventcounter==*number) {
173           if (!strncmp(Line,"CATEGORIES:",11)) {
174             strncpy(type,Line+11,strlen(Line)-11);
175             type[strlen(Line)-11]=0;
176           }
177           if (!strncmp(Line,"DESCRIPTION:",12)) {
178             strncpy(phone,Line+12,strlen(Line)-12);
179             phone[strlen(Line)-12]=0;
180           }
181           if (!strncmp(Line,"SUMMARY:",8)) {
182             strncpy(text,Line+8,strlen(Line)-8);
183             text[strlen(Line)-8]=0;
184           }
185           if (!strncmp(Line,"SUMMARY;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:",48)) {
186             DecodeUTF8(text,Line+48,strlen(Line)-48);
187             text[strlen(Line)-48]=0;
188           }
189           if (!strncmp(Line,"DTSTART:",8)) {
190             strncpy(time,Line+8,strlen(Line)-8);
191             time[strlen(Line)-8]=0;
192           }
193           if (!strncmp(Line,"DALARM:",7)) {
194             strncpy(alarm,Line+7,strlen(Line)-7);
195             alarm[strlen(Line)-7]=0;
196           }
197
198           /* Obsolete */
199           if (!strncmp(Line,"RECURR:",7)) {
200             recurr=mem_to_int(Line+7,strlen(Line)-7);
201           }
202
203           if (!strncmp(Line,"RRULE:D1 :",9)) {
204             recurr=1;
205           }
206           if (!strncmp(Line,"RRULE:W1 :",9)) {
207             recurr=7;
208           }
209           if (!strncmp(Line,"RRULE:W2 :",9)) {
210             recurr=14;
211           }
212           if (!strncmp(Line,"RRULE:YD1 :",10)) {
213             recurr=365;
214           }
215
216           if (!strncmp(Line,"ALTYPE:",7)) {
217             altype=(!strncmp("TONE",Line+7,4)) ? 0x00 : 0x01;
218           }
219         }
220         if (!strcmp(Line,"END:VEVENT")) {
221           if (veventcounter==*number) NoteOK=true;
222           isOK--;
223         }
224         break;
225     }
226     
227     if (NoteOK) break;
228   }
229     
230   if (!NoteOK) {
231     *number=veventcounter;
232 #ifdef DEBUG
233     fprintf(stdout,_("Note not found in VCalendarfile\n"));
234 #endif
235     return GE_TOOSHORT;
236   }
237   
238   FillCalendarNote(cnote, type, text, time, alarm);
239
240   cnote->Recurrance = recurr*24; /* it was in days. I convert in hours */
241   cnote->AlarmType = altype;
242
243   if( strcmp( phone, "" ) ) { /* Invert data if CALL ... */
244     strcpy( cnote->Text, phone );
245     strcpy( cnote->Phone, text ); // alread FillCalendar does it ..
246   }
247
248   fclose(file);
249   
250   return 0;
251 }
252
253 GSM_Error GSM_ReadBinRingtoneFile(char *FileName, GSM_BinRingtone *ringtone)
254 {
255   FILE *file;
256   int i;
257
258   file = fopen(FileName, "rb");
259
260   if (!file)
261     return(GE_CANTOPENFILE);
262
263   ringtone->length=fread(ringtone->frame, 1, 500, file);
264
265   fclose(file);
266   
267   if (ringtone->frame[0]!=0x00 || ringtone->frame[1]!=0x00 ||
268       ringtone->frame[2]!=0x0C || ringtone->frame[3]!=0x01)
269     return GE_NOTSUPPORTED;
270
271   i=5;
272   while (ringtone->frame[i]!=0x00) {
273     ringtone->name[i-5]=ringtone->frame[i];
274     i++;
275   }
276   ringtone->name[i-5]=0x00;
277
278   return GE_NONE;
279 }
280
281 /* Function to convert scale field in to correct number. */
282 int GetRTTLDuration (char *num)
283 {
284
285 int duration=0;
286
287  switch (atoi(num)) {
288  
289  case  1: duration=128; break;
290  case  2: duration= 64; break;
291  case  4: duration= 32; break;
292  case  8: duration= 16; break;
293  case 16: duration=  8; break;
294  case 32: duration=  4; break;
295  }
296    
297  return (duration);
298
299 }
300
301 int GetRTTLScale (char *num)
302 {
303
304   /* This may well need improving. */
305
306   int scale=0;
307
308   if ((atoi(num))<4) scale=(atoi(num));
309   if ((atoi(num))>4) scale=(atoi(num))-4;
310
311   return (scale);
312 }
313
314 GSM_Error GSM_ReadRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
315 {
316   FILE *file;
317   unsigned char buffer[300];
318   GSM_Error error;
319   GSM_Filetypes filetype=RTTL;
320
321   file = fopen(FileName, "rb");
322
323   if (!file)
324     return(GE_CANTOPENFILE);
325
326   fread(buffer, 1, 4, file); /* Read the header of the file. */
327
328   /* Attempt to identify filetype */
329
330   if (memcmp(buffer, "MThd",3)==0)  /* MIDI files have 'MThd' at the start */
331     filetype=MIDI;
332
333   if (buffer[0]==0xc7 && buffer[1]==0x45 && buffer[2]==0xc1 && buffer[3]==0x53)
334     filetype=COMMUNICATOR;
335
336   if (strstr(FileName,".ott")) filetype=OTT; /* OTT files saved by NCDS3 */
337   
338   error=GE_NONE;
339   
340   rewind(file);
341
342   switch (filetype) {
343   case RTTL:
344     error=loadrttl(file,ringtone);
345     fclose(file);
346     break;
347   case OTT:
348     error=loadott(file,ringtone);
349     fclose(file);
350     break;
351   case COMMUNICATOR:
352     error=loadcommunicator(file,ringtone);
353     fclose(file);
354     break;
355   case MIDI:
356     fclose(file);
357     error=loadmid(FileName,ringtone);
358     break;
359   default:
360     error=GE_INVALIDFILEFORMAT;
361   }
362
363   return(error);
364
365 }
366
367 GSM_Error loadott(FILE *file, GSM_Ringtone *ringtone)
368 {
369   char Buffer[2000];
370   int i;
371   
372   i=fread(Buffer, 1, 2000, file);
373
374   if (!feof(file)) return GE_TOOLONG;
375   
376   return GSM_UnPackRingtone(ringtone, Buffer, i);
377 }
378
379 GSM_Error loadcommunicator(FILE *file, GSM_Ringtone *ringtone)
380 {
381   char Buffer[4000];
382   int i,j;
383   
384   i=fread(Buffer, 1, 4000, file);
385
386   if (!feof(file)) return GE_TOOLONG;
387   
388   i=0;j=0;
389   while (true) {
390     if (Buffer[j]==0x00 && Buffer[j+1]==0x02 &&
391         Buffer[j+2]==0x4a && Buffer[j+3]==0x3a) break;
392     if (j==i-4) return GE_INTERNALERROR;
393     j++;
394   }
395   j++;
396   
397   return GSM_UnPackRingtone(ringtone, Buffer+j, i-j);
398 }
399
400 /* TODO: spaces should not be interpreted */
401 /* Note: ringtone have to be in one line (without 0x13 and 0x10 chars) */
402 GSM_Error loadrttl(FILE *file, GSM_Ringtone *ringtone)
403 {
404   int NrNote=0;
405   
406   u8 DefNoteScale=2, DefNoteDuration=4;
407   int DefNoteTempo=63;
408   u8 DefNoteStyle=ContinuousStyle;
409
410   unsigned char buffer[2000];
411   unsigned char *def, *notes, *ptr;
412
413   ringtone->Loop=15; //default value
414
415   fread(buffer, 2000, 1, file);
416
417   /* This is for buggy RTTTL ringtones without name. */
418   if (buffer[0] != RTTTL_SEP[0]) {
419     strtok(buffer, RTTTL_SEP);
420     sprintf(ringtone->name, "%s", buffer);
421     def=strtok(NULL, RTTTL_SEP);
422     notes=strtok(NULL, RTTTL_SEP);
423   }
424   else {
425     sprintf(ringtone->name, "GNOKII");
426     def=strtok(buffer, RTTTL_SEP);
427     notes=strtok(NULL, RTTTL_SEP);
428   }
429
430   ptr=strtok(def, ", ");
431
432   /* Parsing the <defaults> section. */
433   while (ptr) {
434
435     switch(*ptr) {
436     case 'd':
437     case 'D':
438       DefNoteDuration=GetRTTLDuration(ptr+2);
439       break;
440     case 'o':
441     case 'O':
442       DefNoteScale=GetRTTLScale(ptr+2);
443       break;
444     case 'b':
445     case 'B':
446       DefNoteTempo=atoi(ptr+2);
447       break;
448     case 'l':
449     case 'L':
450       ringtone->Loop=atoi(ptr+2);
451       break;
452     case 's':
453     case 'S':
454       switch (*(ptr+1)) {
455         case 'C':
456         case 'c':
457           DefNoteStyle=ContinuousStyle;
458           break;
459         case 'N':
460         case 'n':
461           DefNoteStyle=NaturalStyle;
462           break;
463         case 'S':
464         case 's':
465           DefNoteStyle=StaccatoStyle;
466           break;        
467       }
468       switch (*(ptr+2)) {
469         case 'c':
470         case 'C':
471           DefNoteStyle=ContinuousStyle;
472           break;
473         case 'n':
474         case 'N':
475           DefNoteStyle=NaturalStyle;
476           break;
477         case 's':
478         case 'S':
479           DefNoteStyle=StaccatoStyle;
480           break;        
481       }
482       break;
483     }
484
485     ptr=strtok(NULL,", ");
486   }
487
488 #ifdef DEBUG
489   printf("DefNoteDuration=%d\n", DefNoteDuration);
490   printf("DefNoteScale=%d\n", DefNoteScale);
491 #endif
492
493   ptr=strtok(notes, ", ");
494
495   /* Parsing the <note-command>+ section. */
496   while (ptr && NrNote<MAX_RINGTONE_NOTES) {
497
498     switch(*ptr) {
499       case 'o':
500       case 'O':
501         DefNoteScale=GetRTTLScale(ptr+2);
502         break;
503       case 's':
504       case 'S':
505         switch (*(ptr+1)) {
506           case 'C':
507           case 'c':
508             DefNoteStyle=ContinuousStyle;
509             break;
510           case 'N':
511           case 'n':
512             DefNoteStyle=NaturalStyle;
513             break;
514           case 'S':
515           case 's':
516             DefNoteStyle=StaccatoStyle;
517             break;      
518         }
519         switch (*(ptr+2)) {
520           case 'C':
521           case 'c':
522             DefNoteStyle=ContinuousStyle;
523             break;
524           case 'N':
525           case 'n':
526             DefNoteStyle=NaturalStyle;
527             break;
528           case 'S':
529           case 's':
530             DefNoteStyle=StaccatoStyle;
531             break;      
532         }
533         break;
534       default:
535         /* [<duration>] */
536         ringtone->notes[NrNote].duration=GetRTTLDuration(ptr);
537         if (ringtone->notes[NrNote].duration==0)
538            ringtone->notes[NrNote].duration=DefNoteDuration;
539         
540         /* Skip all numbers in duration specification. */
541         while(isdigit(*ptr))
542           ptr++;
543
544         /* <note> */
545         /* B or b is not in specs, but I decided to put it, because
546            it's in some RTTL files. It's the same to H note */
547              if ((*ptr=='B') || (*ptr=='b')) ringtone->notes[NrNote].note=12;
548         else if ((*ptr=='H') || (*ptr=='h')) ringtone->notes[NrNote].note=12;        
549         else if ((*ptr>='a') && (*ptr<='g')) ringtone->notes[NrNote].note=((*ptr-'a')*2)+10;
550         else if ((*ptr>='A') && (*ptr<='G')) ringtone->notes[NrNote].note=((*ptr-'A')*2)+10;
551         else ringtone->notes[NrNote].note=255;
552
553         if ((ringtone->notes[NrNote].note>13)&&(ringtone->notes[NrNote].note!=255))
554           ringtone->notes[NrNote].note-=14;
555
556         ptr++;
557       
558         if ((*ptr)=='#') {
559           ringtone->notes[NrNote].note++;
560           if ((ringtone->notes[NrNote].note==5) || (ringtone->notes[NrNote].note==13))
561             ringtone->notes[NrNote].note++;
562           ptr++;
563         }
564
565         /* Check for dodgy rttl */
566         /* [<special-duration>] */
567         if (*ptr=='.') {
568           ringtone->notes[NrNote].duration*=1.5;
569           ptr++;
570         }
571
572         /* [<scale>] */
573         if (ringtone->notes[NrNote].note!=255) {
574           if (isdigit(*ptr)) {
575             ringtone->notes[NrNote].note+=GetRTTLScale(ptr)*14;
576             ptr++;
577           } else
578             ringtone->notes[NrNote].note+=DefNoteScale*14;
579         }
580
581         /* [<special-duration>] */
582         if (*ptr=='.') {
583           ringtone->notes[NrNote].duration*=1.5;
584           ptr++;
585         }
586
587         /* Style */
588         ringtone->notes[NrNote].style=DefNoteStyle;
589         
590         /* Tempo */
591         ringtone->notes[NrNote].tempo=DefNoteTempo;
592
593         NrNote++;            
594         
595         break;
596     }
597     ptr=strtok(NULL, ", ");
598   }
599
600   ringtone->NrNotes=NrNote;
601
602   return GE_NONE;
603 }
604
605 GSM_Error GSM_SaveRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
606 {
607
608   FILE *file;
609   bool done=false;
610   
611    file = fopen(FileName, "wb");
612       
613    if (!file)
614      return(GE_CANTOPENFILE);
615         
616    if (strstr(FileName,".ott"))
617    {
618      saveott(file, ringtone);
619      done=true;
620    }
621    if (strstr(FileName,".mid"))
622    {
623      savemid(file, ringtone);
624      done=true;
625    }   
626
627    if (!done) saverttl(file, ringtone);
628
629    fclose(file);
630    
631    return GE_NONE;
632 }
633
634 void saveott(FILE *file, GSM_Ringtone *ringtone)
635 {
636   char Buffer[2000];
637   
638   int i=2000;
639     
640   GSM_PackRingtone(ringtone, Buffer, &i);
641   
642   fwrite(Buffer, 1, i, file);
643 }
644
645 void saverttl(FILE *file, GSM_Ringtone *ringtone)
646 {
647   u8 DefNoteScale=2, DefNoteDuration=4;
648   int DefNoteTempo=63;
649   u8 DefNoteStyle=ContinuousStyle;
650
651   int CurrentNote;
652   int buffer[6];
653   int i,j,k=0;
654   
655   /* Saves ringtone name */
656   fprintf(file,_("%s:"),ringtone->name);
657
658   /* Find the most frequently used duration and use this for the default */
659  
660   for (i=0;i<6;i++) buffer[i]=0;
661   for (i=0;i<ringtone->NrNotes;i++) {
662     switch (ringtone->notes[i].duration) {
663       case 192:buffer[0]++; break;
664       case 128:buffer[0]++; break;
665       case  96:buffer[1]++; break;
666       case  64:buffer[1]++; break;
667       case  48:buffer[2]++; break;
668       case  32:buffer[2]++; break;
669       case  24:buffer[3]++; break;
670       case  16:buffer[3]++; break;
671       case  12:buffer[4]++; break;
672       case   8:buffer[4]++; break;
673       case   6:buffer[5]++; break;
674       case   4:buffer[5]++; break;
675     }
676   }
677
678   /* Now find the most frequently used */
679   j=0;
680   for (i=0;i<6;i++) {
681     if (buffer[i]>j) {
682       k=i; 
683       j=buffer[i];
684     }
685   }
686
687   /* Finally convert and save the default duration */
688
689   switch (k) {
690       case 0: DefNoteDuration=128; fprintf(file, _("d=1,")); break;     
691       case 1: DefNoteDuration= 64; fprintf(file, _("d=2,")); break;     
692       case 2: DefNoteDuration= 32; fprintf(file, _("d=4,")); break;     
693       case 3: DefNoteDuration= 16; fprintf(file, _("d=8,")); break;     
694       case 4: DefNoteDuration=  8; fprintf(file,_("d=16,")); break;     
695       case 5: DefNoteDuration=  4; fprintf(file,_("d=32,")); break;     
696      default: DefNoteDuration= 16; fprintf(file, _("d=8,")); break;     
697   }  
698
699
700   /* Find the most frequently used scale and use this for the default */
701
702   for (i=0;i<6;i++) buffer[i]=0;
703   for (i=0;i<ringtone->NrNotes;i++) {
704     if (ringtone->notes[i].note!=255) {
705       buffer[ringtone->notes[i].note/14]++;
706     }
707   }
708   j=0;
709   for (i=0;i<6;i++) {
710     if (buffer[i]>j) {
711       DefNoteScale=i;
712       j=buffer[i];
713     }
714   }
715
716   if (ringtone->NrNotes!=0) {
717     DefNoteTempo=ringtone->notes[0].tempo;
718     DefNoteStyle=ringtone->notes[0].style;
719   }
720
721   /* Save the default scale */
722   fprintf(file,_("o=%i,"),DefNoteScale+4);  
723
724   switch (DefNoteStyle) {
725     case StaccatoStyle: fprintf(file,_("s=S,")); break;
726     case NaturalStyle : fprintf(file,_("s=N,")); break;
727   }
728
729   /* Save the default tempo */
730   fprintf(file,_("b=%i,"),DefNoteTempo);
731
732   /* Save the default loop */
733   fprintf(file,_("l=%i:"),ringtone->Loop);
734
735 #ifdef DEBUG
736   printf("DefNoteDuration=%d\n", DefNoteDuration);
737   printf("DefNoteScale=%d\n", DefNoteScale);
738   printf("Number of notes=%d\n",ringtone->NrNotes);
739 #endif
740   
741   /* Now loop round for each note */
742
743   for (i=0;i<ringtone->NrNotes;i++) {
744     CurrentNote=ringtone->notes[i].note;
745
746     if (ringtone->notes[i].style!=DefNoteStyle) {
747       DefNoteStyle=ringtone->notes[i].style;
748       switch (DefNoteStyle) {
749         case StaccatoStyle  : fprintf(file,_("s=S")); break;
750         case NaturalStyle   : fprintf(file,_("s=N")); break;
751         case ContinuousStyle: fprintf(file,_("s=C")); break;
752       }
753       /* And a separator before next note */
754       if (i!=ringtone->NrNotes-1)
755         fprintf(file,_(","));
756     }
757     
758     if (ringtone->notes[i].tempo!=DefNoteTempo) {
759       DefNoteTempo=ringtone->notes[i].tempo;
760       fprintf(file,_("b=%i"),DefNoteTempo);
761       if (i!=ringtone->NrNotes-1)
762         fprintf(file,_(","));
763     }    
764     
765     /* This note has a duration different than the default. We must save it */
766     if (ringtone->notes[i].duration!=DefNoteDuration) {
767       switch (ringtone->notes[i].duration) {
768         case 192: fprintf(file, _("1")); break; //192=128*1.5
769         case 128: fprintf(file, _("1")); break;
770         case  96: fprintf(file, _("2")); break; //96=64*1.5
771         case  64: fprintf(file, _("2")); break;
772         case  48: fprintf(file, _("4")); break; //48=32*1.5
773         case  32: fprintf(file, _("4")); break;
774         case  24: fprintf(file, _("8")); break; //24=16*1.5
775         case  16: fprintf(file, _("8")); break;
776         case  12: fprintf(file,_("16")); break; //12=8*1.5
777         case   8: fprintf(file,_("16")); break;
778         case   6: fprintf(file,_("32")); break; //6=4*1.5
779         case   4: fprintf(file,_("32")); break;
780         default: 
781           break;
782       }
783     }
784     
785     /* Now save the actual note */
786     switch (GSM_GetNote(CurrentNote)) {
787       case Note_C  :fprintf(file,_("c"));break;
788       case Note_Cis:fprintf(file,_("c#"));break;
789       case Note_D  :fprintf(file,_("d"));break;
790       case Note_Dis:fprintf(file,_("d#"));break;
791       case Note_E  :fprintf(file,_("e"));break;
792       case Note_F  :fprintf(file,_("f"));break;
793       case Note_Fis:fprintf(file,_("f#"));break;
794       case Note_G  :fprintf(file,_("g"));break;
795       case Note_Gis:fprintf(file,_("g#"));break;
796       case Note_A  :fprintf(file,_("a"));break;
797       case Note_Ais:fprintf(file,_("a#"));break;
798       case Note_H  :fprintf(file,_("h"));break;
799       default      :fprintf(file,_("p"));break; //Pause ?
800     }
801
802     /* Saving info about special duration */
803     if (ringtone->notes[i].duration==128*1.5 ||
804         ringtone->notes[i].duration==64*1.5 ||
805         ringtone->notes[i].duration==32*1.5 ||
806         ringtone->notes[i].duration==16*1.5 ||
807         ringtone->notes[i].duration==8*1.5 ||
808         ringtone->notes[i].duration==4*1.5)
809       fprintf(file,_("."));
810     
811     /* This note has a scale different than the default, so save it */
812     if ( (CurrentNote!=255) && (CurrentNote/14!=DefNoteScale))
813         fprintf(file,_("%i"),(CurrentNote/14)+4);
814     
815     /* And a separator before next note */
816     if (i!=ringtone->NrNotes-1)
817       fprintf(file,_(","));
818
819   }
820 }
821
822 void WriteVarLen(char* midifile, int* current, long value)
823 {
824    long buffer;
825
826    buffer = value & 0x7f;
827
828    while (value >>= 7) {
829       buffer <<= 8;
830       buffer |= 0x80;
831       buffer += (value & 0x7f);
832    }
833
834    while (1) {
835      midifile[(*current)++] = buffer;
836      if (buffer & 0x80)
837        buffer >>= 8;
838      else
839        break;
840    }
841 }
842
843 #define singlepauses
844
845 /* FIXME: need adding tempo before each note and scale too ? */
846 void savemid(FILE* file, GSM_Ringtone *ringtone)
847 {
848   char midifile[3000] = { 0x4D, 0x54, 0x68, 0x64, // MThd
849                           0x00, 0x00, 0x00, 0x06, // chunk length
850                           0x00, 0x00,             // format 0
851                           0x00, 0x01,             // one track
852                           0x00, 0x20,             // 32 per quarter note
853                           0x4D, 0x54, 0x72, 0x6B, // MTrk
854                           0x00, 0x00, 0x00, 0x00, // chunk length
855                           0x00, 0xFF, 0x51, 0x03, // tempo meta event
856                           0x00, 0x00, 0x00        // 3 bytes for us for a quarter note
857                         };
858
859 //{ "c", "c#", "d", "d#", "e",      "f", "f#", "g", "g#", "a", "a#", "h" };
860 char midinotes[14] =
861   { 0,    1,    2,   3,    4,   4,   5,   6,    7,   8,    9,  10 ,   11,   11 };
862
863   int length = 20;
864   int start = 22;
865   int current = 26, i, note, pause = 0;
866   bool notesexisting = false;
867
868   /* FIXME: we need add tempo before each note or so... */
869   long duration=60000000/63;  // us for a quarter note
870   if (ringtone->NrNotes!=0)
871     duration=60000000/ringtone->notes[0].tempo;
872   midifile[current++] = duration >> 16;
873   midifile[current++] = duration >> 8;
874   midifile[current++] = duration;
875
876   for (i = 0; i < ringtone->NrNotes; i++) {
877
878     note = ringtone->notes[i].note;
879     if (note == 255) {   // readmid does not read pauses at the beginning
880
881       if (notesexisting) {
882         pause += ringtone->notes[i].duration;
883 #ifdef singlepauses
884         WriteVarLen(midifile,&current,pause);
885         pause=0;
886         midifile[current++]=0x00;   // pause
887         midifile[current++]=0x00;
888 #endif
889       }
890       
891     } else {
892
893       notesexisting = true;
894       note = 48+12*((note/14)%4) + midinotes[note%14];
895
896       WriteVarLen(midifile,&current,pause);
897       pause=0;
898       midifile[current++]=0x90;   // note on
899       midifile[current++]=note;
900       midifile[current++]=0x64;   // forte
901
902       WriteVarLen(midifile,&current,ringtone->notes[i].duration);
903       midifile[current++]=0x80;   // note off
904       midifile[current++]=note;
905       midifile[current++]=0x64; 
906
907     }
908   }
909
910   if (pause) {
911     WriteVarLen(midifile,&current,pause);
912     midifile[current++]=0x00;   // pause
913     midifile[current++]=0x00;   //
914   }
915   midifile[current++] = 0x00;
916   midifile[current++] = 0xFF;   // track end
917   midifile[current++] = 0x2F;
918   midifile[current++] = 0x00;
919   midifile[length++] = (current-start) >> 8;
920   midifile[length++] = current-start;
921
922   fwrite(midifile,1,current,file);
923 }
924
925 GSM_Error GSM_ReadBitmapFile(char *FileName, GSM_Bitmap *bitmap)
926 {
927
928   FILE *file;
929   unsigned char buffer[300];
930   GSM_Error error;
931   GSM_Filetypes filetype=None;
932
933   file = fopen(FileName, "rb");
934
935   if (!file)
936     return(GE_CANTOPENFILE);
937
938   fread(buffer, 1, 9, file); /* Read the header of the file. */
939
940   /* Attempt to identify filetype */
941
942   if (memcmp(buffer, "NOL",3)==0) {  /* NOL files have 'NOL' at the start */
943     filetype=NOL;
944   } else if (memcmp(buffer, "NGG",3)==0) {  /* NGG files have 'NGG' at the start */
945     filetype=NGG;
946   } else if (memcmp(buffer, "FORM",4)==0) {  /* NSL files have 'FORM' at the start */
947     filetype=NSL;
948   } else if (memcmp(buffer, "NLM",3)==0) {  /* NLM files have 'NLM' at the start */
949     filetype=NLM;
950   } else if (memcmp(buffer, "BM",2)==0) {  /* BMP, I61 and GGP files have 'BM' at the start */
951     filetype=BMP;    
952   } else if (memcmp(buffer, "/* XPM */",9)==0) {  /* XPM files have 'XPM' at the start */  
953     filetype=XPMF;
954   } else filetype=None;
955
956   if (strstr(FileName,".otb")) filetype=OTA; /* OTA files saved by NCDS3 */
957   
958   error=GE_NONE;
959   
960   rewind(file);
961
962   switch (filetype) {
963     case NOL: error=loadnol(file,bitmap); fclose(file); break;
964     case NGG: error=loadngg(file,bitmap); fclose(file); break;
965     case NSL: error=loadnsl(file,bitmap); fclose(file); break;
966     case NLM: error=loadnlm(file,bitmap); fclose(file); break;
967     case OTA: error=loadota(file,bitmap); fclose(file); break;
968     case BMP: error=loadbmp(file,bitmap); fclose(file); break;
969 #ifdef XPM
970     case XPMF:fclose(file);error=loadxpm(FileName,bitmap);break;
971 #endif
972     default : error=GE_INVALIDFILEFORMAT;
973   }
974
975   return(error);
976 }
977
978 #ifdef XPM
979
980 GSM_Error loadxpm(char *filename, GSM_Bitmap *bitmap)
981 {
982   int y,x,error;
983   XpmImage image;
984   XpmInfo info;
985
986   error=XpmReadFileToXpmImage(filename,&image,&info);
987
988   switch (error) {
989     case XpmColorError:  return GE_WRONGCOLORS;break;
990     case XpmColorFailed: return GE_WRONGCOLORS;break;
991     case XpmOpenFailed:  return GE_CANTOPENFILE;break;
992     case XpmFileInvalid: return GE_INVALIDFILEFORMAT;break;
993     case XpmSuccess: break;
994   }
995
996   if (image.ncolors!=2) {
997     printf("Wrong number of colors\n");
998     return GE_WRONGNUMBEROFCOLORS;
999   }
1000
1001   if ((image.height==48) && (image.width==84)) {
1002     bitmap->type=GSM_StartupLogo;
1003   }
1004   else if ((image.height==65) && (image.width==96)) {
1005     bitmap->type=GSM_7110StartupLogo;
1006   }
1007   else if ((image.height==60) && (image.width==96)) {
1008     bitmap->type=GSM_6210StartupLogo;
1009   }
1010   else if ((image.height==28) && (image.width==72)) {
1011     bitmap->type=GSM_PictureImage;
1012   }
1013   else if ((image.height==14) && (image.width==72)) {
1014     bitmap->type=GSM_CallerLogo;
1015   }
1016   else {
1017 #ifdef DEBUG
1018     printf("Invalid Image Size (%dx%d).\n",image.width,image.height);
1019 #endif
1020     return GE_INVALIDIMAGESIZE;
1021   }
1022
1023   bitmap->height=image.height;
1024   bitmap->width=image.width;
1025   bitmap->size=GSM_GetBitmapSize(bitmap);
1026
1027   GSM_ClearBitmap(bitmap);
1028   
1029   for(y=0;y<image.height;y++) {
1030     for(x=0;x<image.width;x++) {
1031       if (image.data[y*image.width+x]==0) GSM_SetPointBitmap(bitmap,x,y);        
1032     }
1033   }
1034
1035   return GE_NONE;
1036 }
1037
1038 #endif
1039
1040 /* Based on the article from the Polish Magazine "Bajtek" 11/92 */
1041                                      /* Marcin-Wiacek@Topnet.PL */
1042 GSM_Error loadbmp(FILE *file, GSM_Bitmap *bitmap)
1043 {
1044   unsigned char buffer[34];
1045   bool first_white;
1046   int w,h,pos,y,x,i,sizeimage;
1047
1048   fread(buffer, 1, 34, file); //required part of header
1049
1050   h=buffer[22]+256*buffer[21]; //height of image in the file
1051   w=buffer[18]+256*buffer[17]; //width of image in the file
1052 #ifdef DEBUG
1053   printf("Image Size in BMP file: %dx%d\n",w,h);
1054 #endif
1055
1056   bitmap->type=GSM_7110StartupLogo;
1057   bitmap->width=96;
1058   bitmap->height=65;
1059   
1060   if (h==48 && w==84) {
1061     bitmap->width=84;
1062     bitmap->height=48;
1063     bitmap->type=GSM_StartupLogo;    
1064   }
1065   if (h==60 && w==96) {
1066     bitmap->width=96;
1067     bitmap->height=60;
1068     bitmap->type=GSM_6210StartupLogo;    
1069   }  
1070   if (h==14 && w==72) {
1071     bitmap->width=72;
1072     bitmap->height=14;
1073     bitmap->type=GSM_CallerLogo;    
1074   }    
1075   if (h==28 && w==72) {
1076     bitmap->width=72;
1077     bitmap->height=28;
1078     bitmap->type=GSM_PictureImage;    
1079   }    
1080   if (h==21 && w==78) {
1081     bitmap->width=78;
1082     bitmap->height=21;
1083     bitmap->type=GSM_7110OperatorLogo;    
1084   }    
1085
1086   bitmap->size=GSM_GetBitmapSize(bitmap);
1087
1088   GSM_ClearBitmap(bitmap);  
1089
1090 #ifdef DEBUG
1091   printf("Number of colors in BMP file: ");
1092   switch (buffer[28]) {
1093     case 1:printf("2 (supported by gnokii)\n");break;
1094     case 4:printf("16 (not supported by gnokii)\n");break;
1095     case 8:printf("256 (not supported by gnokii)\n");break;
1096     case 24:printf("True Color (not supported by gnokii)\n");break;
1097     default:printf("unknown\n");break;
1098   }
1099 #endif
1100   if (buffer[28]!=1) {
1101     printf("Wrong number of colors\n"); //we support only 2 colors images !
1102     return GE_WRONGNUMBEROFCOLORS;
1103   }
1104
1105 #ifdef DEBUG
1106   printf("Compression in BMP file: ");
1107   switch (buffer[30]) {
1108     case 0:printf("no compression (supported by gnokii)\n");break;
1109     case 1:printf("RLE8 (not supported by gnokii)\n");break;
1110     case 2:printf("RLE4 (not supported by gnokii)\n");break;
1111     default:printf("unknown\n");break;
1112   }
1113 #endif  
1114   if (buffer[30]!=0) {
1115 #ifdef DEBUG
1116     printf("Subformat not supported\n"); //we don't support RLE compression
1117 #endif
1118     return GE_SUBFORMATNOTSUPPORTED;
1119   }  
1120   
1121   pos=buffer[10]-34;
1122   fread(buffer, 1, pos, file); //rest of header (if exists) and color palette
1123   
1124 #ifdef DEBUG
1125   printf("First color in BMP file: %i %i %i ",buffer[pos-8], buffer[pos-7], buffer[pos-6]);
1126   if (buffer[pos-8]==0 && buffer[pos-7]==0 && buffer[pos-6]==0) printf("(white)");
1127   if (buffer[pos-8]==0xFF && buffer[pos-7]==0xFF && buffer[pos-6]==0xFF) printf("(black)");
1128   if (buffer[pos-8]==102 && buffer[pos-7]==204 && buffer[pos-6]==102) printf("(green)");
1129   printf("\n");
1130
1131   printf("Second color in BMP file: %i %i %i ",buffer[pos-4], buffer[pos-3], buffer[pos-2]);
1132   if (buffer[pos-4]==0 && buffer[pos-3]==0 && buffer[pos-2]==0) printf("(white)");
1133   if (buffer[pos-4]==0xFF && buffer[pos-3]==0xFF && buffer[pos-2]==0xFF) printf("(black)");
1134   printf("\n");  
1135 #endif
1136   first_white=true;
1137   if (buffer[pos-8]!=0 || buffer[pos-7]!=0 || buffer[pos-6]!=0) first_white=false;
1138  
1139   sizeimage=0;
1140   pos=7;
1141   for (y=h-1;y>=0;y--) { //lines are written from the last to the first
1142     i=1;
1143     for (x=0;x<w;x++) {
1144       if (pos==7) { //new byte !
1145         fread(buffer, 1, 1, file);
1146         sizeimage++;
1147         i++;
1148         if(i==5) i=1; //each line is written in multiply of 4 bytes
1149       }
1150       if (x<=bitmap->width && y<=bitmap->height) { //we have top left corner !
1151         if (first_white) {
1152           if ((buffer[0]&(1<<pos))<=0) GSM_SetPointBitmap(bitmap,x,y);
1153         } else {
1154           if ((buffer[0]&(1<<pos))>0) GSM_SetPointBitmap(bitmap,x,y);
1155         }
1156       }
1157       pos--;
1158       if (pos<0) pos=7; //going to new byte
1159     }
1160     pos=7; //going to new byte
1161     if (i!=1) {
1162       while (i!=5) //each line is written in multiply of 4 bytes
1163       {
1164         fread(buffer, 1, 1, file);
1165         sizeimage++;
1166         i++;
1167       }
1168     }
1169   }
1170
1171 #ifdef DEBUG
1172   printf("Data size in BMP file: %i\n",sizeimage);
1173 #endif
1174     
1175   return(GE_NONE);
1176 }
1177
1178 GSM_Error loadnol(FILE *file, GSM_Bitmap *bitmap)
1179 {
1180
1181   unsigned char buffer[2000];
1182   int i,j;
1183   
1184   bitmap->type=GSM_OperatorLogo;
1185
1186   fread(buffer, 1, 6, file);
1187   fread(buffer, 1, 4, file);
1188   sprintf(bitmap->netcode, "%d %02d", buffer[0]+256*buffer[1], buffer[2]);
1189
1190   fread(buffer, 1, 4, file); /* Width and height of the icon. */
1191   bitmap->width=buffer[0];
1192   bitmap->height=buffer[2];
1193   bitmap->size=GSM_GetBitmapSize(bitmap);
1194
1195   if ((bitmap->height!=14) || (bitmap->width!=72)) {
1196 #ifdef DEBUG
1197     printf("Invalid Image Size (%dx%d).\n",bitmap->width,bitmap->height);
1198 #endif
1199     return GE_INVALIDIMAGESIZE;
1200   }
1201
1202   fread(buffer, 1, 6, file); /* Unknown bytes. */
1203   
1204   for (i=0; i<bitmap->size; i++) {
1205     if (fread(buffer, 1, 8, file)==8) {
1206       bitmap->bitmap[i]=0;
1207       for (j=7; j>=0;j--)
1208         if (buffer[7-j] == '1')
1209           bitmap->bitmap[i]|=(1<<j);
1210     }
1211     else
1212       return (GE_TOOSHORT);
1213   }
1214
1215 #ifdef DEBUG
1216   /* Some programs writes here fileinfo */
1217   if (fread(buffer, 1, 1, file)==1) {
1218     fprintf(stdout, _("Fileinfo: %c"),buffer[0]);
1219     while (fread(buffer, 1, 1, file)==1) {
1220       if (buffer[0]!=0x0A) fprintf(stdout,_("%c"),buffer[0]);
1221     }  
1222     fprintf(stdout, _("\n"));
1223   }
1224 #endif
1225
1226   return(GE_NONE);
1227 }
1228
1229 GSM_Error loadngg(FILE *file, GSM_Bitmap *bitmap)
1230 {
1231
1232   unsigned char buffer[2000];
1233   int i,j;
1234
1235   bitmap->type=GSM_CallerLogo;
1236
1237   fread(buffer, 1, 6, file);
1238   fread(buffer, 1, 4, file); /* Width and height of the icon. */
1239   bitmap->width=buffer[0];
1240   bitmap->height=buffer[2];
1241   bitmap->size=GSM_GetBitmapSize(bitmap);
1242   
1243   if ((bitmap->height!=14) || (bitmap->width!=72)) {
1244 #ifdef DEBUG
1245     printf("Invalid Image Size (%dx%d).\n",bitmap->width,bitmap->height);
1246 #endif
1247     return GE_INVALIDIMAGESIZE;
1248   }
1249   
1250   fread(buffer, 1, 6, file); /* Unknown bytes. */
1251     
1252   for (i=0; i<bitmap->size; i++) {
1253     if (fread(buffer, 1, 8, file)==8){
1254       bitmap->bitmap[i]=0;
1255       for (j=7; j>=0;j--)
1256         if (buffer[7-j] == '1')
1257           bitmap->bitmap[i]|=(1<<j);
1258     }
1259     else
1260       return(GE_TOOSHORT);
1261   }
1262
1263 #ifdef DEBUG
1264   /* Some programs writes here fileinfo */
1265   if (fread(buffer, 1, 1, file)==1) {
1266     fprintf(stdout, _("Fileinfo: %c"),buffer[0]);
1267     while (fread(buffer, 1, 1, file)==1) {
1268       if (buffer[0]!=0x0A) fprintf(stdout,_("%c"),buffer[0]);
1269     }  
1270     fprintf(stdout, _("\n"));
1271   }
1272 #endif
1273   
1274   return(GE_NONE);
1275 }
1276
1277 GSM_Error loadnsl(FILE *file, GSM_Bitmap *bitmap)
1278 {
1279
1280   unsigned char block[6],buffer[505];
1281   int block_size;
1282
1283   bitmap->size=0;
1284   
1285   while (fread(block,1,6,file)==6) {
1286
1287     block_size=block[4]*256+block[5];
1288
1289 #ifdef DEBUG
1290     fprintf(stdout,_("Block %c%c%c%c, size %i\n"),block[0],block[1],block[2],block[3],block_size);
1291 #endif
1292
1293     if (!strncmp(block, "FORM", 4)) {
1294 #ifdef DEBUG
1295       fprintf(stdout,_("  File ID\n"));
1296 #endif
1297     } else
1298     {
1299       if (block_size>504) return(GE_INVALIDFILEFORMAT);
1300
1301       if (block_size!=0) {
1302
1303         fread(buffer,1,block_size,file);
1304         buffer[block_size]=0; //if it's string, we end it with \0
1305
1306 #ifdef DEBUG
1307         if (!strncmp(block, "VERS", 4)) fprintf(stdout,_("  File saved by: %s\n"),buffer);
1308         if (!strncmp(block, "MODL", 4)) fprintf(stdout,_("  Logo saved from: %s\n"),buffer);
1309         if (!strncmp(block, "COMM", 4)) fprintf(stdout,_("  Phone was connected to COM port: %s\n"),buffer);
1310 #endif
1311         
1312         if (!strncmp(block, "NSLD", 4)) {          
1313           bitmap->type=GSM_StartupLogo;
1314           bitmap->height=48;
1315           bitmap->width=84;
1316           bitmap->size=GSM_GetBitmapSize(bitmap);
1317
1318           memcpy(bitmap->bitmap,buffer,bitmap->size);
1319
1320 #ifdef DEBUG
1321           fprintf(stdout,_("  Startup logo (size %i)\n"),block_size);
1322 #endif
1323         }
1324       }
1325     }
1326   }
1327   
1328   if (bitmap->size==0) return(GE_TOOSHORT);
1329
1330   return(GE_NONE);
1331 }
1332
1333 GSM_Error loadnlm (FILE *file, GSM_Bitmap *bitmap)
1334 {
1335   unsigned char buffer[1000];
1336   int pos,pos2,x,y;
1337   div_t division;
1338
1339   fread(buffer,1,5,file);
1340   fread(buffer,1,1,file);
1341
1342   switch (buffer[0]) {
1343   case 0x00: bitmap->type=GSM_OperatorLogo; break;
1344   case 0x01: bitmap->type=GSM_CallerLogo;   break;
1345   case 0x02: bitmap->type=GSM_StartupLogo;  break;
1346   case 0x03: bitmap->type=GSM_PictureImage; break;
1347   default:
1348     return(GE_SUBFORMATNOTSUPPORTED);
1349   }
1350   
1351   fread(buffer,1,4,file);
1352   bitmap->width=buffer[1];
1353   bitmap->height=buffer[2];
1354
1355   if (bitmap->type==GSM_StartupLogo  && bitmap->width==96 && bitmap->height==65)
1356     bitmap->type=GSM_7110StartupLogo;
1357   if (bitmap->type==GSM_StartupLogo  && bitmap->width==96 && bitmap->height==60)
1358     bitmap->type=GSM_6210StartupLogo;
1359   if (bitmap->type==GSM_OperatorLogo && bitmap->width==78 && bitmap->height==21)
1360     bitmap->type=GSM_7110OperatorLogo;
1361
1362   bitmap->size=GSM_GetBitmapSize(bitmap);
1363
1364   division=div(bitmap->width,8);
1365   if (division.rem!=0) division.quot++; /* For startup logos */
1366   
1367   if (fread(buffer,1,(division.quot*bitmap->height),file)!=(division.quot*bitmap->height))
1368     return(GE_TOOSHORT);
1369     
1370   GSM_ClearBitmap(bitmap);
1371   
1372   pos=0;pos2=7;
1373   for (y=0;y<bitmap->height;y++) {
1374     for (x=0;x<bitmap->width;x++) {
1375       if ((buffer[pos]&(1<<pos2))>0) GSM_SetPointBitmap(bitmap,x,y);
1376       pos2--;
1377       if (pos2<0) {pos2=7;pos++;} //going to new byte
1378     }
1379     if (pos2!=7) {pos2=7;pos++;} //for startup logos-new line means new byte
1380   }
1381
1382   return (GE_NONE);
1383 }
1384
1385 GSM_Error loadota(FILE *file, GSM_Bitmap *bitmap)
1386 {
1387
1388   char buffer[4];
1389
1390   fread(buffer,1,4,file);
1391
1392   bitmap->width=buffer[1];
1393   bitmap->height=buffer[2];
1394
1395   if ((bitmap->height==48) && (bitmap->width==84)) {
1396     bitmap->type=GSM_StartupLogo;
1397   }
1398   else if ((bitmap->height==14) && (bitmap->width==72)) {
1399     bitmap->type=GSM_CallerLogo;
1400   }
1401   else {
1402 #ifdef DEBUG
1403     printf("Invalid Image Size (%dx%d).\n",bitmap->width,bitmap->height);
1404 #endif
1405     return GE_INVALIDIMAGESIZE;
1406   }
1407
1408   bitmap->size=GSM_GetBitmapSize(bitmap);
1409   
1410   if (fread(bitmap->bitmap,1,bitmap->size,file)!=bitmap->size)
1411     return(GE_TOOSHORT);
1412
1413   return(GE_NONE);
1414 }
1415
1416 GSM_Error GSM_SaveBitmapFile(char *FileName, GSM_Bitmap *bitmap)
1417 {
1418
1419   FILE *file;
1420   bool done=false;
1421      
1422    file = fopen(FileName, "wb");
1423       
1424    if (!file)
1425      return(GE_CANTOPENFILE);
1426
1427    if (strstr(FileName,".xpm")) { savexpm(file, bitmap); done=true; }   
1428    if (strstr(FileName,".nlm")) { savenlm(file, bitmap); done=true; }
1429    if (strstr(FileName,".ngg")) { savengg(file, bitmap); done=true; }
1430    if (strstr(FileName,".nsl")) { savensl(file, bitmap); done=true; }
1431    if (strstr(FileName,".otb")) { saveota(file, bitmap); done=true; }
1432    if (strstr(FileName,".nol")) { savenol(file, bitmap); done=true; }
1433    if (strstr(FileName,".bmp") ||
1434        strstr(FileName,".ggp") ||
1435        strstr(FileName,".i61"))
1436    {
1437      savebmp(file, bitmap);
1438      done=true;
1439    }
1440    
1441    if (!done)
1442    {
1443      switch (bitmap->type) {
1444        case GSM_CallerLogo      : savengg(file, bitmap); break;
1445        case GSM_OperatorLogo    : savenol(file, bitmap); break;
1446        case GSM_7110OperatorLogo: savebmp(file, bitmap); break;
1447        case GSM_7110StartupLogo : savebmp(file, bitmap); break;
1448        case GSM_6210StartupLogo : savebmp(file, bitmap); break;
1449        case GSM_StartupLogo     : savensl(file, bitmap); break;
1450        case GSM_PictureImage    : savenlm(file, bitmap); break;
1451        case GSM_WelcomeNoteText :                        break;
1452        case GSM_DealerNoteText  :                        break;
1453        case GSM_None            :                        break;
1454      }      
1455    }
1456   
1457    fclose(file);
1458    
1459    return GE_NONE;
1460 }
1461
1462 void savexpm(FILE *file, GSM_Bitmap *bitmap)
1463 {
1464   int x,y;
1465
1466   fprintf(file,_("/* XPM */\n"));
1467   fprintf(file,_("static char * ala_xpm[] = {\n"));
1468   fprintf(file,_("\"%i %i 2 1\",\n"),bitmap->width,bitmap->height);
1469   fprintf(file,_("\".   s c     m #000000       g4 #000000      g #000000       c #000000\",\n"));
1470   fprintf(file,_("\"#   s c     m #ffffff       g4 #ffffff      g #ffffff       c #ffffff\",\n"));
1471
1472   for (y=0;y<bitmap->height;y++) {
1473     fprintf(file,_("\""));
1474     for (x=0;x<bitmap->width;x++)
1475       if (GSM_IsPointBitmap(bitmap,x,y))
1476         fprintf(file,_("."));
1477       else
1478         fprintf(file,_("#"));
1479     fprintf(file,_("\""));
1480     if (y==bitmap->height-1)
1481       fprintf(file,_("};\n"));
1482     else
1483       fprintf(file,_(",\n"));
1484   }
1485 }
1486
1487 /* Based on the article from the Polish Magazine "Bajtek" 11/92 */
1488                                      /* Marcin-Wiacek@Topnet.PL */
1489 void savebmp(FILE *file, GSM_Bitmap *bitmap)
1490 {
1491   int x,y,pos,i,sizeimage;
1492   unsigned char buffer[1];
1493   div_t division;
1494   
1495   unsigned char header[]={
1496 /*1'st header*/   'B','M',             /* BMP file ID */
1497                   0x00,0x00,0x00,0x00, /* Size of file */
1498                   0x00,0x00,           /* Reserved for future use */
1499                   0x00,0x00,           /* Reserved for future use */
1500                     62,0x00,0x00,0x00, /* Offset for image data */
1501                  
1502 /*2'nd header*/     40,0x00,0x00,0x00, /* Length of this part of header */
1503                   0x00,0x00,0x00,0x00, /* Width of image */
1504                   0x00,0x00,0x00,0x00, /* Height of image */             
1505                      1,0x00,           /* How many planes in target device */
1506                      1,0x00,           /* How many colors in image. 1 means 2^1=2 colors */
1507                   0x00,0x00,0x00,0x00, /* Type of compression. 0 means no compression */
1508 /*Sometimes */    0x00,0x00,0x00,0x00, /* Size of part with image data */
1509 /*ttttttt...*/    0xE8,0x03,0x00,0x00, /* XPelsPerMeter */
1510 /*hhiiiiissss*/   0xE8,0x03,0x00,0x00, /* YPelsPerMeter */                
1511 /*part of header*/2,0x00,0x00,0x00, /* How many colors from palette is used */
1512 /*doesn't exist*/ 0x00,0x00,0x00,0x00, /* How many colors from palette is required to display image. 0 means all */
1513                  
1514 /*Color palette*/ 0x00,0x00,0x00,      /* First color in palette in Blue, Green, Red. Here white */
1515                   0x00,                /* Each color in palette is end by 4'th byte */
1516                   102,204,102,      /* Second color in palette in Blue, Green, Red. Here green */
1517                   0x00};               /* Each color in palette is end by 4'th byte */
1518
1519   header[22]=bitmap->height;
1520   header[18]=bitmap->width;
1521      
1522   pos=7;
1523   sizeimage=0;
1524   for (y=bitmap->height-1;y>=0;y--) { //lines are written from the last to the first
1525     i=1;
1526     for (x=0;x<bitmap->width;x++) {
1527       if (pos==7) { //new byte !
1528         if (x!=0) sizeimage++;
1529         i++;
1530         if(i==5) i=1; //each line is written in multiply of 4 bytes
1531       }
1532       pos--;
1533       if (pos<0) pos=7; //going to new byte
1534     }
1535     pos=7; //going to new byte
1536     sizeimage++;
1537     if (i!=1) {
1538       while (i!=5) //each line is written in multiply of 4 bytes
1539       {
1540         sizeimage++;
1541         i++;
1542       }
1543     }
1544   }
1545 #ifdef DEBUG
1546   printf("Data size in BMP file: %i\n",sizeimage);
1547 #endif
1548   division=div(sizeimage,256);
1549   header[35]=division.quot;
1550   header[34]=sizeimage-(division.quot*256);
1551   
1552   sizeimage=sizeimage+sizeof(header);
1553 #ifdef DEBUG
1554   printf("Size of BMP file: %i\n",sizeimage);
1555 #endif
1556   division=div(sizeimage,256);
1557   header[3]=division.quot;
1558   header[2]=sizeimage-(division.quot*256);
1559        
1560   fwrite(header,1,sizeof(header),file);
1561
1562   pos=7;
1563   for (y=bitmap->height-1;y>=0;y--) { //lines are written from the last to the first
1564     i=1;
1565     for (x=0;x<bitmap->width;x++) {
1566       if (pos==7) { //new byte !
1567         if (x!=0) fwrite(buffer, 1, sizeof(buffer), file);
1568         i++;
1569         if(i==5) i=1; //each line is written in multiply of 4 bytes
1570         buffer[0]=0;
1571       }
1572       if (!GSM_IsPointBitmap(bitmap,x,y)) buffer[0]|=(1<<pos);
1573       pos--;
1574       if (pos<0) pos=7; //going to new byte
1575     }
1576     pos=7; //going to new byte
1577     fwrite(buffer, 1, sizeof(buffer), file);
1578     if (i!=1) {
1579       while (i!=5) //each line is written in multiply of 4 bytes
1580       {
1581         buffer[0]=0;
1582         fwrite(buffer, 1, sizeof(buffer), file);
1583         i++;
1584       }
1585     }
1586   }
1587 }
1588
1589 void savengg(FILE *file, GSM_Bitmap *bitmap)
1590 {
1591
1592   char header[]={'N','G','G',0x00,0x01,0x00,
1593                  0x00,0x00,           /* Width */
1594                  0x00,0x00,           /* Height */
1595                  0x01,0x00,0x01,0x00,
1596                  0x00,                /* Unknown.Can't be checksum - for */
1597                                       /* the same logo files can be different */
1598                  0x00};  
1599
1600   char buffer[8];
1601   int i,j;
1602   GSM_Bitmap copy;
1603   
1604   copy=*bitmap;
1605   
1606   GSM_ResizeBitmap(&copy,GSM_CallerLogo);
1607   
1608   header[6]=copy.width;
1609   header[8]=copy.height;
1610
1611   fwrite(header,1,sizeof(header),file);
1612
1613   for (i=0; i<copy.size; i++) {
1614     for (j=7; j>=0;j--)
1615       if ((copy.bitmap[i]&(1<<j))>0) {
1616         buffer[7-j] = '1';
1617       } else {
1618         buffer[7-j] = '0';
1619       }
1620     fwrite(buffer,1,8,file);
1621   }
1622 }
1623   
1624 void savenol(FILE *file, GSM_Bitmap *bitmap)
1625 {
1626
1627   char header[]={'N','O','L',0x00,0x01,0x00,
1628                  0x00,0x00,           /* MCC */
1629                  0x00,0x00,           /* MNC */
1630                  0x00,0x00,           /* Width */
1631                  0x00,0x00,           /* Height */
1632                  0x01,0x00,0x01,0x00,
1633                  0x00,                /* Unknown.Can't be checksum - for */
1634                                       /* the same logo files can be different */
1635                  0x00};
1636   char buffer[8];
1637   int i,j,country,net;
1638   GSM_Bitmap copy;
1639   
1640   copy=*bitmap;
1641   
1642   GSM_ResizeBitmap(&copy,GSM_OperatorLogo);
1643   
1644   sscanf(copy.netcode, "%d %d", &country, &net);
1645
1646   header[6]=country%256;
1647   header[7]=country/256;
1648   header[8]=net%256;
1649   header[9]=net/256;
1650   header[10]=copy.width;
1651   header[12]=copy.height;
1652
1653   fwrite(header,1,sizeof(header),file);
1654   
1655   for (i=0; i<copy.size; i++) {
1656     for (j=7; j>=0;j--)
1657       if ((copy.bitmap[i]&(1<<j))>0) {
1658         buffer[7-j] = '1';
1659       } else {
1660         buffer[7-j] = '0';
1661       }
1662     fwrite(buffer,1,8,file);
1663   }
1664 }
1665
1666 void savensl(FILE *file, GSM_Bitmap *bitmap)
1667 {
1668
1669   u8 header[]={'F','O','R','M', 0x01,0xFE,  /* File ID block,      size 1*256+0xFE=510*/
1670                'N','S','L','D', 0x01,0xF8}; /* Startup Logo block, size 1*256+0xF8=504*/
1671   GSM_Bitmap copy;
1672   
1673   copy=*bitmap;
1674   
1675   GSM_ResizeBitmap(&copy,GSM_StartupLogo);
1676   
1677   fwrite(header,1,sizeof(header),file);
1678
1679   fwrite(copy.bitmap,1,copy.size,file);
1680 }
1681
1682 void saveota(FILE *file, GSM_Bitmap *bitmap)
1683 {
1684
1685   char header[]={0x01,
1686                  0x00, /* Width */
1687                  0x00, /* Height */
1688                  0x01};
1689   GSM_Bitmap copy;
1690   
1691   copy=*bitmap;
1692   
1693   header[1]=copy.width;
1694   header[2]=copy.height;
1695     
1696   fwrite(header,1,sizeof(header),file);
1697
1698   fwrite(copy.bitmap,1,copy.size,file);
1699 }
1700
1701 void savenlm(FILE *file, GSM_Bitmap *bitmap)
1702 {
1703
1704   char header[]={'N','L','M', /* Nokia Logo Manager file ID. */
1705                  0x20,
1706                  0x01,
1707                  0x00,        /* 0x00 (OP), 0x01 (CLI), 0x02 (Startup), 0x03 (Picture)*/
1708                  0x00,        /* Number of images inside file - 1. 0x01==2 images, 0x03==4 images, etc. */
1709                  0x00,        /* Width. */
1710                  0x00,        /* Height. */
1711                  0x01};
1712                  
1713   unsigned char buffer[1000];
1714   int x,y,pos,pos2;
1715   div_t division;
1716   GSM_Bitmap copy;
1717   
1718   copy=*bitmap;
1719   
1720   switch (copy.type) {
1721   case GSM_OperatorLogo    : header[5]=0x00; break;
1722   case GSM_7110OperatorLogo: header[5]=0x00; break;
1723   case GSM_CallerLogo      : header[5]=0x01; break;
1724   case GSM_StartupLogo     : header[5]=0x02; break;
1725   case GSM_7110StartupLogo : header[5]=0x02; break;
1726   case GSM_6210StartupLogo : header[5]=0x02; break;
1727   case GSM_PictureImage    : header[5]=0x03; break;
1728   case GSM_WelcomeNoteText :                 break;
1729   case GSM_DealerNoteText  :                 break;
1730   case GSM_None            :                 break;
1731   }
1732   
1733   header[7]=copy.width;
1734   header[8]=copy.height;
1735   
1736   pos=0;pos2=7;
1737   for (y=0;y<copy.height;y++) {
1738     for (x=0;x<copy.width;x++) {
1739       if (pos2==7) buffer[pos]=0;
1740       
1741       if (GSM_IsPointBitmap(&copy,x,y)) buffer[pos]|=(1<<pos2);
1742       
1743       pos2--;
1744       if (pos2<0) {pos2=7;pos++;} //going to new line
1745     }
1746     if (pos2!=7) {pos2=7;pos++;} //for startup logos - new line with new byte
1747   }
1748   
1749   division=div(copy.width,8);
1750   if (division.rem!=0) division.quot++; /* For startup logos */
1751   
1752   fwrite(header,1,sizeof(header),file);
1753
1754   fwrite(buffer,1,(division.quot*copy.height),file);
1755 }
1756
1757 /* mode == 0 -> overwrite
1758  * mode == 1 -> ask
1759  * mode == 2 -> append
1760  */
1761 int GSM_SaveTextFile(char *FileName, char *text, int mode)
1762 {
1763
1764   FILE *file;
1765
1766   if (mode == 2) file = fopen(FileName, "a");
1767             else file = fopen(FileName, "w");
1768
1769   if (!file) return -1;
1770   
1771   fprintf(file, "%s\n\n", text);
1772   
1773   fclose(file);
1774
1775   return mode;
1776 }
1777
1778 GSM_Error GSM_SaveBackupFile(char *FileName, GSM_Backup *backup)
1779 {
1780
1781   FILE *file;
1782      
1783   file = fopen(FileName, "wb");
1784       
1785   if (!file) return(GE_CANTOPENFILE);
1786
1787   savelmb(file, backup);
1788
1789   fclose(file);
1790    
1791   return GE_NONE;
1792 }
1793
1794 void savelmbstartupentry(FILE *file, GSM_Bitmap startup, GSM_Bitmap text, bool available)
1795 {  
1796   /* Welcome note and logo header block */
1797   char req[1000] = {'W','E','L',' ',    /*block identifier*/
1798                     00,00,              /*block data size*/
1799                     0x02,00,00,00,00,00,
1800
1801                     0x02};              /*number of blocks (like in 6110 frame)*/
1802
1803   int count=13;
1804
1805   if (!available) {
1806   } else {
1807     count=count+N6110_MakeStartupLogoFrame(req+13,startup);
1808   }
1809
1810   req[count++]=0x02;
1811   req[count++]=strlen(text.text);
1812   memcpy(req+count,text.text,strlen(text.text));
1813   count=count+strlen(text.text);
1814
1815   req[4]=(count-12)%256;
1816   req[5]=(count-12)/256;
1817
1818   fwrite(req, 1, count, file);
1819 }                    
1820
1821 void savelmbopentry(FILE *file, GSM_Bitmap bitmap)
1822 {  
1823   /* Operator logo header block */
1824   char req[500] = {'O','L','G',' ',        /*block identifier*/
1825                    0x88,00,                /*block data size*/
1826                    0x02,00,00,00,00,00,
1827
1828                    00};
1829
1830   int count=13,i;
1831
1832   count=count+N6110_MakeOperatorLogoFrame(req+13,bitmap);
1833
1834   if (bitmap.width!=0x48) {
1835     req[4]=(count-7)%256;
1836     req[5]=(count-7)/256;
1837
1838     for (i=1;i<=5;i++) req[count++]=0;
1839
1840     req[17]=req[17]+5; //we fix size of logo block
1841   } else {
1842     req[4]=(count-12)%256;
1843     req[5]=(count-12)/256;
1844   }
1845
1846   fwrite(req, 1, count, file);
1847 }                    
1848
1849 /* Work in progress ! */
1850 void savelmbspeedentry(FILE *file, GSM_SpeedDial speed)
1851 {  
1852   /* Speed dial header block */    
1853   char req[] = {'S','P','D',' ', /*block identifier*/
1854                 0x03,00,         /*block data size*/
1855                 0x02,00,
1856                 00,              /*number of speed dial*/
1857                 00,0xFF,00,
1858
1859                 00,              /*number of speed dial*/
1860                 03,              /*memory type. ME=02;SM=03*/
1861                 00};             /*number of location assigned to speed dial*/
1862
1863   req[8]=req[12]=speed.Number;
1864
1865   if (speed.MemoryType==GMT_ME) req[13]=2; //memory type=GMT_ME    
1866
1867   req[14]=speed.Location;
1868
1869   fwrite(req, 1, 15, file);
1870 }                    
1871
1872 void savelmbcallerentry(FILE *file, GSM_Bitmap bitmap)
1873 {  
1874   char req[500] = {'C','G','R',' ',    /*block identifier*/
1875                    00,00,              /*block data size*/
1876                    02,00,              
1877                    00,                 /*group number=0,1,etc.*/
1878                    00,00,00};
1879
1880   int count=12;
1881
1882   req[8]=bitmap.number;
1883
1884   count=count+N6110_MakeCallerGroupFrame(req+12,bitmap);
1885
1886   req[count++]=0;
1887
1888   req[4]=(count-12)%256;
1889   req[5]=(count-12)/256;
1890
1891   fwrite(req, 1, count, file);
1892 }                    
1893
1894 void savelmbpbkentry(FILE *file, GSM_PhonebookEntry entry)
1895 {
1896   char req[500] = {'P','B','E','2', /*block identifier*/
1897                    00,00,           /*block data size*/
1898                    00,00,           
1899                    00,00,           /*position of phonebook entry*/                              
1900                    03,              /*memory type. ME=02;SM=03*/
1901                    00,
1902
1903                    00,00,           /*position of phonebook entry*/                   
1904                    03,              /*memory type. ME=02;SM=03*/
1905                    00};
1906
1907   int count = 16, blocks;
1908
1909   req[9]=req[13] = (entry.Location >> 8);
1910   req[8]=req[12] = entry.Location & 0xff;
1911
1912   if (entry.MemoryType==GMT_ME) req[10]=req[14]=2;
1913
1914   count=count+N7110_EncodePhonebookFrame(req+16, entry, &blocks);
1915
1916   req[4]=(count-12)%256;
1917   req[5]=(count-12)/256;
1918             
1919   fwrite(req, 1, count, file);      
1920 }
1921
1922 void savelmb(FILE *file, GSM_Backup *backup)
1923 {
1924   int i;
1925
1926   char LMBHeader[] = {'L','M','B',' '}; /*file identifier*/
1927     
1928   /* Phonebook header block */
1929   char PBKHeader[] = {'P','B','K',' ', /*block identifier*/
1930                       0x08,00,         /*block data size*/
1931                       0x02,00,         
1932                       03,              /*memory type. ME=02;SM=03*/
1933                       00,00,00,
1934
1935                       00,00,           /*size of phonebook*/
1936                       14,              /*max length of each position*/
1937                       00,00,00,00,00};
1938                                       
1939   fwrite(LMBHeader, 1, sizeof(LMBHeader), file); /* Write the header of the file. */
1940
1941   if (backup->SIMPhonebookUsed!=0) {
1942     PBKHeader[12]=backup->SIMPhonebookSize%256;
1943     PBKHeader[13]=backup->SIMPhonebookSize/256;
1944     fwrite(PBKHeader, 1, sizeof(PBKHeader), file); 
1945
1946     for (i=0;i<backup->SIMPhonebookUsed;i++)
1947       savelmbpbkentry(file, backup->SIMPhonebook[i]);
1948   }
1949
1950   if (backup->PhonePhonebookUsed!=0) {
1951     PBKHeader[8]=2;     //memory type=GMT_ME
1952     PBKHeader[12]=backup->PhonePhonebookSize%256;
1953     PBKHeader[13]=backup->PhonePhonebookSize/256;
1954     PBKHeader[14]=0x16; //max size of one entry
1955     fwrite(PBKHeader, 1, sizeof(PBKHeader), file); 
1956
1957     for (i=0;i<backup->PhonePhonebookUsed;i++)
1958       savelmbpbkentry(file, backup->PhonePhonebook[i]);
1959   }
1960
1961   if (backup->CallerAvailable)
1962     for (i=0;i<5;i++) savelmbcallerentry(file,backup->CallerGroups[i]);
1963
1964 //  if (backup->SpeedAvailable)
1965 //    for (i=0;i<8;i++) savelmbspeedentry(file,backup->SpeedDials[i]);
1966
1967   if (backup->OperatorLogoAvailable) savelmbopentry(file,backup->OperatorLogo);
1968
1969   savelmbstartupentry(file,backup->StartupLogo,backup->StartupText,backup->StartupLogoAvailable);
1970 }
1971
1972 void loadlmbcallerentry(unsigned char *buffer, unsigned char *buffer2, GSM_Backup *backup, int number)
1973
1974   int i;
1975
1976   backup->CallerAvailable=true;
1977
1978 #ifdef DEBUG
1979   fprintf(stdout, _("  Number %i, name \""), buffer2[0]);
1980   for (i=0;i<buffer2[1];i++) {
1981     fprintf(stdout, _("%c"), buffer2[i+2]);
1982   }
1983   fprintf(stdout, _("\"\n"));
1984
1985   fprintf(stdout,_("  Ringtone ID=%i\n"), buffer2[i+2]);
1986
1987   if (buffer2[i+3]==1) fprintf(stdout,_("  Logo enabled\n"));
1988                   else fprintf(stdout,_("  Logo disabled\n"));  
1989 #endif
1990
1991   backup->CallerGroups[number].number=buffer2[0];
1992   backup->CallerGroups[number].type=GSM_CallerLogo;
1993
1994   for (i=0;i<buffer2[1];i++) {
1995     backup->CallerGroups[number].text[i]=buffer2[i+2];
1996   }
1997   backup->CallerGroups[number].text[buffer2[1]]=0;
1998         
1999   backup->CallerGroups[number].ringtone=buffer2[i+2];
2000         
2001   backup->CallerGroups[number].enabled=false;
2002   if (buffer2[i+3]==1) backup->CallerGroups[number].enabled=true;
2003
2004   backup->CallerGroups[number].width=buffer2[i+7];
2005   backup->CallerGroups[number].height=buffer2[i+8];
2006                 
2007   backup->CallerGroups[number].size=GSM_GetBitmapSize(&backup->CallerGroups[number]);
2008       
2009   memcpy(backup->CallerGroups[number].bitmap,buffer2+i+10,backup->CallerGroups[number].size);
2010
2011 #ifdef DEBUG
2012   fprintf(stdout, _("  Caller logo"));
2013   fprintf(stdout, _(" (size %ix%i - %i bytes)\n"),
2014      backup->CallerGroups[number].width, backup->CallerGroups[number].height, backup->CallerGroups[number].size);
2015   GSM_PrintBitmap(&backup->CallerGroups[number]);
2016 #endif
2017
2018 }                    
2019
2020 void loadlmbopentry(unsigned char *buffer, unsigned char *buffer2, GSM_Backup *backup)
2021 {  
2022   backup->OperatorLogoAvailable=true;
2023
2024   DecodeNetworkCode(buffer2+1, backup->OperatorLogo.netcode);
2025
2026   backup->OperatorLogo.text[0]=0;
2027
2028   backup->OperatorLogo.width=buffer2[7];
2029   backup->OperatorLogo.height=buffer2[8];
2030
2031   backup->OperatorLogo.type=GSM_OperatorLogo;      
2032   if (backup->OperatorLogo.width==78) backup->OperatorLogo.type=GSM_7110OperatorLogo;      
2033
2034   backup->OperatorLogo.size=GSM_GetBitmapSize(&backup->OperatorLogo);      
2035
2036 #ifdef DEBUG
2037   fprintf(stdout, _("  GSM operator logo (size %ix%i - %i bytes) for %s (%s) network.\n"),
2038        backup->OperatorLogo.width, backup->OperatorLogo.height,
2039        backup->OperatorLogo.size, backup->OperatorLogo.netcode,
2040        GSM_GetNetworkName(backup->OperatorLogo.netcode));
2041 #endif
2042
2043   memcpy(backup->OperatorLogo.bitmap,buffer2+10,backup->OperatorLogo.size);
2044
2045 #ifdef DEBUG
2046   GSM_PrintBitmap(&backup->OperatorLogo);
2047 #endif
2048
2049 }                    
2050
2051 void loadlmbpbkentry(unsigned char *buffer, unsigned char *buffer2, GSM_Backup *backup)
2052 {
2053   GSM_PhonebookEntry pbk;
2054
2055 #ifdef DEBUG
2056   fprintf(stdout,_("  Memory : "));
2057   switch(buffer[10]) {
2058     case 2: fprintf(stdout, _("(internal)\n"));break;
2059     case 3: fprintf(stdout, _("(sim)\n"));break;
2060     default: fprintf(stdout, _("(unknown)\n"));break;
2061   }
2062   fprintf(stdout,_("  Location : %i\n"),buffer2[0]+buffer2[1]*256);
2063 #endif
2064
2065   pbk.Empty = true;
2066   pbk.Group = 5;     /* 5 = no group as 6110 */
2067   pbk.Name[0] = 0;
2068   pbk.Number[0] = 0;
2069   pbk.SubEntriesCount = 0;
2070
2071   N7110_DecodePhonebookFrame(&pbk,buffer2+4,(buffer[4]+buffer[5]*256)-4);
2072
2073   pbk.MemoryType=GMT_SM;
2074   if (buffer[10]==2) pbk.MemoryType=GMT_ME;
2075
2076   pbk.Location=buffer2[0]+256*buffer2[1];
2077
2078   if (buffer[10]==2) backup->PhonePhonebook[backup->PhonePhonebookUsed++]=pbk;
2079                 else backup->SIMPhonebook  [backup->SIMPhonebookUsed++]  =pbk;
2080 }
2081
2082 void loadlmbstartupentry(unsigned char *buffer, unsigned char *buffer2, GSM_Backup *backup)
2083 {
2084   int i,j;
2085 #ifdef DEBUG
2086   int z;
2087 #endif
2088
2089   j=1;
2090   for (i=0;i<buffer2[0];i++) {
2091     switch (buffer2[j++]) {
2092       case 1:
2093         backup->StartupLogoAvailable=true;
2094         backup->StartupLogo.height=buffer2[j++];
2095         backup->StartupLogo.width=buffer2[j++];
2096         backup->StartupLogo.text[0]=0;
2097         backup->StartupLogo.type=GSM_StartupLogo;
2098         switch (backup->StartupLogo.height) {
2099           case 65:backup->StartupLogo.type=GSM_7110StartupLogo;break;
2100           case 60:backup->StartupLogo.type=GSM_6210StartupLogo;break;
2101         }
2102         backup->StartupLogo.size=GSM_GetBitmapSize(&backup->StartupLogo);
2103             
2104 #ifdef DEBUG
2105         fprintf(stdout, _("  Block 1 - startup logo (size %ix%i - %i bytes)\n"),
2106               backup->StartupLogo.width, backup->StartupLogo.height, backup->StartupLogo.size);
2107 #endif
2108
2109         memcpy(backup->StartupLogo.bitmap,buffer2+j,backup->StartupLogo.size);
2110 #ifdef DEBUG
2111         GSM_PrintBitmap(&backup->StartupLogo);
2112 #endif
2113         j=j+backup->StartupLogo.size;
2114
2115         break;            
2116       case 2:
2117
2118 #ifdef DEBUG
2119         fprintf(stdout, _("  Block 2 - welcome note \""));
2120         for (z=0;z<buffer2[j];z++) fprintf(stdout, _("%c"),buffer2[j+z+1]);
2121         fprintf(stdout, _("\"\n"));
2122 #endif
2123         break;
2124       default:
2125 #ifdef DEBUG
2126         fprintf(stdout, _("  Unknown block %02x\n"),buffer2[j]);
2127 #endif
2128         break;
2129     }
2130   }
2131 }
2132
2133 GSM_Error loadlmb(FILE *file, GSM_Backup *backup)
2134 {
2135 #ifdef DEBUG
2136   int i;
2137 #endif
2138   int number=0;
2139
2140   unsigned char buffer[12], buffer2[1000]; //for data from file
2141
2142   fread(buffer, 1, 4, file); /* Read the header of the file. */
2143
2144   while (fread(buffer, 1, 12, file)==12) { //while we have something to read
2145
2146 #ifdef DEBUG
2147     /* Info about block in the file */
2148     fprintf(stdout, _("Block \""));
2149     for (i=0;i<4;i++) {fprintf(stdout, _("%c"),buffer[i]);}
2150     fprintf(stdout, _("\" ("));
2151     if (memcmp(buffer, "PBK ",4)==0) {fprintf(stdout, _("Phonebook"));      } else {
2152     if (memcmp(buffer, "PBE2",4)==0) {fprintf(stdout, _("Phonebook entry"));} else {
2153     if (memcmp(buffer, "CGR ",4)==0) {fprintf(stdout, _("Caller group"));   } else {      
2154     if (memcmp(buffer, "SPD ",4)==0) {fprintf(stdout, _("Speed dial"));     } else {      
2155     if (memcmp(buffer, "OLG ",4)==0) {fprintf(stdout, _("Operator logo"));  } else {      
2156     if (memcmp(buffer, "WEL ",4)==0) {fprintf(stdout, _("Startup logo and welcome text")); } else {      
2157                                       fprintf(stdout, _("uknown - ignored"));}}}}}}
2158
2159     fprintf(stdout, _(") - length %i\n"), buffer[4]+buffer[5]*256);
2160 #endif
2161       
2162     fread(buffer2, 1, buffer[4]+buffer[5]*256, file); //reading block data
2163
2164 #ifdef DEBUG
2165     if (memcmp(buffer, "PBK ",4)==0) { //phonebook
2166       fprintf(stdout, _("  Size of phonebook %i, type %i "),(buffer2[0]+buffer2[1]*256),buffer[8]);
2167       switch(buffer[8]) {
2168         case 2 : fprintf(stdout, _("(internal)"));break;
2169         case 3 : fprintf(stdout, _("(sim)"))     ;break;
2170         default: fprintf(stdout, _("(unknown)")) ;break;
2171       }
2172       fprintf(stdout, _(", length of each position - %i\n"),buffer2[2]);
2173     }
2174 #endif        
2175
2176     if (memcmp(buffer, "PBE2",4)==0) //phonebook entry        
2177       loadlmbpbkentry(buffer,buffer2,backup);
2178
2179     if (memcmp(buffer, "CGR ",4)==0) { //caller groups
2180       loadlmbcallerentry(buffer,buffer2,backup,number);
2181       number++;
2182     }
2183
2184     if (memcmp(buffer, "OLG ",4)==0) //operator logo
2185       loadlmbopentry(buffer,buffer2,backup);
2186
2187     if (memcmp(buffer, "WEL ",4)==0) //welcome blocks
2188       loadlmbstartupentry(buffer,buffer2,backup);
2189   }
2190
2191   return(GE_NONE);
2192 }
2193
2194 GSM_Error GSM_ReadBackupFile(char *FileName, GSM_Backup *backup)
2195 {
2196
2197   FILE *file;
2198   unsigned char buffer[300];
2199   GSM_Error error;
2200   GSM_Filetypes filetype=None;
2201
2202   file = fopen(FileName, "rb");
2203
2204   if (!file) return(GE_CANTOPENFILE);
2205
2206   fread(buffer, 1, 4, file); /* Read the header of the file. */
2207
2208   /* Attempt to identify filetype */
2209
2210   if (memcmp(buffer, "LMB ",4)==0) {  /* LMB files have 'LMB ' at the start */
2211     filetype=LMB;
2212   } else filetype=None;
2213
2214   error=GE_NONE;
2215   
2216   rewind(file);
2217
2218   backup->PhonePhonebookUsed=0;
2219   backup->SIMPhonebookUsed=0;
2220   backup->StartupLogoAvailable=false;
2221   backup->StartupText.text[0]=0;
2222   backup->OperatorLogoAvailable=false;
2223   backup->CallerAvailable=false;
2224   backup->SpeedAvailable=false;
2225
2226   switch (filetype) {
2227     case LMB: error=loadlmb(file,backup); fclose(file); break;
2228     default : error=GE_INVALIDFILEFORMAT;
2229   }
2230
2231   return(error);
2232 }
2233
2234 GSM_Error GSM_SaveBinRingtoneFile(char *FileName, GSM_BinRingtone *ringtone)
2235 {
2236
2237   FILE *file;
2238
2239   file = fopen(FileName, "wb");
2240       
2241   if (!file) return(GE_CANTOPENFILE);
2242         
2243   fwrite(ringtone->frame, 1, ringtone->length, file);           
2244
2245   fclose(file);
2246    
2247   return GE_NONE;
2248 }