//returns length to be filtered, 0 if not filtered int check_if_filtered (const char *name) { int t, i, l; for (i = 0; i < MAX_FILTERS; i++) { if (filter_list[i].len > 0 && (use_global_filters || filter_list[i].local)) { if (filter_list[i].wildcard_type==0) { /* no wildcard, normal compare */ if (my_strncompare (filter_list[i].name, name, filter_list[i].len)) { if (!isalpha (name[filter_list[i].len])) { /* fits with end of word? */ return i; // yep, filtered } } } else if (filter_list[i].wildcard_type == 1) { /* *word */ for (t = 0; ; t++) { if (!isalpha (name[t])) break; /* t points now at the end of the word */ } l = filter_list[i].len; if (t >= l-1) { if (my_strncompare (&(filter_list[i].name[1]), &name[t-l], l-1)) return i; } } else if (filter_list[i].wildcard_type == 2) { /* word* */ if (my_strncompare (filter_list[i].name, name, filter_list[i].len-1)) return i; } else if (filter_list[i].wildcard_type==3) { /* *word* */ for (t = 0; ; t++) { if (!isalpha (name[t])) break; if (my_strncompare(&(filter_list[i].name[1]), &name[t], filter_list[i].len-2)) return i;//yep, filtered } } } } return -1;//nope }
Sint32 my_strcompare(const char *dest, const char *src) { Uint32 len; len=strlen(dest); if(len!=strlen(src))return 0; return(my_strncompare(dest, src, len)); }
// TODO: make this automatic or a better command, m is too short int command_msg(char *text, int len) { int no; // find first space, then skip any spaces text = getparams(text); if(my_strncompare(text, "all", 3)) { print_all_messages(); } else { no = atoi(text) - 1; print_message(no); } return 1; }
int test_for_console_command(char *text, int length) { int i; int ptr_length = length; char *text_ptr = text; // Skip leading #s if(*text == '#' || *text == char_cmd_str[0]) { *text = '#'; text++; length--; } //Skip leading spaces for(;isspace(*text); text++,length--); //Check if there's anything left of the command if (length <= 0 || (*text == '@' && length <= 1)) { return 0; } else { int cmd_len; #ifdef TEXT_ALIASES /* Handle numeric shortcuts */ if ( isdigit(text[0]) ) { if ( process_text_alias(text,length) >= 0 ) { return 1; } } #endif /* Look for a matching command */ for(i = 0; i < command_count; i++) { cmd_len = strlen(commands[i].command); if(strlen(text) >= cmd_len && my_strncompare(text, commands[i].command, cmd_len) && (isspace(text[cmd_len]) || text[cmd_len] == '\0')) { /* Command matched */ if(commands[i].callback && commands[i].callback(text+cmd_len, length-cmd_len)) { /* The command was handled and we don't want to send it to the server */ return 1; } else { /* the command wants to be sent to the server */ break; } } } } send_input_text_line (text_ptr, ptr_length); return 0; }
// Filter the lines that contain the desired string from the inventory listing int filter_storage_text (char * input_text, int len, int size) { int istart, iline, ic, diff; int flen; flen = strlen (storage_filter); istart = iline = ic = 0; while (ic < len - flen) { if (input_text[ic] == '\n') { iline = ++ic; } else if (my_strncompare (input_text+ic, storage_filter, flen)) { diff = iline - istart; if (diff > 0) { len -= diff; memmove (input_text + istart, input_text + iline, len * sizeof (char)); ic -= diff; } while (ic < len && input_text[ic] != '\n') ic++; iline = istart = ++ic; } else { ic++; } } if (istart == 0) { safe_snprintf (input_text, size, "<none>"); len = 6; } else { input_text[--istart] = '\0'; len = istart; } storage_filter[0] = '\0'; return len; }
// TODO: make this automatic or a better command, m is too short int command_msg(char *text, int len) { int no;//, m=-1; // find first space, then skip any spaces text = getparams(text); if(my_strncompare(text, "all", 3)) { for(no = 0; no < pm_log.ppl; no++) { print_message(no); } } else { no = atoi(text) - 1; if(no < pm_log.ppl && no >= 0) { print_message(no); } } return 1; }
int filter_or_ignore_text (char *text_to_add, int len, int size, Uint8 channel) { int l, idx; if (len <= 0) return 0; // no point //check for auto receiving #help for (idx = 0; idx < len; idx++) { if (!is_color (text_to_add[idx])) break; } l = len - idx; if (l >= strlen(help_request_str) && text_to_add[idx] == '#' && (strncasecmp (&text_to_add[idx], help_request_str, strlen(help_request_str)) == 0 || strncasecmp (&text_to_add[idx], "#mod chat", 9) == 0)) { auto_open_encyclopedia = 0; } /* DANGER, WILL ROBINSON! The below code should not exist in it's present form. I'd change it, but I'd need access to the server. Simply checking text output (which is used for all sorts of things) for the phrase "Game Date" is very dangerous. Example: what if, in the future, we allow spaces in character names? Someone chooses the name "Game Date" and walks around saying "hi". Everyone's clients in the area interpret this as being a Game Date command. I've made the below code not *as* dangerous. Had a user been able to fake out the below code, previously, it would have caused a buffer overflow in their client if they didn't write in only numbers after it. Now, they won't crash; it'll just be misparsed. General practice recommendation: don't mix server commands with user input. - Karen */ /* ed (ttlanhil): made it check if it's a server colour. still not perfect (this should have been done server-side instead of parsing the date), but safer */ if (from_color_char (text_to_add[0]) == c_green1 && my_strncompare(text_to_add+1,"Game Date", 9)) { //we assume that the server will still send little-endian dd/mm/yyyy... we could make it safer by parsing the format too, but it's simpler to assume const char * const month_names[] = { "Aluwia", "Seedar", "Akbar", "Zartia", "Elandra", "Viasia", "Fruitfall", "Mortia", "Carnelar", "Nimlos", "Chimar", "Vespia" }; const char * const day_names[] = { "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th", "20th", "21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "29th", "30th" }; char new_str[100]; const char *ptr=text_to_add; short unsigned int day=1, month=1, year=0; int offset = 0; while(!isdigit(ptr[offset])) { offset++; if (offset >= sizeof(new_str)) { LOG_ERROR("error (1) parsing date string: %s",text_to_add); //something evil this way comes... return 0; } } ptr += offset; if (sscanf (ptr,"%hu%*[-/]%hu%*[-/]%hu",&day,&month,&year) < 3 || day <= 0 || month <= 0 || day > 30 || month > 12 || year > 9999) { LOG_ERROR("error (2) parsing date string: %s",text_to_add); //something evil this way comes... } else { // only display initial or "#date" user requested date if (!set_date(ptr)) { safe_snprintf(new_str, sizeof(new_str), date_format, day_names[day-1], month_names[month-1], year); LOG_TO_CONSOLE(c_green1, new_str); } //Calculate fraction Big Lunar month (2 conjunction months) less game clock time //Represented in Degrees. skybox_time_d = (SDL_GetTicks()%( 1296000 * 1000 )); skybox_time_d *= 360.0/( 1296000.0 * 1000.0); skybox_time_d = -skybox_time_d; skybox_time_d += 360.0 * (((month%2)*30 + day-1)*360 + game_minute)/21600.0; skybox_update_positions(); return 0; } } if (from_color_char (text_to_add[0]) == c_green1 && my_strncompare(text_to_add+1,"Game Time", 9)) { real_game_second = atoi(&text_to_add[18]); next_second_time = cur_time + 1000; new_second(); } // Check for local messages to be translated into actor movements (contains [somthing]) if (channel == CHAT_LOCAL) { if(parse_text_for_emote_commands(text_to_add, len)) return 0; } if (channel == CHAT_SERVER) { if (my_strncompare(text_to_add+1, "You started to harvest ", 23)) { strncpy(harvest_name, text_to_add+1+23, len-1-23-1); harvest_name[len-1-23-1] = '\0'; harvesting = 1; } else if ((my_strncompare(text_to_add+1, "You stopped harvesting.", 23)) || (my_strncompare(text_to_add+1, "You can't harvest while fighting (duh)!", 39)) || (my_strncompare(text_to_add+1, "You can't do that while trading!", 32)) || (my_strncompare(text_to_add+1, "You are too far away! Get closer!", 33)) || (my_strncompare(text_to_add+1, "You can't harvest here", 22)) || (my_strncompare(text_to_add+1, "You lack the knowledge of ", 26)) || ((my_strncompare(text_to_add+1, "You need to wear ", 17) && strstr(text_to_add, "order to harvest") != NULL)) || ((my_strncompare(text_to_add+1, "You need to have a ", 19) && strstr(text_to_add, "order to harvest") != NULL))) { harvesting = 0; } else if (is_death_message(text_to_add+1)) { // nothing to be done here cause all is done in the test function } else if (my_strncompare(text_to_add+1, "You found ", 10) && strstr(text_to_add+1, " coins.")) { decrement_harvest_counter(atoi(text_to_add+11)); } else if (my_strncompare(text_to_add+1, "Send Item UIDs ", 15)) { if (text_to_add[1+15] == '0') item_uid_enabled = 0; else if (text_to_add[1+15] == '1') item_uid_enabled = 1; printf("item_uid_enabled=%d\n", item_uid_enabled); } else if ((copy_next_LOCATE_ME > 0) && my_strncompare(text_to_add+1, "You are in ", 11)) { char buffer[4096]; switch (copy_next_LOCATE_ME) { case 1: copy_to_clipboard(text_to_add+1); break; case 2: snprintf(buffer, sizeof(buffer), "@My Position: %s", text_to_add + 12); send_input_text_line(buffer, strlen(buffer)); break; } copy_next_LOCATE_ME = 0; return 0; } else if (my_strncompare(text_to_add+1, "You see: ", 9)) { achievements_player_name(text_to_add+10, len-10); } else if (my_strncompare(text_to_add+1, "You just got food poisoned!", 27)) { increment_poison_incidence(); } else if (strstr(text_to_add+1, "aborted the trade.")) { trade_aborted(text_to_add+1); } else if (strstr(text_to_add+1, "Trade session failed")) { trade_aborted(text_to_add+1); } else if (strstr(text_to_add+1, "You have been saved!")) { last_save_time = time(NULL); } } else if (channel == CHAT_LOCAL) { if (harvesting && my_strncompare(text_to_add+1, username_str, strlen(username_str))) { char *ptr = text_to_add+1+strlen(username_str); if (my_strncompare(ptr, " found a ", 9)) { ptr += 9; if (my_strncompare(ptr, "bag of gold, getting ", 21)) { decrement_harvest_counter(atoi(ptr+21)); } else if (!strstr(ptr, " could not carry ")) { decrement_harvest_counter(1); } } } else if (my_strncompare(text_to_add+1, "(*) ", 4)) { increment_summon_counter(text_to_add+1+4); if (summoning_filter) return 0; } } /* check for misc counter strings */ catch_counters_text(text_to_add+1); /* put #mpm in a popup box, on top of all else */ if ((channel == CHAT_MODPM) && (my_strncompare(text_to_add+1, "[Mod PM from", 12))) { display_server_popup_win(text_to_add); } //Make sure we don't check our own messages. if( !(channel == CHAT_PERSONAL && len >= strlen(pm_from_str) && strncasecmp (text_to_add+1, pm_from_str, strlen(pm_from_str)) != 0) && !(channel == CHAT_MODPM && len >= strlen(mod_pm_from_str) && strncasecmp (text_to_add+1, mod_pm_from_str, strlen(mod_pm_from_str)) != 0) ) { //check if ignored - pre_check_if_ignored() checks for Mod PM's etc to not ignore (or it would be asking for trouble) if (pre_check_if_ignored (text_to_add, len, channel)) { return 0; } //All right, we do not ignore the person if (afk) { if (channel == CHAT_PERSONAL || channel == CHAT_MODPM) { // player sent us a PM add_message_to_pm_log (text_to_add, len, channel); if (afk_snd_warning) { do_afk_sound(); } } else if (channel == CHAT_LOCAL && from_color_char (text_to_add[0]) == c_grey1 && is_talking_about_me (&text_to_add[1], len-1, 0)) { // player mentions our name in local chat if (afk_local) { add_message_to_pm_log (&text_to_add[1], len - 1, channel); if (afk_snd_warning) { do_afk_sound(); } } else { send_afk_message (&text_to_add[1], len - 1, channel); } } else if (channel == CHAT_SERVER) { // check if this was a trade attempt int i; for (i = 1; i < len; i++) { if (text_to_add[i] == ' ' || text_to_add[i] == ':' || is_color (text_to_add[i])) { break; } } if (i < len-15 && strncasecmp (&text_to_add[i], " wants to trade", 15) == 0) { send_afk_message (&text_to_add[1], len - 1, channel); if (afk_snd_warning) { do_afk_sound(); } } } } } else { //We sent this PM or MODPM. Can we expect a reply? int len = 0; char name[MAX_USERNAME_LENGTH]; for(;text_to_add[len+8] != ':' && len < MAX_USERNAME_LENGTH - 1; ++len); safe_strncpy(name, text_to_add+8, len+1); if(check_if_ignored(name)){ char msg[65]; safe_snprintf(msg, sizeof(msg), warn_currently_ignoring, name); LOG_TO_CONSOLE(c_red2, msg); } } // parse for URLs find_all_url (text_to_add, len); // look for buddy-wants-to-add-you messages if(channel == CHAT_SERVER && from_color_char (text_to_add[0]) == c_green1) { for (l = 1; l < len; l++) { if (text_to_add[l] == ' ') break; } if (len - l >= strlen(msg_accept_buddy_str) && strncmp (&text_to_add[l], msg_accept_buddy_str, strlen(msg_accept_buddy_str)) == 0 && l <=32) { char name[32]; int i; int cur_char; /*entropy says: I really fail to understand the logic of that safe_snprintf. And gcc can't understand it either because the name is corrupted. so we implement it the old fashioned way. Grum responds: actually it's the MingW compiler on windows that doesn't understand it, because it doesn't terminate the string when the buffer threatens to overflow. It works fine with gcc on Unix, and using sane_safe_snprintf should also fix it on windows. safe_snprintf (name, l, "%s", &text_to_add[1]); */ for (i = 0; i < sizeof (name); i++) { cur_char = text_to_add[i+1]; name[i] = cur_char; if (cur_char == ' ') { name[i] = '\0'; break; } } add_buddy_confirmation (name); } } // look for astrology messages if((channel == CHAT_SERVER) && is_astrology_message (text_to_add)) { return 0; } // filter any naughty words out return filter_text (text_to_add, len, size); }
//returns the new length of the text int filter_text (char *buff, int len, int size) { int i, t, bad_len, rep_len, new_len, idx; if (len > 31 && my_strncompare (buff+1, "Items you have in your storage:", 31)){ //First up, attempt to save the storage list for re-reading later if(size <= sizeof(cached_storage_list)){ memcpy(cached_storage_list, buff, size); have_storage_list = 1; } // See if a search term has been added to the #storage command, and if so, //only list those items with that term if (storage_filter[0] != '\0'){ len = 33 + filter_storage_text (buff+33, len-33, size-33); } } //do we need to do CAPS filtering? if (caps_filter) { int idx, clen = len; // skip any coloring idx = 0; while (is_color (buff[idx]) && clen > 0) { idx++; clen--; } // handle PM's if (buff[idx] == '[' || buff[idx+1] == '[') { while (buff[idx] != '\0' && buff[idx] != ':' && clen > 0) { idx++; clen--; } } // or ignore first word else { while (buff[idx] != '\0' && buff[idx] != ' ' && buff[idx] != ':' && clen > 0) { idx++; clen--; } } while (buff[idx] != '\0' && (buff[idx] == ' ' || buff[idx] == ':' || is_color (buff[idx])) && clen > 0) { idx++; clen--; } // check for hitting the EOS if (buff[idx] == '\0') idx = 0; // if we pass the upper test, entire line goes lower if (len - idx > 4 && my_isupper (&buff[idx], clen)) { // don't call my_tolower, since we're not sure if the string is NULL terminated for (idx = 0; idx < len; idx++) buff[idx] = tolower (buff[idx]); } } //do we need to do any content filtering? if (filtered_so_far == 0) return len; // scan the text for any strings new_len = len; i = 0; while (i < new_len) { /* skip non-alpha characters */ while (i < new_len && !isalpha ((unsigned char)buff[i])) i++; if (i >= new_len) break; /* check if we need to filter this word */ idx = check_if_filtered (&buff[i]); if (idx >= 0) { /* oops, remove this word */ if (filter_list[idx].wildcard_type > 0) { bad_len = 0; for (t = 0; ; t++) { if (!isalpha (buff[i+t])) break; bad_len++; } } else { bad_len = filter_list[idx].len; } rep_len = filter_list[idx].rlen; if (bad_len == rep_len) { memcpy(buff+i, filter_list[idx].replacement, rep_len); } else if (new_len + rep_len - bad_len >= size - 1) { // not enough space for substitution break; } else { memmove(buff+i+rep_len, buff+i+bad_len, new_len-i-bad_len+1); memcpy(buff+i, filter_list[idx].replacement, rep_len); new_len+= rep_len - bad_len; } /* don't filter the replacement text */ i += rep_len; } else { /* skip this word */ while (i < new_len && isalpha (buff[i])) i++; } } return new_len; }