/*
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:
debugLogA("**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;
}