DELTA 77 419032 1498
SVN  ”Lÿ0ÿ0€ÿ0/**********************************************************************
 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/

#ifdef HAVE_CONFIG_H
#include <fc_config.h>
#endif

#include "fc_prehdrs.h"

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef FREECIV_HAVE_WINSOCK
#ifdef FREECIV_HAVE_WINSOCK2
#include <winsock2.h>
#else  /* FREECIV_HAVE_WINSOCK2 */
#include <winsock.h>
#endif /* FREECIV_HAVE_WINSOCK2 */
#endif /* FREECIV_HAVE_WINSOCK */

/* utility */
#include "fcintl.h"
#include "fcthread.h"
#include "log.h"
#include "mem.h"
#include "netintf.h"
#include "netfile.h"
#include "support.h"
#include "timing.h"

/* common */
#include "capstr.h"
#include "connection.h"
#include "dataio.h"
#include "game.h"
#include "map.h"
#include "version.h"

/* server */
#include "console.h"
#include "plrhand.h"
#include "settings.h"
#include "srv_main.h"

#include "meta.h"

static bool server_is_open = FALSE;

static char meta_patches[256] = "";
static char meta_message[256] = "";

static fc_thread *meta_srv_thread = NULL;

/*************************************************************************
 the default metaserver patches for this server
*************************************************************************/
const char *default_meta_patches_string(void)
{
  return "none";
}

/*************************************************************************
  Return static string with default info line to send to metaserver.
*************************************************************************/
const char *default_meta_message_string(void)
{
#if IS_BETA_VERSION
  return "unstable pre-" NEXT_STABLE_VERSION ": beware";
#else  /* IS_BETA_VERSION */
#if IS_DEVEL_VERSION
  return "development version: beware";
#else  /* IS_DEVEL_VERSION */
  return "-";
#endif /* IS_DEVEL_VERSION */
#endif /* IS_BETA_VERSION */
}

/*************************************************************************
 the metaserver patches
*************************************************************************/
const char *get_meta_patches_string(void)
{
  return meta_patches;
}

/*************************************************************************
 the metaserver message
*************************************************************************/
const char *get_meta_message_string(void)
{
  return meta_message;
}

/*************************************************************************
 The server metaserver type
*************************************************************************/
static const char *get_meta_type_string(void)
{
  if (game.server.meta_info.type[0] != '\0') {
    return game.server.meta_info.type;
  }

  return NULL;
}

/*************************************************************************
  The metaserver message set by user
*************************************************************************/
const char *get_user_meta_message_string(void)
{
  if (game.server.meta_info.user_message[0] != '\0') {
    return game.server.meta_info.user_message;
  }

  return NULL;
}

/*************************************************************************
  Update meta message. Set it to user meta message, if it is available.
  Otherwise use provided message.
  It is ok to call this with NULL message. Then it only replaces current
  meta message with user meta message if available.
*************************************************************************/
void maybe_automatic_meta_message(const char *automatic)
{
  const char *user_message;

  user_message = get_user_meta_message_string();

  if (user_message == NULL) {
    /* No user message */
    if (automatic != NULL) {
      set_meta_message_string(automatic);
    }
    return;
  }

  set_meta_message_string(user_message);
}

/*************************************************************************
 set the metaserver patches string
*************************************************************************/
void set_meta_patches_string(const char *string)
{
  sz_strlcpy(meta_patches, string);
}

/*************************************************************************
 set the metaserver message string
*************************************************************************/
void set_meta_message_string(const char *string)
{
  sz_strlcpy(meta_message, string);
}

/*************************************************************************
 set user defined metaserver message string
*************************************************************************/
void set_user_meta_message_string(const char *string)
{
  if (string != NULL && string[0] != '\0') {
    sz_strlcpy(game.server.meta_info.user_message, string);
    set_meta_message_string(string);
  } else {
    /* Remove user meta message. We will use automatic messages instead */
    game.server.meta_info.user_message[0] = '\0';
    set_meta_message_string(default_meta_message_string());    
  }
}

/*************************************************************************
  Return string describing both metaserver name and port.
*************************************************************************/
char *meta_addr_port(void)
{
  return srvarg.metaserver_addr;
}

