/* Omegle plugin for Miranda Instant Messenger _____________________________________________ Copyright © 2011-13 Robert Pösel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "common.h" void OmegleProto::UpdateChat(const TCHAR *name, const TCHAR *message, bool addtolog) { GCDEST gcd = { m_szModuleName }; gcd.ptszID = const_cast(m_tszUserName); GCEVENT gce = {sizeof(gce)}; gce.pDest = &gcd; gce.ptszText = message; gce.time = ::time(NULL); gce.dwFlags = GC_TCHAR; gcd.iType = GC_EVENT_MESSAGE; if (name == NULL) { gcd.iType = GC_EVENT_INFORMATION; name = TranslateT("Server"); gce.bIsMe = false; } else { gce.bIsMe = !_tcscmp(name, this->facy.nick_); } if (addtolog) gce.dwFlags |= GCEF_ADDTOLOG; gce.ptszNick = name; gce.ptszUID = gce.ptszNick; CallServiceSync(MS_GC_EVENT,0,reinterpret_cast(&gce)); } int OmegleProto::OnChatEvent(WPARAM wParam,LPARAM lParam) { GCHOOK *hook = reinterpret_cast(lParam); if(strcmp(hook->pDest->pszModule,m_szModuleName)) return 0; switch(hook->pDest->iType) { case GC_USER_MESSAGE: { std::string text = mir_t2a_cp(hook->ptszText,CP_UTF8); if (text.empty()) break; if (text.substr(0,1) == "/") { // Process commands std::string command = ""; std::string params = ""; std::string::size_type pos = 0; if ((pos = text.find(" ")) != std::string::npos) { command = text.substr(1, pos-1); params = text.substr(pos+1); } else { command = text.substr(1); } if (!stricmp(command.c_str(), "new")) { facy.spy_mode_ = false; facy.question_ = ""; ForkThread(&OmegleProto::NewChatWorker, NULL); break; } else if (!stricmp(command.c_str(), "quit")) { ForkThread(&OmegleProto::StopChatWorker, NULL); break; } else if (!stricmp(command.c_str(), "spy")) { facy.spy_mode_ = true; facy.question_ = ""; ForkThread(&OmegleProto::NewChatWorker, NULL); break; } else if (!stricmp(command.c_str(), "ask")) { if (params.empty()) { // Load last question DBVARIANT dbv; if ( !getU8String( OMEGLE_KEY_LAST_QUESTION,&dbv )) { params = dbv.pszVal; db_free(&dbv); } if (params.empty()) { UpdateChat(NULL, TranslateT("Last question is empty."), false); break; } } else { // Save actual question as last question if (strlen(params.c_str()) >= OMEGLE_QUESTION_MIN_LENGTH) { setU8String( OMEGLE_KEY_LAST_QUESTION, params.c_str()); } } if (strlen(params.c_str()) < OMEGLE_QUESTION_MIN_LENGTH) { UpdateChat(NULL, TranslateT("Your question is too short."), false); break; } facy.spy_mode_ = true; facy.question_ = params; ForkThread(&OmegleProto::NewChatWorker, NULL); break; } else if (!stricmp(command.c_str(), "asl")) { DBVARIANT dbv; if ( !getU8String( OMEGLE_KEY_ASL,&dbv )) { text = dbv.pszVal; db_free(&dbv); } else { UpdateChat(NULL, TranslateT("Your '/asl' setting is empty."), false); break; } } else if (!stricmp(command.c_str(), "help")) { UpdateChat(NULL, TranslateT("There are three different modes of chatting:\ \n1) Standard mode\t - You chat with random stranger privately\ \n2) Question mode\t - You ask two strangers a question and see how they discuss it (you can't join their conversation, only watch)\ \n3) Spy mode\t - You and stranger got a question to discuss from third stranger (he can't join your conversation, only watch)\ \n\nSend '/commands' for available commands."), false); } else if (!stricmp(command.c_str(), "commands")) { UpdateChat(NULL, TranslateT("You can use different commands:\ \n/help\t - show info about chat modes\ \n/new\t - start standard mode\ \n/ask - start question mode with your question\ \n/ask\t - start question mode with your last asked question\ \n/spy\t - start spy mode\ \n/quit\t - disconnect from stranger or stop connecting\ \n/asl\t - send your predefined ASL message\ \n\nNote: You can reconnect to different stranger without disconnecting from current one."), false); break; } else { UpdateChat(NULL, TranslateT("Unknown command. Send '/commands' for list."), false); break; } } else switch (facy.state_) { // Outgoing message case STATE_ACTIVE: LOG("**Chat - Outgoing message: %s", text.c_str()); ForkThread(&OmegleProto::SendMsgWorker, new std::string(text)); break; case STATE_INACTIVE: UpdateChat(NULL, TranslateT("You aren't connected to any stranger. Send '/help' or '/commands' for help."), false); break; case STATE_SPY: UpdateChat(NULL, TranslateT("You can't send messages in question mode."), false); break; //case STATE_WAITING: //case STATE_DISCONNECTING: default: break; } break; } case GC_USER_TYPNOTIFY: if ( facy.state_ == STATE_ACTIVE ) ForkThread(&OmegleProto::SendTypingWorker, mir_tstrdup(hook->ptszText)); break; case GC_USER_LEAVE: case GC_SESSION_TERMINATE: mir_free( facy.nick_ ); ForkThread(&OmegleProto::StopChatWorker, NULL); break; } return 0; } /*void OmegleProto::SendChatEvent(int type) { GCDEST gcd = { m_szModuleName }; gcd.ptszID = const_cast(m_tszUserName); gcd.iType = GC_EVENT_CONTROL; GCEVENT gce = {sizeof(gce)}; gce.dwFlags = GC_TCHAR; gce.pDest = &gcd; CallServiceSync(MS_GC_EVENT,WINDOW_CLEARLOG,reinterpret_cast(&gce)); }*/ void OmegleProto::AddChatContact(const TCHAR *name) { GCDEST gcd = { m_szModuleName }; gcd.ptszID = const_cast(m_tszUserName); gcd.iType = GC_EVENT_JOIN; GCEVENT gce = {sizeof(gce)}; gce.pDest = &gcd; gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG; gce.ptszNick = name; gce.ptszUID = gce.ptszNick; gce.time = static_cast(time(0)); if (name == NULL) gce.bIsMe = false; else gce.bIsMe = !_tcscmp(name, this->facy.nick_); if (gce.bIsMe) gce.ptszStatus = _T("Admin"); else gce.ptszStatus = _T("Normal"); CallServiceSync(MS_GC_EVENT,0,reinterpret_cast(&gce)); } void OmegleProto::DeleteChatContact(const TCHAR *name) { GCDEST gcd = { m_szModuleName }; gcd.ptszID = const_cast(m_tszUserName); gcd.iType = GC_EVENT_PART; GCEVENT gce = {sizeof(gce)}; gce.pDest = &gcd; gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG; gce.ptszNick = name; gce.ptszUID = gce.ptszNick; gce.time = static_cast(time(0)); if (name == NULL) gce.bIsMe = false; else gce.bIsMe = !_tcscmp(name, this->facy.nick_); CallServiceSync(MS_GC_EVENT,0,reinterpret_cast(&gce)); } INT_PTR OmegleProto::OnJoinChat(WPARAM,LPARAM suppress) { GCSESSION gcw = {sizeof(gcw)}; // Create the group chat session gcw.dwFlags = GC_TCHAR; gcw.iType = GCW_CHATROOM; gcw.pszModule = m_szModuleName; gcw.ptszName = m_tszUserName; gcw.ptszID = m_tszUserName; CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw); if(m_iStatus == ID_STATUS_OFFLINE) return 0; // Create a group GCDEST gcd = { m_szModuleName }; gcd.ptszID = const_cast(m_tszUserName); GCEVENT gce = {sizeof(gce)}; gce.pDest = &gcd; gce.dwFlags = GC_TCHAR; gcd.iType = GC_EVENT_ADDGROUP; gce.ptszStatus = _T("Admin"); CallServiceSync( MS_GC_EVENT, NULL, reinterpret_cast(&gce)); gce.ptszStatus = _T("Normal"); CallServiceSync( MS_GC_EVENT, NULL, reinterpret_cast(&gce)); SetTopic(); // Note: Initialization will finish up in SetChatStatus, called separately if (!suppress) SetChatStatus(m_iStatus); return 0; } void OmegleProto::SetTopic(const TCHAR *topic) { GCDEST gcd = { m_szModuleName }; gcd.ptszID = const_cast(m_tszUserName); gcd.iType = GC_EVENT_TOPIC; GCEVENT gce = {sizeof(gce)}; gce.pDest = &gcd; gce.dwFlags = GC_TCHAR; gce.time = ::time(NULL); if (topic == NULL) gce.ptszText = TranslateT("Omegle is a great way of meeting new friends!"); else gce.ptszText = topic; CallServiceSync(MS_GC_EVENT,0, reinterpret_cast(&gce)); } INT_PTR OmegleProto::OnLeaveChat(WPARAM,LPARAM) { GCDEST gcd = { m_szModuleName }; gcd.ptszID = const_cast(m_tszUserName); gcd.iType = GC_EVENT_CONTROL; GCEVENT gce = {sizeof(gce)}; gce.dwFlags = GC_TCHAR; gce.time = ::time(NULL); gce.pDest = &gcd; CallServiceSync(MS_GC_EVENT,SESSION_OFFLINE, reinterpret_cast(&gce)); CallServiceSync(MS_GC_EVENT,SESSION_TERMINATE,reinterpret_cast(&gce)); return 0; } void OmegleProto::SetChatStatus(int status) { GCDEST gcd = { m_szModuleName }; gcd.ptszID = const_cast(m_tszUserName); gcd.iType = GC_EVENT_CONTROL; GCEVENT gce = {sizeof(gce)}; gce.dwFlags = GC_TCHAR; gce.time = ::time(NULL); gce.pDest = &gcd; if(status == ID_STATUS_ONLINE) { // Free previously loaded name mir_free(facy.nick_); // Load actual name from database DBVARIANT dbv; if ( !db_get_ts(NULL, m_szModuleName, OMEGLE_KEY_NAME, &dbv)) { facy.nick_ = mir_tstrdup(dbv.ptszVal); db_free(&dbv); } else { facy.nick_ = mir_tstrdup(TranslateT("You")); db_set_ts(NULL, m_szModuleName, OMEGLE_KEY_NAME, facy.nick_); } // Add self contact AddChatContact(facy.nick_); CallServiceSync(MS_GC_EVENT,SESSION_INITDONE,reinterpret_cast(&gce)); CallServiceSync(MS_GC_EVENT,SESSION_ONLINE, reinterpret_cast(&gce)); } else { CallServiceSync(MS_GC_EVENT,SESSION_OFFLINE,reinterpret_cast(&gce)); } } void OmegleProto::ClearChat() { if (getByte(OMEGLE_KEY_NO_CLEAR, 0)) return; GCDEST gcd = { m_szModuleName }; gcd.ptszID = const_cast(m_tszUserName); gcd.iType = GC_EVENT_CONTROL; GCEVENT gce = {sizeof(gce)}; gce.dwFlags = GC_TCHAR; gce.pDest = &gcd; CallServiceSync(MS_GC_EVENT,WINDOW_CLEARLOG,reinterpret_cast(&gce)); } // TODO: Could this be done better? HANDLE OmegleProto::GetChatHandle() { /*if (facy.chatHandle_ != NULL) return facy.chatHandle_; for (HANDLE hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) { if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0) > 0) { ptrA id = db_get_sa(hContact, m_szModuleName, "ChatRoomId"); if (id != NULL && !strcmp(id, m_szModuleName)) return hContact; } } return NULL;*/ GC_INFO gci = {0}; gci.Flags = HCONTACT; gci.pszModule = m_szModuleName; gci.pszID = const_cast(m_tszUserName); CallService(MS_GC_GETINFO, 0, (LPARAM)(GC_INFO *) &gci); return gci.hContact; }