/[LeafOK_CVS]/pvpgn-1.7.4/src/bnetd/versioncheck.c
ViewVC logotype

Annotation of /pvpgn-1.7.4/src/bnetd/versioncheck.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (hide annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 sysadm 1.1 /*
2     * Copyright (C) 2000 Onlyer (onlyer@263.net)
3     * Copyright (C) 2001 Ross Combs (ross@bnetd.org)
4     * Copyright (C) 2002 Gianluigi Tiesi (sherpya@netfarm.it)
5     * Copyright (C) 2004 CreepLord (creeplord@pvpgn.org)
6     *
7     * This program is free software; you can redistribute it and/or
8     * modify it under the terms of the GNU General Public License
9     * as published by the Free Software Foundation; either version 2
10     * of the License, or (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20     */
21     #define VERSIONCHECK_INTERNAL_ACCESS
22     #include "common/setup_before.h"
23     #include <stdio.h>
24     #ifdef HAVE_STDDEF_H
25     # include <stddef.h>
26     #else
27     # ifndef NULL
28     # define NULL ((void *)0)
29     # endif
30     #endif
31     #ifdef STDC_HEADERS
32     # include <stdlib.h>
33     #else
34     # ifdef HAVE_MALLOC_H
35     # include <malloc.h>
36     # endif
37     #endif
38     #include "compat/strtoul.h"
39     #ifdef HAVE_STRING_H
40     # include <string.h>
41     #else
42     # ifdef HAVE_STRINGS_H
43     # include <strings.h>
44     # endif
45     #endif
46     #ifdef HAVE_MKTIME
47     # ifdef TIME_WITH_SYS_TIME
48     # include <sys/time.h>
49     # include <time.h>
50     # else
51     # ifdef HAVE_SYS_TIME_H
52     # include <sys/time.h>
53     # else
54     # include <time.h>
55     # endif
56     # endif
57     #endif
58     #ifdef HAVE_ASSERT_H
59     # include <assert.h>
60     #endif
61     #include "compat/strchr.h"
62     #include "compat/strdup.h"
63     #include "compat/strcasecmp.h"
64     #include <ctype.h>
65     #include <errno.h>
66     #include "compat/strerror.h"
67     #include "common/eventlog.h"
68     #include "common/list.h"
69     #include "common/util.h"
70     #include "common/proginfo.h"
71     #include "common/token.h"
72     #include "common/field_sizes.h"
73     #include "prefs.h"
74     #include "versioncheck.h"
75     #include "common/tag.h"
76     #include "common/xalloc.h"
77     #include "common/setup_after.h"
78    
79    
80     static t_list * versioninfo_head=NULL;
81     static t_versioncheck dummyvc={ "A=42 B=42 C=42 4 A=A^S B=B^B C=C^C A=A^S", "IX86ver1.mpq", "NoVC" };
82    
83     static int versioncheck_compare_exeinfo(t_parsed_exeinfo * pattern, t_parsed_exeinfo * match);
84    
85     extern t_versioncheck * versioncheck_create(t_tag archtag, t_tag clienttag)
86     {
87     t_elem const * curr;
88     t_versioninfo * vi;
89     t_versioncheck * vc;
90     char archtag_str[5];
91     char clienttag_str[5];
92    
93     LIST_TRAVERSE_CONST(versioninfo_head,curr)
94     {
95     if (!(vi = elem_get_data(curr))) /* should not happen */
96     {
97     eventlog(eventlog_level_error,__FUNCTION__,"version list contains NULL item");
98     continue;
99     }
100    
101     eventlog(eventlog_level_debug,__FUNCTION__,"version check entry archtag=%s, clienttag=%s",
102     tag_uint_to_str(archtag_str,vi->archtag),
103     tag_uint_to_str(clienttag_str,vi->clienttag));
104    
105     if (vi->archtag != archtag)
106     continue;
107     if (vi->clienttag != clienttag)
108     continue;
109    
110     /* FIXME: randomize the selection if more than one match */
111     vc = xmalloc(sizeof(t_versioncheck));
112     vc->eqn = xstrdup(vi->eqn);
113     vc->mpqfile = xstrdup(vi->mpqfile);
114     vc->versiontag = xstrdup(tag_uint_to_str(clienttag_str,clienttag));
115    
116     return vc;
117     }
118    
119     /*
120     * No entries in the file that match, return the dummy because we have to send
121     * some equation and auth mpq to the client. The client is not going to pass the
122     * validation later unless skip_versioncheck or allow_unknown_version is enabled.
123     */
124     return &dummyvc;
125     }
126    
127    
128     extern int versioncheck_destroy(t_versioncheck * vc)
129     {
130     if (!vc)
131     {
132     eventlog(eventlog_level_error,__FUNCTION__,"got NULL vc");
133     return -1;
134     }
135    
136     if (vc==&dummyvc)
137     return 0;
138    
139     xfree((void *)vc->versiontag);
140     xfree((void *)vc->mpqfile);
141     xfree((void *)vc->eqn);
142     xfree(vc);
143    
144     return 0;
145     }
146    
147     extern int versioncheck_set_versiontag(t_versioncheck * vc, char const * versiontag)
148     {
149     if (!vc) {
150     eventlog(eventlog_level_error,__FUNCTION__,"got NULL vc");
151     return -1;
152     }
153     if (!versiontag) {
154     eventlog(eventlog_level_error,__FUNCTION__,"got NULL versiontag");
155     return -1;
156     }
157    
158     if (vc->versiontag!=NULL) xfree((void *)vc->versiontag);
159     vc->versiontag = xstrdup(versiontag);
160     return 0;
161     }
162    
163    
164     extern char const * versioncheck_get_versiontag(t_versioncheck const * vc)
165     {
166     if (!vc) {
167     eventlog(eventlog_level_error,__FUNCTION__,"got NULL vc");
168     return NULL;
169     }
170    
171     return vc->versiontag;
172     }
173    
174    
175     extern char const * versioncheck_get_mpqfile(t_versioncheck const * vc)
176     {
177     if (!vc)
178     {
179     eventlog(eventlog_level_error,__FUNCTION__,"got NULL vc");
180     return NULL;
181     }
182    
183     return vc->mpqfile;
184     }
185    
186    
187     extern char const * versioncheck_get_eqn(t_versioncheck const * vc)
188     {
189     if (!vc)
190     {
191     eventlog(eventlog_level_error,__FUNCTION__,"got NULL vc");
192     return NULL;
193     }
194    
195     return vc->eqn;
196     }
197    
198     t_parsed_exeinfo * parse_exeinfo(char const * exeinfo)
199     {
200     t_parsed_exeinfo * parsed_exeinfo;
201    
202     if (!exeinfo) {
203     return NULL;
204     }
205    
206     parsed_exeinfo = xmalloc(sizeof(t_parsed_exeinfo));
207     parsed_exeinfo->exe = xstrdup(exeinfo);
208     parsed_exeinfo->time = 0;
209     parsed_exeinfo->size = 0;
210    
211     if (strcmp(prefs_get_version_exeinfo_match(),"parse")==0)
212     {
213     #ifdef HAVE_MKTIME
214     struct tm t1;
215     char *exe;
216     char mask[MAX_EXEINFO_STR+1];
217     char * marker;
218     int size;
219     char time_invalid = 0;
220    
221     if ((exeinfo[0]=='\0') || //happens when using war3-noCD and having deleted war3.org
222     (strcmp(exeinfo,"badexe")==0)) //happens when AUTHREQ had no owner/exeinfo entry
223     {
224     xfree((void *)parsed_exeinfo->exe);
225     xfree((void *)parsed_exeinfo);
226     eventlog(eventlog_level_error,__FUNCTION__,"found empty exeinfo");
227     return NULL;
228     }
229    
230     memset(&t1,0,sizeof(t1));
231     t1.tm_isdst = -1;
232    
233     exeinfo = strreverse((char *)exeinfo);
234     if (!(marker = strchr(exeinfo,' ')))
235     {
236     xfree((void *)parsed_exeinfo->exe);
237     xfree((void *)parsed_exeinfo);
238     return NULL;
239     }
240     for (; marker[0]==' ';marker++);
241    
242     if (!(marker = strchr(marker,' ')))
243     {
244     xfree((void *)parsed_exeinfo->exe);
245     xfree((void *)parsed_exeinfo);
246     return NULL;
247     }
248     for (; marker[0]==' ';marker++);
249    
250     if (!(marker = strchr(marker,' ')))
251     {
252     xfree((void *)parsed_exeinfo->exe);
253     xfree((void *)parsed_exeinfo);
254     return NULL;
255     }
256     for (; marker[0]==' ';marker++);
257     marker--;
258     marker[0] = '\0';
259     marker++;
260    
261     exe = xstrdup(marker);
262     xfree((void *)parsed_exeinfo->exe);
263     parsed_exeinfo->exe = strreverse((char *)exe);
264    
265     exeinfo = strreverse((char *)exeinfo);
266    
267     sprintf(mask,"%%02u/%%02u/%%u %%02u:%%02u:%%02u %%u");
268    
269     if (sscanf(exeinfo,mask,&t1.tm_mon,&t1.tm_mday,&t1.tm_year,&t1.tm_hour,&t1.tm_min,&t1.tm_sec,&size)!=7) {
270     if (sscanf(exeinfo,"%*s %*s %u",&size) != 1)
271     {
272    
273     eventlog(eventlog_level_warn,__FUNCTION__,"parser error while parsing pattern \"%s\"",exeinfo);
274     xfree((void *)parsed_exeinfo->exe);
275     xfree((void *)parsed_exeinfo);
276     return NULL; /* neq */
277     }
278     time_invalid=1;
279     }
280    
281     /* Now we have a Y2K problem :) Thanks for using a 2 digit decimal years, Blizzard. */
282     /* 00-79 -> 2000-2079
283     * * 80-99 -> 1980-1999
284     * * 100+ unchanged */
285     if (t1.tm_year<80)
286     t1.tm_year = t1.tm_year + 100;
287    
288     if (time_invalid)
289     parsed_exeinfo->time = -1;
290     else
291     parsed_exeinfo->time = mktime(&t1);
292     parsed_exeinfo->size = size;
293    
294     #else
295     eventlog(eventlog_level_error,__FUNCTION__,"Your system does not support mktime(). Please select another exeinfo matching method.");
296     return NULL;
297     #endif
298     }
299    
300     return parsed_exeinfo;
301     }
302    
303     #define safe_toupper(X) (islower((int)X)?toupper((int)X):(X))
304    
305     /* This implements some dumb kind of pattern matching. Any '?'
306     * signs in the pattern are treated as "don't care" signs. This
307     * means that it doesn't matter what's on this place in the match.
308     */
309     //static int versioncheck_compare_exeinfo(char const * pattern, char const * match)
310     static int versioncheck_compare_exeinfo(t_parsed_exeinfo * pattern, t_parsed_exeinfo * match)
311     {
312     assert(pattern);
313     assert(match);
314    
315     if (!strcasecmp(prefs_get_version_exeinfo_match(),"none"))
316     return 0; /* ignore exeinfo */
317    
318     if (strlen(pattern->exe)!=strlen(match->exe))
319     return 1; /* neq */
320    
321     if (strcmp(prefs_get_version_exeinfo_match(),"exact")==0) {
322     return strcasecmp(pattern->exe,match->exe);
323     } else if (strcmp(prefs_get_version_exeinfo_match(),"exactcase")==0) {
324     return strcmp(pattern->exe,match->exe);
325     } else if (strcmp(prefs_get_version_exeinfo_match(),"wildcard")==0) {
326     unsigned int i;
327    
328     for (i=0;i<strlen(pattern->exe);i++)
329     if ((pattern->exe[i]!='?')&& /* out "don't care" sign */
330     (safe_toupper(pattern->exe[i])!=safe_toupper(match->exe[i])))
331     return 1; /* neq */
332     return 0; /* ok */
333     } else if (strcmp(prefs_get_version_exeinfo_match(),"parse")==0) {
334    
335     if (strcasecmp(pattern->exe,match->exe)!=0)
336     {
337     eventlog(eventlog_level_trace,__FUNCTION__,"filename differs");
338     return 1; /* neq */
339     }
340     if (pattern->size!=match->size)
341     {
342     eventlog(eventlog_level_trace,__FUNCTION__,"size differs");
343     return 1; /* neq */
344     }
345     if ((pattern->time!=-1) && prefs_get_version_exeinfo_maxdiff() && (abs(pattern->time-match->time)>(signed)prefs_get_version_exeinfo_maxdiff()))
346     {
347     eventlog(eventlog_level_trace,__FUNCTION__,"time differs by %i",abs(pattern->time-match->time));
348     return 1;
349     }
350     return 0; /* ok */
351     } else {
352     eventlog(eventlog_level_error,__FUNCTION__,"unknown version exeinfo match method \"%s\"",prefs_get_version_exeinfo_match());
353     return -1; /* neq/fail */
354     }
355     }
356    
357     void free_parsed_exeinfo(t_parsed_exeinfo * parsed_exeinfo)
358     {
359     if (parsed_exeinfo)
360     {
361     if (parsed_exeinfo->exe)
362     xfree((void *)parsed_exeinfo->exe);
363     xfree((void *)parsed_exeinfo);
364     }
365     }
366    
367     extern int versioncheck_validate(t_versioncheck * vc, t_tag archtag, t_tag clienttag, char const * exeinfo, unsigned long versionid, unsigned long gameversion, unsigned long checksum)
368     {
369     t_elem const * curr;
370     t_versioninfo * vi;
371     int badexe,badcs;
372     t_parsed_exeinfo * parsed_exeinfo;
373    
374     if (!vc)
375     {
376     eventlog(eventlog_level_error,__FUNCTION__,"got NULL vc");
377     return -1;
378     }
379    
380     badexe=badcs = 0;
381     parsed_exeinfo = parse_exeinfo(exeinfo);
382     LIST_TRAVERSE_CONST(versioninfo_head,curr)
383     {
384     if (!(vi = elem_get_data(curr))) /* should not happen */
385     {
386     eventlog(eventlog_level_error,__FUNCTION__,"version list contains NULL item");
387     continue;
388     }
389    
390     if (vi->archtag != archtag)
391     continue;
392     if (vi->clienttag != clienttag)
393     continue;
394     if (strcmp(vi->eqn,vc->eqn)!=0)
395     continue;
396     if (strcmp(vi->mpqfile,vc->mpqfile)!=0)
397     continue;
398    
399     if (vi->versionid && vi->versionid != versionid)
400     continue;
401    
402     if (vi->gameversion && vi->gameversion != gameversion)
403     continue;
404    
405    
406     if ((!(parsed_exeinfo)) || (vi->parsed_exeinfo && (versioncheck_compare_exeinfo(vi->parsed_exeinfo,parsed_exeinfo) != 0)))
407     {
408     /*
409     * Found an entry matching but the exeinfo doesn't match.
410     * We need to rember this because if no other matching versions are found
411     * we will return badversion.
412     */
413     badexe = 1;
414     }
415     else
416     badexe = 0;
417    
418     if (vi->checksum && vi->checksum != checksum)
419     {
420     /*
421     * Found an entry matching but the checksum doesn't match.
422     * We need to rember this because if no other matching versions are found
423     * we will return badversion.
424     */
425     badcs = 1;
426     }
427     else
428     badcs = 0;
429    
430     if (vc->versiontag)
431     xfree((void *)vc->versiontag);
432     vc->versiontag = xstrdup(vi->versiontag);
433    
434     if (badexe || badcs)
435     continue;
436    
437     /* Ok, version and checksum matches or exeinfo/checksum are disabled
438     * anyway we have found a complete match */
439     eventlog(eventlog_level_info,__FUNCTION__,"got a matching entry: %s",vc->versiontag);
440     free_parsed_exeinfo(parsed_exeinfo);
441     return 1;
442     }
443    
444     if (badcs) /* A match was found but the checksum was different */
445     {
446     eventlog(eventlog_level_info,__FUNCTION__,"bad checksum, closest match is: %s",vc->versiontag);
447     free_parsed_exeinfo(parsed_exeinfo);
448     return -1;
449     }
450     if (badexe) /* A match was found but the exeinfo string was different */
451     {
452     eventlog(eventlog_level_info,__FUNCTION__,"bad exeinfo, closest match is: %s",vc->versiontag);
453     free_parsed_exeinfo(parsed_exeinfo);
454     return -1;
455     }
456    
457     /* No match in list */
458     eventlog(eventlog_level_info,__FUNCTION__,"no match in list, setting to: %s",vc->versiontag);
459     free_parsed_exeinfo(parsed_exeinfo);
460     return 0;
461     }
462    
463     extern int versioncheck_load(char const * filename)
464     {
465     FILE * fp;
466     unsigned int line;
467     unsigned int pos;
468     char * buff;
469     char * temp;
470     char const * eqn;
471     char const * mpqfile;
472     char const * archtag;
473     char const * clienttag;
474     char const * exeinfo;
475     char const * versionid;
476     char const * gameversion;
477     char const * checksum;
478     char const * versiontag;
479     t_versioninfo * vi;
480    
481     if (!filename)
482     {
483     eventlog(eventlog_level_error,__FUNCTION__,"got NULL filename");
484     return -1;
485     }
486    
487     if (!(versioninfo_head = list_create()))
488     {
489     eventlog(eventlog_level_error,__FUNCTION__,"could create list");
490     return -1;
491     }
492     if (!(fp = fopen(filename,"r")))
493     {
494     eventlog(eventlog_level_error,__FUNCTION__,"could not open file \"%s\" for reading (fopen: %s)",filename,pstrerror(errno));
495     list_destroy(versioninfo_head);
496     versioninfo_head = NULL;
497     return -1;
498     }
499    
500     line = 1;
501     for (; (buff = file_get_line(fp)); line++)
502     {
503     for (pos=0; buff[pos]=='\t' || buff[pos]==' '; pos++);
504     if (buff[pos]=='\0' || buff[pos]=='#')
505     {
506     continue;
507     }
508     if ((temp = strrchr(buff,'#')))
509     {
510     unsigned int len;
511     unsigned int endpos;
512    
513     *temp = '\0';
514     len = strlen(buff)+1;
515     for (endpos=len-1; buff[endpos]=='\t' || buff[endpos]==' '; endpos--);
516     buff[endpos+1] = '\0';
517     }
518    
519     if (!(eqn = next_token(buff,&pos)))
520     {
521     eventlog(eventlog_level_error,__FUNCTION__,"missing eqn near line %u of file \"%s\"",line,filename);
522     continue;
523     }
524     line++;
525     if (!(mpqfile = next_token(buff,&pos)))
526     {
527     eventlog(eventlog_level_error,__FUNCTION__,"missing mpqfile near line %u of file \"%s\"",line,filename);
528     continue;
529     }
530     line++;
531     if (!(archtag = next_token(buff,&pos)))
532     {
533     eventlog(eventlog_level_error,__FUNCTION__,"missing archtag near line %u of file \"%s\"",line,filename);
534     continue;
535     }
536     line++;
537     if (!(clienttag = next_token(buff,&pos)))
538     {
539     eventlog(eventlog_level_error,__FUNCTION__,"missing clienttag near line %u of file \"%s\"",line,filename);
540     continue;
541     }
542     line++;
543     if (!(exeinfo = next_token(buff,&pos)))
544     {
545     eventlog(eventlog_level_error,__FUNCTION__,"missing exeinfo near line %u of file \"%s\"",line,filename);
546     continue;
547     }
548     line++;
549     if (!(versionid = next_token(buff,&pos)))
550     {
551     eventlog(eventlog_level_error,__FUNCTION__,"missing versionid near line %u of file \"%s\"",line,filename);
552     continue;
553     }
554     line++;
555     if (!(gameversion = next_token(buff,&pos)))
556     {
557     eventlog(eventlog_level_error,__FUNCTION__,"missing gameversion near line %u of file \"%s\"",line,filename);
558     continue;
559     }
560     line++;
561     if (!(checksum = next_token(buff,&pos)))
562     {
563     eventlog(eventlog_level_error,__FUNCTION__,"missing checksum near line %u of file \"%s\"",line,filename);
564     continue;
565     }
566     line++;
567     if (!(versiontag = next_token(buff,&pos)))
568     {
569     versiontag = NULL;
570     }
571    
572     vi = xmalloc(sizeof(t_versioninfo));
573     vi->eqn = xstrdup(eqn);
574     vi->mpqfile = xstrdup(mpqfile);
575     if (strlen(archtag)!=4)
576     {
577     eventlog(eventlog_level_error,__FUNCTION__,"invalid arch tag on line %u of file \"%s\"",line,filename);
578     xfree((void *)vi->mpqfile); /* avoid warning */
579     xfree((void *)vi->eqn); /* avoid warning */
580     xfree(vi);
581     continue;
582     }
583     if (!tag_check_arch((vi->archtag = tag_str_to_uint(archtag))))
584     {
585     eventlog(eventlog_level_error,__FUNCTION__,"got unknown archtag \"%s\"",archtag);
586     xfree((void *)vi->mpqfile); /* avoid warning */
587     xfree((void *)vi->eqn); /* avoid warning */
588     xfree(vi);
589     continue;
590     }
591     if (strlen(clienttag)!=4)
592     {
593     eventlog(eventlog_level_error,__FUNCTION__,"invalid client tag on line %u of file \"%s\"",line,filename);
594     xfree((void *)vi->mpqfile); /* avoid warning */
595     xfree((void *)vi->eqn); /* avoid warning */
596     xfree(vi);
597     continue;
598     }
599     if (!tag_check_client((vi->clienttag = tag_str_to_uint(clienttag))))
600     {
601     eventlog(eventlog_level_error,__FUNCTION__,"got unknown clienttag\"%s\"",clienttag);
602     xfree((void *)vi->mpqfile); /* avoid warning */
603     xfree((void *)vi->eqn); /* avoid warning */
604     xfree(vi);
605     continue;
606     }
607     if (strcmp(exeinfo, "NULL") == 0)
608     vi->parsed_exeinfo = NULL;
609     else
610     {
611     if (!(vi->parsed_exeinfo = parse_exeinfo(exeinfo)))
612     {
613     eventlog(eventlog_level_error,__FUNCTION__,"encountered an error while parsing exeinfo");
614     xfree((void *)vi->mpqfile); /* avoid warning */
615     xfree((void *)vi->eqn); /* avoid warning */
616     xfree(vi);
617     continue;
618     }
619     }
620    
621     vi->versionid = strtoul(versionid,NULL,0);
622     if (verstr_to_vernum(gameversion,&vi->gameversion)<0)
623     {
624     eventlog(eventlog_level_error,__FUNCTION__,"malformed version on line %u of file \"%s\"",line,filename);
625     xfree((void *)vi->parsed_exeinfo); /* avoid warning */
626     xfree((void *)vi->mpqfile); /* avoid warning */
627     xfree((void *)vi->eqn); /* avoid warning */
628     xfree(vi);
629     continue;
630     }
631    
632     vi->checksum = strtoul(checksum,NULL,0);
633     if (versiontag)
634     vi->versiontag = xstrdup(versiontag);
635     else
636     vi->versiontag = NULL;
637    
638    
639     list_append_data(versioninfo_head,vi);
640     }
641    
642     file_get_line(NULL); // clear file_get_line buffer
643     if (fclose(fp)<0)
644     eventlog(eventlog_level_error,__FUNCTION__,"could not close versioncheck file \"%s\" after reading (fclose: %s)",filename,pstrerror(errno));
645    
646     return 0;
647     }
648    
649    
650     extern int versioncheck_unload(void)
651     {
652     t_elem * curr;
653     t_versioninfo * vi;
654    
655     if (versioninfo_head)
656     {
657     LIST_TRAVERSE(versioninfo_head,curr)
658     {
659     if (!(vi = elem_get_data(curr))) /* should not happen */
660     {
661     eventlog(eventlog_level_error,__FUNCTION__,"version list contains NULL item");
662     continue;
663     }
664    
665     if (list_remove_elem(versioninfo_head,&curr)<0)
666     eventlog(eventlog_level_error,__FUNCTION__,"could not remove item from list");
667    
668     if (vi->parsed_exeinfo)
669     {
670     if (vi->parsed_exeinfo->exe)
671     xfree((void *)vi->parsed_exeinfo->exe);
672     xfree((void *)vi->parsed_exeinfo); /* avoid warning */
673     }
674     xfree((void *)vi->mpqfile); /* avoid warning */
675     xfree((void *)vi->eqn); /* avoid warning */
676     if (vi->versiontag)
677     xfree((void *)vi->versiontag); /* avoid warning */
678     xfree(vi);
679     }
680    
681     if (list_destroy(versioninfo_head)<0)
682     return -1;
683     versioninfo_head = NULL;
684     }
685    
686     return 0;
687     }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1