/* Copyright © 2009 Jim Porter 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 "proto.h" void TwitterProto::AddToListWorker(void *p) { // TODO: what happens if there is an error? if(p == 0) return; char *name = static_cast(p); try { ScopedLock s(twitter_lock_); twitter_user user = twit_.add_friend(name); s.Unlock(); HANDLE hContact = UsernameToHContact(name); UpdateAvatar(hContact,user.profile_image_url); } catch(const std::exception &e) { ShowPopup((std::string("While adding a friend, an error occurred: ") + e.what()).c_str()); LOG( _T("***** Error adding friend: %s"),e.what()); } mir_free(name); } HANDLE TwitterProto::AddToList(int flags,PROTOSEARCHRESULT *result) { if(m_iStatus != ID_STATUS_ONLINE) return 0; ForkThread(&TwitterProto::AddToListWorker,this,mir_utf8encodeT(result->nick)); return AddToClientList( _T2A(result->nick),""); } // ************************* void TwitterProto::UpdateInfoWorker(void *hContact) { twitter_user user; std::string username; DBVARIANT dbv; if(!db_get_s(hContact,m_szModuleName,TWITTER_KEY_UN,&dbv)) { username = dbv.pszVal; db_free(&dbv); } else return; { ScopedLock s(twitter_lock_); twit_.get_info(username,&user); } UpdateAvatar(hContact,user.profile_image_url,true); ProtoBroadcastAck(m_szModuleName,hContact,ACKTYPE_GETINFO,ACKRESULT_SUCCESS,0,0); } int TwitterProto::GetInfo(HANDLE hContact,int info_type) { if(m_iStatus != ID_STATUS_ONLINE) return 1; if(!IsMyContact(hContact)) // Do nothing for chat rooms return 1; if(info_type == 0) // From clicking "Update" in the Userinfo dialog { ForkThread(&TwitterProto::UpdateInfoWorker,this,hContact); return 0; } return 1; } // ************************* struct search_query { search_query(const std::tstring &_query,bool _by_email) : query(_query),by_email(_by_email) {} std::tstring query; bool by_email; }; void TwitterProto::DoSearch(void *p) { if(p == 0) return; search_query *query = static_cast(p); twitter_user info; bool found = false; try { char* p = mir_utf8encodeT( query->query.c_str()); ScopedLock s(twitter_lock_); if(query->by_email) found = twit_.get_info_by_email(p,&info); else found = twit_.get_info(p,&info); mir_free( p ); } catch(const std::exception &e) { ShowPopup( (std::string("While searching for contacts, an error occurred: ") + e.what()).c_str()); LOG( _T("***** Error searching for contacts: %s"), e.what()); found = false; } if(found) { PROTOSEARCHRESULT psr = {sizeof(psr)}; psr.nick = mir_a2t(info.username. c_str()); psr.firstName = mir_a2t(info.real_name.c_str()); ProtoBroadcastAck(m_szModuleName,0,ACKTYPE_SEARCH,ACKRESULT_DATA,(HANDLE)1, (LPARAM)&psr); ProtoBroadcastAck(m_szModuleName,0,ACKTYPE_SEARCH,ACKRESULT_SUCCESS,(HANDLE)1,0); mir_free(psr.nick); mir_free(psr.firstName); } else { ProtoBroadcastAck(m_szModuleName,0,ACKTYPE_SEARCH,ACKRESULT_SUCCESS,(HANDLE)1,0); } delete query; } HANDLE TwitterProto::SearchBasic(const TCHAR *username) { ForkThread(&TwitterProto::DoSearch,this,new search_query(username,false)); return (HANDLE)1; } HANDLE TwitterProto::SearchByEmail(const TCHAR *email) { ForkThread(&TwitterProto::DoSearch,this,new search_query(email,true)); return (HANDLE)1; } // ************************* void TwitterProto::GetAwayMsgWorker(void *hContact) { if(hContact == 0) return; DBVARIANT dbv; if( !db_get_ts(hContact,"CList","StatusMsg",&dbv)) { ProtoBroadcastAck(m_szModuleName,hContact,ACKTYPE_AWAYMSG,ACKRESULT_SUCCESS, (HANDLE)1,(LPARAM)dbv.ptszVal); db_free(&dbv); } else ProtoBroadcastAck(m_szModuleName,hContact,ACKTYPE_AWAYMSG,ACKRESULT_FAILED, (HANDLE)1,0); } HANDLE TwitterProto::GetAwayMsg(HANDLE hContact) { ForkThread(&TwitterProto::GetAwayMsgWorker, this,hContact); return (HANDLE)1; } int TwitterProto::OnContactDeleted(WPARAM wParam,LPARAM lParam) { if(m_iStatus != ID_STATUS_ONLINE) return 0; const HANDLE hContact = reinterpret_cast(wParam); if(!IsMyContact(hContact)) return 0; DBVARIANT dbv; if( !db_get_s(hContact,m_szModuleName,TWITTER_KEY_UN,&dbv)) { if(in_chat_) DeleteChatContact(dbv.pszVal); ScopedLock s(twitter_lock_); twit_.remove_friend(dbv.pszVal); // Be careful about this until Miranda is fixed db_free(&dbv); } return 0; } // ************************* bool TwitterProto::IsMyContact(HANDLE hContact,bool include_chat) { char *proto = GetContactProto(hContact); if(proto && strcmp(m_szModuleName,proto) == 0) { if(include_chat) return true; return db_get_b(hContact,m_szModuleName,"ChatRoom",0) == 0; } else return false; } HANDLE TwitterProto::UsernameToHContact(const char *name) { for(HANDLE hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { if(!IsMyContact(hContact)) continue; DBVARIANT dbv; if( !db_get_s(hContact,m_szModuleName,TWITTER_KEY_UN,&dbv)) { if(strcmp(name,dbv.pszVal) == 0) { db_free(&dbv); return hContact; } else db_free(&dbv); } } return 0; } HANDLE TwitterProto::AddToClientList(const char *name,const char *status) { // First, check if this contact exists HANDLE hContact = UsernameToHContact(name); if(hContact) return hContact; if(in_chat_) AddChatContact(name); // If not, make a new contact! hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0); if(hContact) { if(CallService(MS_PROTO_ADDTOCONTACT,(WPARAM)hContact,(LPARAM)m_szModuleName) == 0) { db_set_s(hContact,m_szModuleName,TWITTER_KEY_UN,name); db_set_w(hContact,m_szModuleName,"Status",ID_STATUS_ONLINE); db_set_utf(hContact,"CList","StatusMsg",status); std::string url = profile_base_url(twit_.get_base_url())+http::url_encode(name); db_set_s(hContact,m_szModuleName,"Homepage",url.c_str()); DBVARIANT dbv; if(!db_get_ts(NULL,m_szModuleName,TWITTER_KEY_GROUP,&dbv)) { db_set_ts(hContact,"CList","Group",dbv.ptszVal); db_free(&dbv); } return hContact; } else CallService(MS_DB_CONTACT_DELETE,(WPARAM)hContact,0); } return 0; } void TwitterProto::SetAllContactStatuses(int status) { for(HANDLE hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { if(!IsMyContact(hContact)) continue; db_set_w(hContact,m_szModuleName,"Status",status); } SetChatStatus(status); }