/*************************************************************************
 we couldn't find or connect to the metaserver.
*************************************************************************/
static void metaserver_failed(void)
{
  con_puts(C_METAERROR, _("Not reporting to the metaserver in this game."));
  con_flush();

  server_close_meta();
}

/****************************************************************************
  Insert a setting in the metaserver message. Return TRUE if it succeded.
****************************************************************************/
static inline bool meta_insert_setting(struct netfile_post *post,
                                       const char *set_name)
{
  const struct setting *pset = setting_by_name(set_name);
  char buf[256];

  fc_assert_ret_val_msg(NULL != pset, FALSE,
                        "Setting \"%s\" not found!", set_name);
  netfile_add_form_str(post, "vn[]", setting_name(pset));
  netfile_add_form_str(post, "vv[]",
                       setting_value_name(pset, FALSE, buf, sizeof(buf)));
  return TRUE;
}

/*************************************************************************
  Send POST to metaserver. This runs in its own thread.
*************************************************************************/
static void send_metaserver_post(void *arg)
{
  struct netfile_post *post = (struct netfile_post *) arg;
  char *addr;

  if (srvarg.bind_meta_addr != NULL) {
    addr = srvarg.bind_meta_addr;
  } else {
    addr = srvarg.bind_addr;
  }

  if (!netfile_send_post(srvarg.metaserver_addr, post, NULL, NULL, addr)) {
    con_puts(C_METAERROR, _("Error connecting to metaserver"));
    metaserver_failed();
  }

  netfile_close_post(post);
}

