void buyingstore_create(struct map_session_data *sd, int zenylimit, unsigned char result, const char *storename, const uint8 *itemlist, unsigned int count) { unsigned int i, weight, listidx; struct item_data *id; if(!result || count == 0) { // canceled, or no items return; } if(!battle_config.feature_buying_store || pc_istrading(sd) || sd->buyingstore.slots == 0 || count > sd->buyingstore.slots || zenylimit <= 0 || zenylimit > sd->status.zeny || !storename[0]) { // disabled or invalid input sd->buyingstore.slots = 0; clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0); return; } if(!pc_can_give_items(sd)) { // custom: GM is not allowed to buy (give zeny) sd->buyingstore.slots = 0; clif_displaymessage(sd->fd, msg_txt(246)); clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0); return; } if(sd->sc.data[SC_NOCHAT] && (sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM)) { // custom: mute limitation return; } if(map->list[sd->bl.m].flag.novending) { // custom: no vending maps clif_displaymessage(sd->fd, msg_txt(276)); // "You can't open a shop on this map" return; } if(map->getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING)) { // custom: no vending cells clif_displaymessage(sd->fd, msg_txt(204)); // "You can't open a shop on this cell." return; } weight = sd->weight; // check item list for(i = 0; i < count; i++) { // itemlist: <name id>.W <amount>.W <price>.L unsigned short nameid, amount; int price, idx; nameid = RBUFW(itemlist,i*8+0); amount = RBUFW(itemlist,i*8+2); price = RBUFL(itemlist,i*8+4); if((id = itemdb_exists(nameid)) == NULL || amount == 0) { // invalid input break; } if(price <= 0 || price > BUYINGSTORE_MAX_PRICE) { // invalid price: unlike vending, items cannot be bought at 0 Zeny break; } if(!id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_get_group_level(sd), pc_get_group_level(sd)) || (idx = pc_search_inventory(sd, nameid)) == -1) { // restrictions: allowed, no character-bound items and at least one must be owned break; } if(sd->status.inventory[idx].amount+amount > BUYINGSTORE_MAX_AMOUNT) { // too many items of same kind break; } if(i) { // duplicate check. as the client does this too, only malicious intent should be caught here ARR_FIND(0, i, listidx, sd->buyingstore.items[listidx].nameid == nameid); if(listidx != i) { // duplicate ShowWarning(read_message("Source.map.map_buyingstore_s2"), nameid, amount, sd->status.account_id, sd->status.char_id); break; } } weight+= id->weight*amount; sd->buyingstore.items[i].nameid = nameid; sd->buyingstore.items[i].amount = amount; sd->buyingstore.items[i].price = price; } if(i != count) { // invalid item/amount/price sd->buyingstore.slots = 0; clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0); return; } if((sd->max_weight*90)/100 < weight) { // not able to carry all wanted items without getting overweight (90%) sd->buyingstore.slots = 0; clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE_OVERWEIGHT, weight); return; } // success sd->state.buyingstore = true; sd->buyer_id = buyingstore_getuid(); sd->buyingstore.zenylimit = zenylimit; sd->buyingstore.slots = i; // store actual amount of items safestrncpy(sd->message, storename, sizeof(sd->message)); clif_buyingstore_myitemlist(sd); clif_buyingstore_entry(sd); }
bool buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count) { unsigned int i, weight, listidx; char message_sql[MESSAGE_SIZE * 2]; if( !result || count == 0 ) // Canceled, or no items return false; if( !battle_config.feature_buying_store || pc_istrading(sd) || sd->buyingstore.slots == 0 || count > sd->buyingstore.slots || zenylimit <= 0 || zenylimit > sd->status.zeny || !storename[0] ) { // Disabled or invalid input sd->buyingstore.slots = 0; clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0); return false; } if( !pc_can_give_items(sd) ) { // Custom: GM is not allowed to buy (give zeny) sd->buyingstore.slots = 0; clif_displaymessage(sd->fd, msg_txt(246)); clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0); return false; } if( sd->sc.data[SC_NOCHAT] && (sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM) ) // Custom: Mute limitation return false; if( map[sd->bl.m].flag.novending ) { // Custom: No vending maps clif_displaymessage(sd->fd, msg_txt(276)); // "You can't open a shop on this map" return false; } if( map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) ) { // Custom: No vending cells clif_displaymessage(sd->fd, msg_txt(204)); // "You can't open a shop on this cell." return false; } weight = sd->weight; // Check item list for( i = 0; i < count; i++ ) { // itemlist: <name id>.W <amount>.W <price>.L unsigned short nameid, amount; int price, idx; struct item_data* id; nameid = RBUFW(itemlist,i * 8 + 0); amount = RBUFW(itemlist,i * 8 + 2); price = RBUFL(itemlist,i * 8 + 4); if( (id = itemdb_exists(nameid)) == NULL || amount == 0 ) // Invalid input break; // Invalid price: Unlike vending, items cannot be bought at 0 Zeny if( price <= 0 || price > BUYINGSTORE_MAX_PRICE ) break; // Restrictions: Allowed, no character-bound items and at least one must be owned if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_get_group_level(sd), pc_get_group_level(sd)) || (idx = pc_search_inventory(sd, nameid)) == -1 ) break; if( sd->status.inventory[idx].amount + amount > BUYINGSTORE_MAX_AMOUNT ) // Too many items of same kind break; if( i ) { // Duplicate check. As the client does this too, only malicious intent should be caught here ARR_FIND(0, i, listidx, sd->buyingstore.items[listidx].nameid == nameid); if( listidx != i ) { // Duplicate ShowWarning("buyingstore_create: Found duplicate item on buying list (nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n", nameid, amount, sd->status.account_id, sd->status.char_id); break; } } weight += id->weight * amount; sd->buyingstore.items[i].nameid = nameid; sd->buyingstore.items[i].amount = amount; sd->buyingstore.items[i].price = price; } if( i != count ) { // Invalid item/amount/price sd->buyingstore.slots = 0; clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0); return false; } if( (sd->max_weight * 90) / 100 < weight ) { // Not able to carry all wanted items without getting overweight (90%) sd->buyingstore.slots = 0; clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE_OVERWEIGHT, weight); return false; } // Success sd->state.buyingstore = true; sd->buyer_id = buyingstore_getuid(); sd->buyingstore.zenylimit = zenylimit; sd->buyingstore.slots = i; // Store actual amount of items safestrncpy(sd->message, storename, sizeof(sd->message)); Sql_EscapeString(mmysql_handle, message_sql, sd->message); if( Sql_Query(mmysql_handle, "INSERT INTO `%s`(`id`,`account_id`,`char_id`,`sex`,`map`,`x`,`y`,`title`,`limit`,`autotrade`) VALUES( %d, %d, %d, '%c', '%s', %d, %d, '%s', %d, %d );", buyingstore_db, sd->buyer_id, sd->status.account_id, sd->status.char_id, !sd->status.sex ? 'F' : 'M', map[sd->bl.m].name, sd->bl.x, sd->bl.y, message_sql, sd->buyingstore.zenylimit, sd->state.autotrade) != SQL_SUCCESS ) Sql_ShowDebug(mmysql_handle); for( i = 0; i < sd->buyingstore.slots; i++ ) if( Sql_Query(mmysql_handle, "INSERT INTO `%s`(`buyingstore_id`,`index`,`item_id`,`amount`,`price`) VALUES( %d, %d, %d, %d, %d );", buyingstore_items_db, sd->buyer_id, i, sd->buyingstore.items[i].nameid, sd->buyingstore.items[i].amount, sd->buyingstore.items[i].price) != SQL_SUCCESS ) Sql_ShowDebug(mmysql_handle); clif_buyingstore_myitemlist(sd); clif_buyingstore_entry(sd); return true; }
/** * Initializing autotraders from table */ void do_init_buyingstore_autotrade(void) { if( battle_config.feature_autotrade ) { uint16 i, items = 0; autotrader_count = 0; // Get autotrader from table. `map`, `x`, and `y`, aren't used here // Just read player that has data at buyingstore_items [Cydh] if( Sql_Query(mmysql_handle, "SELECT `id`, `account_id`, `char_id`, `sex`, `title`, `limit` " "FROM `%s` " "WHERE `autotrade` = 1 AND `limit` > 0 AND (SELECT COUNT(`buyingstore_id`) FROM `%s` WHERE `buyingstore_id` = `id`) > 0;", buyingstore_db, buyingstore_items_db) != SQL_SUCCESS ) { Sql_ShowDebug(mmysql_handle); return; } if( (autotrader_count = (uint32)Sql_NumRows(mmysql_handle)) > 0 ) { // Init autotraders CREATE(autotraders, struct s_autotrade *, autotrader_count); if( autotraders == NULL ) { //This is shouldn't happen [Cydh] ShowError("Failed to initialize buyingstore autotraders!\n"); Sql_FreeResult(mmysql_handle); return; } // Init each autotrader data i = 0; while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) && i < autotrader_count ) { size_t len; char* data; CREATE(autotraders[i], struct s_autotrade, 1); Sql_GetData(mmysql_handle, 0, &data, NULL); autotraders[i]->buyer_id = atoi(data); Sql_GetData(mmysql_handle, 1, &data, NULL); autotraders[i]->account_id = atoi(data); Sql_GetData(mmysql_handle, 2, &data, NULL); autotraders[i]->char_id = atoi(data); Sql_GetData(mmysql_handle, 3, &data, NULL); autotraders[i]->sex = (data[0] == 'F') ? 0 : 1; Sql_GetData(mmysql_handle, 4, &data, &len); safestrncpy(autotraders[i]->title, data, min(len + 1, MESSAGE_SIZE)); Sql_GetData(mmysql_handle, 5, &data, NULL); autotraders[i]->limit = atoi(data); autotraders[i]->count = 0; // Initialize player CREATE(autotraders[i]->sd, struct map_session_data, 1); pc_setnewpc(autotraders[i]->sd, autotraders[i]->account_id, autotraders[i]->char_id, 0, gettick(), autotraders[i]->sex, 0); autotraders[i]->sd->state.autotrade = 1; chrif_authreq(autotraders[i]->sd, true); i++; } Sql_FreeResult(mmysql_handle); // Init items on vending list each autotrader for( i = 0; i < autotrader_count; i++ ) { struct s_autotrade *at = NULL; uint16 j; if( autotraders[i] == NULL ) continue; at = autotraders[i]; if( SQL_ERROR == Sql_Query(mmysql_handle, "SELECT `item_id`, `amount`, `price` " "FROM `%s` " "WHERE `buyingstore_id` = %d " "ORDER BY `index` ASC;", buyingstore_items_db, at->buyer_id) ) { Sql_ShowDebug(mmysql_handle); continue; } if( !(at->count = (uint32)Sql_NumRows(mmysql_handle)) ) { map_quit(at->sd); continue; } // Init the list CREATE(at->entries, struct s_autotrade_entry *,at->count); //Add the item into list j = 0; while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) && j < at->count ) { char* data; CREATE(at->entries[j], struct s_autotrade_entry, 1); Sql_GetData(mmysql_handle, 0, &data, NULL); at->entries[j]->item_id = atoi(data); Sql_GetData(mmysql_handle, 1, &data, NULL); at->entries[j]->amount = atoi(data); Sql_GetData(mmysql_handle, 2, &data, NULL); at->entries[j]->price = atoi(data); j++; } items += j; Sql_FreeResult(mmysql_handle); } ShowStatus("Done loading '"CL_WHITE"%d"CL_RESET"' autotraders with '"CL_WHITE"%d"CL_RESET"' items.\n", autotrader_count, items); }
/* * Validate recipients, count delivery types and errors, and handle aliasing * FIXME check for dupes!!!!! * * Returns 0 if all addresses are ok, ret->num_error = -1 if no addresses * were specified, or the number of addresses found invalid. * * Caller needs to free the result using free_recipients() */ recptypes *validate_recipients(const char *supplied_recipients, const char *RemoteIdentifier, int Flags) { struct CitContext *CCC = CC; recptypes *ret; char *recipients = NULL; char *org_recp; char this_recp[256]; char this_recp_cooked[256]; char append[SIZ]; long len; int num_recps = 0; int i, j; int mailtype; int invalid; struct ctdluser tempUS; struct ctdlroom tempQR; struct ctdlroom tempQR2; int err = 0; char errmsg[SIZ]; int in_quotes = 0; /* Initialize */ ret = (recptypes *) malloc(sizeof(recptypes)); if (ret == NULL) return(NULL); /* Set all strings to null and numeric values to zero */ memset(ret, 0, sizeof(recptypes)); if (supplied_recipients == NULL) { recipients = strdup(""); } else { recipients = strdup(supplied_recipients); } /* Allocate some memory. Yes, this allocates 500% more memory than we will * actually need, but it's healthier for the heap than doing lots of tiny * realloc() calls instead. */ len = strlen(recipients) + 1024; ret->errormsg = malloc(len); ret->recp_local = malloc(len); ret->recp_internet = malloc(len); ret->recp_ignet = malloc(len); ret->recp_room = malloc(len); ret->display_recp = malloc(len); ret->recp_orgroom = malloc(len); org_recp = malloc(len); ret->errormsg[0] = 0; ret->recp_local[0] = 0; ret->recp_internet[0] = 0; ret->recp_ignet[0] = 0; ret->recp_room[0] = 0; ret->recp_orgroom[0] = 0; ret->display_recp[0] = 0; ret->recptypes_magic = RECPTYPES_MAGIC; /* Change all valid separator characters to commas */ for (i=0; !IsEmptyStr(&recipients[i]); ++i) { if ((recipients[i] == ';') || (recipients[i] == '|')) { recipients[i] = ','; } } /* Now start extracting recipients... */ while (!IsEmptyStr(recipients)) { for (i=0; i<=strlen(recipients); ++i) { if (recipients[i] == '\"') in_quotes = 1 - in_quotes; if ( ( (recipients[i] == ',') && (!in_quotes) ) || (recipients[i] == 0) ) { safestrncpy(this_recp, recipients, i+1); this_recp[i] = 0; if (recipients[i] == ',') { strcpy(recipients, &recipients[i+1]); } else { strcpy(recipients, ""); } break; } } striplt(this_recp); if (IsEmptyStr(this_recp)) break; MSG_syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp); ++num_recps; strcpy(org_recp, this_recp); alias(this_recp); alias(this_recp); mailtype = alias(this_recp); for (j = 0; !IsEmptyStr(&this_recp[j]); ++j) { if (this_recp[j]=='_') { this_recp_cooked[j] = ' '; } else { this_recp_cooked[j] = this_recp[j]; } } this_recp_cooked[j] = '\0'; invalid = 0; errmsg[0] = 0; switch(mailtype) { case MES_LOCAL: if (!strcasecmp(this_recp, "sysop")) { ++ret->num_room; strcpy(this_recp, CtdlGetConfigStr("c_aideroom")); if (!IsEmptyStr(ret->recp_room)) { strcat(ret->recp_room, "|"); } strcat(ret->recp_room, this_recp); } else if ( (!strncasecmp(this_recp, "room_", 5)) && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) { /* Save room so we can restore it later */ tempQR2 = CCC->room; CCC->room = tempQR; /* Check permissions to send mail to this room */ err = CtdlDoIHavePermissionToPostInThisRoom( errmsg, sizeof errmsg, RemoteIdentifier, Flags, 0 /* 0 = not a reply */ ); if (err) { ++ret->num_error; invalid = 1; } else { ++ret->num_room; if (!IsEmptyStr(ret->recp_room)) { strcat(ret->recp_room, "|"); } strcat(ret->recp_room, &this_recp_cooked[5]); if (!IsEmptyStr(ret->recp_orgroom)) { strcat(ret->recp_orgroom, "|"); } strcat(ret->recp_orgroom, org_recp); } /* Restore room in case something needs it */ CCC->room = tempQR2; } else if (CtdlGetUser(&tempUS, this_recp) == 0) { ++ret->num_local; strcpy(this_recp, tempUS.fullname); if (!IsEmptyStr(ret->recp_local)) { strcat(ret->recp_local, "|"); } strcat(ret->recp_local, this_recp); } else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) { ++ret->num_local; strcpy(this_recp, tempUS.fullname); if (!IsEmptyStr(ret->recp_local)) { strcat(ret->recp_local, "|"); } strcat(ret->recp_local, this_recp); } else { ++ret->num_error; invalid = 1; } break; case MES_INTERNET: /* Yes, you're reading this correctly: if the target * domain points back to the local system or an attached * Citadel directory, the address is invalid. That's * because if the address were valid, we would have * already translated it to a local address by now. */ if (IsDirectory(this_recp, 0)) { ++ret->num_error; invalid = 1; } else { ++ret->num_internet; if (!IsEmptyStr(ret->recp_internet)) { strcat(ret->recp_internet, "|"); } strcat(ret->recp_internet, this_recp); } break; case MES_IGNET: ++ret->num_ignet; if (!IsEmptyStr(ret->recp_ignet)) { strcat(ret->recp_ignet, "|"); } strcat(ret->recp_ignet, this_recp); break; case MES_ERROR: ++ret->num_error; invalid = 1; break; } if (invalid) { if (IsEmptyStr(errmsg)) { snprintf(append, sizeof append, "Invalid recipient: %s", this_recp); } else { snprintf(append, sizeof append, "%s", errmsg); } if ( (strlen(ret->errormsg) + strlen(append) + 3) < SIZ) { if (!IsEmptyStr(ret->errormsg)) { strcat(ret->errormsg, "; "); } strcat(ret->errormsg, append); } } else { if (IsEmptyStr(ret->display_recp)) { strcpy(append, this_recp); } else { snprintf(append, sizeof append, ", %s", this_recp); } if ( (strlen(ret->display_recp)+strlen(append)) < SIZ) { strcat(ret->display_recp, append); } } } free(org_recp); if ((ret->num_local + ret->num_internet + ret->num_ignet + ret->num_room + ret->num_error) == 0) { ret->num_error = (-1); strcpy(ret->errormsg, "No recipients specified."); } MSGM_syslog(LOG_DEBUG, "validate_recipients()\n"); MSG_syslog(LOG_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local); MSG_syslog(LOG_DEBUG, " room: %d <%s>\n", ret->num_room, ret->recp_room); MSG_syslog(LOG_DEBUG, " inet: %d <%s>\n", ret->num_internet, ret->recp_internet); MSG_syslog(LOG_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet); MSG_syslog(LOG_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg); free(recipients); return(ret); }
/* * Handle subjects with RFC2047 encoding such as: * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?= */ void utf8ify_rfc822_string(char *buf) { char *start, *end, *next, *nextend, *ptr; char newbuf[1024]; char charset[128]; char encoding[16]; char istr[1024]; iconv_t ic = (iconv_t)(-1) ; char *ibuf; /**< Buffer of characters to be converted */ char *obuf; /**< Buffer for converted characters */ size_t ibuflen; /**< Length of input buffer */ size_t obuflen; /**< Length of output buffer */ char *isav; /**< Saved pointer to input buffer */ char *osav; /**< Saved pointer to output buffer */ int passes = 0; int i, len, delta; int illegal_non_rfc2047_encoding = 0; /* Sometimes, badly formed messages contain strings which were simply * written out directly in some foreign character set instead of * using RFC2047 encoding. This is illegal but we will attempt to * handle it anyway by converting from a user-specified default * charset to UTF-8 if we see any nonprintable characters. */ len = strlen(buf); for (i=0; i<len; ++i) { if ((buf[i] < 32) || (buf[i] > 126)) { illegal_non_rfc2047_encoding = 1; i = len; ///< take a shortcut, it won't be more than one. } } if (illegal_non_rfc2047_encoding) { const char *default_header_charset = "iso-8859-1"; if ( (strcasecmp(default_header_charset, "UTF-8")) && (strcasecmp(default_header_charset, "us-ascii")) ) { ctdl_iconv_open("UTF-8", default_header_charset, &ic); if (ic != (iconv_t)(-1) ) { ibuf = malloc(1024); isav = ibuf; safestrncpy(ibuf, buf, 1024); ibuflen = strlen(ibuf); obuflen = 1024; obuf = (char *) malloc(obuflen); osav = obuf; iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen); osav[1024-obuflen] = 0; strcpy(buf, osav); free(osav); iconv_close(ic); free(isav); } } } /* pre evaluate the first pair */ nextend = end = NULL; len = strlen(buf); start = strstr(buf, "=?"); if (start != NULL) FindNextEnd (start, end); while ((start != NULL) && (end != NULL)) { next = strstr(end, "=?"); if (next != NULL) FindNextEnd(next, nextend); if (nextend == NULL) next = NULL; /* did we find two partitions */ if ((next != NULL) && ((next - end) > 2)) { ptr = end + 2; while ((ptr < next) && (isspace(*ptr) || (*ptr == '\r') || (*ptr == '\n') || (*ptr == '\t'))) ptr ++; /* did we find a gab just filled with blanks? */ if (ptr == next) { memmove (end + 2, next, len - (next - start)); /* now terminate the gab at the end */ delta = (next - end) - 2; len -= delta; buf[len] = '\0'; /* move next to its new location. */ next -= delta; nextend -= delta; } } /* our next-pair is our new first pair now. */ start = next; end = nextend; } /* Now we handle foreign character sets properly encoded * in RFC2047 format. */ start = strstr(buf, "=?"); FindNextEnd((start != NULL)? start : buf, end); while (start != NULL && end != NULL && end > start) { extract_token(charset, start, 1, '?', sizeof charset); extract_token(encoding, start, 2, '?', sizeof encoding); extract_token(istr, start, 3, '?', sizeof istr); ibuf = malloc(1024); isav = ibuf; if (!strcasecmp(encoding, "B")) { /**< base64 */ ibuflen = CtdlDecodeBase64(ibuf, istr, strlen(istr)); } else if (!strcasecmp(encoding, "Q")) { /**< quoted-printable */ size_t len; unsigned long pos; len = strlen(istr); pos = 0; while (pos < len) { if (istr[pos] == '_') istr[pos] = ' '; pos++; } ibuflen = CtdlDecodeQuotedPrintable(ibuf, istr, len); } else { strcpy(ibuf, istr); /**< unknown encoding */ ibuflen = strlen(istr); } ctdl_iconv_open("UTF-8", charset, &ic); if (ic != (iconv_t)(-1) ) { obuflen = 1024; obuf = (char *) malloc(obuflen); osav = obuf; iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen); osav[1024-obuflen] = 0; end = start; end++; strcpy(start, ""); remove_token(end, 0, '?'); remove_token(end, 0, '?'); remove_token(end, 0, '?'); remove_token(end, 0, '?'); strcpy(end, &end[1]); snprintf(newbuf, sizeof newbuf, "%s%s%s", buf, osav, end); strcpy(buf, newbuf); free(osav); iconv_close(ic); } else { end = start; end++; strcpy(start, ""); remove_token(end, 0, '?'); remove_token(end, 0, '?'); remove_token(end, 0, '?'); remove_token(end, 0, '?'); strcpy(end, &end[1]); snprintf(newbuf, sizeof newbuf, "%s(unreadable)%s", buf, end); strcpy(buf, newbuf); } free(isav); /* * Since spammers will go to all sorts of absurd lengths to get their * messages through, there are LOTS of corrupt headers out there. * So, prevent a really badly formed RFC2047 header from throwing * this function into an infinite loop. */ ++passes; if (passes > 20) return; start = strstr(buf, "=?"); FindNextEnd((start != NULL)? start : buf, end); } }
static int mail_fromsql(int char_id, struct mail_data* md) { int i, j; struct mail_message *msg; struct item *item; char *data; StringBuf buf; memset(md, 0, sizeof(struct mail_data)); md->amount = 0; md->full = false; StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`"); for (i = 0; i < MAX_SLOTS; i++) StrBuf->Printf(&buf, ",`card%d`", i); // I keep the `status` < 3 just in case someone forget to apply the sqlfix StrBuf->Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", mail_db, char_id, MAIL_MAX_INBOX + 1); if( SQL_ERROR == SQL->Query(sql_handle, StrBuf->Value(&buf)) ) Sql_ShowDebug(sql_handle); StrBuf->Destroy(&buf); for (i = 0; i < MAIL_MAX_INBOX && SQL_SUCCESS == SQL->NextRow(sql_handle); ++i ) { msg = &md->msg[i]; SQL->GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); SQL->GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); SQL->GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); SQL->GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); SQL->GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); SQL->GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); SQL->GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); SQL->GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); SQL->GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); item = &msg->item; SQL->GetData(sql_handle,10, &data, NULL); item->amount = (short)atoi(data); SQL->GetData(sql_handle,11, &data, NULL); item->nameid = atoi(data); SQL->GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); SQL->GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); SQL->GetData(sql_handle,14, &data, NULL); item->identify = atoi(data); SQL->GetData(sql_handle,15, &data, NULL); item->unique_id = strtoull(data, NULL, 10); item->expire_time = 0; item->bound = 0; for (j = 0; j < MAX_SLOTS; j++) { SQL->GetData(sql_handle, 16 + j, &data, NULL); item->card[j] = atoi(data); } } md->full = ( SQL->NumRows(sql_handle) > MAIL_MAX_INBOX ); md->amount = i; SQL->FreeResult(sql_handle); md->unchecked = 0; md->unread = 0; for (i = 0; i < md->amount; i++) { msg = &md->msg[i]; if( msg->status == MAIL_NEW ) { if ( SQL_ERROR == SQL->Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id) ) Sql_ShowDebug(sql_handle); msg->status = MAIL_UNREAD; md->unchecked++; } else if ( msg->status == MAIL_UNREAD ) md->unread++; } ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount); return 1; }
/* * Aliasing for network mail. * (Error messages have been commented out, because this is a server.) */ int alias(char *name) { /* process alias and routing info for mail */ struct CitContext *CCC = CC; FILE *fp; int a, i; char aaa[SIZ], bbb[SIZ]; char *ignetcfg = NULL; char *ignetmap = NULL; int at = 0; char node[64]; char testnode[64]; char buf[SIZ]; char original_name[256]; safestrncpy(original_name, name, sizeof original_name); striplt(name); remove_any_whitespace_to_the_left_or_right_of_at_symbol(name); stripallbut(name, '<', '>'); fp = fopen(file_mail_aliases, "r"); if (fp == NULL) { fp = fopen("/dev/null", "r"); } if (fp == NULL) { return (MES_ERROR); } strcpy(aaa, ""); strcpy(bbb, ""); while (fgets(aaa, sizeof aaa, fp) != NULL) { while (isspace(name[0])) strcpy(name, &name[1]); aaa[strlen(aaa) - 1] = 0; strcpy(bbb, ""); for (a = 0; aaa[a] != '\0'; ++a) { if (aaa[a] == ',') { strcpy(bbb, &aaa[a + 1]); aaa[a] = 0; break; } } if (!strcasecmp(name, aaa)) strcpy(name, bbb); } fclose(fp); /* Hit the Global Address Book */ if (CtdlDirectoryLookup(aaa, name, sizeof aaa) == 0) { strcpy(name, aaa); } if (strcasecmp(original_name, name)) { MSG_syslog(LOG_INFO, "%s is being forwarded to %s\n", original_name, name); } /* Change "user @ xxx" to "user" if xxx is an alias for this host */ for (a=0; name[a] != '\0'; ++a) { if (name[a] == '@') { if (CtdlHostAlias(&name[a+1]) == hostalias_localhost) { name[a] = 0; MSG_syslog(LOG_INFO, "Changed to <%s>\n", name); break; } } } /* determine local or remote type, see citadel.h */ at = haschar(name, '@'); if (at == 0) return(MES_LOCAL); /* no @'s - local address */ if (at > 1) return(MES_ERROR); /* >1 @'s - invalid address */ remove_any_whitespace_to_the_left_or_right_of_at_symbol(name); /* figure out the delivery mode */ extract_token(node, name, 1, '@', sizeof node); /* If there are one or more dots in the nodename, we assume that it * is an FQDN and will attempt SMTP delivery to the Internet. */ if (haschar(node, '.') > 0) { return(MES_INTERNET); } /* Otherwise we look in the IGnet maps for a valid Citadel node. * Try directly-connected nodes first... */ ignetcfg = CtdlGetSysConfig(IGNETCFG); for (i=0; i<num_tokens(ignetcfg, '\n'); ++i) { extract_token(buf, ignetcfg, i, '\n', sizeof buf); extract_token(testnode, buf, 0, '|', sizeof testnode); if (!strcasecmp(node, testnode)) { free(ignetcfg); return(MES_IGNET); } } free(ignetcfg); /* * Then try nodes that are two or more hops away. */ ignetmap = CtdlGetSysConfig(IGNETMAP); for (i=0; i<num_tokens(ignetmap, '\n'); ++i) { extract_token(buf, ignetmap, i, '\n', sizeof buf); extract_token(testnode, buf, 0, '|', sizeof testnode); if (!strcasecmp(node, testnode)) { free(ignetmap); return(MES_IGNET); } } free(ignetmap); /* If we get to this point it's an invalid node name */ return (MES_ERROR); }
void mmo_send_global_accreg(AccountDB* self, int fd, int account_id, int char_id) { Sql* sql_handle = ((AccountDB_SQL*)self)->accounts; AccountDB_SQL* db = (AccountDB_SQL*)self; char* data; int plen = 0; size_t len; if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", db->global_acc_reg_str_table, account_id) ) Sql_ShowDebug(sql_handle); WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x2726; // 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(WFIFOCP(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(WFIFOCP(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) = 0x2726; // 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; } } WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); Sql_FreeResult(sql_handle); if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", db->global_acc_reg_num_table, account_id) ) Sql_ShowDebug(sql_handle); WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x2726; // 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(WFIFOCP(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) = 0x2726; // 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; } } WFIFOB(fd, 12) = 1; WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); Sql_FreeResult(sql_handle); }
void inter_auctions_fromsql(void) { int i; char *data; StringBuf buf; unsigned int tick = gettick(), endtick; time_t now = time(NULL); StringBuf_Init(&buf); StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`"); for( i = 0; i < MAX_SLOTS; i++ ) StringBuf_Printf(&buf, ",`card%d`", i); for (i = 0; i < MAX_ITEM_RDM_OPT; ++i) { StringBuf_Printf(&buf, ", `option_id%d`", i); StringBuf_Printf(&buf, ", `option_val%d`", i); StringBuf_Printf(&buf, ", `option_parm%d`", i); } StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", schema_config.auction_db); if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) Sql_ShowDebug(sql_handle); StringBuf_Destroy(&buf); while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { struct item *item; struct auction_data *auction; CREATE(auction, struct auction_data, 1); Sql_GetData(sql_handle, 0, &data, NULL); auction->auction_id = atoi(data); Sql_GetData(sql_handle, 1, &data, NULL); auction->seller_id = atoi(data); Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(auction->seller_name, data, NAME_LENGTH); Sql_GetData(sql_handle, 3, &data, NULL); auction->buyer_id = atoi(data); Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(auction->buyer_name, data, NAME_LENGTH); Sql_GetData(sql_handle, 5, &data, NULL); auction->price = atoi(data); Sql_GetData(sql_handle, 6, &data, NULL); auction->buynow = atoi(data); Sql_GetData(sql_handle, 7, &data, NULL); auction->hours = atoi(data); Sql_GetData(sql_handle, 8, &data, NULL); auction->timestamp = atoi(data); item = &auction->item; Sql_GetData(sql_handle, 9, &data, NULL); item->nameid = atoi(data); Sql_GetData(sql_handle,10, &data, NULL); safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH); Sql_GetData(sql_handle,11, &data, NULL); auction->type = atoi(data); Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); Sql_GetData(sql_handle,14, &data, NULL); item->unique_id = strtoull(data, NULL, 10); item->identify = 1; item->amount = 1; item->expire_time = 0; for( i = 0; i < MAX_SLOTS; i++ ) { Sql_GetData(sql_handle, 15 + i, &data, NULL); item->card[i] = atoi(data); } for (i = 0; i < MAX_ITEM_RDM_OPT; i++) { Sql_GetData(sql_handle, 15 + MAX_SLOTS + i*3, &data, NULL); item->option[i].id = atoi(data); Sql_GetData(sql_handle, 16 + MAX_SLOTS + i*3, &data, NULL); item->option[i].value = atoi(data); Sql_GetData(sql_handle, 17 + MAX_SLOTS + i*3, &data, NULL); item->option[i].param = atoi(data); } if( auction->timestamp > now ) endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick; else endtick = tick + 10000; // 10 Second's to process ended auctions auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0); idb_put(auction_db_, auction->auction_id, auction); } Sql_FreeResult(sql_handle); }
int log_config_read(const char* cfgName) { static int count = 0; char line[1024], w1[1024], w2[1024]; FILE *fp; if( count++ == 0 ) log_set_defaults(); if( ( fp = fopen(cfgName, "r") ) == NULL ) { ShowError("Log configuration file not found at: %s\n", cfgName); return 1; } while( fgets(line, sizeof(line), fp) ) { if( line[0] == '/' && line[1] == '/' ) continue; if( sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) == 2 ) { if( strcmpi(w1, "enable_logs") == 0 ) log_config.enable_logs = (e_log_pick_type)config_switch(w2); else if( strcmpi(w1, "sql_logs") == 0 ) log_config.sql_logs = (bool)config_switch(w2); //start of common filter settings else if( strcmpi(w1, "rare_items_log") == 0 ) log_config.rare_items_log = atoi(w2); else if( strcmpi(w1, "refine_items_log") == 0 ) log_config.refine_items_log = atoi(w2); else if( strcmpi(w1, "price_items_log") == 0 ) log_config.price_items_log = atoi(w2); else if( strcmpi(w1, "amount_items_log") == 0 ) log_config.amount_items_log = atoi(w2); //end of common filter settings else if( strcmpi(w1, "log_branch") == 0 ) log_config.branch = config_switch(w2); else if( strcmpi(w1, "log_filter") == 0 ) log_config.filter = config_switch(w2); else if( strcmpi(w1, "log_zeny") == 0 ) log_config.zeny = config_switch(w2); else if( strcmpi( w1, "log_cash" ) == 0 ) log_config.cash = config_switch( w2 ); else if( strcmpi(w1, "log_commands") == 0 ) log_config.commands = config_switch(w2); else if( strcmpi(w1, "log_npc") == 0 ) log_config.npc = config_switch(w2); else if( strcmpi(w1, "log_chat") == 0 ) log_config.chat = config_switch(w2); else if( strcmpi(w1, "log_mvpdrop") == 0 ) log_config.mvpdrop = config_switch(w2); else if( strcmpi(w1, "log_feeding") == 0 ) log_config.feeding = config_switch(w2); else if( strcmpi(w1, "log_chat_woe_disable") == 0 ) log_config.log_chat_woe_disable = (bool)config_switch(w2); else if( strcmpi(w1, "log_branch_db") == 0 ) safestrncpy(log_config.log_branch, w2, sizeof(log_config.log_branch)); else if( strcmpi(w1, "log_pick_db") == 0 ) safestrncpy(log_config.log_pick, w2, sizeof(log_config.log_pick)); else if( strcmpi(w1, "log_zeny_db") == 0 ) safestrncpy(log_config.log_zeny, w2, sizeof(log_config.log_zeny)); else if( strcmpi(w1, "log_mvpdrop_db") == 0 ) safestrncpy(log_config.log_mvpdrop, w2, sizeof(log_config.log_mvpdrop)); else if( strcmpi(w1, "log_gm_db") == 0 ) safestrncpy(log_config.log_gm, w2, sizeof(log_config.log_gm)); else if( strcmpi(w1, "log_npc_db") == 0 ) safestrncpy(log_config.log_npc, w2, sizeof(log_config.log_npc)); else if( strcmpi(w1, "log_chat_db") == 0 ) safestrncpy(log_config.log_chat, w2, sizeof(log_config.log_chat)); else if( strcmpi( w1, "log_cash_db" ) == 0 ) safestrncpy( log_config.log_cash, w2, sizeof( log_config.log_cash ) ); else if( strcmpi( w1, "log_feeding_db" ) == 0 ) safestrncpy( log_config.log_feeding, w2, sizeof( log_config.log_feeding ) ); // log file timestamp format else if( strcmpi( w1, "log_timestamp_format" ) == 0 ) safestrncpy(log_timestamp_format, w2, sizeof(log_timestamp_format)); //support the import command, just like any other config else if( strcmpi(w1,"import") == 0 ) log_config_read(w2); else ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); } } fclose(fp); if( --count == 0 ) { // report final logging state const char* target = log_config.sql_logs ? "table" : "file"; if( log_config.enable_logs && log_config.filter ) { ShowInfo("Logging item transactions to %s '%s'.\n", target, log_config.log_pick); } if( log_config.branch ) { ShowInfo("Logging monster summon item usage to %s '%s'.\n", target, log_config.log_pick); } if( log_config.chat ) { ShowInfo("Logging chat to %s '%s'.\n", target, log_config.log_chat); } if( log_config.commands ) { ShowInfo("Logging commands to %s '%s'.\n", target, log_config.log_gm); } if( log_config.mvpdrop ) { ShowInfo("Logging MVP monster rewards to %s '%s'.\n", target, log_config.log_mvpdrop); } if( log_config.npc ) { ShowInfo("Logging 'logmes' messages to %s '%s'.\n", target, log_config.log_npc); } if( log_config.zeny ) { ShowInfo("Logging Zeny transactions to %s '%s'.\n", target, log_config.log_zeny); } if( log_config.cash ) { ShowInfo( "Logging Cash transactions to %s '%s'.\n", target, log_config.log_cash ); } if( log_config.feeding ) { ShowInfo( "Logging Feeding items to %s '%s'.\n", target, log_config.log_feeding ); } } return 0; }
/*========================================== * Open shop * data := {<index>.w <amount>.w <value>.l}[count] *------------------------------------------*/ void vending_openvending(struct map_session_data* sd, const char* message, bool flag, const uint8* data, int count) { int i, j; int vending_skill_lvl; nullpo_retv(sd); if( !flag ) // cancelled return; // nothing to do if (pc_istrading(sd)) return; // can't have 2 shops at once vending_skill_lvl = pc_checkskill(sd, MC_VENDING); // skill level and cart check if( !vending_skill_lvl || !pc_iscarton(sd) ) { clif_skill_fail(sd, MC_VENDING, 0, 0); return; } // check number of items in shop if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl ) { // invalid item count clif_skill_fail(sd, MC_VENDING, 0, 0); return; } // filter out invalid items i = 0; for( j = 0; j < count; j++ ) { int index = *(uint16*)(data + 8*j + 0); unsigned int amount = *(uint16*)(data + 8*j + 2); unsigned int value = *(uint32*)(data + 8*j + 4); index -= 2; // offset adjustment (client says that the first cart position is 2) if( index < 0 || index >= MAX_CART // invalid position || pc_cartitem_amount(sd, index, amount) < 0 // invalid item or insufficient quantity //NOTE: official server does not do any of the following checks! || !sd->status.cart[index].identify // unidentified item || sd->status.cart[index].attribute == 1 // broken item || !itemdb_cantrade(&sd->status.cart[index], pc_isGM(sd), pc_isGM(sd)) ) // untradeable item continue; sd->vending[i].index = index; sd->vending[i].amount = amount; sd->vending[i].value = cap_value(value, 1, (unsigned int)battle_config.vending_max_value); i++; // item successfully added } if( i != j ) clif_displaymessage (sd->fd, msg_txt(266)); //"Some of your items cannot be vended and were removed from the shop." if( i == 0 ) { // no valid item found clif_skill_fail(sd, MC_VENDING, 0, 0); // custom reply packet return; } sd->vender_id = sd->bl.id; sd->vend_num = i; safestrncpy(sd->message, message, MESSAGE_SIZE); pc_stop_walking(sd,1); clif_openvending(sd,sd->vender_id,sd->vending); clif_showvendingboard(&sd->bl,message,0); }
/** * Reading main configuration file. * @param cfgName: Name of the configuration (could be fullpath) * @param normal: Config read normally when server started * @return True:success, Fals:failure (file not found|readable) */ bool login_config_read(const char* cfgName, bool normal) { char line[1024], w1[32], w2[1024]; FILE* fp = fopen(cfgName, "r"); if (fp == NULL) { ShowError("Configuration file (%s) not found.\n", cfgName); return false; } while(fgets(line, sizeof(line), fp)) { if (line[0] == '/' && line[1] == '/') continue; if (sscanf(line, "%31[^:]: %1023[^\r\n]", w1, w2) < 2) continue; // Config that loaded only when server started, not by reloading config file if (normal) { if( !strcmpi(w1, "bind_ip") ) { login_config.login_ip = host2ip(w2); if( login_config.login_ip ) { char ip_str[16]; ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); } } else if( !strcmpi(w1, "login_port") ) login_config.login_port = (uint16)atoi(w2); else if(!strcmpi(w1, "console")) login_config.console = (bool)config_switch(w2); } if(!strcmpi(w1,"timestamp_format")) safestrncpy(timestamp_format, w2, 20); else if(strcmpi(w1,"db_path")==0) safestrncpy(db_path, w2, ARRAYLENGTH(db_path)); else if(!strcmpi(w1,"stdout_with_ansisequence")) stdout_with_ansisequence = config_switch(w2); else if(!strcmpi(w1,"console_silent")) { msg_silent = atoi(w2); if( msg_silent ) /* only bother if we actually have this enabled */ ShowInfo("Console Silent Setting: %d\n", atoi(w2)); } else if (strcmpi(w1, "console_msg_log") == 0) console_msg_log = atoi(w2); else if (strcmpi(w1, "console_log_filepath") == 0) safestrncpy(console_log_filepath, w2, sizeof(console_log_filepath)); else if(!strcmpi(w1, "log_login")) login_config.log_login = (bool)config_switch(w2); else if(!strcmpi(w1, "new_account")) login_config.new_account_flag = (bool)config_switch(w2); else if(!strcmpi(w1, "new_acc_length_limit")) login_config.new_acc_length_limit = (bool)config_switch(w2); else if(!strcmpi(w1, "start_limited_time")) login_config.start_limited_time = atoi(w2); else if(!strcmpi(w1, "use_MD5_passwords")) login_config.use_md5_passwds = (bool)config_switch(w2); else if(!strcmpi(w1, "group_id_to_connect")) login_config.group_id_to_connect = atoi(w2); else if(!strcmpi(w1, "min_group_id_to_connect")) login_config.min_group_id_to_connect = atoi(w2); else if(!strcmpi(w1, "date_format")) safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); else if(!strcmpi(w1, "allowed_regs")) //account flood protection system login_config.allowed_regs = atoi(w2); else if(!strcmpi(w1, "time_allowed")) login_config.time_allowed = atoi(w2); else if(!strcmpi(w1, "use_dnsbl")) login_config.use_dnsbl = (bool)config_switch(w2); else if(!strcmpi(w1, "dnsbl_servers")) safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); else if(!strcmpi(w1, "ipban_cleanup_interval")) login_config.ipban_cleanup_interval = (unsigned int)atoi(w2); else if(!strcmpi(w1, "ip_sync_interval")) login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. else if(!strcmpi(w1, "client_hash_check")) login_config.client_hash_check = config_switch(w2); else if(!strcmpi(w1, "client_hash")) { int group = 0; char md5[33]; if (sscanf(w2, "%3d, %32s", &group, md5) == 2) { struct client_hash_node *nnode; CREATE(nnode, struct client_hash_node, 1); if (strcmpi(md5, "disabled") == 0) { nnode->hash[0] = '\0'; } else { int i; for (i = 0; i < 32; i += 2) { char buf[3]; unsigned int byte; memcpy(buf, &md5[i], 2); buf[2] = 0; sscanf(buf, "%2x", &byte); nnode->hash[i / 2] = (uint8)(byte & 0xFF); } } nnode->group_id = group; nnode->next = login_config.client_hash_nodes; login_config.client_hash_nodes = nnode; } } else if(strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
/** * Check/authentication of a connection. * @param sd: string (atm:md5key or dbpass) * @param isServer: string (atm:md5key or dbpass) * @return : * -1: success * 0: unregistered id; * 1: incorrect pass; * 2: expired id * 3: blacklisted (or registration limit exceeded if new acc); * 5: invalid client_version|hash; * 6: banned * x: acc state (TODO document me deeper) */ int login_mmo_auth(struct login_session_data* sd, bool isServer) { struct mmo_account acc; int len; char ip[16]; ip2str(session[sd->fd]->client_addr, ip); // DNS Blacklist check if( login_config.use_dnsbl ) { char r_ip[16]; char ip_dnsbl[256]; char* dnsbl_serv; uint8* sin_addr = (uint8*)&session[sd->fd]->client_addr; sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); for( dnsbl_serv = strtok(login_config.dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) { sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv)); if( host2ip(ip_dnsbl) ) { ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); return 3; } } } len = strnlen(sd->userid, NAME_LENGTH); // Account creation with _M/_F if( login_config.new_account_flag ) { if( len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths sd->passwdenc == 0 && // unencoded password sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4) ) // _M/_F suffix { int result; // remove the _M/_F suffix len -= 2; sd->userid[len] = '\0'; result = login_mmo_auth_new(sd->userid, sd->passwd, TOUPPER(sd->userid[len+1]), ip); if( result != -1 ) return result;// Failed to make account. [Skotlex]. } } if( !accounts->load_str(accounts, &acc, sd->userid) ) { ShowNotice("Unknown account (account: %s, ip: %s)\n", sd->userid, ip); return 0; // 0 = Unregistered ID } if( !login_check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass) ) { ShowNotice("Invalid password (account: '%s', ip: %s)\n", sd->userid, ip); return 1; // 1 = Incorrect Password } if( acc.expiration_time != 0 && acc.expiration_time < time(NULL) ) { ShowNotice("Connection refused (account: %s, expired ID, ip: %s)\n", sd->userid, ip); return 2; // 2 = This ID is expired } if( acc.unban_time != 0 && acc.unban_time > time(NULL) ) { char tmpstr[24]; timestamp2string(tmpstr, sizeof(tmpstr), acc.unban_time, login_config.date_format); ShowNotice("Connection refused (account: %s, banned until %s, ip: %s)\n", sd->userid, tmpstr, ip); return 6; // 6 = Your are Prohibited to log in until %s } if( acc.state != 0 ) { ShowNotice("Connection refused (account: %s, state: %d, ip: %s)\n", sd->userid, acc.state, ip); return acc.state - 1; } if( login_config.client_hash_check && !isServer ) { struct client_hash_node *node = NULL; bool match = false; for( node = login_config.client_hash_nodes; node; node = node->next ) { if( acc.group_id < node->group_id ) continue; if( *node->hash == '\0' // Allowed to login without hash || (sd->has_client_hash && memcmp(node->hash, sd->client_hash, 16) == 0 ) // Correct hash ) { match = true; break; } } if( !match ) { char smd5[33]; int i; if( !sd->has_client_hash ) { ShowNotice("Client didn't send client hash (account: %s, ip: %s)\n", sd->userid, acc.state, ip); return 5; } for( i = 0; i < 16; i++ ) sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]); ShowNotice("Invalid client hash (account: %s, sent md5: %d, ip: %s)\n", sd->userid, smd5, ip); return 5; } } ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip); // update session data sd->account_id = acc.account_id; sd->login_id1 = rnd() + 1; sd->login_id2 = rnd() + 1; safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin)); sd->sex = acc.sex; sd->group_id = acc.group_id; // update account data timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S"); safestrncpy(acc.last_ip, ip, sizeof(acc.last_ip)); acc.unban_time = 0; acc.logincount++; accounts->save(accounts, &acc); if( sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM ) ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM); return -1; // account OK }
/*-------------------------------------- * name : instance name * Return value could be * -4 = already exists | -3 = no free instances | -2 = owner not found | -1 = invalid type * On success return instance_id *--------------------------------------*/ int instance_create(int owner_id, const char *name, enum instance_owner_type type) { struct map_session_data *sd = NULL; unsigned short *icptr = NULL; struct party_data *p = NULL; struct guild *g = NULL; short *iptr = NULL; int i, j; switch ( type ) { case IOT_NONE: break; case IOT_CHAR: if( ( sd = iMap->id2sd(owner_id) ) == NULL ) { ShowError("instance_create: character %d not found for instance '%s'.\n", owner_id, name); return -2; } iptr = sd->instance; icptr = &sd->instances; break; case IOT_PARTY: if( ( p = party->search(owner_id) ) == NULL ) { ShowError("instance_create: party %d not found for instance '%s'.\n", owner_id, name); return -2; } iptr = p->instance; icptr = &p->instances; break; case IOT_GUILD: if( ( g = guild->search(owner_id) ) == NULL ) { ShowError("instance_create: guild %d not found for instance '%s'.\n", owner_id, name); return -2; } iptr = g->instance; icptr = &g->instances; break; default: ShowError("instance_create: unknown type %d for owner_id %d and name %s.\n", type,owner_id,name); return -1; } if( type != IOT_NONE && *icptr ) { ARR_FIND(0, *icptr, i, strcmp(instances[iptr[i]].name,name) == 0 ); if( i != *icptr ) return -4;/* already got this instance */ } ARR_FIND(0, instance->instances, i, instances[i].state == INSTANCE_FREE); if( i == instance->instances ) RECREATE(instances, struct instance_data, ++instance->instances); instances[i].state = INSTANCE_IDLE; instances[i].id = i; instances[i].idle_timer = INVALID_TIMER; instances[i].idle_timeout = instances[i].idle_timeoutval = 0; instances[i].progress_timer = INVALID_TIMER; instances[i].progress_timeout = 0; instances[i].users = 0; instances[i].map = NULL; instances[i].num_map = 0; instances[i].owner_id = owner_id; instances[i].owner_type = type; instances[i].vars = idb_alloc(DB_OPT_RELEASE_DATA); safestrncpy( instances[i].name, name, sizeof(instances[i].name) ); if( type != IOT_NONE ) { ARR_FIND(0, *icptr, j, iptr[j] == -1); if( j == *icptr ) { switch( type ) { case IOT_CHAR: RECREATE(sd->instance, unsigned short, ++*icptr); sd->instance[sd->instances-1] = i; break; case IOT_PARTY: RECREATE(p->instance, unsigned short, ++*icptr); p->instance[p->instances-1] = i; break; case IOT_GUILD: RECREATE(g->instance, unsigned short, ++*icptr); g->instance[g->instances-1] = i; break; } } else