Chat-O-Matic/protocols/aim/AIM.cpp

497 lines
12 KiB
C++

#include <stdio.h>
#include <errno.h>
#include <string>
#include <Entry.h>
#include "AIM.h"
const char* kProtocolName = "aim";
CayaProtocolMessengerInterface *gServerMsgr;
AIMProtocol::AIMProtocol()
{
}
AIMProtocol::~AIMProtocol()
{
Shutdown();
}
status_t
AIMProtocol::Init(CayaProtocolMessengerInterface* msgr)
{
printf("init\n");
gServerMsgr = msgr;
fIMCommHandle = imcomm_create_handle();
fOnline = false;
imcomm_register_callback(fIMCommHandle, IMCOMM_IM_INCOMING, (void (*)())GotMessage);
imcomm_register_callback(fIMCommHandle, IMCOMM_IM_SIGNON, (void (*)())BuddyOnline);
imcomm_register_callback(fIMCommHandle, IMCOMM_IM_SIGNOFF, (void (*)())BuddyOffline);
imcomm_register_callback(fIMCommHandle, IMCOMM_IM_BUDDYAWAY, (void (*)())BuddyAway);
imcomm_register_callback(fIMCommHandle, IMCOMM_IM_BUDDYUNAWAY, (void (*)())BuddyBack);
imcomm_register_callback(fIMCommHandle, IMCOMM_IM_AWAYMSG, (void (*)())BuddyAwayMsg);
imcomm_register_callback(fIMCommHandle, IMCOMM_IM_IDLEINFO, (void (*)())BuddyIdle);
imcomm_register_callback(fIMCommHandle, IMCOMM_IM_PROFILE, (void (*)())BuddyProfile);
// XXX missing IMCOMM_ERROR, IMCOMM_FORMATTED_SN, IMCOMM_HANDLE_DELETED
return B_OK;
}
status_t
AIMProtocol::Shutdown()
{
LogOff();
return B_OK;
}
status_t
AIMProtocol::Process(BMessage* msg)
{
msg->PrintToStream();
switch (msg->what) {
case IM_MESSAGE:
{
int32 im_what = 0;
msg->FindInt32("im_what", &im_what);
switch (im_what) {
case IM_SET_STATUS:
{
int32 status = msg->FindInt32("status");
BString status_msg("");
msg->FindString("message", &status_msg);
char *smsg = strdup(status_msg.String());
switch (status) {
case CAYA_ONLINE:
{
if (!fOnline) {
A_LogOn();
} else {
imcomm_set_unaway(fIMCommHandle);
}
break;
}
case CAYA_AWAY:
imcomm_set_away(fIMCommHandle,
smsg);
break;
case CAYA_EXTENDED_AWAY:
imcomm_set_away(fIMCommHandle,
smsg);
// UnsupportedOperation(); ?
break;
case CAYA_DO_NOT_DISTURB:
imcomm_set_away(fIMCommHandle,
smsg);
// UnsupportedOperation(); ?
break;
case CAYA_OFFLINE:
LogOff();
break;
default:
break;
}
free(smsg);
BMessage msg(IM_MESSAGE);
msg.AddInt32("im_what", IM_STATUS_SET);
msg.AddString("protocol", kProtocolName);
msg.AddInt32("status", status);
gServerMsgr->SendMessage(&msg);
break;
}
case IM_SET_NICKNAME:
{
UnsupportedOperation();
break;
}
case IM_SEND_MESSAGE:
{
const char* buddy = msg->FindString("id");
const char* sms = msg->FindString("message");
imcomm_im_send_message(fIMCommHandle, buddy,
sms, 0);
// XXX send a message to let caya know
// we did it
BMessage msg(IM_MESSAGE);
msg.AddInt32("im_what", IM_MESSAGE_SENT);
msg.AddString("protocol", kProtocolName);
msg.AddString("id", buddy);
msg.AddString("message", sms);
gServerMsgr->SendMessage(&msg);
break;
}
case IM_REGISTER_CONTACTS:
{
const char* buddy = NULL;
char *buddy_copy;
for (int i = 0;
msg->FindString("id", i, &buddy) == B_OK;
i++) {
buddy_copy = strdup(buddy);
imcomm_im_add_buddy(fIMCommHandle, buddy_copy);
free(buddy_copy);
}
break;
}
case IM_UNREGISTER_CONTACTS:
{
const char* buddy = NULL;
for (int i = 0;
msg->FindString("id", i, &buddy) == B_OK;
i++) {
imcomm_im_remove_buddy(fIMCommHandle, buddy);
}
break;
}
case IM_USER_STARTED_TYPING:
{
// UnsupportedOperation();
break;
}
case IM_USER_STOPPED_TYPING:
{
// UnsupportedOperation();
break;
}
case IM_GET_CONTACT_INFO:
UnsupportedOperation();
break;
case IM_SEND_AUTH_ACK:
{
UnsupportedOperation();
break;
}
case IM_SPECIAL_TO_PROTOCOL:
UnsupportedOperation();
break;
default:
msg->PrintToStream();
return B_ERROR;
}
break;
}
default:
// We don't handle this what code
return B_ERROR;
}
return B_OK;
}
void
AIMProtocol::UnsupportedOperation() {
printf("noop\n");
}
const char*
AIMProtocol::GetSignature()
{
return kProtocolName;
}
const char*
AIMProtocol::GetFriendlySignature()
{
return "AOL Instant Messenger";
}
status_t
AIMProtocol::UpdateSettings(BMessage& msg)
{
const char* username = NULL;
const char* password = NULL;
msg.FindString("username", &username);
msg.FindString("password", &password);
// msg.FindString("server", &server);
// msg.FindInt32("port", &server);
if ((username == NULL) || (password == NULL)) {
//LOG( kProtocolName, liHigh, "Invalid settings!");
printf("Invalid settings");
return B_ERROR;
}
if ((fUsername != username) || (fPassword != password)) {
fUsername = username;
fPassword = password;
// XXX kill the handle and sign back in?
}
return B_OK;
}
uint32
AIMProtocol::GetEncoding()
{
return 0xffff; // No conversion, AIMProtocol handles UTF-8 ???
}
status_t
AIMProtocol::A_LogOn()
{
int ret = imcomm_im_signon(fIMCommHandle, fUsername, fPassword);
printf("ret: %d\n", ret);
if (ret == IMCOMM_RET_OK) {
fIMCommThread = spawn_thread(WaitForData, "imcomm receiver",
B_LOW_PRIORITY, this);
resume_thread(fIMCommThread);
fOnline = true;
return B_OK;
}
return B_ERROR;
}
status_t
AIMProtocol::LogOff()
{
fOnline = false;
imcomm_delete_handle_now(fIMCommHandle);
return B_OK;
}
int32
AIMProtocol::WaitForData(void *aimProtocol) {
// XXX No need for aimProtocol since imcomm does its own callback thing
printf("wait\n");
fd_set readset;
struct timeval tm;
while (1) {
FD_ZERO(&readset);
tm.tv_sec = 2;
tm.tv_usec = 500000;
IMCOMM_RET ret = imcomm_select(1, &readset, NULL, NULL, &tm);
if (ret != IMCOMM_RET_OK && errno == EINTR) continue;
}
return 0;
}
void
AIMProtocol::GotMessage(void *imcomm, char *who, int auto, char *recvmsg) {
BMessage msg(IM_MESSAGE);
msg.AddInt32("im_what", IM_MESSAGE_RECEIVED);
msg.AddString("protocol", kProtocolName);
msg.AddString("id", who);
msg.AddString("message", strip_html(recvmsg));
gServerMsgr->SendMessage(&msg);
}
void
AIMProtocol::BuddyOnline(void *imcomm, char *who) {
BMessage msg(IM_MESSAGE);
msg.AddInt32("im_what", IM_STATUS_CHANGED);
msg.AddString("protocol", kProtocolName);
msg.AddString("id", who);
msg.AddInt32("status", CAYA_ONLINE);
gServerMsgr->SendMessage(&msg);
}
void
AIMProtocol::BuddyOffline(void *imcomm, char *who) {
BMessage msg(IM_MESSAGE);
msg.AddInt32("im_what", IM_STATUS_CHANGED);
msg.AddString("protocol", kProtocolName);
msg.AddString("id", who);
msg.AddInt32("status", CAYA_OFFLINE);
gServerMsgr->SendMessage(&msg);
}
void
AIMProtocol::BuddyAway(void *imcomm, char *who) {
imcomm_request_awaymsg(imcomm, who);
}
void
AIMProtocol::BuddyBack(void *imcomm, char *who) {
BMessage msg(IM_MESSAGE);
msg.AddInt32("im_what", IM_STATUS_CHANGED);
msg.AddString("protocol", kProtocolName);
msg.AddString("id", who);
msg.AddInt32("status", CAYA_ONLINE);
gServerMsgr->SendMessage(&msg);
}
void
AIMProtocol::BuddyAwayMsg(void *imcomm, char *who, char *awaymsg) {
BMessage msg(IM_MESSAGE);
msg.AddInt32("im_what", IM_STATUS_CHANGED);
msg.AddString("protocol", kProtocolName);
msg.AddString("id", who);
msg.AddInt32("status", CAYA_EXTENDED_AWAY);
msg.AddString("message", strip_html(awaymsg));
gServerMsgr->SendMessage(&msg);
}
void
AIMProtocol::BuddyIdle(void *imcomm, char *who, long idletime) {
BMessage msg(IM_MESSAGE);
msg.AddInt32("im_what", IM_STATUS_CHANGED);
msg.AddString("protocol", kProtocolName);
msg.AddString("id", who);
msg.AddInt32("status", CAYA_ONLINE);
gServerMsgr->SendMessage(&msg);
}
void
AIMProtocol::BuddyProfile(void *handle, char *who, char *profile) {
// XXX vcard is probably an issue
}
char *
AIMProtocol::strip_html(const char *message)
{
char *temp;
int x, xnot, y, count, inhtml;
size_t len = strlen(message);
temp = (char*)malloc(len + 1);
for (x = 0, count = 0, inhtml = 0; x < len; x++) {
if (message[x] == '<' && inhtml == 0) {
if (x + 10 < len) {
/**
** Convert links into
** [http://url] link text
**/
if (strncasecmp(message + x, "<a href=\"", 9) == 0) {
xnot = x + 9;
for (y = xnot; y < len; y++) {
if (message[y] == '\"') {
/*
* we don't have to
* worry about the
* buffer size,
* because it's
* guaranteed to be
* bigger
*/
memcpy(temp + count, "[", 1);
memcpy(temp + count + 1, message + xnot,
y - xnot);
memcpy(temp + count + 1 + (y - xnot), "] ", 2);
count += y - xnot + 3;
x = y;
break;
}
}
}
}
if (x + 3 < len) {
if (strncasecmp(message + x, "<br>", 4) == 0) {
temp[count] = '\n';
count++;
x += 3;
continue;
}
}
inhtml = 1;
continue;
}
if (inhtml) {
if (message[x] == '>')
inhtml = 0;
continue;
}
if (message[x] == '&') {
if (x + 4 < len) {
if (strncmp(message + x, "&amp;", 5) == 0) {
temp[count] = '&';
count++;
x += 4;
continue;
}
}
if (x + 5 < len) {
if (strncmp(message + x, "&quot;", 6) == 0) {
temp[count] = '\"';
count++;
x += 5;
continue;
}
if (strncmp(message + x, "&nbsp;", 6) == 0) {
temp[count] = ' ';
count++;
x += 5;
continue;
}
}
if (x + 3 < len) {
if (strncmp(message + x, "&lt;", 4) == 0) {
temp[count] = '<';
count++;
x += 3;
continue;
}
}
if (x + 3 < len) {
if (strncmp(message + x, "&gt;", 4) == 0) {
temp[count] = '>';
count++;
x += 3;
continue;
}
}
}
if (message[x] == '\n' || message[x] == '\r')
continue;
else
temp[count] = message[x];
count++;
}
temp = (char*)realloc(temp, count + 1);
temp[count] = 0;
return temp;
}