diff -ruN atftp-0.7-orig/debian/atftpd/usr/share/doc/atftpd/README.grandstream atftp-0.7/debian/atftpd/usr/share/doc/atftpd/README.grandstream
--- atftp-0.7-orig/debian/atftpd/usr/share/doc/atftpd/README.grandstream	1970-01-01 01:00:00.000000000 +0100
+++ atftp-0.7/debian/atftpd/usr/share/doc/atftpd/README.grandstream	2006-02-21 12:21:55.000000000 +0100
@@ -0,0 +1,26 @@
+GrandStream provisioning for atftpd
+------------------------------------
+This patch was inpirated by Gratissip Tftpd.
+
+How to use
+New GETOPT has been added 
+  --grandstream <filename>
+The <filename> looks like
+--- cut ---
+xxxxxxxxxxxx	<version>
+--- cut ---
+
+The xxxxxxxxxxxx is the MAC address of the GS phone,
+the <version> is the firmware version we want to servre
+for thos phone.  There can be also the prefix of the MAC 
+address such as 000b82 (grandstream network). The first match
+is used, so put the more specific MAC address first.
+The location for the firwmare files is 
+<tftpboot>/grandstream/firmwares/<version>/. 
+The config files must be located in the <tftpboot>/grandstream/configs/.
+The ring files must be located in the <tftpboot>/grandstream/rings/.
+
+
+For debuging run the atftpd with verbose=7 and see syslog messages.
+
+	Peter Hudec <peter.hudec@globaltel.sk>
diff -ruN atftp-0.7-orig/debian/atftpd.docs atftp-0.7/debian/atftpd.docs
--- atftp-0.7-orig/debian/atftpd.docs	2004-02-18 03:28:33.000000000 +0100
+++ atftp-0.7/debian/atftpd.docs	2005-08-04 09:20:57.000000000 +0200
@@ -3,6 +3,7 @@
 README.CVS
 README.MCAST
 README.PCRE
+README.grandstream
 FAQ
 BUGS
 test/mtftp.conf
diff -ruN atftp-0.7-orig/debian/changelog atftp-0.7/debian/changelog
--- atftp-0.7-orig/debian/changelog	2006-02-22 10:15:04.404878000 +0100
+++ atftp-0.7/debian/changelog	2006-02-21 12:21:13.000000000 +0100
@@ -1,3 +1,23 @@
+atftp (0.7-10.hudecof) unstable; urgency=low
+
+  * added support for custom ringtones
+    looking for filre rings/ring<num>.bin_<gsid>
+
+ -- Peter Hudec <peter.hudec@globaltel.sk>  Tue, 02 Feb 2006 12:21:00 +0100
+
+atftp (0.7-9.hudecof) unstable; urgency=low
+
+  * fixed one bug
+
+ -- Peter Hudec <hudecof@water.hudecof.net>  Tue, 16 Aug 2005 21:24:02 +0200
+
+atftp (0.7-8.hudecof) unstable; urgency=low
+
+  * Added support for GrandStream phones
+  * read README.grandstream
+
+ -- Peter Hudec <hudecof@water.hudecof.net>  Thu,  4 Aug 2005 09:13:59 +0200
+
 atftp (0.7-7) unstable; urgency=low
 
   * Fixed a FTBFS on amd64. Closes: #297549
diff -ruN atftp-0.7-orig/Makefile.am atftp-0.7/Makefile.am
--- atftp-0.7-orig/Makefile.am	2006-02-22 10:15:04.412877000 +0100
+++ atftp-0.7/Makefile.am	2005-07-21 11:56:28.000000000 +0200
@@ -24,7 +24,7 @@
 EXTRA_DIST       = $(dist_docs) $(dist_dirs) $(man_MANS) $(dist_scripts)
 
 noinst_HEADERS   = argz.h logger.h options.h stats.h tftp.h tftp_def.h tftp_io.h \
