bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { if (GetAccountID() == 0) { clog(WORLD__CLIENT_ERR,"Enter world with no logged in account"); eqs->Close(); return true; } if(GetAdmin() < 0) { clog(WORLD__CLIENT,"Account banned or suspended."); eqs->Close(); return true; } if (RuleI(World, MaxClientsPerIP) >= 0) { client_list.GetCLEIP(this->GetIP()); //Check current CLE Entry IPs against incoming connection } EnterWorld_Struct *ew=(EnterWorld_Struct *)app->pBuffer; strn0cpy(char_name, ew->name, 64); EQApplicationPacket *outapp; uint32 tmpaccid = 0; charid = database.GetCharacterInfo(char_name, &tmpaccid, &zoneID, &instanceID); if (charid == 0 || tmpaccid != GetAccountID()) { clog(WORLD__CLIENT_ERR,"Could not get CharInfo for '%s'",char_name); eqs->Close(); return true; } // Make sure this account owns this character if (tmpaccid != GetAccountID()) { clog(WORLD__CLIENT_ERR,"This account does not own the character named '%s'",char_name); eqs->Close(); return true; } if(!pZoning && ew->return_home && !ew->tutorial) { CharacterSelect_Struct* cs = new CharacterSelect_Struct; memset(cs, 0, sizeof(CharacterSelect_Struct)); database.GetCharSelectInfo(GetAccountID(), cs); bool home_enabled = false; for(int x = 0; x < 10; ++x) { if(strcasecmp(cs->name[x], char_name) == 0) { if(cs->gohome[x] == 1) { home_enabled = true; break; } } } safe_delete(cs); if(home_enabled) { zoneID = database.MoveCharacterToBind(charid,4); } else { clog(WORLD__CLIENT_ERR,"'%s' is trying to go home before they're able...",char_name); database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able."); eqs->Close(); return true; } } if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) { CharacterSelect_Struct* cs = new CharacterSelect_Struct; memset(cs, 0, sizeof(CharacterSelect_Struct)); database.GetCharSelectInfo(GetAccountID(), cs); bool tutorial_enabled = false; for(int x = 0; x < 10; ++x) { if(strcasecmp(cs->name[x], char_name) == 0) { if(cs->tutorial[x] == 1) { tutorial_enabled = true; break; } } } safe_delete(cs); if(tutorial_enabled) { zoneID = RuleI(World, TutorialZoneID); database.MoveCharacterToZone(charid, database.GetZoneName(zoneID)); } else { clog(WORLD__CLIENT_ERR,"'%s' is trying to go to tutorial but are not allowed...",char_name); database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character."); eqs->Close(); return true; } } if (zoneID == 0 || !database.GetZoneName(zoneID)) { // This is to save people in an invalid zone, once it's removed from the DB database.MoveCharacterToZone(charid, "arena"); clog(WORLD__CLIENT_ERR, "Zone not found in database zone_id=%i, moveing char to arena character:%s", zoneID, char_name); } if(instanceID > 0) { if(!database.VerifyInstanceAlive(instanceID, GetCharID())) { zoneID = database.MoveCharacterToBind(charid); instanceID = 0; } else { if(!database.VerifyZoneInstance(zoneID, instanceID)) { zoneID = database.MoveCharacterToBind(charid); instanceID = 0; } } } if(!pZoning) { database.SetGroupID(char_name, 0, charid); database.SetFirstLogon(charid, 1); if (RuleB(World, AnnounceJoinQuits) == true) //this is having an issue, its not taking a true false swap, only takes default. { zoneserver_list.SendEmoteMessage(0, 0, 0, 15, "%s is logging on!", GetCharName()); clog(WORLD__CLIENT_ERR, "Character is logging on: %s", GetCharName()); } } else{ uint32 groupid=database.GetGroupID(char_name); if(groupid>0){ char* leader=0; char leaderbuf[64]={0}; if((leader=database.GetGroupLeaderForLogin(char_name,leaderbuf)) && strlen(leader)>1){ EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); GroupJoin_Struct* gj=(GroupJoin_Struct*)outapp3->pBuffer; gj->action=8; strcpy(gj->yourname,char_name); strcpy(gj->membername,leader); QueuePacket(outapp3); safe_delete(outapp3); } } } outapp = new EQApplicationPacket(OP_MOTD); char tmp[500] = {0}; if (database.GetVariable("MOTD", tmp, 500)) { outapp->size = strlen(tmp)+1; outapp->pBuffer = new uchar[outapp->size]; memset(outapp->pBuffer,0,outapp->size); strcpy((char*)outapp->pBuffer, tmp); } else { // Null Message of the Day. :) outapp->size = 1; outapp->pBuffer = new uchar[outapp->size]; outapp->pBuffer[0] = 0; } QueuePacket(outapp); safe_delete(outapp); int MailKey = MakeRandomInt(1, INT_MAX); database.SetMailKey(charid, GetIP(), MailKey); char ConnectionType; ConnectionType = 'C'; EQApplicationPacket *outapp2 = new EQApplicationPacket(OP_SetChatServer); char buffer[112]; const WorldConfig *Config = WorldConfig::get(); sprintf(buffer,"%s,%i,%s.%s,%c%08X", Config->ChatHost.c_str(), Config->ChatPort, Config->ShortName.c_str(), this->GetCharName(), ConnectionType, MailKey ); outapp2->size=strlen(buffer)+1; outapp2->pBuffer = new uchar[outapp2->size]; memcpy(outapp2->pBuffer,buffer,outapp2->size); QueuePacket(outapp2); safe_delete(outapp2); EnterWorld(); return true; }
/* Takes care of incoming packets */ void HandleMessage(aocConnection *aoc, aocMessage *msg) { char *charname, *pgrp_name, *grp_name; unsigned char *text, *blob; int text_len, blob_len; uint32_t uid, pgrp_uid; unsigned char *group_id; switch(msg->type) { /* This is the first packet you receive after establishing a connection to the chat server. The message contains a 32 byte human readable hex string, which you should pass to the aocKeyexGenerateKey() function to generate a login key, and then reply with aocSendLoginResponse(). Packet contents: msg->argv[0] = (String) LoginSeed */ case AOC_SRV_LOGIN_SEED: { char *key; /* Generate a valid login key. */ key = aocKeyexGenerateKey(AOC_STR(msg->argv[0]), conf_username, conf_username); if(key == NULL) { printf("Could not generate login key.\n"); running = 0; break; } /* Send authenticate packet */ aocSendLoginResponse(aoc, 0, conf_username, key); aocFree(key); } break; /* This packet is received is your username or password is incorrect. It contains a human readable error string. The server will disconnect you after sending this message. Packet contents: msg->argv[0] = (String) ErrorMessage */ case AOC_SRV_LOGIN_ERROR: printf("Server said: %s\n", AOC_STR(msg->argv[0])); running = 0; break; /* This packet is received after you have successfully authenticated yourself with aocSendLoginResponse(). The packet contains a list of all characters on the account. You should reply with aocSendLoginSelectChar(). Packet contents: (4 arrays) msg->argv[...] = (Integer) UserID msg->argv[...] = (String) Charname msg->argv[...] = (Integer) Level msg->argv[...] = (Integer) Online Status (0 or 1) All 4 arrays have the same size in this packet. (Though you should probably handle cases where they have different sizes... as the following code does) */ case AOC_SRV_LOGIN_CHARLIST: { int nchars, i; /* The number of characters (taken from the length of the first array) */ nchars = aocMsgArraySize(msg, 0); /* Decode the packet. */ for(i=0; i<nchars; i++) { void *user_id, *charname, *level, *status; /* Get values from all 4 arrays */ user_id = aocMsgArrayValue(msg, 0, i, NULL, NULL); charname = aocMsgArrayValue(msg, 1, i, NULL, NULL); level = aocMsgArrayValue(msg, 2, i, NULL, NULL); status = aocMsgArrayValue(msg, 3, i, NULL, NULL); if(charname == NULL) continue; /* Compare char name with conf_charname */ if(strcmp(AOC_STR(charname), aocNameLowerCase(conf_charname)) != 0) continue; printf("Logging in as %s... (UserID %d, Level %d, Status %d)\n", AOC_STR(charname), user_id ? AOC_INT(user_id) : (int)AOC_INVALID_UID, level ? AOC_INT(level) : 0, status ? AOC_INT(status) : 0); aocSendLoginSelectChar(aoc, AOC_INT(user_id)); my_user_id = AOC_INT(user_id); break; } if(my_user_id == AOC_INVALID_UID) { printf("No character named '%s' was found.\n", ao_char); running = 0; } } break; /* This packet is received after you have selected a character. Packet contents: None */ case AOC_SRV_LOGIN_OK: printf("Logged in!\n"); break; case AOC_SRV_CLIENT_UNKNOWN: uid = AOC_INT(msg->argv[0]); printf("UserID %d does not exist.\n", uid); break; case AOC_SRV_CLIENT_NAME: uid = AOC_INT(msg->argv[0]); charname = AOC_STR(msg->argv[1]); aocNameListInsert(namelist, uid, charname, NULL); break; case AOC_SRV_LOOKUP_RESULT: uid = AOC_INT(msg->argv[0]); charname = AOC_STR(msg->argv[1]); if(uid == AOC_INVALID_UID) { printf("Character '%s' does not exist.\n", charname); break; } /* Add the charname / user id to the name list */ aocNameListInsert(namelist, uid, charname, NULL); break; case AOC_SRV_PRIVATE_MSG: uid = AOC_INT(msg->argv[0]); charname = GetCharName(uid); text = AOC_STR(msg->argv[1]); text_len = msg->argl[1]; blob = AOC_STR(msg->argv[2]); blob_len = msg->argl[2]; /* Remove color styles, etc.. */ aocStripStyles(text, text_len, 0); /* Remove unprintable characters */ for(i=0; i<text_len; i++) if(text[i] < 32) text[i] = '.'; printf("[%s]: %s\n", charname, text); break; /* To receive this packet you must be in-game, hence you will never receive it with libaochat. Packet contents: msg->argv[0] = (Integer) UserID msg->argv[1] = (String) Text msg->argv[2] = (String) Blob */ case AOC_SRV_VICINITY_MSG: break; /* This is usually used for broadcast messages, such as information about upcoming downtimes, when people "ding" 220, etc... Packet contents: msg->argv[0] = (String) Sender msg->argv[1] = (String) Text msg->argv[2] = (String) Blob */ case AOC_SRV_ANONVICINITY_MSG: break; /* System message. Packet contents: msg->argv[0] = (String) Message */ case AOC_SRV_SYSTEM_MSG: printf("System message: %s\n", AOC_STR(msg->argv[0])); break; /* This packet contains information about buddy status and type. You will receive it when you log on, when one of your buddies change status, and when you add/change a buddy with aocSendBuddyAdd(). It is sent once per buddy. :) Packet contents: msg->argv[0] = (Integer) UserID msg->argv[1] = (Integer) Status (0 = Offline, 1 = Online) msg->argv[2] = (String) Buddy type ('\0' = Temp, '\1' = Perm) (AOC_BUDDY_TEMPORARY, AOC_BUDDY_PERMANENT) */ case AOC_SRV_BUDDY_STATUS: printf("%s buddy %s changed his/her status to %s.\n", AOC_STR(msg->argv[2])[0] ? "Permanent" : "Temporary", GetCharName(uid), AOC_INT(msg->argv[1]) ? "online" : "offline" ); break; /* This packet is sent in reply to buddy remove packets. Packet contents: msg->argv[0] = (Integer) UserID */ case AOC_SRV_BUDDY_REMOVED: uid = AOC_INT(msg->argv[0]); printf("%s was removed from your buddy list.\n", GetCharName(uid)); break; /* This packet is sent when you receive an invite to someone's private group. Packet contents: msg->argv[0] = (Integer) UserID (aka PrivateGroupID) */ case AOC_SRV_PRIVGRP_INVITE: break; /* This packet is sent when you have been kicked from someone's private group. Packet contents: msg->argv[0] = (Integer) UserID (aka PrivateGroupID) */ case AOC_SRV_PRIVGRP_KICK: break; /* This packet is sent when you have left someone's private group. Note however that there is no way to actually part a group. I guess funcom's programmers have a weird sense of humor... Packet contents: msg->argv[0] = (Integer) UserID (aka PrivateGroupID) */ case AOC_SRV_PRIVGRP_PART: break; /* This packet is sent when someone joins a private group that you are currently in. Packet contents: msg->argv[0] = (Integer) UserID (aka PrivateGroupID) msg->argv[1] = (Integer) UserID */ case AOC_SRV_PRIVGRP_CLIJOIN: break; /* This packet is sent when someone leaves a private group that you are currently in. (ie. was kicked by the private group owner) Packet contents: msg->argv[0] = (Integer) UserID (aka PrivateGroupID) msg->argv[1] = (Integer) UserID */ case AOC_SRV_PRIVGRP_CLIPART: break; /* Private group message. Packet contents: msg->argv[0] = (Integer) UserID (aka PrivateGroupID) msg->argv[1] = (Integer) UserID msg->argv[2] = (String) Text msg->argv[3] = (String) Blob */ case AOC_SRV_PRIVGRP_MSG: break; case AOC_SRV_GROUP_INFO: break; case AOC_SRV_GROUP_PART: break; case AOC_SRV_GROUP_MSG: break; /* This packet is sent in reply to pings. Packet contents: msg->argv[0] = (String) UserData */ case AOC_SRV_PONG: printf("Pong!\n"); break; /* This packet is sent to you if someone types "/cc info yourcharname" in game. Packet contents: msg->argv[0] = (Raw) Binary Data */ case AOC_SRV_FORWARD: break; /* Unknown. */ case AOC_SRV_AMD_MUX_INFO: break; } return; }