NNGS围棋服务器修改用户的注册方式
                 作者: YKL
    
    NNGS围棋服务器默认的用户注册方式需要用户提供一个邮件帐号,
注册成功后会给用户提供的邮件帐号里发送一封确认邮件,用户的密码
就包含在这封邮件里。但在局域网里这么做显得有些繁琐,能不能不让
用户提供邮件帐号,把密码直接显示给用户呢?

打开$your directory/nngs-1.1.14/nrat目录中的comproc.c文件
($your directory代表nngs-1.1.14目录所在的路径),找到com_register
函数,该函数就是Register命令对应的代码,代码如下:

int com_register(int p, struct parameter * param)
{
  char text[2048];
  char *pname = param[0].val.word;
  char *email = param[1].val.word;
  const char *fullname = param[2].val.string;
  char passwd[sizeof parray[p].passwd];
  char login[sizeof parray[p].login];
  char tmp[200];
  char salt[3];
  int p1, p2;
  int i;
  int shuttime = globClock;
  int len;

  len=strlen(pname);
  if (len > MAX_NAME) {
    pcn_out(p, CODE_ERROR, FORMAT_PLAYER_NAME_IS_TOO_LONG);
    return COM_OK;
  }
  if (len < MIN_NAME) {
    pcn_out(p, CODE_ERROR, FORMAT_PLAYER_NAME_IS_TOO_SHORT);
    return COM_OK;
  }
  if (!strncasecmp(pname, "guest", 5)) {
    pcn_out(p, CODE_ERROR, FORMAT_IT_WOULD_NOT_BE_NICE_TO_REGISTER_GUEST);
    return COM_OK;
  }
  if (!alphastring(pname)) {
    pcn_out(p, CODE_ERROR,  FORMAT_ILLEGAL_CHARACTERS_IN_PLAYER_NAME_ONLY_A_Z_A_Z_0_9_ALLOWED_);
    return COM_OK;
  }
  if (in_list_match("badname", pname)) {
    pcn_out(p, CODE_ERROR, FORMAT_THAT_NAME_IS_NOT_PERMITTED);
    return COM_OK;
  }
  if (param[2].type != TYPE_STRING) fullname = "Not Provided";
  strcpy(login, pname);
  stolower(login);
  p1 = player_fetch(login);
  if (p1>=0 && parray[p1].slotstat.registered) {
    pcn_out(p, CODE_ERROR, FORMAT_A_PLAYER_BY_THE_NAME_s_IS_ALREADY_REGISTERED_,
		 login);
    player_forget(p1);
    return COM_OK;
  }
  player_forget(p1);
  if (!chkaddr(email)) {
    pcn_out(p, CODE_ERROR, FORMAT_INVALID_EMAIL_ADDRESSn);
    return COM_OK;
  }
  p1 = player_new();
  do_copy(parray[p1].login, login, sizeof parray[0].login);
  do_copy(parray[p1].pname, pname, sizeof parray[0].pname);
  do_copy(parray[p1].rank, "NR", sizeof parray[0].rank);
  do_copy(parray[p1].ranked, "NR", sizeof parray[0].ranked);
  do_copy(parray[p1].srank, "NR", sizeof parray[0].srank);
  do_copy(parray[p1].fullname, fullname, sizeof parray[0].fullname);
  do_copy(parray[p1].email, email, sizeof parray[0].email);
  do_copy(parray[p1].RegDate, strltime((time_t *) &shuttime), sizeof parray[0].RegDate);
  for (i = 0; i < PASSLEN; i++) {
    passwd[i] = 'a' + rand() % 26;
  }
  passwd[i] = '\0';
  salt[0] = 'a' + rand() % 26;
  salt[1] = 'a' + rand() % 26;
  salt[2] = '\0';
  do_copy(parray[p1].passwd, mycrypt(passwd, salt), sizeof parray[0].passwd);
  parray[p1].adminLevel = ADMIN_REGISTERED_USER;
  parray[p1].slotstat.registered = 1;
  parray[p1].slotstat.valid = 1;
  player_dirty(p1);
  /* player_save(p1); this save can be omitted */
  player_forget(p1);

  sprintf(text, "\nWelcome to %s!  Here is your account info:\n\n\
  Login Name: %s\n\
  Full Name: %s\n\
  Email Address: %s\n\
  Initial Password: %s\n\n\
  Host registered from: %s as %s \n\n\
If any of this information is incorrect, please contact the administrator\n\
to get it corrected at %s.\n\n\
Please write down your password, as it will be your initial password\n\
To access the server, telnet to %s\n\
Please change your password after logging in.  See \"help password\"\n\
For additional help, type \"help welcome\" while on the server.\n\n\
On WWW, please try %s/\n\n\
Regards,\n\n\
NNGS admins\n\n--",
          server_name,
          pname, fullname,
          email, passwd,
          dotQuad(parray[p].thisHost),
          parray[p].pname,
          server_email, server_address,server_http);
  sprintf(tmp, "%s Account Created (%s)", server_name, pname);
  if ((i = mail_string_to_address(email, tmp, text)) < 0)
    Logit("mail_string_to_address(\"%s\", ...) returned %d", email, i);
  sprintf(text, "\n\
  Login Name: %s\n\
  Full Name: %s\n\
  Email Address: %s\n\
  Initial Password: %s\n\
  Host registered from: %s \n\n--",
          pname, fullname, email, passwd,
          dotQuad(parray[p].thisHost));
  /* Mail a copy to geek for testing / verification.  */
  if(geek_email) {
    if ((i = mail_string_to_address(geek_email, tmp, text)) < 0)
      Logit("mail_string_to_address(\"%s\", ...) returned %d", geek_email, i);
  }
  Logit("NewPlayer: %s [%s] %s (%s) by user %s",
                   pname, email, fullname, passwd, parray[p].pname);
  pcn_out(p, CODE_INFO,  FORMAT_YOU_ARE_NOW_REGISTERED_CONFIRMATION_TOGETHER_WITH_PASSWORD_IS_SENT_TO_YOURn);
  pcn_out_prompt(p, CODE_INFO, FORMAT_EMAIL_ADDRESS_sn, email);
  for (p2 = 0; p2 < parray_top; p2++) { /* Announce to all online admins */
    if (!parray[p2].slotstat.online) continue;
    if (parray[p2].adminLevel < ADMIN_ADMIN) continue;
    pcn_out_prompt(p2, CODE_SHOUT, FORMAT_NEW_PLAYER_s_s_BY_ss_n,
		   pname, email,
		   (parray[p].slotstat.registered ? "" : "guest "),
		   parray[p].pname);
  }
  new_players++;
  return COM_OK;
}

我修改后的代码如下:

int com_register(int p, struct parameter * param)
{
  char text[2048];
  char *pname = param[0].val.word;
/*  char *email = param[1].val.word;  */ 
 /*将接收email参数的语句注释掉,struct parameter 的定义见$your  directory/nngs-1.1.14/nrat/command.h*/
  const char *fullname = param[1].val.string; 
 /*将fullname接收的参数由第三个参数改为第二个参数*/
  char passwd[sizeof parray[p].passwd];
  char login[sizeof parray[p].login];
  char tmp[200];
  char salt[3];
  int p1, p2;
  int i;
  int shuttime = globClock;
  int len;

  len=strlen(pname);
  if (len > MAX_NAME) {
    pcn_out(p, CODE_ERROR, FORMAT_PLAYER_NAME_IS_TOO_LONG);
    return COM_OK;
  }
  if (len < MIN_NAME) {
    pcn_out(p, CODE_ERROR, FORMAT_PLAYER_NAME_IS_TOO_SHORT);
    return COM_OK;
  }
  if (!strncasecmp(pname, "guest", 5)) {
    pcn_out(p, CODE_ERROR, FORMAT_IT_WOULD_NOT_BE_NICE_TO_REGISTER_GUEST);
    return COM_OK;
  }
  if (!alphastring(pname)) {
    pcn_out(p, CODE_ERROR,  FORMAT_ILLEGAL_CHARACTERS_IN_PLAYER_NAME_ONLY_A_Z_A_Z_0_9_ALLOWED_);
    return COM_OK;
  }
  if (in_list_match("badname", pname)) {
    pcn_out(p, CODE_ERROR, FORMAT_THAT_NAME_IS_NOT_PERMITTED);
    return COM_OK;
  }
  if (param[1].type != TYPE_STRING) fullname = "Not Provided";  
/*前面将fullname接收的参数由第三个参数改为第二个参数,这里也相应更改*/
  strcpy(login, pname);
  stolower(login);
  p1 = player_fetch(login);
  if (p1>=0 && parray[p1].slotstat.registered) {
    pcn_out(p, CODE_ERROR, FORMAT_A_PLAYER_BY_THE_NAME_s_IS_ALREADY_REGISTERED_,
		 login);
    player_forget(p1);
    return COM_OK;
  }
  player_forget(p1);
  if (!chkaddr(email)) {
    pcn_out(p, CODE_ERROR, FORMAT_INVALID_EMAIL_ADDRESSn);
    return COM_OK;
  }
  p1 = player_new();
  do_copy(parray[p1].login, login, sizeof parray[0].login);
  do_copy(parray[p1].pname, pname, sizeof parray[0].pname);
  do_copy(parray[p1].rank, "NR", sizeof parray[0].rank);
  do_copy(parray[p1].ranked, "NR", sizeof parray[0].ranked);
  do_copy(parray[p1].srank, "NR", sizeof parray[0].srank);
  do_copy(parray[p1].fullname, fullname, sizeof parray[0].fullname);
  do_copy(parray[p1].email, "Not Provided", sizeof parray[0].email);    /*将email的值设为 "Not Provided"*/
  do_copy(parray[p1].RegDate, strltime((time_t *) &shuttime), sizeof parray[0].RegDate);
  for (i = 0; i < PASSLEN; i++) {
    passwd[i] = 'a' + rand() % 26;
  }
  passwd[i] = '\0';
  salt[0] = 'a' + rand() % 26;
  salt[1] = 'a' + rand() % 26;
  salt[2] = '\0';
  do_copy(parray[p1].passwd, mycrypt(passwd, salt), sizeof parray[0].passwd);
  parray[p1].adminLevel = ADMIN_REGISTERED_USER;
  parray[p1].slotstat.registered = 1;
  parray[p1].slotstat.valid = 1;
  player_dirty(p1);
  /* player_save(p1); this save can be omitted */
  player_forget(p1);

/*  sprintf(text, "\nWelcome to %s!  Here is your account info:\n\n\
  Login Name: %s\n\
  Full Name: %s\n\
  Email Address: %s\n\
  Initial Password: %s\n\n\
  Host registered from: %s as %s \n\n\
If any of this information is incorrect, please contact the administrator\n\
to get it corrected at %s.\n\n\
Please write down your password, as it will be your initial password\n\
To access the server, telnet to %s\n\
Please change your password after logging in.  See \"help password\"\n\
For additional help, type \"help welcome\" while on the server.\n\n\
On WWW, please try %s/\n\n\
Regards,\n\n\
NNGS admins\n\n--",
          server_name,
          pname, fullname,
          email, passwd,
          dotQuad(parray[p].thisHost),
          parray[p].pname,
          server_email, server_address,server_http);
  sprintf(tmp, "%s Account Created (%s)", server_name, pname); */   
 /*这两句的内容就是服务器发给用户的确认邮件的内容,这里把它们注释掉。如果你仍采用邮件确认的 方式,你可以把它们的内容改成你喜欢的内容。*/
/*  if ((i = mail_string_to_address(email, tmp, text)) < 0)
    Logit("mail_string_to_address(\"%s\", ...) returned %d", email, i);
  sprintf(text, "\n\
  Login Name: %s\n\
  Full Name: %s\n\
  Email Address: %s\n\
  Initial Password: %s\n\
  Host registered from: %s \n\n--",
          pname, fullname, email, passwd,
          dotQuad(parray[p].thisHost));  */    /*与email有关的语句注释掉*/
  /* Mail a copy to geek for testing / verification.  */
/*  if(geek_email) {
    if ((i = mail_string_to_address(geek_email, tmp, text)) < 0)
      Logit("mail_string_to_address(\"%s\", ...) returned %d", geek_email, i);
  }  */    /*与email有关的语句注释掉*/
  Logit("NewPlayer: %s [%s] %s (%s) by user %s",
                   pname, "Not Provided", fullname, passwd, parray[p].pname);    /*将email改 为"Not Provided"*/
  pcn_out(p, CODE_INFO,  FORMAT_YOU_ARE_NOW_REGISTERED_CONFIRMATION_TOGETHER_WITH_PASSWORD_IS_SENT_TO_YOURn);
/*  pcn_out_prompt(p, CODE_INFO, FORMAT_EMAIL_ADDRESS_sn, email);  */    /*与email有关的语句 注释掉*/
  pcn_out_prompt(p, CODE_INFO, FORMAT_PNAME_sn, pname);    /*新增的输出用户名的语句*/
  pcn_out_prompt(p, CODE_INFO, FORMAT_PASSWD_sn, passwd);    /*新增的输出password的语句*/
  for (p2 = 0; p2 < parray_top; p2++) { /* Announce to all online admins */
    if (!parray[p2].slotstat.online) continue;
    if (parray[p2].adminLevel < ADMIN_ADMIN) continue;
    pcn_out_prompt(p2, CODE_SHOUT, FORMAT_NEW_PLAYER_s_s_BY_ss_n,
		   pname, "Not Provided",
		   (parray[p].slotstat.registered ? "" : "guest "),
		   parray[p].pname);
  }    /*将email改为"Not Provided"*/
  new_players++;
  return COM_OK;
}

pcn_out和pcn_out_prompt语句用到的FORMAT_***参数的定义在$your  directory/nngs-1.1.14/src/formats.h文件里。在这里我将formats.h文件里的 FORMAT_YOU_ARE_NOW_REGISTERED_CONFIRMATION_TOGETHER_WITH_PASSWORD_IS_SENT_TO_YOURn由"You are  now registered! Confirmation together with password is sent to your\n"改为了"You are now  registered!\n",并且在文件中
#define FORMAT_SERVER_VERSION_sn 843
ENG(FORMAT_SERVER_VERSION_sn,"Server version: %s\n");
这一条定义后增加了两个定义:
#define FORMAT_PNAME_sn 844
ENG(FORMAT_PNAME_sn,"your login name: %s\n");
    
#define FORMAT_PASSWD_sn 845
ENG(FORMAT_PASSWD_sn,"your password: %s\n");

你也可以把定义的内容写成中文的。关于formats.h文件里定义的格式,
打开formats.h文件一看便知。

修改后重新make install一下即可。

现在用户注册时只需输入register login_ name full_name格式的命令
就可以了,密码会直接显示给用户。

别忘了修改一下register命令的帮助文件:)。
BTW:comproc.c文件包含了nngs里各个命令所对应的代码,你可以按你的
意愿尽情定制哦。



欢迎与我联系cccp401@sohu.com