-		   tftpd.h tftpd_pcre.h tftpd_mtftp.h
+		   tftpd.h tftpd_pcre.h tftpd_mtftp.h tftpd_grandstream.h
 
 bin_PROGRAMS     = atftp
 atftp_LDADD      = $(LIBTERMCAP) $(LIBREADLINE)
@@ -35,7 +35,7 @@
 atftpd_LDADD     = $(LIBWRAP) $(LIBPTHREAD) $(LIBPCRE)
 atftpd_SOURCES   = tftpd.c logger.c options.c stats.c tftp_io.c tftp_def.c \
                    tftpd_file.c tftpd_list.c tftpd_mcast.c argz.c tftpd_pcre.c \
-		   tftpd_mtftp.c
+		   tftpd_mtftp.c tftpd_grandstream.h
 
 install-exec-hook:
 	(cd $(DESTDIR)$(sbindir) && ln -s atftpd in.tftpd)
diff -ruN atftp-0.7-orig/Makefile.in atftp-0.7/Makefile.in
--- atftp-0.7-orig/Makefile.in	2006-02-22 10:15:04.418876000 +0100
+++ atftp-0.7/Makefile.in	2005-07-21 11:59:09.000000000 +0200
@@ -82,7 +82,7 @@
 	stats.$(OBJEXT) tftp_io.$(OBJEXT) tftp_def.$(OBJEXT) \
 	tftpd_file.$(OBJEXT) tftpd_list.$(OBJEXT) \
 	tftpd_mcast.$(OBJEXT) argz.$(OBJEXT) tftpd_pcre.$(OBJEXT) \
-	tftpd_mtftp.$(OBJEXT)
+	tftpd_mtftp.$(OBJEXT) tftpd_grandstream.$(OBJEXT)
 atftpd_OBJECTS = $(am_atftpd_OBJECTS)
 atftpd_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
@@ -98,7 +98,7 @@
 @AMDEP_TRUE@	./$(DEPDIR)/tftpd_list.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/tftpd_mcast.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/tftpd_mtftp.Po \
-@AMDEP_TRUE@	./$(DEPDIR)/tftpd_pcre.Po
+@AMDEP_TRUE@	./$(DEPDIR)/tftpd_pcre.Po ./$(DEPDIR)/tftpd_grandstream.Po
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
 	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 CCLD = $(CC)
@@ -224,7 +224,7 @@
 dist_dirs = test redhat docs debian
 EXTRA_DIST = $(dist_docs) $(dist_dirs) $(man_MANS) $(dist_scripts)
 noinst_HEADERS = argz.h logger.h options.h stats.h tftp.h tftp_def.h tftp_io.h \
-		   tftpd.h tftpd_pcre.h tftpd_mtftp.h
+		   tftpd.h tftpd_pcre.h tftpd_mtftp.h tftpd_grandstream.h
 
 atftp_LDADD = $(LIBTERMCAP) $(LIBREADLINE)
 atftp_SOURCES = tftp.c tftp_io.c logger.c options.c tftp_def.c tftp_file.c \
@@ -233,7 +233,7 @@
 atftpd_LDADD = $(LIBWRAP) $(LIBPTHREAD) $(LIBPCRE)
 atftpd_SOURCES = tftpd.c logger.c options.c stats.c tftp_io.c tftp_def.c \
                    tftpd_file.c tftpd_list.c tftpd_mcast.c argz.c tftpd_pcre.c \
-		   tftpd_mtftp.c
+		   tftpd_mtftp.c tftpd_grandstream.c
 
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
diff -ruN atftp-0.7-orig/options.c atftp-0.7/options.c
--- atftp-0.7-orig/options.c	2003-04-25 02:16:18.000000000 +0200
+++ atftp-0.7/options.c	2005-07-21 09:04:28.000000000 +0200
@@ -272,6 +272,19 @@
      }
      return ERR;
 }
