Translation update done using Pootle.
[gammu.git] / gammu / files.c
blobcd16f44dae9a50d60025a0065a29e7e4c046ca1d
1 #define _GNU_SOURCE /* For strcasestr */
2 #include <string.h>
4 #include "../helper/locales.h"
6 #include <gammu.h>
7 #include <stdlib.h>
8 #include <signal.h>
10 #ifdef WIN32
11 # include <windows.h>
12 # include <process.h>
13 # ifdef _MSC_VER
14 # include <sys/utime.h>
15 # else
16 # include <utime.h>
17 # endif
18 #else
19 # include <utime.h>
20 #endif
22 #include "files.h"
23 #include "memory.h"
24 #include "message.h"
25 #include "common.h"
27 #include "../helper/formats.h"
28 #include "../helper/printing.h"
29 #include "../helper/string.h"
31 /**
32 * Displays status of filesystem (if available).
34 static GSM_Error PrintFileSystemStatus(void)
36 GSM_FileSystemStatus Status;
37 GSM_Error error;
39 error = GSM_GetFileSystemStatus(gsm, &Status);
40 if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) {
41 return error;
44 Print_Error(error);
46 printf("\n");
48 printf(LISTFORMAT, _("Phone memory"));
49 printf(_("%i bytes (free %i bytes, used %i bytes)"),
50 Status.Free + Status.Used, Status.Free, Status.Used);
51 printf("\n");
53 if (Status.UsedImages != 0 || Status.UsedSounds != 0
54 || Status.UsedThemes != 0) {
55 printf(LISTFORMAT, _("Usage details"));
56 printf(_("images: %i, sounds: %i, themes: %i"),
57 Status.UsedImages, Status.UsedSounds, Status.UsedThemes);
58 printf("\n");
61 return error;
64 void GetFileSystemStatus(int argc UNUSED, char *argv[]UNUSED)
66 GSM_Error error;
67 GSM_Init(TRUE);
69 error = PrintFileSystemStatus();
70 Print_Error(error);
72 GSM_Terminate();
75 void GetFileSystem(int argc, char *argv[])
77 GSM_Error error;
78 gboolean Start = TRUE, MemoryCard = FALSE;
79 GSM_File Files;
80 int j;
81 long usedphone = 0, usedcard = 0;
82 char FolderName[256], IDUTF[200];
84 GSM_Init(TRUE);
86 while (1) {
87 error = GSM_GetNextFileFolder(gsm, &Files, Start);
88 if (error == ERR_EMPTY)
89 break;
90 if (error != ERR_FOLDERPART)
91 Print_Error(error);
93 if (!Files.Folder) {
94 if (GSM_IsPhoneFeatureAvailable
95 (GSM_GetModelInfo(gsm), F_FILES2)) {
96 if (DecodeUnicodeString(Files.ID_FullName)[0] ==
97 'a') {
98 MemoryCard = TRUE;
99 usedcard += Files.Used;
100 } else {
101 usedphone += Files.Used;
103 } else {
104 usedphone += Files.Used;
108 if (argc <= 2 || !strcasecmp(argv[2], "-flatall") == 0) {
109 /* Nokia filesystem 1 */
110 if (UnicodeLength(Files.ID_FullName) != 0 &&
111 (DecodeUnicodeString(Files.ID_FullName)[0] == 'C' ||
112 DecodeUnicodeString(Files.ID_FullName)[0] ==
113 'c')) {
114 printf("%8s.",
115 DecodeUnicodeString(Files.ID_FullName));
117 if (Files.Protected) {
118 /* l10n: One char to indicate protected file */
119 printf("%s", _("P"));
120 } else {
121 printf(" ");
123 if (Files.ReadOnly) {
124 /* l10n: One char to indicate read only file */
125 printf("%s", _("R"));
126 } else {
127 printf(" ");
129 if (Files.Hidden) {
130 /* l10n: One char to indicate hidden file */
131 printf("%s", _("H"));
132 } else {
133 printf(" ");
135 if (Files.System) {
136 /* l10n: One char to indicate system file */
137 printf("%s", _("S"));
138 } else {
139 printf(" ");
141 if (argc > 2 && strcasecmp(argv[2], "-flat") == 0) {
142 if (!Files.Folder) {
143 if (strcasecmp(argv[2], "-flatall") ==
144 0) {
145 if (!Files.ModifiedEmpty) {
146 printf(" %30s",
147 OSDateTime(Files.
148 Modified,
149 FALSE));
150 } else
151 printf(" %30c", 0x20);
152 printf(" %9li", (long)Files.Used);
153 printf(" ");
154 } else
155 printf("|-- ");
156 } else {
157 if (error == ERR_FOLDERPART) {
158 printf("%s ", _("Part of folder"));
159 } else {
160 printf("%s ", _("Folder"));
163 } else {
164 if (Files.Level != 1) {
165 for (j = 0; j < Files.Level - 2; j++)
166 printf(" | ");
167 printf(" |-- ");
169 if (Files.Folder) {
170 if (error == ERR_FOLDERPART) {
171 printf("%s ", _("Part of folder"));
172 } else {
173 printf("%s ", _("Folder"));
177 printf("\"%s\"\n", DecodeUnicodeConsole(Files.Name));
178 } else if (argc > 2 && strcasecmp(argv[2], "-flatall") == 0) {
179 /* format for a folder ID;Folder;FOLDER_NAME;[FOLDER_PARAMETERS]
180 * format for a file ID;File;FOLDER_NAME;FILE_NAME;DATESTAMP;FILE_SIZE;[FILE_PARAMETERS] */
181 EncodeUTF8QuotedPrintable(IDUTF, Files.ID_FullName);
182 printf("%s;", IDUTF);
183 if (!Files.Folder) {
184 printf("%s", _("File;"));
185 printf("\"%s\";", FolderName);
186 printf("\"%s\";",
187 DecodeUnicodeConsole(Files.Name));
188 if (!Files.ModifiedEmpty) {
189 printf("\"%s\";",
190 OSDateTime(Files.Modified,
191 FALSE));
192 } else
193 printf("\"%c\";", 0x20);
194 printf("%ld;", (long)Files.Used);
195 } else {
196 if (error == ERR_FOLDERPART) {
197 printf("%s;", _("Part of folder"));
198 } else {
199 printf("%s;", _("Folder"));
201 printf("\"%s\";",
202 DecodeUnicodeConsole(Files.Name));
203 strcpy(FolderName,
204 DecodeUnicodeConsole(Files.Name));
207 if (Files.Protected)
208 printf("%s", _("P"));
209 if (Files.ReadOnly)
210 printf("%s", _("R"));
211 if (Files.Hidden)
212 printf("%s", _("H"));
213 if (Files.System)
214 printf("%s", _("S"));
215 printf("\n");
217 Start = FALSE;
220 error = PrintFileSystemStatus();
222 if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) {
223 printf("\n");
224 printf(_("Used in phone: %li bytes"), usedphone);
225 if (MemoryCard)
226 printf(_(", used in card: %li bytes"), usedcard);
227 printf("\n");
230 GSM_Terminate();
233 void SetFileAttrib(int argc, char *argv[])
235 GSM_File Files;
236 GSM_Error error;
237 int i;
239 Files.ReadOnly = FALSE;
240 Files.Protected = FALSE;
241 Files.System = FALSE;
242 Files.Hidden = FALSE;
244 DecodeUTF8QuotedPrintable(Files.ID_FullName, argv[2], strlen(argv[2]));
246 for (i = 3; i < argc; i++) {
247 if (strcasecmp(argv[i], "-readonly") == 0) {
248 Files.ReadOnly = TRUE;
249 } else if (strcasecmp(argv[i], "-protected") == 0) {
250 Files.Protected = TRUE;
251 } else if (strcasecmp(argv[i], "-system") == 0) {
252 Files.System = TRUE;
253 } else if (strcasecmp(argv[i], "-hidden") == 0) {
254 Files.Hidden = TRUE;
255 } else {
256 fprintf(stderr, _("Unknown attribute (%s)\n"), argv[i]);
260 GSM_Init(TRUE);
262 error = GSM_SetFileAttributes(gsm, &Files);
263 Print_Error(error);
265 GSM_Terminate();
268 void GetRootFolders(int argc UNUSED, char *argv[]UNUSED)
270 GSM_File File;
271 char IDUTF[200];
273 GSM_Init(TRUE);
275 File.ID_FullName[0] = 0;
276 File.ID_FullName[1] = 0;
278 while (1) {
279 if (GSM_GetNextRootFolder(gsm, &File) != ERR_NONE)
280 break;
281 EncodeUTF8QuotedPrintable(IDUTF, File.ID_FullName);
282 printf("%s ", IDUTF);
283 printf("- %s\n", DecodeUnicodeString(File.Name));
286 GSM_Terminate();
289 void GetFolderListing(int argc UNUSED, char *argv[])
291 GSM_Error error;
292 gboolean Start = TRUE;
293 GSM_File Files;
294 char IDUTF[200];
296 GSM_Init(TRUE);
298 DecodeUTF8QuotedPrintable(Files.ID_FullName, argv[2], strlen(argv[2]));
300 while (1) {
301 error = GSM_GetFolderListing(gsm, &Files, Start);
302 if (error == ERR_EMPTY)
303 break;
304 if (error != ERR_FOLDERPART) {
305 Print_Error(error);
306 } else {
307 printf("%s\n\n", _("Part of folder only"));
310 /* format for a folder ID;Folder;[FOLDER_PARAMETERS]
311 * format for a file ID;File;FILE_NAME;DATESTAMP;FILE_SIZE;[FILE_PARAMETERS] */
312 EncodeUTF8QuotedPrintable(IDUTF, Files.ID_FullName);
313 printf("%s;", IDUTF);
314 if (!Files.Folder) {
315 printf("%s", _("File;"));
316 printf("\"%s\";", DecodeUnicodeConsole(Files.Name));
317 if (!Files.ModifiedEmpty) {
318 printf("\"%s\";",
319 OSDateTime(Files.Modified, FALSE));
320 } else
321 printf("\"%c\";", 0x20);
322 printf("%ld;", (long)Files.Used);
323 } else {
324 printf("%s", _("Folder"));
325 printf(";\"%s\";", DecodeUnicodeConsole(Files.Name));
328 if (Files.Protected)
329 printf("%s", _("P"));
330 if (Files.ReadOnly)
331 printf("%s", _("R"));
332 if (Files.Hidden)
333 printf("%s", _("H"));
334 if (Files.System)
335 printf("%s", _("S"));
336 printf("\n");
338 Start = FALSE;
341 GSM_Terminate();
344 static void GetOneFile(GSM_File * File, gboolean newtime, int i)
346 GSM_Error error;
347 FILE *file;
348 gboolean start;
349 unsigned char buffer[5000];
350 struct utimbuf filedate;
351 int Handle, Size, p, q, j, old1;
352 time_t t_time1, t_time2;
353 long diff;
355 if (File->Buffer != NULL) {
356 free(File->Buffer);
357 File->Buffer = NULL;
359 File->Used = 0;
360 start = TRUE;
362 t_time1 = time(NULL);
363 old1 = 65536;
365 error = ERR_NONE;
366 while (error == ERR_NONE) {
367 error = GSM_GetFilePart(gsm, File, &Handle, &Size);
368 if (error == ERR_NONE || error == ERR_EMPTY
369 || error == ERR_WRONGCRC) {
370 if (start) {
371 printf(_("Getting \"%s\"\n"),
372 DecodeUnicodeConsole(File->Name));
373 start = FALSE;
375 if (File->Folder) {
376 free(File->Buffer);
377 GSM_Terminate();
378 printf("%s\n",
379 _ ("Is a folder. Please give only file names."));
380 Terminate(2);
382 if (Size == 0) {
383 fprintf(stderr, "*");
384 } else {
385 fprintf(stderr, "\r");
386 fprintf(stderr, _("%i percent"),
387 (int)(File->Used * 100 / Size));
388 if (File->Used * 100 / Size >= 2) {
389 t_time2 = time(NULL);
390 diff = t_time2 - t_time1;
391 p = diff * (Size -
392 File->Used) / File->Used;
393 if (p != 0) {
394 if (p < old1)
395 old1 = p;
396 q = old1 / 60;
397 fprintf(stderr,
399 (" (%02i:%02i minutes left)"),
400 q, old1 - q * 60);
401 } else {
402 fprintf(stderr, "%30c", 0x20);
406 if (error == ERR_EMPTY)
407 break;
408 if (error == ERR_WRONGCRC) {
409 printf_warn("%s\n",
410 _("File checksum calculated by phone doesn't match with value calculated by Gammu. File is damaged or there is a error in Gammu."));
411 break;
414 Print_Error(error);
416 t_time2 = time(NULL);
417 diff = t_time2 - t_time1;
418 if ((diff > 0) && (File->Used > 0)) {
419 fprintf(stderr, "\r");
420 if (Size != 0) {
421 fprintf(stderr, _("%i percent done."), (int)(File->Used * 100 / Size));
423 fprintf(stderr, _("%lu Bytes in %li seconds, %lu Bytes/sec"),
424 (long unsigned int) File->Used, (long unsigned int) diff, (long unsigned int) File->Used / diff);
426 fprintf(stderr, "\n");
427 fflush(stderr);
428 if (error == ERR_NONE || error == ERR_EMPTY || error == ERR_WRONGCRC) {
429 if (File->Used != 0) {
430 sprintf(buffer, "%s", DecodeUnicodeConsole(File->Name));
431 for (j = strlen(buffer) - 1; j > 0; j--) {
432 if (buffer[j] == '\\' || buffer[j] == '/')
433 break;
435 if (buffer[j] == '\\' || buffer[j] == '/') {
436 sprintf(buffer, "%s",
437 DecodeUnicodeConsole(File->Name +
438 j * 2 + 2));
440 file = fopen(buffer, "wb");
441 if (file == NULL) {
442 sprintf(buffer, "file%s",
443 DecodeUnicodeString(File->ID_FullName));
444 file = fopen(buffer, "wb");
446 if (file == NULL) {
447 sprintf(buffer, "file%i", i);
448 file = fopen(buffer, "wb");
450 if (file == NULL)
451 Print_Error(ERR_CANTOPENFILE);
452 printf(_(" Saving to %s\n"), buffer);
453 if (fwrite(File->Buffer, 1, File->Used, file) != File->Used) {
454 printf_err("%s", _("Error while writing file!\n"));
456 free(File->Buffer);
457 File->Buffer = NULL;
458 fclose(file);
459 if (!newtime && !File->ModifiedEmpty) {
460 /* access time */
461 filedate.actime = Fill_Time_T(File->Modified);
462 /* modification time */
463 filedate.modtime = Fill_Time_T(File->Modified);
464 smprintf(gsm, "Setting date of %s\n", buffer);
465 utime(buffer, &filedate);
471 void GetFiles(int argc, char *argv[])
473 GSM_File File;
474 int i;
475 gboolean newtime = FALSE;
477 File.Buffer = NULL;
479 GSM_Init(TRUE);
481 for (i = 2; i < argc; i++) {
482 if (strcasecmp(argv[i], "-newtime") == 0) {
483 newtime = TRUE;
484 continue;
487 DecodeUTF8QuotedPrintable(File.ID_FullName, argv[i],
488 strlen(argv[i]));
489 smprintf(gsm, "grabbing '%s' '%s'\n",
490 DecodeUnicodeString(File.ID_FullName), argv[i]);
491 GetOneFile(&File, newtime, i);
494 GSM_Terminate();
497 void GetFileFolder(int argc, char *argv[])
499 GSM_Error error;
500 gboolean Start = TRUE;
501 GSM_File File;
502 int level = 0, allnum = 0, num = 0, filelevel = 0, i = 0;
503 gboolean newtime = FALSE, found;
504 unsigned char IDUTF[200];
506 File.Buffer = NULL;
508 GSM_Init(TRUE);
510 for (i = 2; i < argc; i++) {
511 if (strcasecmp(argv[i], "-newtime") == 0) {
512 newtime = TRUE;
513 continue;
515 allnum++;
518 while (allnum != num) {
519 error = GSM_GetNextFileFolder(gsm, &File, Start);
520 if (error == ERR_EMPTY)
521 break;
522 Print_Error(error);
524 if (level == 0) {
525 /* We search for file or folder */
526 found = FALSE;
527 for (i = 2; i < argc; i++) {
528 if (strcasecmp(argv[i], "-newtime") == 0) {
529 continue;
531 smprintf(gsm, "comparing %s %s\n",
532 DecodeUnicodeString(File.ID_FullName),
533 argv[i]);
534 DecodeUTF8QuotedPrintable(IDUTF, argv[i],
535 strlen(argv[i]));
536 if (mywstrncasecmp(File.ID_FullName, IDUTF, 0)) {
537 smprintf(gsm, "found folder");
538 found = TRUE;
539 if (File.Folder) {
540 level = 1;
541 filelevel = File.Level + 1;
542 Start = FALSE;
543 } else {
544 level = 2;
546 break;
549 if (found && File.Folder)
550 continue;
552 if (level == 1) {
553 /* We have folder */
554 smprintf(gsm, "%i %i\n", File.Level, filelevel);
555 if (File.Level != filelevel) {
556 level = 0;
557 num++;
561 if (level != 0 && !File.Folder) {
562 GetOneFile(&File, newtime, i);
563 i++;
566 if (level == 2) {
567 level = 0;
568 num++;
571 Start = FALSE;
574 free(File.Buffer);
575 GSM_Terminate();
578 void AddOneFile(GSM_File * File, const char *text, const gboolean send)
580 GSM_Error error;
581 int Pos, Handle, i, j, old1;
582 time_t t_time1, t_time2;
583 GSM_DateTime dt;
584 long diff;
586 GSM_GetCurrentDateTime(&dt);
587 t_time1 = Fill_Time_T(dt);
588 old1 = 65536;
590 smprintf(gsm, "Adding file to filesystem now\n");
591 error = ERR_NONE;
592 Pos = 0;
593 while (error == ERR_NONE) {
594 if (send) {
595 error = GSM_SendFilePart(gsm, File, &Pos, &Handle);
596 } else {
597 error = GSM_AddFilePart(gsm, File, &Pos, &Handle);
599 if (error != ERR_EMPTY && error != ERR_WRONGCRC)
600 Print_Error(error);
601 if (File->Used != 0) {
602 fprintf(stderr, "\r");
603 fprintf(stderr, "%s ", text);
604 fprintf(stderr, _("%i percent"),
605 (int)(Pos * 100 / File->Used));
606 if (Pos * 100 / File->Used >= 2) {
607 GSM_GetCurrentDateTime(&dt);
608 t_time2 = Fill_Time_T(dt);
609 diff = t_time2 - t_time1;
610 i = diff * (File->Used - Pos) / Pos;
611 if (i != 0) {
612 if (i < old1)
613 old1 = i;
614 j = old1 / 60;
615 fprintf(stderr,
616 _(" (%02i:%02i minutes left)"),
617 j, old1 - (j * 60));
618 } else {
619 fprintf(stderr, "%30c", ' ');
624 fprintf(stderr, "\n");
625 if (error == ERR_WRONGCRC) {
626 printf_warn("%s\n",
627 _("File checksum calculated by phone doesn't match with value calculated by Gammu. File is damaged or there is a error in Gammu."));
631 void AddSendFile(int argc, char *argv[])
633 GSM_Error error;
634 GSM_File File;
635 int i, nextlong;
636 char IDUTF[200];
637 gboolean sendfile = FALSE;
638 int optint = 2;
640 if (strcasestr(argv[1], "sendfile") != NULL) {
641 sendfile = TRUE;
644 File.Buffer = NULL;
645 if (!sendfile) {
646 DecodeUTF8QuotedPrintable(File.ID_FullName, argv[optint],
647 strlen(argv[optint]));
648 optint++;
650 error = GSM_ReadFile(argv[optint], &File);
651 Print_Error(error);
652 EncodeUnicode(File.Name, argv[optint], strlen(argv[optint]));
653 for (i = strlen(argv[optint]) - 1; i > 0; i--) {
654 if (argv[optint][i] == '\\' || argv[optint][i] == '/')
655 break;
657 if (argv[optint][i] == '\\' || argv[optint][i] == '/') {
658 EncodeUnicode(File.Name, argv[optint] + i + 1,
659 strlen(argv[optint]) - i - 1);
661 optint++;
663 GSM_IdentifyFileFormat(&File);
665 File.Protected = FALSE;
666 File.ReadOnly = FALSE;
667 File.Hidden = FALSE;
668 File.System = FALSE;
670 if (argc > optint) {
671 nextlong = 0;
672 for (i = optint; i < argc; i++) {
673 switch (nextlong) {
674 case 0:
675 if (strcasecmp(argv[i], "-type") == 0) {
676 nextlong = 1;
677 continue;
679 if (strcasecmp(argv[i], "-protected") ==
680 0) {
681 File.Protected = TRUE;
682 continue;
684 if (strcasecmp(argv[i], "-readonly") ==
685 0) {
686 File.ReadOnly = TRUE;
687 continue;
689 if (strcasecmp(argv[i], "-hidden") == 0) {
690 File.Hidden = TRUE;
691 continue;
693 if (strcasecmp(argv[i], "-system") == 0) {
694 File.System = TRUE;
695 continue;
697 if (strcasecmp(argv[i], "-newtime") ==
698 0) {
699 File.ModifiedEmpty = TRUE;
700 continue;
702 printf(_("Parameter \"%s\" unknown\n"),
703 argv[i]);
704 Terminate(2);
705 case 1:
706 if (strcasecmp(argv[i], "JAR") == 0) {
707 File.Type = GSM_File_Java_JAR;
708 } else if (strcasecmp(argv[i], "JPG") ==
709 0) {
710 File.Type = GSM_File_Image_JPG;
711 } else if (strcasecmp(argv[i], "BMP") ==
712 0) {
713 File.Type = GSM_File_Image_BMP;
714 } else if (strcasecmp(argv[i], "WBMP")
715 == 0) {
716 File.Type = GSM_File_Image_WBMP;
717 } else if (strcasecmp(argv[i], "GIF") ==
718 0) {
719 File.Type = GSM_File_Image_GIF;
720 } else if (strcasecmp(argv[i], "PNG") ==
721 0) {
722 File.Type = GSM_File_Image_PNG;
723 } else if (strcasecmp(argv[i], "MIDI")
724 == 0) {
725 File.Type = GSM_File_Sound_MIDI;
726 } else if (strcasecmp(argv[i], "AMR") ==
727 0) {
728 File.Type = GSM_File_Sound_AMR;
729 } else if (strcasecmp(argv[i], "NRT") ==
730 0) {
731 File.Type = GSM_File_Sound_NRT;
732 } else if (strcasecmp(argv[i], "3GP") ==
733 0) {
734 File.Type = GSM_File_Video_3GP;
735 } else {
736 printf(_
737 ("What file type (\"%s\") ?\n"),
738 argv[i]);
739 Terminate(2);
741 nextlong = 0;
742 break;
745 if (nextlong != 0) {
746 printf_err("%s\n", _("Parameter missing!"));
747 Terminate(2);
751 GSM_Init(TRUE);
753 AddOneFile(&File, _("Writing:"), sendfile);
754 EncodeUTF8QuotedPrintable(IDUTF, File.ID_FullName);
755 printf(_("ID of new file is \"%s\"\n"), IDUTF);
757 free(File.Buffer);
758 GSM_Terminate();
761 void AddFolder(int argc UNUSED, char *argv[])
763 GSM_Error error;
764 char IDUTF[200];
765 GSM_File File;
767 DecodeUTF8QuotedPrintable(File.ID_FullName, argv[2], strlen(argv[2]));
768 EncodeUnicode(File.Name, argv[3], strlen(argv[3]));
769 File.ReadOnly = FALSE;
771 GSM_Init(TRUE);
773 error = GSM_AddFolder(gsm, &File);
774 Print_Error(error);
775 EncodeUTF8QuotedPrintable(IDUTF, File.ID_FullName);
776 printf(_("ID of new folder is \"%s\"\n"), IDUTF);
778 GSM_Terminate();
781 void DeleteFolder(int argc UNUSED, char *argv[]UNUSED)
783 GSM_Error error;
784 unsigned char buffer[500];
786 GSM_Init(TRUE);
788 DecodeUTF8QuotedPrintable(buffer, argv[2], strlen(argv[2]));
790 error = GSM_DeleteFolder(gsm, buffer);
791 Print_Error(error);
793 GSM_Terminate();
796 void DeleteFiles(int argc, char *argv[])
798 GSM_Error error;
799 int i;
800 unsigned char buffer[500];
802 GSM_Init(TRUE);
804 for (i = 2; i < argc; i++) {
805 DecodeUTF8QuotedPrintable(buffer, argv[i], strlen(argv[i]));
806 error = GSM_DeleteFile(gsm, buffer);
807 Print_Error(error);
810 GSM_Terminate();
813 /* How should editor hadle tabs in this file? Add editor commands here.
814 * vim: noexpandtab sw=8 ts=8 sts=8: