summaryrefslogtreecommitdiff
path: root/src/char/inter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/char/inter.c')
-rw-r--r--src/char/inter.c417
1 files changed, 253 insertions, 164 deletions
diff --git a/src/char/inter.c b/src/char/inter.c
index 63e1564ff..34ecebd36 100644
--- a/src/char/inter.c
+++ b/src/char/inter.c
@@ -42,7 +42,6 @@ char char_server_pw[32] = "ragnarok";
char char_server_db[32] = "ragnarok";
char default_codepage[32] = ""; //Feature by irmin.
-static struct accreg *accreg_pt;
unsigned int party_share_level = 10;
// recv. packet list
@@ -592,127 +591,225 @@ void mapif_parse_accinfo(int fd) {
return;
}
-//--------------------------------------------------------
-// Save registry to sql
-int inter_accreg_tosql(int account_id, int char_id, struct accreg* reg, int type)
-{
- struct global_reg* r;
- StringBuf buf;
- int i;
-
- if( account_id <= 0 )
- return 0;
- reg->account_id = account_id;
- reg->char_id = char_id;
-
- //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
- switch( type )
- {
- case 3: //Char Reg
- if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) )
- Sql_ShowDebug(sql_handle);
- account_id = 0;
- break;
- case 2: //Account Reg
- if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) )
- Sql_ShowDebug(sql_handle);
- char_id = 0;
- break;
- case 1: //Account2 Reg
- ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
- return 0;
- default:
- ShowError("inter_accreg_tosql: Invalid type %d\n", type);
- return 0;
- }
-
- if( reg->reg_num <= 0 )
- return 0;
-
- StrBuf->Init(&buf);
- StrBuf->Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", reg_db);
-
- for( i = 0; i < reg->reg_num; ++i ) {
- r = &reg->reg[i];
- if( r->str[0] != '\0' && r->value[0] != '\0' ) {
- char str[32];
- char val[256];
-
- if( i > 0 )
- StrBuf->AppendStr(&buf, ",");
-
- SQL->EscapeString(sql_handle, str, r->str);
- SQL->EscapeString(sql_handle, val, r->value);
-
- StrBuf->Printf(&buf, "('%d','%d','%d','%s','%s')", type, account_id, char_id, str, val);
+/**
+ * Handles save reg data from map server and distributes accordingly.
+ *
+ * @param val either str or int, depending on type
+ * @param type false when int, true otherwise
+ **/
+void inter_savereg(int account_id, int char_id, const char *key, unsigned int index, intptr_t val, bool is_string) {
+ /* to login server we go! */
+ if( key[0] == '#' && key[1] == '#' ) {/* global account reg */
+ global_accreg_to_login_add(key,index,val,is_string);
+ } else if ( key[0] == '#' ) {/* local account reg */
+ if( is_string ) {
+ if( val ) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", acc_reg_str_db, account_id, key, index, (char*)val) )
+ Sql_ShowDebug(sql_handle);
+ } else {
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", acc_reg_str_db, account_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ }
+ } else {
+ if( val ) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%d')", acc_reg_num_db, account_id, key, index, (int)val) )
+ Sql_ShowDebug(sql_handle);
+ } else {
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", acc_reg_num_db, account_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ }
+ }
+ } else { /* char reg */
+ if( is_string ) {
+ if( val ) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`char_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", char_reg_str_db, char_id, key, index, (char*)val) )
+ Sql_ShowDebug(sql_handle);
+ } else {
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", char_reg_str_db, char_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ }
+ } else {
+ if( val ) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`char_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%d')", char_reg_num_db, char_id, key, index, (int)val) )
+ Sql_ShowDebug(sql_handle);
+ } else {
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", char_reg_num_db, char_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ }
}
}
-
- if( SQL_ERROR == SQL->QueryStr(sql_handle, StrBuf->Value(&buf)) ) {
- Sql_ShowDebug(sql_handle);
- }
-
- StrBuf->Destroy(&buf);
-
- return 1;
+
}
// Load account_reg from sql (type=2)
-int inter_accreg_fromsql(int account_id,int char_id, struct accreg *reg, int type)
+int inter_accreg_fromsql(int account_id,int char_id, int fd, int type)
{
- struct global_reg* r;
char* data;
size_t len;
- int i;
+ unsigned int plen = 0;
- if( reg == NULL)
- return 0;
-
- memset(reg, 0, sizeof(struct accreg));
- reg->account_id = account_id;
- reg->char_id = char_id;
+ switch( type ) {
+ case 3: //char reg
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `char_id`='%d'", char_reg_str_db, char_id) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ case 2: //account reg
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", acc_reg_str_db, account_id) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ case 1: //account2 reg
+ ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
+ return 0;
+ default:
+ ShowError("inter_accreg_fromsql: Invalid type %d\n", type);
+ return 0;
+ }
+
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 1;/* is string type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+
+ /**
+ * Vessel!
+ *
+ * str type
+ * { keyLength(B), key(<keyLength>), index(L), valLength(B), val(<valLength>) }
+ **/
+ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) {
+
+ SQL->GetData(sql_handle, 0, &data, NULL);
+ len = strlen(data)+1;
+
+ WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(fd,plen), data, len);
+ plen += len;
+
+ SQL->GetData(sql_handle, 1, &data, NULL);
+
+ WFIFOL(fd, plen) = (unsigned int)atol(data);
+ plen += 4;
+
+ SQL->GetData(sql_handle, 2, &data, NULL);
+ len = strlen(data)+1;
+
+ WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(fd,plen), data, len);
+ plen += len;
+
+ WFIFOW(fd, 14) += 1;
+
+ if( plen > 60000 ) {
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
+ /* prepare follow up */
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 1;/* is string type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+ }
+ }
+
+ /* mark & go. */
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
- //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
- switch( type )
- {
- case 3: //char reg
- if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) )
- Sql_ShowDebug(sql_handle);
- break;
- case 2: //account reg
- if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) )
- Sql_ShowDebug(sql_handle);
- break;
- case 1: //account2 reg
- ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
- return 0;
- default:
- ShowError("inter_accreg_fromsql: Invalid type %d\n", type);
- return 0;
+ SQL->FreeResult(sql_handle);
+
+ switch( type ) {
+ case 3: //char reg
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `char_id`='%d'", char_reg_num_db, char_id) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ case 2: //account reg
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", acc_reg_num_db, account_id) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ case 1: //account2 reg
+ ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
+ return 0;
}
- for( i = 0; i < MAX_REG_NUM && SQL_SUCCESS == SQL->NextRow(sql_handle); ++i )
- {
- r = &reg->reg[i];
- // str
- SQL->GetData(sql_handle, 0, &data, &len);
- memcpy(r->str, data, min(len, sizeof(r->str)));
- // value
- SQL->GetData(sql_handle, 1, &data, &len);
- memcpy(r->value, data, min(len, sizeof(r->value)));
+
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 0;/* is int type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+
+ /**
+ * Vessel!
+ *
+ * int type
+ * { keyLength(B), key(<keyLength>), index(L), value(L) }
+ **/
+ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) {
+
+ SQL->GetData(sql_handle, 0, &data, NULL);
+ len = strlen(data)+1;
+
+ WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(fd,plen), data, len);
+ plen += len;
+
+ SQL->GetData(sql_handle, 1, &data, NULL);
+
+ WFIFOL(fd, plen) = (unsigned int)atol(data);
+ plen += 4;
+
+ SQL->GetData(sql_handle, 2, &data, NULL);
+
+ WFIFOL(fd, plen) = atoi(data);
+ plen += 4;
+
+ WFIFOW(fd, 14) += 1;
+
+ if( plen > 60000 ) {
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
+ /* prepare follow up */
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 0;/* is int type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+ }
}
- reg->reg_num = i;
+
+ /* mark as complete & go. */
+ WFIFOB(fd, 12) = type;
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
SQL->FreeResult(sql_handle);
return 1;
}
-// Initialize
-int inter_accreg_sql_init(void)
-{
- CREATE(accreg_pt, struct accreg, 1);
- return 0;
-
-}
-
/*==========================================
* read config file
*------------------------------------------*/
@@ -833,7 +930,6 @@ int inter_init_sql(const char *file)
inter_homunculus_sql_init();
inter_mercenary_sql_init();
inter_elemental_sql_init();
- inter_accreg_sql_init();
inter_mail_sql_init();
inter_auction_sql_init();
@@ -857,8 +953,6 @@ void inter_final(void)
inter_mail_sql_final();
inter_auction_sql_final();
- if (accreg_pt) aFree(accreg_pt);
-
do_final_msg();
return;
}
@@ -921,36 +1015,15 @@ int mapif_wis_end(struct WisData *wd, int flag)
}
// Account registry transfer to map-server
-static void mapif_account_reg(int fd, unsigned char *src)
-{
- WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO
- mapif_sendallwos(fd, src, WBUFW(src,2));
-}
+//static void mapif_account_reg(int fd, unsigned char *src)
+//{
+// WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO
+// mapif_sendallwos(fd, src, WBUFW(src,2));
+//}
// Send the requested account_reg
-int mapif_account_reg_reply(int fd,int account_id,int char_id, int type)
-{
- struct accreg *reg=accreg_pt;
- WFIFOHEAD(fd, 13 + 5000);
- inter_accreg_fromsql(account_id,char_id,reg,type);
-
- WFIFOW(fd,0)=0x3804;
- WFIFOL(fd,4)=account_id;
- WFIFOL(fd,8)=char_id;
- WFIFOB(fd,12)=type;
- if(reg->reg_num==0){
- WFIFOW(fd,2)=13;
- }else{
- int i,p;
- for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) {
- p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place.
- p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1;
- }
- WFIFOW(fd,2)=p;
- if (p>= 5000)
- ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id);
- }
- WFIFOSET(fd,WFIFOW(fd,2));
+int mapif_account_reg_reply(int fd,int account_id,int char_id, int type) {
+ inter_accreg_fromsql(account_id,char_id,fd,type);
return 0;
}
@@ -1128,34 +1201,50 @@ int mapif_parse_WisToGM(int fd)
// Save account_reg into sql (type=2)
int mapif_parse_Registry(int fd)
{
- int j,p,len, max;
- struct accreg *reg=accreg_pt;
-
- memset(accreg_pt,0,sizeof(struct accreg));
- switch (RFIFOB(fd, 12)) {
- case 3: //Character registry
- max = GLOBAL_REG_NUM;
- break;
- case 2: //Account Registry
- max = ACCOUNT_REG_NUM;
- break;
- case 1: //Account2 registry, must be sent over to login server.
- return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4);
- default:
- return 1;
- }
- for(j=0,p=13;j<max && p<RFIFOW(fd,2);j++){
- sscanf((char*)RFIFOP(fd,p), "%31c%n",reg->reg[j].str,&len);
- reg->reg[j].str[len]='\0';
- p +=len+1; //+1 to skip the '\0' between strings.
- sscanf((char*)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len);
- reg->reg[j].value[len]='\0';
- p +=len+1;
- }
- reg->reg_num=j;
+ int account_id = RFIFOL(fd, 4), char_id = RFIFOL(fd, 8), count = RFIFOW(fd, 12);
+
+ if( count ) {
+ int cursor = 14, i;
+ char key[32], sval[254];
+ unsigned int index;
+
+ global_accreg_to_login_start(account_id,char_id);
+
+ for(i = 0; i < count; i++) {
+ safestrncpy(key, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor));
+ cursor += RFIFOB(fd, cursor) + 1;
+
+ index = RFIFOL(fd, cursor);
+ cursor += 4;
+
+ switch (RFIFOB(fd, cursor++)) {
+ /* int */
+ case 0:
+ inter_savereg(account_id,char_id,key,index,RFIFOL(fd, cursor),false);
+ cursor += 4;
+ break;
+ case 1:
+ inter_savereg(account_id,char_id,key,index,0,false);
+ break;
+ /* str */
+ case 2:
+ safestrncpy(sval, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor));
+ cursor += RFIFOB(fd, cursor) + 1;
+ inter_savereg(account_id,char_id,key,index,(intptr_t)sval,true);
+ break;
+ case 3:
+ inter_savereg(account_id,char_id,key,index,0,true);
+ break;
+
+ default:
+ ShowError("mapif_parse_Registry: unknown type %d\n",RFIFOB(fd, cursor - 1));
+ return 1;
+ }
- inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12));
- mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers.
+ }
+
+ global_accreg_to_login_send();
+ }
return 0;
}