+char* opt_get_gsmodel(struct tftp_opt *options) 
+{
+     if (options[OPT_GSMODEL].enabled && options[OPT_GSMODEL].specified)
+	  return options[OPT_GSMODEL].value;	     
+     return NULL;
+}
+
+char* opt_get_gsid(struct tftp_opt *options) 
+{
+     if (options[OPT_GSID].enabled && options[OPT_GSID].specified)
+	  return options[OPT_GSID].value;	     
+     return NULL;
+}
 
 void opt_set_tsize(int tsize, struct tftp_opt *options)
 {
@@ -294,6 +307,16 @@
               mc);
 }
 
+void opt_set_gsmodel(char *gsmodel, struct tftp_opt *options)
+{
+     snprintf(options[OPT_GSMODEL].value, VAL_SIZE, "%s", gsmodel);
+}
+
+void opt_set_gsid(char *gsid, struct tftp_opt *options)
+{
+     snprintf(options[OPT_GSID].value, VAL_SIZE, "%s", gsid);
+}
+
 /*
  * Format the content of the options structure (this is the content of a
  * read or write request) to a string.
diff -ruN atftp-0.7-orig/options.h atftp-0.7/options.h
--- atftp-0.7-orig/options.h	2001-07-07 01:35:18.000000000 +0200
+++ atftp-0.7/options.h	2005-07-21 09:05:20.000000000 +0200
@@ -39,10 +39,14 @@
 int opt_get_timeout(struct tftp_opt *options);
 int opt_get_blksize(struct tftp_opt *options);
 int opt_get_multicast(struct tftp_opt *options, char *addr, int *port, int *mc);
+char* opt_get_gsmodel(struct tftp_opt *options);
+char* opt_get_gsid(struct tftp_opt *options);
 void opt_set_tsize(int tsize, struct tftp_opt *options);
 void opt_set_timeout(int timeout, struct tftp_opt *options);
 void opt_set_blksize(int blksize, struct tftp_opt *options);
 void opt_set_multicast(struct tftp_opt *options, char *addr, int port, int mc);
+void opt_set_gsmodel(char *gsmodel, struct tftp_opt *options);
+void opt_set_gsid(char *gsmodel, struct tftp_opt *options);
 void opt_request_to_string(struct tftp_opt *options, char *string, int len);
 void opt_options_to_string(struct tftp_opt *options, char *string, int len);
 
diff -ruN atftp-0.7-orig/README.grandstream atftp-0.7/README.grandstream
--- atftp-0.7-orig/README.grandstream	1970-01-01 01:00:00.000000000 +0100
+++ atftp-0.7/README.grandstream	2006-02-21 12:21:55.000000000 +0100
@@ -0,0 +1,26 @@
+GrandStream provisioning for atftpd
+------------------------------------
+This patch was inpirated by Gratissip Tftpd.
+
+How to use
+New GETOPT has been added 
+  --grandstream <filename>
+The <filename> looks like
+--- cut ---
+xxxxxxxxxxxx	<version>
+--- cut ---
+
+The xxxxxxxxxxxx is the MAC address of the GS phone,
+the <version> is the firmware version we want to servre
+for thos phone.  There can be also the prefix of the MAC 
+address such as 000b82 (grandstream network). The first match
+is used, so put the more specific MAC address first.
+The location for the firwmare files is 
+<tftpboot>/grandstream/firmwares/<version>/. 
+The config files must be located in the <tftpboot>/grandstream/configs/.
+The ring files must be located in the <tftpboot>/grandstream/rings/.
+
+
+For debuging run the atftpd with verbose=7 and see syslog messages.
+
+	Peter Hudec <peter.hudec@globaltel.sk>
diff -ruN atftp-0.7-orig/tftpd.c atftp-0.7/tftpd.c
--- atftp-0.7-orig/tftpd.c	2004-02-27 03:05:26.000000000 +0100
+++ atftp-0.7/tftpd.c	2005-07-21 15:07:55.000000000 +0200
@@ -44,6 +44,7 @@
 #include "stats.h"
 #ifdef HAVE_PCRE
 #include "tftpd_pcre.h"
+#include "tftpd_grandstream.h"
 #endif
 #ifdef HAVE_MTFTP
 #include "tftpd_mtftp.h"
@@ -109,7 +110,8 @@
 #ifdef HAVE_PCRE
 /* Use for PCRE file name substitution */
 tftpd_pcre_self_t *pcre_top = NULL;
-char *pcre_file;
+tftpd_grandstream_self_t *grandstream_top = NULL;
+char *pcre_file, *grandstream_file;
 #endif
 
 #ifdef HAVE_MTFTP
@@ -204,6 +206,11 @@
           if ((pcre_top = tftpd_pcre_open(pcre_file)) == NULL)
                logger(LOG_WARNING, "Failed to initialise PCRE, continuing anyway.");
      }
+     if (grandstream_file)
+     {
+	  if ((grandstream_top = tftpd_grandstream_open(grandstream_file)) == NULL)
+	       logger(LOG_WARNING, "Failed to initialise GRANDSTREAM, continuing anyway.");
+     }
 #endif
 
 #ifdef RATE_CONTROL
@@ -521,6 +528,8 @@
      /* remove allocated memory for tftpd_pcre */
      if (pcre_top)
           tftpd_pcre_close(pcre_top);
+     if (grandstream_top)
+	  tftpd_grandstream_close(grandstream_top);
 #endif
 
      /* some cleaning */
@@ -785,6 +794,7 @@
 #define OPT_MTFTP      '7'
 #define OPT_MTFTP_PORT '8'
 #define OPT_TRACE      '9'
+#define OPT_GRANDSTREAM 'g'
 
 /*
  * Parse the command line using the standard getopt function.
@@ -826,6 +836,7 @@
 #ifdef HAVE_PCRE
           { "pcre", 1, NULL, OPT_PCRE },
           { "pcre-test", 1, NULL, OPT_PCRE_TEST },
+	  { "grandstream", 1, NULL, OPT_GRANDSTREAM },
 #endif
 #ifdef HAVE_MTFTP
           { "mtftp", 1, NULL, OPT_MTFTP },
@@ -955,6 +966,9 @@
                     else
                          printf("Substitution: \"%s\" -> \"%s\"\n", string, out);
                }
+          case OPT_GRANDSTREAM:
+               grandstream_file = strdup(optarg);
+               break;
 #endif
           case OPT_PORT_CHECK:
                source_port_checking = 0;
@@ -1129,6 +1143,7 @@
 #ifdef HAVE_PCRE
             "  --pcre <file>              : use this file for pattern replacement\n"
             "  --pcre-test <file>         : just test pattern file, not starting server\n"
+	    "  --grandstream <file>       : use this file for GrandStream phones firmware control\n"
 #endif
 #ifdef HAVE_MTFTP
             "  --mtftp <file>             : mtftp configuration file\n"
diff -ruN atftp-0.7-orig/tftp_def.c atftp-0.7/tftp_def.c
--- atftp-0.7-orig/tftp_def.c	2004-02-13 04:16:09.000000000 +0100
+++ atftp-0.7/tftp_def.c	2005-07-20 19:01:47.000000000 +0200
@@ -37,6 +37,8 @@
      { "timeout", "5", 0, 1 },  /* 2348, 2349, 2090.  */
      { "blksize", "512", 0, 1 }, /* This is the default option */
      { "multicast", "", 0, 1 }, /* structure */
+     { "grandstream_MODEL", "", 0, 1 }, /* for GransStream provisioning system */
+     { "grandstream_ID", "", 0, 1 },
      { "", "", 0, 0}
 };
 
diff -ruN atftp-0.7-orig/tftp_def.h atftp-0.7/tftp_def.h
--- atftp-0.7-orig/tftp_def.h	2004-02-13 04:16:09.000000000 +0100
+++ atftp-0.7/tftp_def.h	2005-07-21 09:10:43.000000000 +0200
@@ -40,9 +40,11 @@
 #define OPT_TIMEOUT   3
 #define OPT_BLKSIZE   4
 #define OPT_MULTICAST 5
-#define OPT_NUMBER    7
+#define OPT_GSMODEL   6
+#define OPT_GSID      7
+#define OPT_NUMBER    9
 
-#define OPT_SIZE     12
+#define OPT_SIZE     20
 #define VAL_SIZE     MAXLEN
 
 extern char *tftp_errmsg[9];
diff -ruN atftp-0.7-orig/tftpd_file.c atftp-0.7/tftpd_file.c
--- atftp-0.7-orig/tftpd_file.c	2004-02-18 03:21:47.000000000 +0100
+++ atftp-0.7/tftpd_file.c	2006-02-21 13:52:27.000000000 +0100
@@ -35,6 +35,7 @@
 #include "options.h"
 #ifdef HAVE_PCRE
 #include "tftpd_pcre.h"
+#include "tftpd_grandstream.h"
 #endif
 
 #define S_BEGIN         0
@@ -58,6 +59,7 @@
 
 #ifdef HAVE_PCRE
 extern tftpd_pcre_self_t *pcre_top;
+extern tftpd_grandstream_self_t *grandstream_top;
 #endif
 
 
@@ -439,6 +441,35 @@
      /* file name verification */
      Strncpy(filename, data->tftp_options[OPT_FILENAME].value,
              MAXLEN);
+#ifdef HAVE_PCRE     
+     char *gsid, *gsmodel;
+     char gsfilename[MAXLEN];
+     if ((gsid = opt_get_gsid(data->tftp_options)) != NULL) 
+     {
+         gsmodel = opt_get_gsmodel(data->tftp_options);
+	 logger(LOG_DEBUG, "GrandStream phone: %s/%s\n", gsmodel, gsid);
+	 if (strstr(filename, TFTPD_GRANDSTREAM_CFGFILE_PREFIX) == filename) {				// CFG file prefix
+	     logger(LOG_DEBUG, "Requested file serving from configs");
+	     snprintf(gsfilename, sizeof(gsfilename), "grandstream/configs/%s", filename);
+	     strncpy(filename, gsfilename, MAXLEN);
+	 } else if (strstr(filename, TFTPD_GRANDSTREAM_RNGFILE_PREFIX) == filename) {			// RING file prefix
+	     logger(LOG_DEBUG, "Requested file serving from ringtones");
+	     snprintf(gsfilename, sizeof(gsfilename), "grandstream/rings/%s_%s", filename, gsid);
+	     strncpy(filename, gsfilename, MAXLEN);
+	 } else  if (grandstream_top != NULL) {								// else is a FIRMWARE
+	     logger(LOG_DEBUG, "Requested file serving from firmwares");
+	     if (tftpd_grandstream_sub(grandstream_top, string, MAXLEN, gsid) < 0) 
+	     {
+	         logger(LOG_DEBUG, "GrandStream ID not found in the database");
+	     } else {
+	         logger(LOG_DEBUG, "GrandStream ID found in database: %s/%s", gsid, string);	 
+	         snprintf(gsfilename, sizeof(gsfilename), "grandstream/firmwares/%s/%s", string, filename);
+	         strncpy(filename, gsfilename, MAXLEN);
+	     }
+	 }
+     }
+#endif
+     logger(LOG_DEBUG, "the filename is: %s\n", filename);
      if (tftpd_rules_check(filename) != OK)
      {
           tftp_send_error(sockfd, sa, EACCESS, data->data_buffer, data->data_buffer_size);
diff -ruN atftp-0.7-orig/tftpd_grandstream.c atftp-0.7/tftpd_grandstream.c
--- atftp-0.7-orig/tftpd_grandstream.c	1970-01-01 01:00:00.000000000 +0100
+++ atftp-0.7/tftpd_grandstream.c	2005-08-16 21:20:42.000000000 +0200
@@ -0,0 +1,173 @@
+#include "config.h"
+
+#if HAVE_PCRE
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "tftp_def.h"
+#include "config.h"
+#include "logger.h"
+
+#include "tftpd_grandstream.h"
+
+
+#define OVECCOUNT 30
+
+tftpd_grandstream_self_t *tftpd_grandstream_open(char *filename) 
+{
+     int linecount;
+     int erroffset;
+     int matches;
+     int ovector[OVECCOUNT];
+     char line[MAXLEN];
+     const char *error;
+     FILE *fh;
+     int subnum;
+     char **substrlist;
+     pcre *file_re;
+     pcre_extra *file_pe;
+     tftpd_grandstream_self_t *self;
+     tftpd_grandstream_firmware_t *fw, **curfw;
+
+     if ((fh = fopen(filename, "r")) == NULL) 
+     {
+         logger(LOG_ERR, "Cannot open  %s for reading: %s",
+	     filename, strerror(errno));
+	     return NULL;
+     }
+
+     /* compile and study pattern for lines */
+     logger(LOG_DEBUG, "Using file pattern %s", TFTPD_GRANDSTREAM_FILE_PATTERN);
+     if ((file_re = pcre_compile(TFTPD_GRANDSTREAM_FILE_PATTERN, 0,
+                                 &error, &erroffset, NULL)) == NULL)
+     {
+          logger(LOG_ERR, "PCRE file pattern failed to compile");
+          return NULL;
+     }
+
+
+     /* allocate header  and copy info */
+     if ((self = calloc(1, sizeof(tftpd_grandstream_self_t))) == NULL)
+     {
+          logger(LOG_ERR, "calloc filed");
+          return NULL;
+     }
+
+     file_pe = pcre_study(file_re, 0, &error);
+     if (error != NULL)
+     {
+          logger(LOG_ERR, "PCRE file pattern failed to study");
+          return NULL;
+     }
+
+     self->lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
+     Strncpy(self->filename, filename, MAXLEN);
+
+     for (linecount = 1, curfw = &self->list;
+          fgets(line, MAXLEN, fh) != NULL;
+          linecount++, curfw = &fw->next)
+     {
+          logger(LOG_DEBUG,"file: %s line: %d value: %s",
+                 filename, linecount, line);
+    
+	  /* allocate space for GrandStream info */
+          if ((fw = (tftpd_grandstream_firmware_t *)calloc(1,sizeof(tftpd_grandstream_firmware_t))) == NULL) 
+          {
+               tftpd_grandstream_close(self);
+               return NULL;
+          }
+          *curfw = fw;
+
+	  /* for each pattern read, compile and store the pattern */
+          matches = pcre_exec(file_re, file_pe, line, (int)(strlen(line)),
+                              0, 0, ovector, OVECCOUNT);
+         /* log substring to help with debugging */
+          pcre_get_substring_list(line, ovector, matches, (const char ***)&substrlist);
+          for(subnum = 0; subnum <= matches; subnum++)
+          {
+               logger(LOG_DEBUG,"file: %s line: %d substring: %d value: %s",
+                      filename, linecount, subnum, substrlist[subnum]);
+          }
+          pcre_free_substring_list((const char **)substrlist);
+
+	  if (matches < 2)
+          {
+               logger(LOG_ERR, "error with pattern in file \"%s\" line %d",
+                      filename, linecount);
+               tftpd_grandstream_close(self);
+               pcre_free(file_re);
+               pcre_free(file_pe);
+               return NULL;
+          }
+          /* remember line number */
+          fw->linenum = linecount;
+          
+          /* extract left side */
+          pcre_get_substring(line, ovector, matches, 1, (const char **)&fw->gsid);
+
+	  /* extract right side */
+          pcre_get_substring(line, ovector, matches, 2, (const char **)&fw->firmware);
+          logger(LOG_DEBUG,"gs id: %s gs fw: %s", fw->gsid, fw->firmware);
+     }
+
+     /* clean up */
+     pcre_free(file_re);
+     pcre_free(file_pe);
+     /* close file */
+     fclose(fh);
+     return self;
+}
+
+char *tftpd_grandstream_getfilename(tftpd_grandstream_self_t *self)
+{
+     return self->filename;
+}
+
+int tftpd_grandstream_sub(tftpd_grandstream_self_t *self, char *outstr, int outlen, char *str)
+{
+     tftpd_grandstream_firmware_t *fw;
+
+     /* lock for duration */
+     pthread_mutex_lock(&self->lock);
+     
+     logger(LOG_DEBUG, "Looking to match firmware for \"%s\"", str);
+     /* interate over pattern list */
+     for(fw = self->list; fw != NULL; fw = fw->next)
+     {
+          if (strstr(str, fw->gsid) != str)
+		continue;
+          
+          strncpy(outstr, fw->firmware, outlen); 	 
+	  logger(LOG_DEBUG,"Matched \"%s\" with firmware \"%s\"", fw->gsid, fw->firmware);
+	  pthread_mutex_unlock(&self->lock);
+          return 0;
+     }
+ 	
+     logger(LOG_DEBUG, "Failed to match firmware for \"%s\"", str);
+     pthread_mutex_unlock(&self->lock);
+ 
+     return -1; 
+}
+
+void tftpd_grandstream_close(tftpd_grandstream_self_t *self)
+{
+     tftpd_grandstream_firmware_t *next, *cur;
+
+     /* free up list */
+     pthread_mutex_lock(&self->lock);
+     
+     cur = self->list;
+     while (cur != NULL)
+     {
+          next = cur->next;
+          pcre_free_substring(cur->gsid);
+          pcre_free_substring(cur->firmware);
+          free(cur);
+          cur = next;
+     }
+     pthread_mutex_unlock(&self->lock);
+     free(self);
+}
+#endif
diff -ruN atftp-0.7-orig/tftpd_grandstream.h atftp-0.7/tftpd_grandstream.h
--- atftp-0.7-orig/tftpd_grandstream.h	1970-01-01 01:00:00.000000000 +0100
+++ atftp-0.7/tftpd_grandstream.h	2006-02-21 12:18:39.000000000 +0100
@@ -0,0 +1,35 @@
+#ifndef TFTPD_GRANDSTREAM_H
+#define TFTPD_GRANDSTREAM_H
+#include <pthread.h>
+#include <pcre.h>
+#include <tftpd.h>
+
+#define TFTPD_GRANDSTREAM_FILE_PATTERN "^(\\S+)\\s+(\\S+)$"
+#define TFTPD_GRANDSTREAM_CFGFILE_PREFIX "cfg"
+#define TFTPD_GRANDSTREAM_RNGFILE_PREFIX "ring"
+
+struct tftpd_grandstream_firmware
+{
+     unsigned int linenum;
+     char* gsid;
+     char* firmware;
+     struct tftpd_grandstream_firmware *next;
+};
+
+typedef struct tftpd_grandstream_firmware tftpd_grandstream_firmware_t;
+
+struct tftpd_grandstream_self
+{
+     pthread_mutex_t lock;
+     char filename[MAXLEN];
+     struct tftpd_grandstream_firmware *list;
+};
+
+typedef struct tftpd_grandstream_self tftpd_grandstream_self_t;
+
+tftpd_grandstream_self_t *tftpd_grandstream_open(char *filename);
+char *tftpd_grandstream_getfilename(tftpd_grandstream_self_t *self);
+int tftpd_grandstream_sub(tftpd_grandstream_self_t *self, char *outstr, int outlen, char *str);
+void tftpd_grandstream_close(tftpd_grandstream_self_t *self);
+
+#endif