/*************************************************************************
 construct the POST message and send info to metaserver.
*************************************************************************/
static bool send_to_metaserver(enum meta_flag flag)
{
  int players = 0;
  int humans = 0;
  char host[512];
  char state[20];
  char rs[256];
  struct netfile_post *post;

  switch(server_state()) {
  case S_S_INITIAL:
    sz_strlcpy(state, "Pregame");
    break;
  case S_S_RUNNING:
    sz_strlcpy(state, "Running");
    break;
  case S_S_OVER:
    sz_strlcpy(state, "Game Ended");
    break;
  }

  /* get hostname */
  if (srvarg.identity_name[0] != '\0') {
    sz_strlcpy(host, srvarg.identity_name);
  } else if (fc_gethostname(host, sizeof(host)) != 0) {
    sz_strlcpy(host, "unknown");
  }

  if (game.control.version[0] != '\0') {
    fc_snprintf(rs, sizeof(rs), "%s %s", game.control.name, game.control.version);
  } else {
    sz_strlcpy(rs, game.control.name);
  }

  /* Freed in metaserver thread function send_metaserver_post() */
  post = netfile_start_post();

  netfile_add_form_str(post, "host", host);
  netfile_add_form_int(post, "port", srvarg.port);
  netfile_add_form_str(post, "state", state);
  netfile_add_form_str(post, "ruleset", rs);

  if (flag == META_GOODBYE) {
    netfile_add_form_int(post, "bye", 1);
  } else {
    const char *srvtype = get_meta_type_string();

    if (srvtype != NULL) {
      netfile_add_form_str(post, "type", srvtype);
    }
    netfile_add_form_str(post, "version", VERSION_STRING);
    netfile_add_form_str(post, "patches",
                         get_meta_patches_string());
    netfile_add_form_str(post, "capability", our_capability);

    netfile_add_form_str(post, "serverid", srvarg.serverid);
    netfile_add_form_str(post, "message",
                         get_meta_message_string());

    /* NOTE: send info for ALL players or none at all. */
    if (normal_player_count() == 0) {
      netfile_add_form_int(post, "dropplrs", 1);
    } else {
      players = 0; /* a counter for players_available */
      humans = 0;

      players_iterate(plr) {
        bool is_player_available = TRUE;
        char type[15];
        struct connection *pconn = conn_by_user(plr->username);

        if (!plr->is_alive) {
          sz_strlcpy(type, "Dead");
        } else if (is_barbarian(plr)) {
          sz_strlcpy(type, "Barbarian");
        } else if (is_ai(plr)) {
          sz_strlcpy(type, "A.I.");
        } else if (is_human(plr)) {
          sz_strlcpy(type, "Human");
        } else {
          sz_strlcpy(type, "-");
        }

        netfile_add_form_str(post, "plu[]", plr->username);
        netfile_add_form_str(post, "plt[]", type);
        netfile_add_form_str(post, "pll[]", player_name(plr));
        netfile_add_form_str(post, "pln[]",
                             plr->nation != NO_NATION_SELECTED 
                             ? nation_plural_for_player(plr)
                             : "none");
        netfile_add_form_str(post, "plf[]",
                             plr->nation != NO_NATION_SELECTED 
                             ? nation_of_player(plr)->flag_graphic_str
                             : "none");
        netfile_add_form_str(post, "plh[]",
                             pconn ? pconn->addr : "");

        /* is this player available to take?
         * TODO: there's some duplication here with 
         * stdinhand.c:is_allowed_to_take() */
        if (is_barbarian(plr) && !strchr(game.server.allow_take, 'b')) {
          is_player_available = FALSE;
        } else if (!plr->is_alive && !strchr(game.server.allow_take, 'd')) {
          is_player_available = FALSE;
        } else if (is_ai(plr)
                   && !strchr(game.server.allow_take,
                              (game.info.is_new_game ? 'A' : 'a'))) {
          is_player_available = FALSE;
        } else if (is_human(plr)
                   && !strchr(game.server.allow_take,
                              (game.info.is_new_game ? 'H' : 'h'))) {
          is_player_available = FALSE;
        }

        if (pconn) {
          is_player_available = FALSE;
        }

        if (is_player_available) {
          players++;
        }

        if (is_human(plr) && plr->is_alive) {
          humans++;
        }
      } players_iterate_end;

      /* send the number of available players. */
      netfile_add_form_int(post, "available", players);
      netfile_add_form_int(post, "humans", humans);
    }

    /* Send some variables: should be listed in inverted order? */
    {
      static const char *settings[] = {
        "timeout", "endturn", "minplayers", "maxplayers",
        "aifill", "allowtake", "generator"
      };
      int i;

      for (i = 0; i < ARRAY_SIZE(settings); i++) {
        meta_insert_setting(post, settings[i]);
      }

      /* HACK: send the most determinant setting for the map size. */
      switch (game.map.server.mapsize) {
      case MAPSIZE_FULLSIZE:
        meta_insert_setting(post, "size");
        break;
      case MAPSIZE_PLAYER:
        meta_insert_setting(post, "tilesperplayer");
        break;
      case MAPSIZE_XYSIZE:
        meta_insert_setting(post, "xsize");
        meta_insert_setting(post, "ysize");
        break;
      }
    }

    /* Turn and year. */
    netfile_add_form_str(post, "vn[]", "turn");
    netfile_add_form_int(post, "vv[]", game.info.turn);
    netfile_add_form_str(post, "vn[]", "year");

    if (server_state() != S_S_INITIAL) {
      netfile_add_form_int(post, "vv[]", game.info.year);
    } else {
      netfile_add_form_str(post, "vv[]", "Calendar not set up");
    }
  }

  if (meta_srv_thread != NULL) {
    /* Previously started thread */
    fc_thread_wait(meta_srv_thread);
  } else {
    meta_srv_thread = fc_malloc(sizeof(meta_srv_thread));
  }

  /* Send POST in new thread */
  fc_thread_start(meta_srv_thread, &send_metaserver_post, post);

  return TRUE;
}

/*************************************************************************
  Stop sending updates to metaserver
*************************************************************************/
void server_close_meta(void)
{
  server_is_open = FALSE;
}

/*************************************************************************
 lookup the correct address for the metaserver.
*************************************************************************/
bool server_open_meta(void)
{
  if (meta_patches[0] == '\0') {
    set_meta_patches_string(default_meta_patches_string());
  }
  if (meta_message[0] == '\0') {
    set_meta_message_string(default_meta_message_string());
  }

  server_is_open = TRUE;

  return TRUE;
}

/**************************************************************************
 are we sending info to the metaserver?
**************************************************************************/
bool is_metaserver_open(void)
{
  return server_is_open;
}

/**************************************************************************
  Control when we send info to the metaserver.
**************************************************************************/
bool send_server_info_to_metaserver(enum meta_flag flag)
{
  static struct timer *last_send_timer = NULL;
  static bool want_update;

  if (!server_is_open) {
    return FALSE;
  }

  /* if we're bidding farewell, ignore all timers */
  if (flag == META_GOODBYE) { 
    if (last_send_timer) {
      timer_destroy(last_send_timer);
      last_send_timer = NULL;
    }
    send_to_metaserver(flag);

    /* Wait metaserver thread to finish */
    fc_thread_wait(meta_srv_thread);
    free(meta_srv_thread);
    meta_srv_thread = NULL;

    return TRUE;
  }

  /* don't allow the user to spam the metaserver with updates */
  if (last_send_timer && (timer_read_seconds(last_send_timer)
                                          < METASERVER_MIN_UPDATE_INTERVAL)) {
    if (flag == META_INFO) {
      want_update = TRUE; /* we couldn't update now, but update a.s.a.p. */
    }
    return FALSE;
  }

  /* if we're asking for a refresh, only do so if 
   * we've exceeded the refresh interval */
  if ((flag == META_REFRESH) && !want_update && last_send_timer 
      && (timer_read_seconds(last_send_timer) < METASERVER_REFRESH_INTERVAL)) {
    return FALSE;
  }

  /* start a new timer if we haven't already */
  if (!last_send_timer) {
    last_send_timer = timer_new(TIMER_USER, TIMER_ACTIVE);
  }

  timer_clear(last_send_timer);
  timer_start(last_send_timer);
  want_update = FALSE;

  return send_to_metaserver(flag);
}
ENDREP
id: 4s.5ck.r32355/16347
type: file
pred: 4s.5ck.r31685/12692
count: 128
text: 32355 0 16319 16304 e1e448e65c266024fee62ae9a9ec8200
props: 11087 3026 111 0 c246f5509cfd811186cfd3230be7c3ab
cpath: /trunk/server/meta.c
copyroot: 15280 /trunk

PLAIN
K 11
Makefile.am
V 23
file 5q.5ck.r31933/9662
K 13
actiontools.c
V 25
file 1p83.5ck.r31161/6148
K 13
actiontools.h
V 26
file 1p86.5ck.r30751/20576
K 8
advisors
V 24
dir 4n2.5ck.r32103/50121
K 9
aiiface.c
V 25
file 4gm.5ck.r26905/55786
K 9
aiiface.h
V 25
file 4gn.5ck.r26905/56374
K 9
animals.c
V 24
file vnk.5ck.r31065/7891
K 9
animals.h
V 25
file vnm.5ck.r26905/63257
K 6
auth.c
V 23
file 39c.5ck.r31944/210
K 6
auth.h
V 25
file 39d.5ck.r18977/19170
K 11
barbarian.c
V 24
file lw.5ck.r30874/23837
K 11
barbarian.h
V 23
file lx.5ck.r28605/1460
K 14
citizenshand.c
V 25
file 6mz.5ck.r29645/54068
K 14
citizenshand.h
V 25
file 6n0.5ck.r26905/56662
K 10
cityhand.c
V 23
file 10.5ck.r32233/8157
K 10
cityhand.h
V 23
file 4f.0.r13297/423686
K 11
citytools.c
V 23
file 4g.5ck.r32278/5097
K 11
citytools.h
V 24
file 4h.5ck.r29273/23520
K 10
cityturn.c
V 23
file 4i.5ck.r32236/6974
K 10
cityturn.h
V 23
file 4j.5ck.r31247/3607
K 11
civserver.c
V 23
file 4k.5ck.r32099/6107
K 10
commands.c
V 25
file 2ly.5ck.r30812/39680
K 10
commands.h
V 25
file 2lz.5ck.r28012/47664
K 13
connecthand.c
V 25
file 2dw.5ck.r32146/32206
K 13
connecthand.h
V 24
file 2dx.5ck.r23606/2057
K 9
console.c
V 24
file dd.5ck.r32112/35934
K 9
console.h
V 23
file de.5ck.r31514/8658
K 10
diplhand.c
V 22
file 4m.5ck.r31332/500
K 10
diplhand.h
V 23
file 4n.5ck.r27517/8916
K 11
diplomats.c
V 24
file vz.5ck.r32287/98481
K 11
diplomats.h
V 23
file w0.5ck.r29361/9281
K 10
edithand.c
V 25
file 3bk.5ck.r32146/32452
K 10
edithand.h
V 25
file 4ez.5ck.r26905/64705
K 6
fcdb.c
V 23
file 6l3.5ck.r30952/119
K 6
fcdb.h
V 25
file 6l4.5ck.r26905/57239
K 10
gamehand.c
V 22
file 4o.5ck.r32335/605
K 10
gamehand.h
V 22
file 4p.5ck.r32335/848
K 9
generator
V 23
dir 2me.5ck.r32268/1064
K 10
handchat.c
V 23
file 4q.5ck.r25915/6654
K 10
handchat.h
V 24
file dj.5ck.r18270/28229
K 12
legacysave.c
V 22
file vl.5tv.r32308/203
K 12
legacysave.h
V 23
file vm.5tw.r30931/2151
K 9
maphand.c
V 24
file 13.5ck.r32077/88870
K 9
maphand.h
V 24
file 14.5ck.r31935/37915
K 6
meta.c
V 24
file 4s.5ck.r32355/16347
K 6
meta.h
V 23
file 4t.5ck.r27204/3095
K 6
mood.c
V 26
file 112c.5ck.r26905/63547
K 6
mood.h
V 26
file 112e.5ck.r26905/64129
K 8
notify.c
V 23
file 4i2.5ck.r31785/854
K 8
notify.h
V 25
file 4i3.5ck.r31370/14432
K 9
plrhand.c
V 24
file 4u.5ck.r31935/38156
K 9
plrhand.h
V 24
file 4v.5ck.r31792/36273
K 8
report.c
V 24
file vi.5ck.r30328/90100
K 8
report.h
V 23
file vj.5ck.r29899/8035
K 10
rscompat.c
V 26
file 1kte.5ck.r32287/98729
K 10
rscompat.h
V 26
file 1ktg.5ck.r32239/10026
K 10
rssanity.c
V 24
file hew.5ck.r32241/8981
K 10
rssanity.h
V 24
file hey.5ck.r31144/1251
K 9
ruleset.c
V 22
file 8w.5ck.r32291/143
K 9
ruleset.h
V 23
file 8x.5ck.r31448/1338
K 13
sanitycheck.c
V 22
file wi.5ck.r30957/384
K 13
sanitycheck.h
V 24
file wj.5ck.r28075/17176
K 12
savecompat.c
V 25
file qva.5ck.r32304/12710
K 12
savecompat.h
V 25
file qvc.5ck.r32304/12956
K 10
savegame.c
V 26
file 28ln.5ck.r32146/33449
K 10
savegame.h
V 25
file 4m1.5tx.r31444/17678
K 11
savegame2.c
V 23
file 4m0.5ck.r32352/163
K 11
savegame2.h
V 24
file 4m1.5ck.r31395/8224
K 11
savegame3.c
V 23
file 4m0.5ql.r32352/406
K 11
savegame3.h
V 25
file 25ch.5ck.r31395/8732
K 7
score.c
V 25
file 2eg.5ck.r29645/57467
K 7
score.h
V 24
file 2eh.5ck.r21929/6179
K 9
scripting
V 23
dir 31x.5ck.r32143/5997
K 8
sernet.c
V 23
file 15.5ck.r32161/7386
K 8
sernet.h
V 24
file 4y.5ck.r31871/13834
K 10
settings.c
V 25
file 2m0.5ck.r32032/11897
K 10
settings.h
V 24
file 2m1.5ck.r31955/9949
K 11
spacerace.c
V 23
file 9a.5ck.r31476/5877
K 11
spacerace.h
V 23
file 9b.5ck.r31476/6121
K 9
srv_log.c
V 25
file 15t.5el.r28853/27603
K 9
srv_log.h
V 25
file 15u.5em.r28012/47157
K 10
srv_main.c
V 23
file vg.5ck.r32335/1086
K 10
srv_main.h
V 23
file vh.5ck.r31620/2345
K 11
stdinhand.c
V 23
file 4z.5ck.r32170/1896
K 11
stdinhand.h
V 23
file 50.5ck.r32170/2140
K 11
techtools.c
V 23
file 33n.5ck.r31623/100
K 11
techtools.h
V 23
file 33o.5ck.r31623/343
K 10
unithand.c
V 23
file 18.5ck.r32256/4021
K 10
unithand.h
V 23
file 19.5ck.r32233/8645
K 11
unittools.c
V 23
file 1a.5ck.r32256/4264
K 11
unittools.h
V 23
file 1b.5ck.r31164/5815
K 8
voting.c
V 25
file 4ex.5ck.r26905/57525
K 8
voting.h
V 25
file 4ey.5ck.r26905/58399
END
ENDREP
id: z.5ck.r32355/20817
type: dir
pred: z.5ck.r32352/4899
count: 6519
text: 32355 16587 4217 0 43a62e9ce920ff6c3cebe4f4771419f8
props: 23990 448 166 0 e5026e1cb18fe57b41417951bfac7b19
cpath: /trunk/server
copyroot: 15280 /trunk

PLAIN
K 9
ABOUT-NLS
V 24
file fu.5ck.r31532/74309
K 7
AUTHORS
V 24
file 5u.5ck.r22143/14016
K 7
COPYING
V 22
file 1h.5ck.r29454/952
K 9
ChangeLog
V 26
file 6l.5ck.r31297/7697235
K 7
INSTALL
V 21
file 6.5ck.r31852/396
K 11
Makefile.am
V 22
file 59.5ck.r31919/510
K 4
NEWS
V 24
file 6m.5ck.r25634/30702
K 6
README
V 20
file 7.0.r4421/96382
K 2
ai
V 21
dir 8.5ck.r32297/4083
K 10
autogen.sh
V 22
file 12o.5ck.r32156/48
K 9
bootstrap
V 24
dir 2p5.5ck.r32151/15367
K 6
client
V 21
dir d.5ck.r32343/5794
K 6
common
V 22
dir p.5ck.r32340/11466
K 12
configure.ac
V 22
file 149.5ck.r32293/50
K 4
data
V 22
dir w.5ck.r32339/21889
K 12
dependencies
V 23
dir 2yu.5ck.r31822/5233
K 3
doc
V 23
dir k7.5ck.r32274/46739
K 10
fc_version
V 25
file 2lo.5en.r32287/98231
K 11
gen_headers
V 24
dir 1hsw.5ck.r32275/6188
K 3
lua
V 24
dir 2c5e.5ck.r31919/4841
K 2
m4
V 23
dir 12p.5ck.r32329/3378
K 7
scripts
V 23
dir 2yo.5ck.r31852/3843
K 6
server
V 22
dir z.5ck.r32355/20817
K 5
tests
V 22
dir 2g9.5ck.r31520/584
K 5
tools
V 24
dir 4pj.5js.r32339/25113
K 12
translations
V 24
dir t0a.5ck.r32351/32663
K 7
utility
V 22
dir 1c.5ck.r32322/3305
K 5
win32
V 23
dir 2eu.5ck.r32173/2405
END
ENDREP
id: 3.5ck.r32355/22213
type: dir
pred: 3.5ck.r32352/6291
count: 21130
text: 32355 21045 1155 0 2152687afd6ccf818d01c278796a9fa5
props: 28036 14655 292 0 9e1d5de0253c723466868990c52c129f
cpath: /trunk
copyroot: 15280 /trunk

PLAIN
K 8
branches
V 19
dir 1.0.r32354/6198
K 4
tags
V 19
dir 2.0.r31807/7857
K 5
trunk
V 22
dir 3.5ck.r32355/22213
K 7
website
V 20
dir 3ge.0.r31885/802
END
ENDREP
id: 0.0.r32355/22602
type: dir
pred: 0.0.r32354/6515
count: 32355
text: 32355 22437 152 0 6dd785f4346f79ddfbba5a2b8a6e9393
cpath: /
copyroot: 0 /

4s.5ck.t32354-1 modify true false /trunk/server/meta.c


22602 22749
