diff options
author | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-05-18 10:51:56 +0000 |
---|---|---|
committer | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-05-18 10:51:56 +0000 |
commit | e08998140f9b5cbdc973fae0554042925f431df3 (patch) | |
tree | 06fbc2fa84aebf7d4006eef1bb577f2cd7f687a7 /protocols/FacebookRM | |
parent | a85e238092f480e9de278ae507af710633fa2824 (diff) |
renaming FacebookRM folder
git-svn-id: http://svn.miranda-ng.org/main/trunk@35 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/FacebookRM')
49 files changed, 10201 insertions, 0 deletions
diff --git a/protocols/FacebookRM/JSON_CAJUN/Readme.txt b/protocols/FacebookRM/JSON_CAJUN/Readme.txt new file mode 100644 index 0000000000..8b9505cebf --- /dev/null +++ b/protocols/FacebookRM/JSON_CAJUN/Readme.txt @@ -0,0 +1,14 @@ +CAJUN* is a C++ API for the JSON object interchange format. JSON is like XML, except it doesn't suck**. It is specifically designed for representing (in plain text format) structures familiar to software engineers: booleans, numerics, strings, arrays, and objects (i.e. name/value pairs, associative array, etc.); it humbly leaves text markup to XML. It is ideal for storing persistent application data, such as configuration or user data files.
+
+Too many JSON parsers I've seen suffer from overly complex designs and confusing interfaces, so in true software engineer form, I thought I could do better. The goal of JSON was to create an simple, "minimalist" interface while sacrificing absolutely no power or flexibility. The STL containers, while not without their violations of that spirit, served as an inspiration. The end result is (IMHO) an interface that should be immediately intuitive to anyone familiar with C++ and the Standard Library containers. It can best be described as working with an "element", where an element may consist of:
+* String (mimics std::string)
+* Numeric (double)
+* Boolean (bool)
+* Array (std::vector<UnknownElement>)
+* Object (unsorted std::map<std::string, UnknownElement>)
+* UnknownElement - like boost::any, but restricted to types below. Used to aggregate elements within Objects & Arrays, and for reading documents of unknown structure
+
+As with any design, sacrifices were made with CAJUN. Most situations I've encountered where JSON is well-suited (reading & writing application configuration and data files) are not typically performance bottlenecks, so simplicity, safety & flexibility were favored over raw speed. The end result is a library with simple, typesafe classes, no memory-management burden on the user, and exception-based error reporting.
+
+* C++ API for JSON. A pint on me for who ever comes up with a good meaning for "UN".
+** To be fair, XML doesn't suck intentionally, it is just often used inappropriately.
\ No newline at end of file diff --git a/protocols/FacebookRM/JSON_CAJUN/ReleaseNotes.txt b/protocols/FacebookRM/JSON_CAJUN/ReleaseNotes.txt new file mode 100644 index 0000000000..8e43b6f928 --- /dev/null +++ b/protocols/FacebookRM/JSON_CAJUN/ReleaseNotes.txt @@ -0,0 +1,35 @@ +2.0.1 (11/17/2009)
+* A couple of Reader functions not inlined, sometimes resulting in linker duplicate symbols. Oops.
+
+
+2.0.0 (11/14/2009)
+* Redesign/simplicification of the element class relationships:
+ * Element/Element_T base class or *Imp classes eliminated. Originally necessary for aggregation by Object/Array, but now unnecessary with UnknownElement type
+ * json_cast<> functions eliminated. Static type safety relaxed, allowing more concise document data extraction code (dynamic type safety still completely maintained).
+ * Quick-Interpreter/-Builder classes eliminated. Equivalent functionality now in "UnknownElement", but now more accessible
+ In summary, simpler design, less code in library, less code necessary to utilize library. See test app for many more new examples.
+* Entire library is now inlined. Bound to be controversial, but...
+ * Modern compilers should eliminate redundant object code
+ * Fixes problems associated with different runtime libraries, library debug information, security & debug iterator compile-time options under MSVC++, among other things.
+ * Simply include the appropriate file & go - no linker settings to mess with.
+* Added 64-bit build targets for MSVC 8/9 test app, just because.
+* Scan/Parse exceptions moved into Reader class scope, and Parse exceptions fixed to always include bad token string
+* A few more random bug fixes
+* Tested under:
+ * MSVC++ 2005
+ * MSVC++ 2008
+ * GCC 4.4.0
+
+1.1.0 (08/30/2009)
+* Implemented operator == for all element types
+* Added makefile for building with g++ (thanks George Morgan).
+* Fixed a few compiler errors on non-Visual Studio compilers (my C++ wasn't as ANSI as I thought...)
+* Support for (non-standard) comments REMOVED
+* Support for Visual Studio 7.1 (2003) REMOVED
+* Fixed the "Unexpected token..." exception string (was gibberish)
+* Improvements to the QuickInterpreter & QuickBuilder interfaces
+* Elements now sanity-check themselves during operations and throw an exception accordingly, for example if an Object gets tricked into thinking it's an Array (reinterpret_cast, reading a document with an Array root element into an Object, etc)
+* Other random minor bug fixes & general cleanup
+
+1.0.0 (01/31/2009)
+* Initial release! Remaining work: better documentation, better test/sample app, yada yada
diff --git a/protocols/FacebookRM/JSON_CAJUN/elements.h b/protocols/FacebookRM/JSON_CAJUN/elements.h new file mode 100644 index 0000000000..f255dcd9a5 --- /dev/null +++ b/protocols/FacebookRM/JSON_CAJUN/elements.h @@ -0,0 +1,272 @@ +/**********************************************
+
+License: BSD
+Project Webpage: http://cajun-jsonapi.sourceforge.net/
+Author: Terry Caton
+
+***********************************************/
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <string>
+#include <stdexcept>
+
+/*
+
+TODO:
+* better documentation (doxygen?)
+* Unicode support
+* parent element accessors
+
+*/
+
+namespace json
+{
+
+
+/////////////////////////////////////////////////
+// forward declarations (more info further below)
+
+
+class Visitor;
+class ConstVisitor;
+
+template <typename ValueTypeT>
+class TrivialType_T;
+
+typedef TrivialType_T<double> Number;
+typedef TrivialType_T<bool> Boolean;
+typedef TrivialType_T<std::string> String;
+
+class Object;
+class Array;
+class Null;
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// Exception - base class for all JSON-related runtime errors
+
+class Exception : public std::runtime_error
+{
+public:
+ Exception(const std::string& sMessage);
+};
+
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// UnknownElement - provides a typesafe surrogate for any of the JSON-
+// sanctioned element types. This class allows the Array and Object
+// class to effectively contain a heterogeneous set of child elements.
+// The cast operators provide convenient implicit downcasting, while
+// preserving dynamic type safety by throwing an exception during a
+// a bad cast.
+// The object & array element index operators (operators [std::string]
+// and [size_t]) provide convenient, quick access to child elements.
+// They are a logical extension of the cast operators. These child
+// element accesses can be chained together, allowing the following
+// (when document structure is well-known):
+// String str = objInvoices[1]["Customer"]["Company"];
+
+
+class UnknownElement
+{
+public:
+ UnknownElement();
+ UnknownElement(const UnknownElement& unknown);
+ UnknownElement(const Object& object);
+ UnknownElement(const Array& array);
+ UnknownElement(const Number& number);
+ UnknownElement(const Boolean& boolean);
+ UnknownElement(const String& string);
+ UnknownElement(const Null& null);
+
+ ~UnknownElement();
+
+ UnknownElement& operator = (const UnknownElement& unknown);
+
+ // implicit cast to actual element type. throws on failure
+ operator const Object& () const;
+ operator const Array& () const;
+ operator const Number& () const;
+ operator const Boolean& () const;
+ operator const String& () const;
+ operator const Null& () const;
+
+ // implicit cast to actual element type. *converts* on failure, and always returns success
+ operator Object& ();
+ operator Array& ();
+ operator Number& ();
+ operator Boolean& ();
+ operator String& ();
+ operator Null& ();
+
+ // provides quick access to children when real element type is object
+ UnknownElement& operator[] (const std::string& key);
+ const UnknownElement& operator[] (const std::string& key) const;
+
+ // provides quick access to children when real element type is array
+ UnknownElement& operator[] (size_t index);
+ const UnknownElement& operator[] (size_t index) const;
+
+ // implements visitor pattern
+ void Accept(ConstVisitor& visitor) const;
+ void Accept(Visitor& visitor);
+
+ // tests equality. first checks type, then value if possible
+ bool operator == (const UnknownElement& element) const;
+
+private:
+ class Imp;
+
+ template <typename ElementTypeT>
+ class Imp_T;
+
+ class CastVisitor;
+ class ConstCastVisitor;
+
+ template <typename ElementTypeT>
+ class CastVisitor_T;
+
+ template <typename ElementTypeT>
+ class ConstCastVisitor_T;
+
+ template <typename ElementTypeT>
+ const ElementTypeT& CastTo() const;
+
+ template <typename ElementTypeT>
+ ElementTypeT& ConvertTo();
+
+ Imp* m_pImp;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Array - mimics std::deque<UnknownElement>. The array contents are effectively
+// heterogeneous thanks to the ElementUnknown class. push_back has been replaced
+// by more generic insert functions.
+
+class Array
+{
+public:
+ typedef std::deque<UnknownElement> Elements;
+ typedef Elements::iterator iterator;
+ typedef Elements::const_iterator const_iterator;
+
+ iterator Begin();
+ iterator End();
+ const_iterator Begin() const;
+ const_iterator End() const;
+
+ iterator Insert(const UnknownElement& element, iterator itWhere);
+ iterator Insert(const UnknownElement& element);
+ iterator Erase(iterator itWhere);
+ void Resize(size_t newSize);
+ void Clear();
+
+ size_t Size() const;
+ bool Empty() const;
+
+ UnknownElement& operator[] (size_t index);
+ const UnknownElement& operator[] (size_t index) const;
+
+ bool operator == (const Array& array) const;
+
+private:
+ Elements m_Elements;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Object - mimics std::map<std::string, UnknownElement>. The member value
+// contents are effectively heterogeneous thanks to the UnknownElement class
+
+class Object
+{
+public:
+ struct Member {
+ Member(const std::string& nameIn = std::string(), const UnknownElement& elementIn = UnknownElement());
+
+ bool operator == (const Member& member) const;
+
+ std::string name;
+ UnknownElement element;
+ };
+
+ typedef std::list<Member> Members; // map faster, but does not preserve order
+ typedef Members::iterator iterator;
+ typedef Members::const_iterator const_iterator;
+
+ bool operator == (const Object& object) const;
+
+ iterator Begin();
+ iterator End();
+ const_iterator Begin() const;
+ const_iterator End() const;
+
+ size_t Size() const;
+ bool Empty() const;
+
+ iterator Find(const std::string& name);
+ const_iterator Find(const std::string& name) const;
+
+ iterator Insert(const Member& member);
+ iterator Insert(const Member& member, iterator itWhere);
+ iterator Erase(iterator itWhere);
+ void Clear();
+
+ UnknownElement& operator [](const std::string& name);
+ const UnknownElement& operator [](const std::string& name) const;
+
+private:
+ class Finder;
+
+ Members m_Members;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// TrivialType_T - class template for encapsulates a simple data type, such as
+// a string, number, or boolean. Provides implicit const & noncost cast operators
+// for that type, allowing "DataTypeT type = trivialType;"
+
+
+template <typename DataTypeT>
+class TrivialType_T
+{
+public:
+ TrivialType_T(const DataTypeT& t = DataTypeT());
+
+ operator DataTypeT&();
+ operator const DataTypeT&() const;
+
+ DataTypeT& Value();
+ const DataTypeT& Value() const;
+
+ bool operator == (const TrivialType_T<DataTypeT>& trivial) const;
+
+private:
+ DataTypeT m_tValue;
+};
+
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Null - doesn't do much of anything but satisfy the JSON spec. It is the default
+// element type of UnknownElement
+
+class Null
+{
+public:
+ bool operator == (const Null& trivial) const;
+};
+
+
+} // End namespace
+
+
+#include "elements.inl"
diff --git a/protocols/FacebookRM/JSON_CAJUN/elements.inl b/protocols/FacebookRM/JSON_CAJUN/elements.inl new file mode 100644 index 0000000000..deb838cb3f --- /dev/null +++ b/protocols/FacebookRM/JSON_CAJUN/elements.inl @@ -0,0 +1,412 @@ +/**********************************************
+
+License: BSD
+Project Webpage: http://cajun-jsonapi.sourceforge.net/
+Author: Terry Caton
+
+***********************************************/
+
+#include "visitor.h"
+#include "reader.h"
+#include <cassert>
+#include <algorithm>
+#include <map>
+
+/*
+
+TODO:
+* better documentation
+
+*/
+
+namespace json
+{
+
+
+inline Exception::Exception(const std::string& sMessage) :
+ std::runtime_error(sMessage) {}
+
+
+/////////////////////////
+// UnknownElement members
+
+class UnknownElement::Imp
+{
+public:
+ virtual ~Imp() {}
+ virtual Imp* Clone() const = 0;
+
+ virtual bool Compare(const Imp& imp) const = 0;
+
+ virtual void Accept(ConstVisitor& visitor) const = 0;
+ virtual void Accept(Visitor& visitor) = 0;
+};
+
+
+template <typename ElementTypeT>
+class UnknownElement::Imp_T : public UnknownElement::Imp
+{
+public:
+ Imp_T(const ElementTypeT& element) : m_Element(element) {}
+ virtual Imp* Clone() const { return new Imp_T<ElementTypeT>(*this); }
+
+ virtual void Accept(ConstVisitor& visitor) const { visitor.Visit(m_Element); }
+ virtual void Accept(Visitor& visitor) { visitor.Visit(m_Element); }
+
+ virtual bool Compare(const Imp& imp) const
+ {
+ ConstCastVisitor_T<ElementTypeT> castVisitor;
+ imp.Accept(castVisitor);
+ return castVisitor.m_pElement &&
+ m_Element == *castVisitor.m_pElement;
+ }
+
+private:
+ ElementTypeT m_Element;
+};
+
+
+class UnknownElement::ConstCastVisitor : public ConstVisitor
+{
+ virtual void Visit(const Array& array) {}
+ virtual void Visit(const Object& object) {}
+ virtual void Visit(const Number& number) {}
+ virtual void Visit(const String& string) {}
+ virtual void Visit(const Boolean& boolean) {}
+ virtual void Visit(const Null& null) {}
+};
+
+template <typename ElementTypeT>
+class UnknownElement::ConstCastVisitor_T : public ConstCastVisitor
+{
+public:
+ ConstCastVisitor_T() : m_pElement(0) {}
+ virtual void Visit(const ElementTypeT& element) { m_pElement = &element; } // we don't know what this is, but it overrides one of the base's no-op functions
+ const ElementTypeT* m_pElement;
+};
+
+
+class UnknownElement::CastVisitor : public Visitor
+{
+ virtual void Visit(Array& array) {}
+ virtual void Visit(Object& object) {}
+ virtual void Visit(Number& number) {}
+ virtual void Visit(String& string) {}
+ virtual void Visit(Boolean& boolean) {}
+ virtual void Visit(Null& null) {}
+};
+
+template <typename ElementTypeT>
+class UnknownElement::CastVisitor_T : public CastVisitor
+{
+public:
+ CastVisitor_T() : m_pElement(0) {}
+ virtual void Visit(ElementTypeT& element) { m_pElement = &element; } // we don't know what this is, but it overrides one of the base's no-op functions
+ ElementTypeT* m_pElement;
+};
+
+
+
+
+inline UnknownElement::UnknownElement() : m_pImp( new Imp_T<Null>( Null() ) ) {}
+inline UnknownElement::UnknownElement(const UnknownElement& unknown) : m_pImp( unknown.m_pImp->Clone()) {}
+inline UnknownElement::UnknownElement(const Object& object) : m_pImp( new Imp_T<Object>(object) ) {}
+inline UnknownElement::UnknownElement(const Array& array) : m_pImp( new Imp_T<Array>(array) ) {}
+inline UnknownElement::UnknownElement(const Number& number) : m_pImp( new Imp_T<Number>(number) ) {}
+inline UnknownElement::UnknownElement(const Boolean& boolean) : m_pImp( new Imp_T<Boolean>(boolean) ) {}
+inline UnknownElement::UnknownElement(const String& string) : m_pImp( new Imp_T<String>(string) ) {}
+inline UnknownElement::UnknownElement(const Null& null) : m_pImp( new Imp_T<Null>(null) ) {}
+
+inline UnknownElement::~UnknownElement() { delete m_pImp; }
+
+inline UnknownElement::operator const Object& () const { return CastTo<Object>(); }
+inline UnknownElement::operator const Array& () const { return CastTo<Array>(); }
+inline UnknownElement::operator const Number& () const { return CastTo<Number>(); }
+inline UnknownElement::operator const Boolean& () const { return CastTo<Boolean>(); }
+inline UnknownElement::operator const String& () const { return CastTo<String>(); }
+inline UnknownElement::operator const Null& () const { return CastTo<Null>(); }
+
+inline UnknownElement::operator Object& () { return ConvertTo<Object>(); }
+inline UnknownElement::operator Array& () { return ConvertTo<Array>(); }
+inline UnknownElement::operator Number& () { return ConvertTo<Number>(); }
+inline UnknownElement::operator Boolean& () { return ConvertTo<Boolean>(); }
+inline UnknownElement::operator String& () { return ConvertTo<String>(); }
+inline UnknownElement::operator Null& () { return ConvertTo<Null>(); }
+
+inline UnknownElement& UnknownElement::operator = (const UnknownElement& unknown)
+{
+ delete m_pImp;
+ m_pImp = unknown.m_pImp->Clone();
+ return *this;
+}
+
+inline UnknownElement& UnknownElement::operator[] (const std::string& key)
+{
+ // the people want an object. make us one if we aren't already
+ Object& object = ConvertTo<Object>();
+ return object[key];
+}
+
+inline const UnknownElement& UnknownElement::operator[] (const std::string& key) const
+{
+ // throws if we aren't an object
+ const Object& object = CastTo<Object>();
+ return object[key];
+}
+
+inline UnknownElement& UnknownElement::operator[] (size_t index)
+{
+ // the people want an array. make us one if we aren't already
+ Array& array = ConvertTo<Array>();
+ return array[index];
+}
+
+inline const UnknownElement& UnknownElement::operator[] (size_t index) const
+{
+ // throws if we aren't an array
+ const Array& array = CastTo<Array>();
+ return array[index];
+}
+
+
+template <typename ElementTypeT>
+const ElementTypeT& UnknownElement::CastTo() const
+{
+ ConstCastVisitor_T<ElementTypeT> castVisitor;
+ m_pImp->Accept(castVisitor);
+ if (castVisitor.m_pElement == 0)
+ throw Exception("Bad cast");
+ return *castVisitor.m_pElement;
+}
+
+
+
+template <typename ElementTypeT>
+ElementTypeT& UnknownElement::ConvertTo()
+{
+ CastVisitor_T<ElementTypeT> castVisitor;
+ m_pImp->Accept(castVisitor);
+ if (castVisitor.m_pElement == 0)
+ {
+ // we're not the right type. fix it & try again
+ *this = ElementTypeT();
+ m_pImp->Accept(castVisitor);
+ }
+
+ return *castVisitor.m_pElement;
+}
+
+
+inline void UnknownElement::Accept(ConstVisitor& visitor) const { m_pImp->Accept(visitor); }
+inline void UnknownElement::Accept(Visitor& visitor) { m_pImp->Accept(visitor); }
+
+
+inline bool UnknownElement::operator == (const UnknownElement& element) const
+{
+ return m_pImp->Compare(*element.m_pImp);
+}
+
+
+
+//////////////////
+// Object members
+
+
+inline Object::Member::Member(const std::string& nameIn, const UnknownElement& elementIn) :
+ name(nameIn), element(elementIn) {}
+
+inline bool Object::Member::operator == (const Member& member) const
+{
+ return name == member.name &&
+ element == member.element;
+}
+
+class Object::Finder : public std::unary_function<Object::Member, bool>
+{
+public:
+ Finder(const std::string& name) : m_name(name) {}
+ bool operator () (const Object::Member& member) {
+ return member.name == m_name;
+ }
+
+private:
+ std::string m_name;
+};
+
+
+
+inline Object::iterator Object::Begin() { return m_Members.begin(); }
+inline Object::iterator Object::End() { return m_Members.end(); }
+inline Object::const_iterator Object::Begin() const { return m_Members.begin(); }
+inline Object::const_iterator Object::End() const { return m_Members.end(); }
+
+inline size_t Object::Size() const { return m_Members.size(); }
+inline bool Object::Empty() const { return m_Members.empty(); }
+
+inline Object::iterator Object::Find(const std::string& name)
+{
+ return std::find_if(m_Members.begin(), m_Members.end(), Finder(name));
+}
+
+inline Object::const_iterator Object::Find(const std::string& name) const
+{
+ return std::find_if(m_Members.begin(), m_Members.end(), Finder(name));
+}
+
+inline Object::iterator Object::Insert(const Member& member)
+{
+ return Insert(member, End());
+}
+
+inline Object::iterator Object::Insert(const Member& member, iterator itWhere)
+{
+ iterator it = Find(member.name);
+ if (it != m_Members.end())
+ throw Exception("Object member already exists: " + member.name);
+
+ it = m_Members.insert(itWhere, member);
+ return it;
+}
+
+inline Object::iterator Object::Erase(iterator itWhere)
+{
+ return m_Members.erase(itWhere);
+}
+
+inline UnknownElement& Object::operator [](const std::string& name)
+{
+
+ iterator it = Find(name);
+ if (it == m_Members.end())
+ {
+ Member member(name);
+ it = Insert(member, End());
+ }
+ return it->element;
+}
+
+inline const UnknownElement& Object::operator [](const std::string& name) const
+{
+ const_iterator it = Find(name);
+ if (it == End())
+ throw Exception("Object member not found: " + name);
+ return it->element;
+}
+
+inline void Object::Clear()
+{
+ m_Members.clear();
+}
+
+inline bool Object::operator == (const Object& object) const
+{
+ return m_Members == object.m_Members;
+}
+
+
+/////////////////
+// Array members
+
+inline Array::iterator Array::Begin() { return m_Elements.begin(); }
+inline Array::iterator Array::End() { return m_Elements.end(); }
+inline Array::const_iterator Array::Begin() const { return m_Elements.begin(); }
+inline Array::const_iterator Array::End() const { return m_Elements.end(); }
+
+inline Array::iterator Array::Insert(const UnknownElement& element, iterator itWhere)
+{
+ return m_Elements.insert(itWhere, element);
+}
+
+inline Array::iterator Array::Insert(const UnknownElement& element)
+{
+ return Insert(element, End());
+}
+
+inline Array::iterator Array::Erase(iterator itWhere)
+{
+ return m_Elements.erase(itWhere);
+}
+
+inline void Array::Resize(size_t newSize)
+{
+ m_Elements.resize(newSize);
+}
+
+inline size_t Array::Size() const { return m_Elements.size(); }
+inline bool Array::Empty() const { return m_Elements.empty(); }
+
+inline UnknownElement& Array::operator[] (size_t index)
+{
+ size_t nMinSize = index + 1; // zero indexed
+ if (m_Elements.size() < nMinSize)
+ m_Elements.resize(nMinSize);
+ return m_Elements[index];
+}
+
+inline const UnknownElement& Array::operator[] (size_t index) const
+{
+ if (index >= m_Elements.size())
+ throw Exception("Array out of bounds");
+ return m_Elements[index];
+}
+
+inline void Array::Clear() {
+ m_Elements.clear();
+}
+
+inline bool Array::operator == (const Array& array) const
+{
+ return m_Elements == array.m_Elements;
+}
+
+
+////////////////////////
+// TrivialType_T members
+
+template <typename DataTypeT>
+TrivialType_T<DataTypeT>::TrivialType_T(const DataTypeT& t) :
+ m_tValue(t) {}
+
+template <typename DataTypeT>
+TrivialType_T<DataTypeT>::operator DataTypeT&()
+{
+ return Value();
+}
+
+template <typename DataTypeT>
+TrivialType_T<DataTypeT>::operator const DataTypeT&() const
+{
+ return Value();
+}
+
+template <typename DataTypeT>
+DataTypeT& TrivialType_T<DataTypeT>::Value()
+{
+ return m_tValue;
+}
+
+template <typename DataTypeT>
+const DataTypeT& TrivialType_T<DataTypeT>::Value() const
+{
+ return m_tValue;
+}
+
+template <typename DataTypeT>
+bool TrivialType_T<DataTypeT>::operator == (const TrivialType_T<DataTypeT>& trivial) const
+{
+ return m_tValue == trivial.m_tValue;
+}
+
+
+
+//////////////////
+// Null members
+
+inline bool Null::operator == (const Null& trivial) const
+{
+ return true;
+}
+
+
+
+} // End namespace
diff --git a/protocols/FacebookRM/JSON_CAJUN/reader.h b/protocols/FacebookRM/JSON_CAJUN/reader.h new file mode 100644 index 0000000000..2f576c752e --- /dev/null +++ b/protocols/FacebookRM/JSON_CAJUN/reader.h @@ -0,0 +1,125 @@ +/**********************************************
+
+License: BSD
+Project Webpage: http://cajun-jsonapi.sourceforge.net/
+Author: Terry Caton
+
+***********************************************/
+
+#pragma once
+
+#include "elements.h"
+#include <iostream>
+#include <vector>
+
+namespace json
+{
+
+class Reader
+{
+public:
+ // this structure will be reported in one of the exceptions defined below
+ struct Location
+ {
+ Location();
+
+ unsigned int m_nLine; // document line, zero-indexed
+ unsigned int m_nLineOffset; // character offset from beginning of line, zero indexed
+ unsigned int m_nDocOffset; // character offset from entire document, zero indexed
+ };
+
+ // thrown during the first phase of reading. generally catches low-level problems such
+ // as errant characters or corrupt/incomplete documents
+ class ScanException : public Exception
+ {
+ public:
+ ScanException(const std::string& sMessage, const Reader::Location& locError) :
+ Exception(sMessage),
+ m_locError(locError) {}
+
+ Reader::Location m_locError;
+ };
+
+ // thrown during the second phase of reading. generally catches higher-level problems such
+ // as missing commas or brackets
+ class ParseException : public Exception
+ {
+ public:
+ ParseException(const std::string& sMessage, const Reader::Location& locTokenBegin, const Reader::Location& locTokenEnd) :
+ Exception(sMessage),
+ m_locTokenBegin(locTokenBegin),
+ m_locTokenEnd(locTokenEnd) {}
+
+ Reader::Location m_locTokenBegin;
+ Reader::Location m_locTokenEnd;
+ };
+
+
+ // if you know what the document looks like, call one of these...
+ static void Read(Object& object, std::istream& istr);
+ static void Read(Array& array, std::istream& istr);
+ static void Read(String& string, std::istream& istr);
+ static void Read(Number& number, std::istream& istr);
+ static void Read(Boolean& boolean, std::istream& istr);
+ static void Read(Null& null, std::istream& istr);
+
+ // ...otherwise, if you don't know, call this & visit it
+ static void Read(UnknownElement& elementRoot, std::istream& istr);
+
+private:
+ struct Token
+ {
+ enum Type
+ {
+ TOKEN_OBJECT_BEGIN, // {
+ TOKEN_OBJECT_END, // }
+ TOKEN_ARRAY_BEGIN, // [
+ TOKEN_ARRAY_END, // ]
+ TOKEN_NEXT_ELEMENT, // ,
+ TOKEN_MEMBER_ASSIGN, // :
+ TOKEN_STRING, // "xxx"
+ TOKEN_NUMBER, // [+/-]000.000[e[+/-]000]
+ TOKEN_BOOLEAN, // true -or- false
+ TOKEN_NULL // null
+ };
+
+ Type nType;
+ std::string sValue;
+
+ // for malformed file debugging
+ Reader::Location locBegin;
+ Reader::Location locEnd;
+ };
+
+ class InputStream;
+ class TokenStream;
+ typedef std::vector<Token> Tokens;
+
+ template <typename ElementTypeT>
+ static void Read_i(ElementTypeT& element, std::istream& istr);
+
+ // scanning istream into token sequence
+ void Scan(Tokens& tokens, InputStream& inputStream);
+
+ void EatWhiteSpace(InputStream& inputStream);
+ void MatchString(std::string& sValue, InputStream& inputStream);
+ void MatchNumber(std::string& sNumber, InputStream& inputStream);
+ void MatchExpectedString(const std::string& sExpected, InputStream& inputStream);
+
+ // parsing token sequence into element structure
+ void Parse(UnknownElement& element, TokenStream& tokenStream);
+ void Parse(Object& object, TokenStream& tokenStream);
+ void Parse(Array& array, TokenStream& tokenStream);
+ void Parse(String& string, TokenStream& tokenStream);
+ void Parse(Number& number, TokenStream& tokenStream);
+ void Parse(Boolean& boolean, TokenStream& tokenStream);
+ void Parse(Null& null, TokenStream& tokenStream);
+
+ const std::string& MatchExpectedToken(Token::Type nExpected, TokenStream& tokenStream);
+};
+
+
+} // End namespace
+
+
+#include "reader.inl"
\ No newline at end of file diff --git a/protocols/FacebookRM/JSON_CAJUN/reader.inl b/protocols/FacebookRM/JSON_CAJUN/reader.inl new file mode 100644 index 0000000000..26339497a0 --- /dev/null +++ b/protocols/FacebookRM/JSON_CAJUN/reader.inl @@ -0,0 +1,524 @@ +/**********************************************
+
+License: BSD
+Project Webpage: http://cajun-jsonapi.sourceforge.net/
+Author: Terry Caton
+
+***********************************************/
+
+#include <cassert>
+#include <set>
+#include <sstream>
+
+/*
+
+TODO:
+* better documentation
+* unicode character decoding
+
+*/
+
+namespace json
+{
+
+
+ inline std::istream& operator >> (std::istream& istr, UnknownElement& elementRoot) {
+ Reader::Read(elementRoot, istr);
+ return istr;
+}
+
+inline Reader::Location::Location() :
+ m_nLine(0),
+ m_nLineOffset(0),
+ m_nDocOffset(0)
+{}
+
+
+//////////////////////
+// Reader::InputStream
+
+class Reader::InputStream // would be cool if we could inherit from std::istream & override "get"
+{
+public:
+ InputStream(std::istream& iStr) :
+ m_iStr(iStr) {}
+
+ // protect access to the input stream, so we can keeep track of document/line offsets
+ char Get(); // big, define outside
+ char Peek() {
+ assert(m_iStr.eof() == false); // enforce reading of only valid stream data
+ return m_iStr.peek();
+ }
+
+ bool EOS() {
+ m_iStr.peek(); // apparently eof flag isn't set until a character read is attempted. whatever.
+ return m_iStr.eof();
+ }
+
+ const Location& GetLocation() const { return m_Location; }
+
+private:
+ std::istream& m_iStr;
+ Location m_Location;
+};
+
+
+inline char Reader::InputStream::Get()
+{
+ assert(m_iStr.eof() == false); // enforce reading of only valid stream data
+ char c = m_iStr.get();
+
+ ++m_Location.m_nDocOffset;
+ if (c == '\n') {
+ ++m_Location.m_nLine;
+ m_Location.m_nLineOffset = 0;
+ }
+ else {
+ ++m_Location.m_nLineOffset;
+ }
+
+ return c;
+}
+
+
+
+//////////////////////
+// Reader::TokenStream
+
+class Reader::TokenStream
+{
+public:
+ TokenStream(const Tokens& tokens);
+
+ const Token& Peek();
+ const Token& Get();
+
+ bool EOS() const;
+
+private:
+ const Tokens& m_Tokens;
+ Tokens::const_iterator m_itCurrent;
+};
+
+
+inline Reader::TokenStream::TokenStream(const Tokens& tokens) :
+ m_Tokens(tokens),
+ m_itCurrent(tokens.begin())
+{}
+
+inline const Reader::Token& Reader::TokenStream::Peek() {
+ assert(m_itCurrent != m_Tokens.end());
+ return *(m_itCurrent);
+}
+
+inline const Reader::Token& Reader::TokenStream::Get() {
+ assert(m_itCurrent != m_Tokens.end());
+ return *(m_itCurrent++);
+}
+
+inline bool Reader::TokenStream::EOS() const {
+ return m_itCurrent == m_Tokens.end();
+}
+
+///////////////////
+// Reader (finally)
+
+
+inline void Reader::Read(Object& object, std::istream& istr) { Read_i(object, istr); }
+inline void Reader::Read(Array& array, std::istream& istr) { Read_i(array, istr); }
+inline void Reader::Read(String& string, std::istream& istr) { Read_i(string, istr); }
+inline void Reader::Read(Number& number, std::istream& istr) { Read_i(number, istr); }
+inline void Reader::Read(Boolean& boolean, std::istream& istr) { Read_i(boolean, istr); }
+inline void Reader::Read(Null& null, std::istream& istr) { Read_i(null, istr); }
+inline void Reader::Read(UnknownElement& unknown, std::istream& istr) { Read_i(unknown, istr); }
+
+
+template <typename ElementTypeT>
+void Reader::Read_i(ElementTypeT& element, std::istream& istr)
+{
+ Reader reader;
+
+ Tokens tokens;
+ InputStream inputStream(istr);
+ reader.Scan(tokens, inputStream);
+
+ TokenStream tokenStream(tokens);
+ reader.Parse(element, tokenStream);
+
+ if (tokenStream.EOS() == false)
+ {
+ const Token& token = tokenStream.Peek();
+ std::string sMessage = "Expected End of token stream; found " + token.sValue;
+ throw ParseException(sMessage, token.locBegin, token.locEnd);
+ }
+}
+
+
+inline void Reader::Scan(Tokens& tokens, InputStream& inputStream)
+{
+ while (EatWhiteSpace(inputStream), // ignore any leading white space...
+ inputStream.EOS() == false) // ...before checking for EOS
+ {
+ // if all goes well, we'll create a token each pass
+ Token token;
+ token.locBegin = inputStream.GetLocation();
+
+ // gives us null-terminated string
+ std::string sChar;
+ sChar.push_back(inputStream.Peek());
+
+ switch (sChar[0])
+ {
+ case '{':
+ token.sValue = sChar[0];
+ MatchExpectedString(sChar, inputStream);
+ token.nType = Token::TOKEN_OBJECT_BEGIN;
+ break;
+
+ case '}':
+ token.sValue = sChar[0];
+ MatchExpectedString(sChar, inputStream);
+ token.nType = Token::TOKEN_OBJECT_END;
+ break;
+
+ case '[':
+ token.sValue = sChar[0];
+ MatchExpectedString(sChar, inputStream);
+ token.nType = Token::TOKEN_ARRAY_BEGIN;
+ break;
+
+ case ']':
+ token.sValue = sChar[0];
+ MatchExpectedString(sChar, inputStream);
+ token.nType = Token::TOKEN_ARRAY_END;
+ break;
+
+ case ',':
+ token.sValue = sChar[0];
+ MatchExpectedString(sChar, inputStream);
+ token.nType = Token::TOKEN_NEXT_ELEMENT;
+ break;
+
+ case ':':
+ token.sValue = sChar[0];
+ MatchExpectedString(sChar, inputStream);
+ token.nType = Token::TOKEN_MEMBER_ASSIGN;
+ break;
+
+ case '"':
+ MatchString(token.sValue, inputStream);
+ token.nType = Token::TOKEN_STRING;
+ break;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ MatchNumber(token.sValue, inputStream);
+ token.nType = Token::TOKEN_NUMBER;
+ break;
+
+ case 't':
+ token.sValue = "true";
+ MatchExpectedString(token.sValue, inputStream);
+ token.nType = Token::TOKEN_BOOLEAN;
+ break;
+
+ case 'f':
+ token.sValue = "false";
+ MatchExpectedString(token.sValue, inputStream);
+ token.nType = Token::TOKEN_BOOLEAN;
+ break;
+
+ case 'n':
+ token.sValue = "null";
+ MatchExpectedString(token.sValue, inputStream);
+ token.nType = Token::TOKEN_NULL;
+ break;
+
+ default: {
+ std::string sErrorMessage = "Unexpected character in stream: " + sChar;
+ throw ScanException(sErrorMessage, inputStream.GetLocation());
+ }
+ }
+
+ token.locEnd = inputStream.GetLocation();
+ tokens.push_back(token);
+ }
+}
+
+
+inline void Reader::EatWhiteSpace(InputStream& inputStream)
+{
+ while (inputStream.EOS() == false &&
+ ::isspace(inputStream.Peek()))
+ inputStream.Get();
+}
+
+inline void Reader::MatchExpectedString(const std::string& sExpected, InputStream& inputStream)
+{
+ std::string::const_iterator it(sExpected.begin()),
+ itEnd(sExpected.end());
+ for ( ; it != itEnd; ++it) {
+ if (inputStream.EOS() || // did we reach the end before finding what we're looking for...
+ inputStream.Get() != *it) // ...or did we find something different?
+ {
+ std::string sMessage = "Expected string: " + sExpected;
+ throw ScanException(sMessage, inputStream.GetLocation());
+ }
+ }
+
+ // all's well if we made it here, return quietly
+}
+
+
+inline void Reader::MatchString(std::string& string, InputStream& inputStream)
+{
+ MatchExpectedString("\"", inputStream);
+
+ while (inputStream.EOS() == false &&
+ inputStream.Peek() != '"')
+ {
+ char c = inputStream.Get();
+
+ // escape?
+ if (c == '\\' &&
+ inputStream.EOS() == false) // shouldn't have reached the end yet
+ {
+ c = inputStream.Get();
+ switch (c) {
+ case '/': string.push_back('/'); break;
+ case '"': string.push_back('"'); break;
+ case '\\': string.push_back('\\'); break;
+ case 'b': string.push_back('\b'); break;
+ case 'f': string.push_back('\f'); break;
+ case 'n': string.push_back('\n'); break;
+ case 'r': string.push_back('\r'); break;
+ case 't': string.push_back('\t'); break;
+//
+// misacek: Modification due to need
+//
+// case 'u': // TODO: what do we do with this?
+ case 'u': string.append("\\u"); break;
+//
+ default: {
+ std::string sMessage = "Unrecognized escape sequence found in string: \\" + c;
+ throw ScanException(sMessage, inputStream.GetLocation());
+ }
+ }
+ }
+ else {
+ string.push_back(c);
+ }
+ }
+
+ // eat the last '"' that we just peeked
+ MatchExpectedString("\"", inputStream);
+}
+
+
+inline void Reader::MatchNumber(std::string& sNumber, InputStream& inputStream)
+{
+ const char sNumericChars[] = "0123456789.eE-+";
+ std::set<char> numericChars;
+ numericChars.insert(sNumericChars, sNumericChars + sizeof(sNumericChars));
+
+ while (inputStream.EOS() == false &&
+ numericChars.find(inputStream.Peek()) != numericChars.end())
+ {
+ sNumber.push_back(inputStream.Get());
+ }
+}
+
+
+inline void Reader::Parse(UnknownElement& element, Reader::TokenStream& tokenStream)
+{
+ if (tokenStream.EOS()) {
+ std::string sMessage = "Unexpected end of token stream";
+ throw ParseException(sMessage, Location(), Location()); // nowhere to point to
+ }
+
+ const Token& token = tokenStream.Peek();
+ switch (token.nType) {
+ case Token::TOKEN_OBJECT_BEGIN:
+ {
+ // implicit non-const cast will perform conversion for us (if necessary)
+ Object& object = element;
+ Parse(object, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_ARRAY_BEGIN:
+ {
+ Array& array = element;
+ Parse(array, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_STRING:
+ {
+ String& string = element;
+ Parse(string, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_NUMBER:
+ {
+ Number& number = element;
+ Parse(number, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_BOOLEAN:
+ {
+ Boolean& boolean = element;
+ Parse(boolean, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_NULL:
+ {
+ Null& null = element;
+ Parse(null, tokenStream);
+ break;
+ }
+
+ default:
+ {
+ std::string sMessage = "Unexpected token: " + token.sValue;
+ throw ParseException(sMessage, token.locBegin, token.locEnd);
+ }
+ }
+}
+
+
+inline void Reader::Parse(Object& object, Reader::TokenStream& tokenStream)
+{
+ MatchExpectedToken(Token::TOKEN_OBJECT_BEGIN, tokenStream);
+
+ bool bContinue = (tokenStream.EOS() == false &&
+ tokenStream.Peek().nType != Token::TOKEN_OBJECT_END);
+ while (bContinue)
+ {
+ Object::Member member;
+
+ // first the member name. save the token in case we have to throw an exception
+ const Token& tokenName = tokenStream.Peek();
+ member.name = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
+
+ // ...then the key/value separator...
+ MatchExpectedToken(Token::TOKEN_MEMBER_ASSIGN, tokenStream);
+
+ // ...then the value itself (can be anything).
+ Parse(member.element, tokenStream);
+
+ // try adding it to the object (this could throw)
+ try
+ {
+ object.Insert(member);
+ }
+ catch (Exception&)
+ {
+ // must be a duplicate name
+ std::string sMessage = "Duplicate object member token: " + member.name;
+ throw ParseException(sMessage, tokenName.locBegin, tokenName.locEnd);
+ }
+
+ bContinue = (tokenStream.EOS() == false &&
+ tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT);
+ if (bContinue)
+ MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream);
+ }
+
+ MatchExpectedToken(Token::TOKEN_OBJECT_END, tokenStream);
+}
+
+
+inline void Reader::Parse(Array& array, Reader::TokenStream& tokenStream)
+{
+ MatchExpectedToken(Token::TOKEN_ARRAY_BEGIN, tokenStream);
+
+ bool bContinue = (tokenStream.EOS() == false &&
+ tokenStream.Peek().nType != Token::TOKEN_ARRAY_END);
+ while (bContinue)
+ {
+ // ...what's next? could be anything
+ Array::iterator itElement = array.Insert(UnknownElement());
+ UnknownElement& element = *itElement;
+ Parse(element, tokenStream);
+
+ bContinue = (tokenStream.EOS() == false &&
+ tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT);
+ if (bContinue)
+ MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream);
+ }
+
+ MatchExpectedToken(Token::TOKEN_ARRAY_END, tokenStream);
+}
+
+
+inline void Reader::Parse(String& string, Reader::TokenStream& tokenStream)
+{
+ string = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
+}
+
+
+inline void Reader::Parse(Number& number, Reader::TokenStream& tokenStream)
+{
+ const Token& currentToken = tokenStream.Peek(); // might need this later for throwing exception
+ const std::string& sValue = MatchExpectedToken(Token::TOKEN_NUMBER, tokenStream);
+
+ std::istringstream iStr(sValue);
+ double dValue;
+ iStr >> dValue;
+
+ // did we consume all characters in the token?
+ if (iStr.eof() == false)
+ {
+ std::string sMessage = "Unexpected character in NUMBER token: " + iStr.peek();
+ throw ParseException(sMessage, currentToken.locBegin, currentToken.locEnd);
+ }
+
+ number = dValue;
+}
+
+
+inline void Reader::Parse(Boolean& boolean, Reader::TokenStream& tokenStream)
+{
+ const std::string& sValue = MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream);
+ boolean = (sValue == "true" ? true : false);
+}
+
+
+inline void Reader::Parse(Null&, Reader::TokenStream& tokenStream)
+{
+ MatchExpectedToken(Token::TOKEN_NULL, tokenStream);
+}
+
+
+inline const std::string& Reader::MatchExpectedToken(Token::Type nExpected, Reader::TokenStream& tokenStream)
+{
+ if (tokenStream.EOS())
+ {
+ std::string sMessage = "Unexpected End of token stream";
+ throw ParseException(sMessage, Location(), Location()); // nowhere to point to
+ }
+
+ const Token& token = tokenStream.Get();
+ if (token.nType != nExpected)
+ {
+ std::string sMessage = "Unexpected token: " + token.sValue;
+ throw ParseException(sMessage, token.locBegin, token.locEnd);
+ }
+
+ return token.sValue;
+}
+
+} // End namespace
diff --git a/protocols/FacebookRM/JSON_CAJUN/visitor.h b/protocols/FacebookRM/JSON_CAJUN/visitor.h new file mode 100644 index 0000000000..8a28d7a64a --- /dev/null +++ b/protocols/FacebookRM/JSON_CAJUN/visitor.h @@ -0,0 +1,44 @@ +/**********************************************
+
+License: BSD
+Project Webpage: http://cajun-jsonapi.sourceforge.net/
+Author: Terry Caton
+
+***********************************************/
+
+#pragma once
+
+#include "elements.h"
+
+namespace json
+{
+
+
+class Visitor
+{
+public:
+ virtual ~Visitor() {}
+
+ virtual void Visit(Array& array) = 0;
+ virtual void Visit(Object& object) = 0;
+ virtual void Visit(Number& number) = 0;
+ virtual void Visit(String& string) = 0;
+ virtual void Visit(Boolean& boolean) = 0;
+ virtual void Visit(Null& null) = 0;
+};
+
+class ConstVisitor
+{
+public:
+ virtual ~ConstVisitor() {}
+
+ virtual void Visit(const Array& array) = 0;
+ virtual void Visit(const Object& object) = 0;
+ virtual void Visit(const Number& number) = 0;
+ virtual void Visit(const String& string) = 0;
+ virtual void Visit(const Boolean& boolean) = 0;
+ virtual void Visit(const Null& null) = 0;
+};
+
+
+} // End namespace
diff --git a/protocols/FacebookRM/JSON_CAJUN/writer.h b/protocols/FacebookRM/JSON_CAJUN/writer.h new file mode 100644 index 0000000000..c364bcb289 --- /dev/null +++ b/protocols/FacebookRM/JSON_CAJUN/writer.h @@ -0,0 +1,57 @@ +/**********************************************
+
+License: BSD
+Project Webpage: http://cajun-jsonapi.sourceforge.net/
+Author: Terry Caton
+
+***********************************************/
+
+#pragma once
+
+#include "elements.h"
+#include "visitor.h"
+
+namespace json
+{
+
+class Writer : private ConstVisitor
+{
+public:
+ static void Write(const Object& object, std::ostream& ostr);
+ static void Write(const Array& array, std::ostream& ostr);
+ static void Write(const String& string, std::ostream& ostr);
+ static void Write(const Number& number, std::ostream& ostr);
+ static void Write(const Boolean& boolean, std::ostream& ostr);
+ static void Write(const Null& null, std::ostream& ostr);
+ static void Write(const UnknownElement& elementRoot, std::ostream& ostr);
+
+private:
+ Writer(std::ostream& ostr);
+
+ template <typename ElementTypeT>
+ static void Write_i(const ElementTypeT& element, std::ostream& ostr);
+
+ void Write_i(const Object& object);
+ void Write_i(const Array& array);
+ void Write_i(const String& string);
+ void Write_i(const Number& number);
+ void Write_i(const Boolean& boolean);
+ void Write_i(const Null& null);
+ void Write_i(const UnknownElement& unknown);
+
+ virtual void Visit(const Array& array);
+ virtual void Visit(const Object& object);
+ virtual void Visit(const Number& number);
+ virtual void Visit(const String& string);
+ virtual void Visit(const Boolean& boolean);
+ virtual void Visit(const Null& null);
+
+ std::ostream& m_ostr;
+ int m_nTabDepth;
+};
+
+
+} // End namespace
+
+
+#include "writer.inl"
\ No newline at end of file diff --git a/protocols/FacebookRM/JSON_CAJUN/writer.inl b/protocols/FacebookRM/JSON_CAJUN/writer.inl new file mode 100644 index 0000000000..eeb3db94b9 --- /dev/null +++ b/protocols/FacebookRM/JSON_CAJUN/writer.inl @@ -0,0 +1,153 @@ +/**********************************************
+
+License: BSD
+Project Webpage: http://cajun-jsonapi.sourceforge.net/
+Author: Terry Caton
+
+***********************************************/
+
+#include "writer.h"
+#include <iostream>
+#include <iomanip>
+
+/*
+
+TODO:
+* better documentation
+* unicode character encoding
+
+*/
+
+namespace json
+{
+
+
+inline void Writer::Write(const UnknownElement& elementRoot, std::ostream& ostr) { Write_i(elementRoot, ostr); }
+inline void Writer::Write(const Object& object, std::ostream& ostr) { Write_i(object, ostr); }
+inline void Writer::Write(const Array& array, std::ostream& ostr) { Write_i(array, ostr); }
+inline void Writer::Write(const Number& number, std::ostream& ostr) { Write_i(number, ostr); }
+inline void Writer::Write(const String& string, std::ostream& ostr) { Write_i(string, ostr); }
+inline void Writer::Write(const Boolean& boolean, std::ostream& ostr) { Write_i(boolean, ostr); }
+inline void Writer::Write(const Null& null, std::ostream& ostr) { Write_i(null, ostr); }
+
+
+inline Writer::Writer(std::ostream& ostr) :
+ m_ostr(ostr),
+ m_nTabDepth(0)
+{}
+
+template <typename ElementTypeT>
+void Writer::Write_i(const ElementTypeT& element, std::ostream& ostr)
+{
+ Writer writer(ostr);
+ writer.Write_i(element);
+ ostr.flush(); // all done
+}
+
+inline void Writer::Write_i(const Array& array)
+{
+ if (array.Empty())
+ m_ostr << "[]";
+ else
+ {
+ m_ostr << '[' << std::endl;
+ ++m_nTabDepth;
+
+ Array::const_iterator it(array.Begin()),
+ itEnd(array.End());
+ while (it != itEnd) {
+ m_ostr << std::string(m_nTabDepth, '\t');
+
+ Write_i(*it);
+
+ if (++it != itEnd)
+ m_ostr << ',';
+ m_ostr << std::endl;
+ }
+
+ --m_nTabDepth;
+ m_ostr << std::string(m_nTabDepth, '\t') << ']';
+ }
+}
+
+inline void Writer::Write_i(const Object& object)
+{
+ if (object.Empty())
+ m_ostr << "{}";
+ else
+ {
+ m_ostr << '{' << std::endl;
+ ++m_nTabDepth;
+
+ Object::const_iterator it(object.Begin()),
+ itEnd(object.End());
+ while (it != itEnd) {
+ m_ostr << std::string(m_nTabDepth, '\t') << '"' << it->name << "\" : ";
+ Write_i(it->element);
+
+ if (++it != itEnd)
+ m_ostr << ',';
+ m_ostr << std::endl;
+ }
+
+ --m_nTabDepth;
+ m_ostr << std::string(m_nTabDepth, '\t') << '}';
+ }
+}
+
+inline void Writer::Write_i(const Number& numberElement)
+{
+ m_ostr << std::setprecision(20) << numberElement.Value();
+}
+
+inline void Writer::Write_i(const Boolean& booleanElement)
+{
+ m_ostr << (booleanElement.Value() ? "true" : "false");
+}
+
+inline void Writer::Write_i(const String& stringElement)
+{
+ m_ostr << '"';
+
+ const std::string& s = stringElement.Value();
+ std::string::const_iterator it(s.begin()),
+ itEnd(s.end());
+ for (; it != itEnd; ++it)
+ {
+ switch (*it)
+ {
+ case '"': m_ostr << "\\\""; break;
+ case '\\': m_ostr << "\\\\"; break;
+ case '\b': m_ostr << "\\b"; break;
+ case '\f': m_ostr << "\\f"; break;
+ case '\n': m_ostr << "\\n"; break;
+ case '\r': m_ostr << "\\r"; break;
+ case '\t': m_ostr << "\\t"; break;
+ //case '\u': m_ostr << ""; break; ??
+ default: m_ostr << *it; break;
+ }
+ }
+
+ m_ostr << '"';
+}
+
+inline void Writer::Write_i(const Null& )
+{
+ m_ostr << "null";
+}
+
+inline void Writer::Write_i(const UnknownElement& unknown)
+{
+ unknown.Accept(*this);
+}
+
+inline void Writer::Visit(const Array& array) { Write_i(array); }
+inline void Writer::Visit(const Object& object) { Write_i(object); }
+inline void Writer::Visit(const Number& number) { Write_i(number); }
+inline void Writer::Visit(const String& string) { Write_i(string); }
+inline void Writer::Visit(const Boolean& boolean) { Write_i(boolean); }
+inline void Writer::Visit(const Null& null) { Write_i(null); }
+
+
+
+} // End namespace
diff --git a/protocols/FacebookRM/_changelog.txt b/protocols/FacebookRM/_changelog.txt new file mode 100644 index 0000000000..556d59a9e2 --- /dev/null +++ b/protocols/FacebookRM/_changelog.txt @@ -0,0 +1,303 @@ +
+0.1.3.2
+-------
+
+- Revision of proper SSL request composition
+- Added a check to disallow running with Miranda 0.10 alpha build #1
+- (Finally) fixed a crash invocation due to inproper handling with close window
+procedure data
+
+0.1.3.1
+-------
+
+- Fixed crash invocation when trying to set empty/NULL status message
+- Removed unneeded self-profile update on sending wall post
+- Fixed Facebook Messages URL when clicking on a notification
+- Fixed balloon notifications artefacts
+- Fixed showing events when not enabled
+- Fixed notifying of 0 new messages
+- Fixed a crash invoked when closing of web chat windows enabled
+- Fixed a memory leak inside windows closing function
+
+0.1.3.0
+-------
+
+- Improved detection of missing avatar
+- Better self-idle handling
+- Added advanced options for Notifications
+- Fixed HTTP requests time-out handling to match 0.9.14+ way
+- Improved error logging
+- Added an option to close chat windows on web
+- Added support for sending and receiving typing notifications
+- Better reconnect/keep-alive procedures (hopefully)
+- Fix for popup on-click hyperlinks
+- Fix for HTML in notifications and feeds
+- Fixed logout procedure
+- Contacts going offline no more shown when logging out
+
+0.1.2.1
+-------
+
+- Added an option to forge usage of secure (HTTPS) connection
+- Rewritten status menu items creation code to work properly with new Miranda 0.9 feature to move them into main menu
+- Fixed memory leak when processing messages and notifications
+- Fixed a crash caused by internal list implementation
+- Work-around fix for disconnecting issues due to core time-out handling changes
+
+0.1.2.0
+-------
+
+- Fixed thread forking causing enormous number of dead handles being not closed as they should
+- New enhanced storage for buddy list during runtime (mainly solves data leaks with previous solution)
+- Thread synchronization & data locking revision (may prevent crashes, buffer overflows etc.)
+- Optimized code flow on various places (prevents data leaks, prettier code etc.)
+- Revised Debug build & its settings (f.e. memory leaks logging)
+- Fixed proper acknowledge of Offline status to core when signing off (no clist redraw required)
+
+0.1.1.2
+-------
+
+- Quick fix for change in Logout procedure/bug when receiving logout action
+- Introducing new friend requests and new messages notifications when logging in (working when notifications enabled)
+
+0.1.1.1
+-------
+
+- Quick fix for change in machine security response code
+- Quick fix for changes in setting and clearing Mind status
+- Contact is marked as online when receiving a message before Buddy list update loop makes him online
+
+0.1.1.0
+-------
+
+- Added per-user lock for future usage
+- Added storing of all headers for requests -- store_cookies( ) refactored to store_headers( )
+- Added notification sound -- ShowEvent( ) refactored to NotifyEvent( )
+- Added work-around to work with Machine security feature
+- Fixed API check required due to Google Code wiki changes
+- Dropped old Home page support
+- Added code to support notifying about new messages
+- Added code to support notifying about new friend requests
+- Fixed getting away message to proper differentiate ANSI/Unicode requests
+- Fixed NSL on Contact info page
+- Fixed global Offline status when signing off Facebook
+- Fixed (probably) missing conversion of messages between ANSI/Unicode/UTF-8
+- Fixed processing Feeds
+- Added hidden feature to set Ignore Online notification by default
+
+0.1.0.2
+-------
+
+- (Hopefully) fixed avatar issue (own avatar bundled with some contacts)
+- Preparation for PopUp linking with contacts
+- Revision of contact update rules
+- Translation improvements
+
+0.1.0.1
+-------
+
+- Instant fix for changed URLs of Facebook Chat servers
+- Fix for a high CPU usage issue caused by mistake in handling connection errors
+
+0.1.0.0
+-------
+
+- Replaced JSON_C by CAJUN JSON parser
+- Fixed minor avatar-related crash
+- Added support for a redesigned Facebook site
+- Minor buddy list thread-safety improvement
+- Minor code refactoring
+- Added Notifications
+- Added API version checking
+- Improved logging low-level process
+...
+
+0.0.0.7
+-------
+
+- Fixed occasional blocking crash on startup caused by missing personal avatar
+file
+- Reworked contacts parsing
+- Thread-safe buddy loop
+- Featuring notifications, including Live Feed
+- More encoding options in HTTP traffic
+- More proper parsing of homepage
+- Renamed html_special_chars_decode to special_expressions_decode
+- Enhanced threads killing and locking
+- Improved sign-off
+- Fixed broken keep-alive hadling
+- Rewritten contacts update logic
+- Redesigned "What's on my mind" dialog
+- Fixed some JSON parser bugs
+- Fixed default user-agent string
+- Fixed contacts status to be loaded before protocol is marked online
+- Simplified number-to-string convertor definitions
+
+0.0.0.6
+-------
+
+- Added internal _APP logging (not present in public releases)
+- Some more logging events
+- Made HTTP headers to be quite "static" during runtime (enhanced handling +
+manipulation)
+- Optimized User agent storage manipulation
+- Improved HTTP request success/error handling
+- Lot of strings and data pointers moved from char-fields to C++ std::string +
+optimized usage, getting rid of possible leaks
+- Added secret DB option to disable performing Logout action when signing off
+- Fixed serious JSON parser comparison typos (= -> ==)
+- Fixed usage of int intead of proper std::string::size_type where applicable
+- Fixed conversion of HTML entities which appeared in users' real names and
+status messages
+- Fixed incorrect sequence number incrementation (caused minor looping and
+receiving messages multiple times)
+- Fixed updating avatars + status messages in some cases (f.e. when contact has
+no status message set)
+- Optimized utils::time functions
+- Optimized and fixed utils::number::random to return integer instead of strict
+std::string
+- Added utils::conversion::to_string function (as this is often usable :) +
+macros for use as a data type parameter
+- Added utils::text::find_first function (as an front-end for std::string
+searching)
+- Added utils::text::html_special_chars and html_special_chars_decode
+- Renamed utils::text::find_all to count_all to match what this function really
+does
+- Removed some unused variables
+
+Notes:
+- 100% CPU usage issue should be gone now, but in case it doesn't, you don't have to kill Miranda, turning protocol off, then disabling it and re-enabling it again should be enough
+
+0.0.0.5
+-------
+
+- Added loading of own avatar and status message
+- Added option to set Facebook "What's on my mind?" via Miranda status message system
+- Better handling of own credentials (own nickname, avatar, status)
+- Fixed serious mistake in Message server URL generation which caused all accounts using channels 01--09 to disconnect immediately
+- Added timeout limitation + response success/error system
+- Heavily optimized service of updating contacts' details + moved into separate threads to project buddy updates immediately
+- Logging system improvements
+- Processing improvements
+- Initial translation support
+- Proper logout request
+- Handling of non-supported statuses -- Offline + Invisible results in Offline status, otherwise you're marked as Online
+- Fix for a condition deciding whether buddy list update is needed
+- Re-factorized some functions to better fit a proper object model
+- Proper milliseconds time stamp for outgoing messages
+- Signing off is signalized with "Connecting" icon (Experimental)
+- Removed some rare HTTP User-Agents
+- Editing E-mail and Password impossible when Online (Experimental)
+- Simplified JSON parser entry point
+- Modified memory-freeing function, should solve related rare crashes
+- Fix for a crash when calling Cookies dialog (I hope)
+- Logging files are now properly placed inside Miranda root only, no more mess elsewhere
+- Each account now has it's own logging file
+- Removed force disconnection flag for messages-updating request -- this request usually times out from time to time
+- Removed unneeded new-lines from protocol logs
+- 2 hidden variables: (BYTE)EnableRealLogoutSignal and (BYTE)TimeoutsLimit
+
+Notes:
+- You'll have to delete all your contacts and let them reload (or at least delete their DB "RealName" values or rename them to "Nick"), otherwise contacts will stay unnamed in the CL - the names weren't handled 100% correctly, the same as unique user identification.
+- Own avatar is now handled and processed, so it's visible where possible (tabSRMM, inside Tipper when hovering account icon in statusbar, ...)
+- Real names updating option has gone from now as contact's RealName/Nick value is updated normally, if you want anyone to have custom name, you can edit it like elsewhere (clist module stores this elsewhere and prioritizes this value before others)
+
+Known issues:
+- [FIXED] 100% CPU usage issue
+
+0.0.0.4
+-------
+
+- Finally reached persistent connection - silent session refresh + periodical reconnect like original web client - although the connection may fall down, restrictive politics will disconnect when any error occurs (mostly server time-out)
+- Redesigned session control to fit original web client
+- Raised default update loop poll rate to 24 seconds - less traffic, optimal processing load side by side with message loop, which has poll rate of 55 seconds when not active
+- Work-around for last protocol change (not receiving status message with periodical updates) by loading mobile profile page to get the data (maybe usable for other user details in future)
+- Rewritten update process to request only changes since last check for updates - minimal traffic, noticefuly reduced processing load
+- Completely rewritten contacts handling - this solves a) avatar flickering b) updating status, real name and idle flag too often
+- Fixed reloading avatar when not needed
+- Parsing improvements (solves many issues like buffer overruns/overflows)
+- Fixed leak of User-Agent strings
+- Better handling of garbage collecting on shutdown
+- Possibility to see actual cookies via Options dialog
+- Optional toggling of logging (default off)
+- Extra icon for "Mind" function
+- Light performance improvements in getting data from results
+- More sophisticated logging system
+
+Known issues:
+
+- [FIXED] Status messages may contain HTML character entities for some specific characters
+- [FIXED] Protocol is signed off each time server times out -- will be changed in next version, disconnecting only when connection is down (more exactly when reaching 3 time-outs, while error increments time-out counter, success decrements -- cheap, but working solution)
+- [FIXED] Accounts linked with message servers 0.channel01--0.channel09 can't connect for more than just a few seconds followed by possible crash because of my beginner's bug in URL generation causing fake connection time-out
+
+0.0.0.3
+-------
+
+- Isolated response processings (avoiding crashes)
+- Fixed crashes caused by illegal processing of foreign typing notifications
+- Added a response validation & logout mechanism which safely closes connection and threads on disconnection/logout
+- Removed Away status, inactivity is controlled by server as Idle
+- Raised minimal poll rate to 10 seconds (interval of updating contact list)
+- Removed some unneeded code
+- Added an option to change user-agent (if FB would ever like to block us, hahah xD)
+- Fixed message server URL "virginity" flag :))
+
+Known issues:
+
+- [FIXED] Login session gets down after some time (should be more than 1 hour), the reason or a way to avoid this is not known to me, yet
+
+0.0.0.2
+-------
+
+- Fixed JSON parsing issues, now data change should be OK
+- Repaired timestamps for outgoing messages
+- Added "Clear" option in Mind dialog (when no Mind status filled in)
+- Added Mind status item toggling (hidden when offline, shown otherwise)
+- Added safer logout
+- Fixed Updater support (I hope :))
+- Poll rate customization
+- Implemented idle/away, but not working on the server :/
+- Improvements in a logging system
+- Some code reorganization, mainly making some processing safe
+- More pretty code management
+
+Known issues:
+
+- [FIXED] Crash is invoked when receiving typing notification from FB with no message followed in a "packet" (both events use similar format => bad exception for non-message content leading to buffer overrun)
+- [FIXED] Plugin doesn't detect when the connection is closed/logged out remotely (rarely, but may happen, may bring some crash)
+- [FIXED] Avatars may flicker, their updating process hasn't been optimized, yet
+
+0.0.0.1
+-------
+
+- Working avatars
+- Improvements to JSON parsing, still needs pretty enhancements
+- Introducing smart-like logging
+- Many code management changes
+- Checked all dialogs validity
+- Bringing some basic options to work
+- Marked probably almost all memory leaks which should be solved
+- Marked some things to take a look on + solution options somewhere
+- Managed all TODOs
+- Removed some unneeded, deprecated and testing code
+
+Known issues:
+
+- [FIXED] Frequent crashes caused by saving cookies on login and when obtaining updates/messages periodically (parse error)
+
+0.0.0.0
+-------
+
+Private initial release
+
+All-time Issues
+---------------
+
+- Nothing, yet :)
+
+All-time Not-issues
+-------------------
+
+- Status messages are not set properly when you set them to often - server limit requires captcha confirmation when you flood
+- Being often disconnected - server fault, trying to find a work-around, but that's not easy - pidgin-facebookchat reports same thing
+- Away status as is not applicable, FB doesn't support any active/controllable Away status, only server-driven Idle.
diff --git a/protocols/FacebookRM/avatars.cpp b/protocols/FacebookRM/avatars.cpp new file mode 100644 index 0000000000..a316d9fe68 --- /dev/null +++ b/protocols/FacebookRM/avatars.cpp @@ -0,0 +1,233 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka
+
+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 <http://www.gnu.org/licenses/>.
+
+File name : $HeadURL: http://eternityplugins.googlecode.com/svn/trunk/facebook/avatars.cpp $
+Revision : $Revision: 91 $
+Last change by : $Author: n3weRm0re.ewer $
+Last change on : $Date: 2011-01-08 11:10:34 +0100 (so, 08 1 2011) $
+
+*/
+
+#include "common.h"
+
+bool FacebookProto::GetDbAvatarInfo(PROTO_AVATAR_INFORMATION &ai, std::string *url)
+{
+ DBVARIANT dbv;
+ if (!DBGetContactSettingString(ai.hContact, m_szModuleName, FACEBOOK_KEY_AV_URL, &dbv))
+ {
+ std::string new_url = dbv.pszVal;
+ DBFreeVariant(&dbv);
+
+ if (new_url.empty())
+ return false;
+
+ if (url)
+ *url = new_url;
+
+ if (!DBGetContactSettingString(ai.hContact, m_szModuleName, FACEBOOK_KEY_ID, &dbv))
+ {
+ std::string ext = new_url.substr(new_url.rfind('.'));
+ std::string filename = GetAvatarFolder() + '\\' + dbv.pszVal + ext;
+ DBFreeVariant(&dbv);
+
+ ai.hContact = ai.hContact;
+ ai.format = ext_to_format(ext);
+ strncpy(ai.filename, filename.c_str(), sizeof(ai.filename));
+ ai.filename[sizeof(ai.filename)-1] = 0;
+
+ return true;
+ }
+ }
+ return false;
+}
+
+void FacebookProto::CheckAvatarChange(HANDLE hContact, std::string image_url)
+{
+ // Facebook contacts always have some avatar - keep avatar in database even if we have loaded empty one (e.g. for 'On Mobile' contacts)
+ if (image_url.empty())
+ return;
+
+ if (DBGetContactSettingByte(NULL, m_szModuleName, FACEBOOK_KEY_BIG_AVATARS, DEFAULT_BIG_AVATARS))
+ {
+ std::string::size_type pos = image_url.rfind( "_q." );
+ if (pos != std::string::npos)
+ image_url = image_url.replace( pos, 3, "_s." );
+ }
+
+ DBVARIANT dbv;
+ bool update_required = true;
+ if (!DBGetContactSettingString(hContact, m_szModuleName, FACEBOOK_KEY_AV_URL, &dbv))
+ {
+ update_required = image_url != dbv.pszVal;
+ DBFreeVariant(&dbv);
+ }
+ if (update_required || !hContact)
+ {
+ DBWriteContactSettingString(hContact, m_szModuleName, FACEBOOK_KEY_AV_URL, image_url.c_str());
+ if (hContact)
+ ProtoBroadcastAck(m_szModuleName, hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
+ else
+ {
+ PROTO_AVATAR_INFORMATION ai = {sizeof(ai)};
+ if (GetAvatarInfo(update_required ? GAIF_FORCE : 0, (LPARAM)&ai) != GAIR_WAITFOR)
+ CallService(MS_AV_REPORTMYAVATARCHANGED, (WPARAM)m_szModuleName, 0);
+ }
+ }
+}
+
+void FacebookProto::UpdateAvatarWorker(void *)
+{
+ HANDLE nlc = NULL;
+
+ LOG("***** UpdateAvatarWorker");
+
+ for (;;)
+ {
+ std::string url;
+ PROTO_AVATAR_INFORMATION ai = {sizeof(ai)};
+ ai.hContact = avatar_queue[0];
+
+ if (Miranda_Terminated())
+ {
+ LOG("***** Terminating avatar update early: %s", url.c_str());
+ break;
+ }
+
+ if (GetDbAvatarInfo(ai, &url))
+ {
+ LOG("***** Updating avatar: %s", url.c_str());
+ bool success = facy.save_url(url, std::string(ai.filename), nlc);
+
+ if (ai.hContact)
+ ProtoBroadcastAck(m_szModuleName, ai.hContact, ACKTYPE_AVATAR, success ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, (HANDLE)&ai, 0);
+ else if (success)
+ CallService(MS_AV_REPORTMYAVATARCHANGED, (WPARAM)m_szModuleName, 0);
+ }
+
+ ScopedLock s(avatar_lock_);
+ avatar_queue.erase(avatar_queue.begin());
+ if (avatar_queue.empty())
+ break;
+ }
+ Netlib_CloseHandle(nlc);
+}
+
+std::string FacebookProto::GetAvatarFolder()
+{
+ char path[MAX_PATH];
+ if ( hAvatarFolder_ && FoldersGetCustomPath(hAvatarFolder_,path,sizeof(path), "") == 0 )
+ return path;
+ else
+ return def_avatar_folder_;
+}
+
+int FacebookProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
+{
+ int res = 0;
+
+ switch (wParam)
+ {
+ case AF_MAXSIZE:
+ ((POINT*)lParam)->x = -1;
+ ((POINT*)lParam)->y = -1;
+ break;
+
+ case AF_MAXFILESIZE:
+ res = 0;
+ break;
+
+ case AF_PROPORTION:
+ res = PIP_NONE;
+ break;
+
+ case AF_FORMATSUPPORTED:
+ res = (lParam == PA_FORMAT_JPEG || lParam == PA_FORMAT_GIF);
+ break;
+
+ case AF_DELAYAFTERFAIL:
+ res = 60 * 1000;
+ break;
+
+ case AF_ENABLED:
+ case AF_DONTNEEDDELAYS:
+ case AF_FETCHALWAYS:
+ res = 1;
+ break;
+ }
+
+ return res;
+}
+
+int FacebookProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam)
+{
+ if (!lParam)
+ return GAIR_NOAVATAR;
+
+ PROTO_AVATAR_INFORMATION* AI = ( PROTO_AVATAR_INFORMATION* )lParam;
+
+ if (GetDbAvatarInfo(*AI, NULL))
+ {
+ if (_access(AI->filename, 0) || (wParam & GAIF_FORCE))
+ {
+ LOG("***** Starting avatar request thread for %s", AI->filename);
+ ScopedLock s( avatar_lock_ );
+
+ if (std::find(avatar_queue.begin(), avatar_queue.end(), AI->hContact) == avatar_queue.end())
+ {
+ bool is_empty = avatar_queue.empty();
+ avatar_queue.push_back(AI->hContact);
+ if (is_empty)
+ ForkThread(&FacebookProto::UpdateAvatarWorker, this, NULL);
+ }
+
+ return GAIR_WAITFOR;
+ }
+
+ LOG("***** Giving AvatarInfo: %s", AI->filename);
+ return GAIR_SUCCESS;
+ }
+ return GAIR_NOAVATAR;
+}
+
+int FacebookProto::GetMyAvatar(WPARAM wParam, LPARAM lParam)
+{
+ LOG("***** GetMyAvatar");
+
+ if (!wParam || !lParam)
+ return -3;
+
+ char* buf = ( char* )wParam;
+ int size = ( int )lParam;
+
+ PROTO_AVATAR_INFORMATION ai = {sizeof(ai)};
+ switch (GetAvatarInfo(0, (LPARAM)&ai))
+ {
+ case GAIR_SUCCESS:
+ strncpy(buf, ai.filename, size);
+ buf[size-1] = 0;
+ return 0;
+
+ case GAIR_WAITFOR:
+ return -1;
+
+ default:
+ return -2;
+ }
+}
diff --git a/protocols/FacebookRM/avatars.h b/protocols/FacebookRM/avatars.h new file mode 100644 index 0000000000..18f8e1c100 --- /dev/null +++ b/protocols/FacebookRM/avatars.h @@ -0,0 +1,32 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+struct update_avatar
+{
+ update_avatar(HANDLE hContact,const std::string &url,const std::string &file)
+ : hContact(hContact),url(url),file(file) {}
+
+ HANDLE hContact;
+ std::string url, file;
+};
diff --git a/protocols/FacebookRM/chat.cpp b/protocols/FacebookRM/chat.cpp new file mode 100644 index 0000000000..7326254541 --- /dev/null +++ b/protocols/FacebookRM/chat.cpp @@ -0,0 +1,317 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+void FacebookProto::UpdateChat(const char *chat_id, const char *id, const char *name, const char *message)
+{
+ GCDEST gcd = { m_szModuleName };
+ gcd.ptszID = mir_a2t(chat_id);
+
+ GCEVENT gce = {sizeof(gce)};
+ gce.pDest = &gcd;
+ gce.ptszText = mir_a2t_cp(message,CP_UTF8);
+ gce.time = ::time(NULL);
+ gce.dwFlags = GC_TCHAR;
+ gcd.iType = GC_EVENT_MESSAGE;
+ gce.bIsMe = !strcmp(id,facy.self_.user_id.c_str());
+ gce.dwFlags |= GCEF_ADDTOLOG;
+
+ gce.ptszNick = mir_a2t_cp(name,CP_UTF8);
+ gce.ptszUID = mir_a2t(id);
+
+ CallServiceSync(MS_GC_EVENT,0,reinterpret_cast<LPARAM>(&gce));
+
+ mir_free(const_cast<TCHAR*>(gce.ptszUID));
+ mir_free(const_cast<TCHAR*>(gce.ptszNick));
+ mir_free(const_cast<TCHAR*>(gce.ptszText));
+ mir_free(const_cast<TCHAR*>(gcd.ptszID));
+
+
+ // Close chat window, if set
+ ForkThread( &FacebookProto::MessagingWorker, this, new send_messaging(chat_id, FACEBOOK_SEND_MESSAGE ) );
+}
+
+int FacebookProto::OnChatOutgoing(WPARAM wParam,LPARAM lParam)
+{
+ GCHOOK *hook = reinterpret_cast<GCHOOK*>(lParam);
+ char *text;
+ char *id;
+
+ if (strcmp(hook->pDest->pszModule,m_szModuleName))
+ return 0;
+
+ switch(hook->pDest->iType)
+ {
+ case GC_USER_MESSAGE:
+ {
+ text = mir_t2a_cp(hook->ptszText,CP_UTF8);
+ std::string msg = text;
+
+ id = mir_t2a_cp(hook->pDest->ptszID,CP_UTF8);
+ std::string chat_id = id;
+
+ mir_free(text);
+ mir_free(id);
+
+ if (isOnline()) {
+ LOG("**Chat - Outgoing message: %s", text);
+ ForkThread(&FacebookProto::SendChatMsgWorker, this, new send_chat(chat_id, msg) );
+ }
+
+ break;
+ }
+
+ case GC_USER_LEAVE:
+ case GC_SESSION_TERMINATE:
+ {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void FacebookProto::AddChatContact(const char *chat_id, const char *id, const char *name)
+{
+ GCDEST gcd = { m_szModuleName };
+ gcd.ptszID = mir_a2t(chat_id);
+ gcd.iType = GC_EVENT_JOIN;
+
+ GCEVENT gce = {sizeof(gce)};
+ gce.pDest = &gcd;
+ gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG;
+ gce.ptszNick = mir_a2t_cp(name, CP_UTF8);
+ gce.ptszUID = mir_a2t(id);
+ gce.time = ::time(NULL);
+ gce.bIsMe = !strcmp(id, facy.self_.user_id.c_str());
+
+ if (gce.bIsMe)
+ gce.ptszStatus = _T("Admin");
+ else
+ gce.ptszStatus = _T("Normal");
+
+ CallServiceSync(MS_GC_EVENT,0,reinterpret_cast<LPARAM>(&gce));
+
+ mir_free(const_cast<TCHAR*>(gce.ptszNick));
+ mir_free(const_cast<TCHAR*>(gce.ptszUID));
+ mir_free(const_cast<TCHAR*>(gcd.ptszID));
+}
+
+
+void FacebookProto::RemoveChatContact(const char *chat_id, const char *id)
+{
+ // We dont want to remove our self-contact from chat. Ever.
+ if (!strcmp(id, facy.self_.user_id.c_str()))
+ return;
+
+ GCDEST gcd = { m_szModuleName };
+ gcd.ptszID = mir_a2t(chat_id);
+ gcd.iType = GC_EVENT_PART;
+
+ GCEVENT gce = {sizeof(gce)};
+ gce.pDest = &gcd;
+ gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG;
+ //gce.ptszNick = mir_a2t_cp(name, CP_UTF8);
+ gce.ptszUID = mir_a2t(id);
+ gce.ptszNick = gce.ptszUID;
+ gce.time = ::time(NULL);
+ gce.bIsMe = false;//!strcmp(id, facy.self_.user_id.c_str());
+
+ CallServiceSync(MS_GC_EVENT,0,reinterpret_cast<LPARAM>(&gce));
+
+ mir_free(const_cast<TCHAR*>(gcd.ptszID));
+ mir_free(const_cast<TCHAR*>(gce.ptszNick));
+ mir_free(const_cast<TCHAR*>(gce.ptszUID));
+}
+
+char *FacebookProto::GetChatUsers(const char *chat_id)
+{
+ GC_INFO gci = {0};
+ gci.Flags = USERS;
+ gci.pszModule = m_szModuleName;
+ gci.pszID = mir_a2t(chat_id);
+ CallService(MS_GC_GETINFO, 0, (LPARAM)(GC_INFO *) &gci);
+
+ LOG("**Chat - Users in chat %s: %s", chat_id, gci.pszUsers);
+
+ mir_free(gci.pszID);
+
+ // mir_free(gci.pszUsers);
+ return gci.pszUsers;
+}
+
+bool FacebookProto::IsChatContact(const char *chat_id, const char *id)
+{
+ char *users = GetChatUsers(chat_id);
+ bool found = false;
+
+ if (users != NULL && strstr(users, id) != NULL)
+ found = true;
+
+ mir_free(users);
+ return found;
+}
+
+void FacebookProto::AddChat(const char *id, const char *name)
+{
+ GCSESSION gcw = {sizeof(gcw)};
+
+ // Create the group chat session
+ gcw.dwFlags = GC_TCHAR;
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszModule = m_szModuleName;
+ gcw.ptszName = mir_a2t_cp(name, CP_UTF8);
+ gcw.ptszID = mir_a2t(id);
+ CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw);
+
+ mir_free(const_cast<TCHAR*>(gcw.ptszName));
+ mir_free(const_cast<TCHAR*>(gcw.ptszID));
+
+ // Send setting events
+ GCDEST gcd = { m_szModuleName };
+ gcd.ptszID = mir_a2t(id);
+
+ GCEVENT gce = {sizeof(gce)};
+ gce.pDest = &gcd;
+ gce.dwFlags = GC_TCHAR;
+
+ // Create a user statuses
+ gcd.iType = GC_EVENT_ADDGROUP;
+ gce.ptszStatus = _T("Admin");
+ CallServiceSync( MS_GC_EVENT, NULL, reinterpret_cast<LPARAM>(&gce) );
+ gce.ptszStatus = _T("Normal");
+ CallServiceSync( MS_GC_EVENT, NULL, reinterpret_cast<LPARAM>(&gce) );
+
+ // Finish initialization
+ gcd.iType = GC_EVENT_CONTROL;
+ gce.time = ::time(NULL);
+ gce.pDest = &gcd;
+
+ // Add self contact
+ AddChatContact(id, facy.self_.user_id.c_str(), facy.self_.real_name.c_str());
+ CallServiceSync(MS_GC_EVENT,SESSION_INITDONE,reinterpret_cast<LPARAM>(&gce));
+ CallServiceSync(MS_GC_EVENT,SESSION_ONLINE, reinterpret_cast<LPARAM>(&gce));
+
+ mir_free(const_cast<TCHAR*>(gcd.ptszID));
+}
+
+/*void FacebookProto::SetTopic(const char *topic)
+{
+ GCDEST gcd = { m_szModuleName };
+ gcd.ptszID = const_cast<TCHAR*>(m_tszUserName);
+ gcd.iType = GC_EVENT_TOPIC;
+
+ GCEVENT gce = {sizeof(gce)};
+ gce.pDest = &gcd;
+ gce.dwFlags = GC_TCHAR;
+ gce.time = ::time(NULL);
+
+ std::string top = Translate(topic);
+ gce.ptszText = mir_a2t(top.c_str());
+ CallServiceSync(MS_GC_EVENT,0, reinterpret_cast<LPARAM>(&gce));
+}
+*/
+
+int FacebookProto::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_ONLINE)
+ return 0;
+
+ // Create a group
+ GCDEST gcd = { m_szModuleName };
+ gcd.ptszID = const_cast<TCHAR*>(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<LPARAM>(&gce) );
+
+ gce.ptszStatus = _T("Normal");
+ CallServiceSync( MS_GC_EVENT, NULL, reinterpret_cast<LPARAM>(&gce) );
+
+ SetTopic("Omegle is a great way of meeting new friends!");
+
+ // Note: Initialization will finish up in SetChatStatus, called separately
+ if(!suppress)
+ SetChatStatus(m_iStatus);
+*/
+ return 0;
+}
+
+int FacebookProto::OnLeaveChat(WPARAM,LPARAM)
+{
+ GCDEST gcd = { m_szModuleName };
+ gcd.ptszID = NULL;
+ 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<LPARAM>(&gce));
+ CallServiceSync(MS_GC_EVENT,SESSION_TERMINATE,reinterpret_cast<LPARAM>(&gce));
+
+ return 0;
+}
+
+/*
+void FacebookProto::SetChatStatus(int status)
+{
+ GCDEST gcd = { m_szModuleName };
+ gcd.ptszID = const_cast<TCHAR*>(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)
+ {
+ // Add self contact
+ AddChatContact(facy.nick_.c_str());
+
+ CallServiceSync(MS_GC_EVENT,SESSION_INITDONE,reinterpret_cast<LPARAM>(&gce));
+ CallServiceSync(MS_GC_EVENT,SESSION_ONLINE, reinterpret_cast<LPARAM>(&gce));
+ }
+ else
+ {
+ CallServiceSync(MS_GC_EVENT,SESSION_OFFLINE,reinterpret_cast<LPARAM>(&gce));
+ }
+}
+*/
\ No newline at end of file diff --git a/protocols/FacebookRM/client.h b/protocols/FacebookRM/client.h new file mode 100644 index 0000000000..40555c2dfc --- /dev/null +++ b/protocols/FacebookRM/client.h @@ -0,0 +1,189 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+#define FORCE_DISCONNECT true
+
+class facebook_client
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+
+ // Client definition
+
+ facebook_client( )
+ {
+ username_ = password_ = \
+ post_form_id_ = dtsg_ = \
+ chat_sequence_num_ = chat_channel_host_ = chat_channel_partition_ = chat_channel_jslogger_ = \
+ logout_hash_ = "";
+
+ msgid_ = error_count_ = last_feeds_update_ = last_notification_time_ = 0;
+
+ https_ = is_idle_ = invisible_ = is_typing_ = false;
+
+ buddies_lock_ = send_message_lock_ = NULL;
+ hMsgCon = NULL;
+ hFcbCon = NULL;
+ fcb_conn_lock_ = NULL;
+ }
+
+ HANDLE hMsgCon;
+ HANDLE hFcbCon;
+ HANDLE fcb_conn_lock_;
+
+ // Parent handle
+
+ FacebookProto* parent;
+
+ // User data
+
+ facebook_user self_;
+
+ std::string username_;
+ std::string password_;
+
+ std::string post_form_id_;
+ std::string dtsg_;
+ std::string logout_hash_;
+ std::string chat_channel_host_;
+ std::string chat_channel_jslogger_;
+ std::string chat_channel_partition_;
+ std::string chat_sequence_num_;
+ std::string chat_reconnect_reason_;
+ bool invisible_;
+ bool is_typing_;
+ bool is_idle_;
+ bool https_;
+ time_t last_feeds_update_;
+ unsigned __int64 last_notification_time_;
+ int msgid_;
+
+ ////////////////////////////////////////////////////////////
+
+ // Client vs protocol communication
+
+ void client_notify( TCHAR* message );
+
+ ////////////////////////////////////////////////////////////
+
+ // Cookies, Data storage
+
+ HANDLE cookies_lock_;
+
+ std::map< std::string, std::string > cookies;
+
+ std::string get_newsfeed_type( );
+
+ char* load_cookies( );
+ void store_headers( http::response* resp, NETLIBHTTPHEADER* headers, int headers_count );
+ void clear_cookies( );
+
+ ////////////////////////////////////////////////////////////
+
+ // Connection handling
+
+ unsigned int error_count_;
+
+ bool validate_response( http::response* );
+
+ bool handle_entry( std::string method );
+ bool handle_success( std::string method );
+ bool handle_error( std::string method, bool force_disconnect = false );
+
+ void __inline increment_error( ) { this->error_count_++; }
+ void __inline decrement_error( ) { if ( error_count_ > 0 ) error_count_--; }
+ void __inline reset_error( ) { error_count_ = 0; }
+
+ ////////////////////////////////////////////////////////////
+
+ // Login handling
+
+ bool login( const std::string &username, const std::string &password );
+ bool logout( );
+
+ const std::string & get_username() const;
+
+ ////////////////////////////////////////////////////////////
+
+ // Session handling
+
+ bool home( );
+ bool reconnect( );
+ bool chat_state( bool online = true );
+
+ ////////////////////////////////////////////////////////////
+
+ // Updates handling
+
+ List::List< facebook_user > buddies;
+ HANDLE buddies_lock_;
+ HANDLE send_message_lock_;
+
+ bool buddy_list( );
+ bool load_friends( );
+ bool feeds( );
+
+ ////////////////////////////////////////////////////////////
+
+ // Messages handling
+
+ bool channel( );
+ bool send_message( std::string message_recipient, std::string message_text, std::string *error_text, bool use_inbox = false );
+ void close_chat( std::string message_recipient );
+ void chat_mark_read( std::string message_recipient );
+
+ ////////////////////////////////////////////////////////////
+
+ // Status handling
+
+ bool set_status(const std::string &text);
+
+ ////////////////////////////////////////////////////////////
+
+ // HTTP communication
+
+ http::response flap( const int request_type, std::string* request_data = NULL, std::string* request_get_data = NULL );
+ bool save_url(const std::string &url,const std::string &filename, HANDLE &nlc);
+
+ DWORD choose_security_level( int );
+ int choose_method( int );
+ std::string choose_proto( int );
+ std::string choose_server( int, std::string* data = NULL, std::string* get_data = NULL );
+ std::string choose_action( int, std::string* data = NULL, std::string* get_data = NULL );
+ std::string choose_request_url( int, std::string* data = NULL, std::string* get_data = NULL );
+
+ NETLIBHTTPHEADER* get_request_headers( int request_type, int* headers_count );
+
+ ////////////////////////////////////////////////////////////
+
+ // Netlib handle
+
+ HANDLE handle_;
+
+ void set_handle(HANDLE h)
+ {
+ handle_ = h;
+ }
+};
diff --git a/protocols/FacebookRM/common.h b/protocols/FacebookRM/common.h new file mode 100644 index 0000000000..b1f2d2ce90 --- /dev/null +++ b/protocols/FacebookRM/common.h @@ -0,0 +1,106 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+//#pragma warning(push)
+//#pragma warning(disable:4312)
+#pragma warning(disable:4996)
+
+#define MIRANDA_VER 0x1000
+#define _WIN32_WINNT 0x0500
+#define _WIN32_WINDOWS 0x0500
+
+#include <m_stdhdr.h>
+
+#include <string>
+#include <sstream>
+#include <fstream>
+#include <list>
+#include <map>
+#include <vector>
+#include <algorithm>
+
+#include <stdarg.h>
+#include <time.h>
+#include <assert.h>
+#include <io.h>
+
+#include <windows.h>
+#include <win2k.h>
+#include <commctrl.h>
+
+#include <newpluginapi.h>
+#include <m_version.h>
+#include <m_system.h>
+#include <m_system_cpp.h>
+#include <m_avatars.h>
+#include <m_button.h>
+#include <m_chat.h>
+#include <m_clc.h>
+#include <m_clist.h>
+#include <m_clistint.h>
+#include <m_clui.h>
+#include <m_database.h>
+#include <m_history.h>
+#include <m_idle.h>
+#include <m_ignore.h>
+#include <m_langpack.h>
+#include <m_message.h>
+#include <m_netlib.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_protocols.h>
+#include <m_protosvc.h>
+#include <m_protoint.h>
+#include <m_protomod.h>
+#include <m_skin.h>
+#include <statusmodes.h>
+#include <m_userinfo.h>
+#include <m_addcontact.h>
+#include <m_icolib.h>
+#include <m_utils.h>
+#include <m_hotkeys.h>
+
+#include <m_updater.h>
+#include <m_folders.h>
+
+class FacebookProto;
+
+#include "definitions.h"
+#include "entities.h"
+#include "avatars.h"
+#include "http.h"
+#include "list.hpp"
+#include "utils.h"
+#include "client.h"
+#include "proto.h"
+#include "json.h"
+#include "db.h"
+#include "constants.h"
+#include "dialogs.h"
+#include "theme.h"
+#include "resource.h"
+
+extern HINSTANCE g_hInstance;
+extern std::string g_strUserAgent;
+extern DWORD g_mirandaVersion;
\ No newline at end of file diff --git a/protocols/FacebookRM/communication.cpp b/protocols/FacebookRM/communication.cpp new file mode 100644 index 0000000000..d17e40e5a5 --- /dev/null +++ b/protocols/FacebookRM/communication.cpp @@ -0,0 +1,1314 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+void facebook_client::client_notify( TCHAR* message )
+{
+ parent->NotifyEvent( parent->m_tszUserName, message, NULL, FACEBOOK_EVENT_CLIENT );
+}
+
+http::response facebook_client::flap( const int request_type, std::string* request_data, std::string* request_get_data )
+{
+ NETLIBHTTPREQUEST nlhr = {sizeof( NETLIBHTTPREQUEST )};
+ nlhr.requestType = choose_method( request_type );
+ std::string url = choose_request_url( request_type, request_data, request_get_data );
+ nlhr.szUrl = (char*)url.c_str( );
+ nlhr.flags = NLHRF_HTTP11 | NLHRF_NODUMP | choose_security_level( request_type );
+ nlhr.headers = get_request_headers( request_type, &nlhr.headersCount );
+
+ switch (request_type)
+ {
+ case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+ nlhr.timeout = 1000 * 65; break;
+ case FACEBOOK_REQUEST_MESSAGE_SEND:
+ nlhr.timeout = 1000 * 10; break;
+ default:
+ nlhr.timeout = 1000 * 15; break;
+ }
+
+ if ( request_data != NULL )
+ {
+ nlhr.pData = (char*)(*request_data).c_str();
+ nlhr.dataLength = (int)request_data->length( );
+ }
+
+ parent->Log("@@@@@ Sending request to '%s'", nlhr.szUrl);
+
+ switch ( request_type )
+ {
+ case FACEBOOK_REQUEST_LOGIN:
+ nlhr.nlc = NULL;
+ break;
+
+ case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+ nlhr.nlc = hMsgCon;
+ nlhr.flags |= NLHRF_PERSISTENT;
+ break;
+
+ default:
+ WaitForSingleObject(fcb_conn_lock_, INFINITE);
+ nlhr.nlc = hFcbCon;
+ nlhr.flags |= NLHRF_PERSISTENT;
+ break;
+ }
+
+ NETLIBHTTPREQUEST* pnlhr = ( NETLIBHTTPREQUEST* )CallService( MS_NETLIB_HTTPTRANSACTION, (WPARAM)handle_, (LPARAM)&nlhr );
+
+ utils::mem::detract(nlhr.headers[3].szValue);
+ utils::mem::detract(nlhr.headers);
+
+ http::response resp;
+
+ switch ( request_type )
+ {
+ case FACEBOOK_REQUEST_LOGIN:
+ case FACEBOOK_REQUEST_SETUP_MACHINE:
+ break;
+
+ case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+ hMsgCon = pnlhr ? pnlhr->nlc : NULL;
+ break;
+
+ default:
+ ReleaseMutex(fcb_conn_lock_);
+ hFcbCon = pnlhr ? pnlhr->nlc : NULL;
+ break;
+ }
+
+ if ( pnlhr != NULL )
+ {
+ parent->Log("@@@@@ Got response with code %d", pnlhr->resultCode);
+ store_headers( &resp, pnlhr->headers, pnlhr->headersCount );
+ resp.code = pnlhr->resultCode;
+ resp.data = pnlhr->pData ? pnlhr->pData : "";
+
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pnlhr);
+ } else {
+ parent->Log("!!!!! No response from server (time-out)");
+ resp.code = HTTP_CODE_FAKE_DISCONNECTED;
+ // Better to have something set explicitely as this value
+ // is compaired in all communication requests
+ }
+
+ if (DBGetContactSettingByte( NULL, parent->m_szModuleName, FACEBOOK_KEY_VALIDATE_RESPONSE, 0 ) == 1)
+ validate_response(&resp);
+
+ return resp;
+}
+
+bool facebook_client::validate_response( http::response* resp )
+{
+ if ( resp->code == HTTP_CODE_FAKE_DISCONNECTED )
+ {
+ parent->Log(" ! ! Request has timed out, connection or server error");
+ return false;
+ }
+
+ if (DBGetContactSettingByte( NULL, parent->m_szModuleName, FACEBOOK_KEY_VALIDATE_RESPONSE, 0 ) == 2) {
+ return true;
+ }
+
+/*
+ // TODO: Is this from jarvis? Or me? Add it?
+ std::string cookie = utils::text::source_get_value(&resp->data, 2, "setCookie(\\\"", ");");
+ if (!cookie.empty()) {
+ std::string cookie_name = utils::text::source_get_value(&cookie, 1, "\\\"");
+ std::string cookie_value = utils::text::source_get_value(&cookie, 3, "\\\"", "\\\"", "\\\"");
+
+ parent->Log(" New cookie from response '%s': %s", cookie_name.c_str(), cookie_value.c_str());
+ this->cookies[cookie_name] = cookie_value;
+ }
+*/
+ std::string::size_type pos = resp->data.find( "\"error\":" );
+ if ( pos != std::string::npos )
+ try
+ {
+ pos += 8;
+ int error_num = atoi( resp->data.substr( pos, resp->data.find( ",", pos ) - pos ).c_str() );
+ if ( error_num != 0 )
+ {
+ std::string error = "";
+ pos = resp->data.find( "\"errorDescription\":\"", pos );
+ if (pos != std::string::npos ) {
+ pos += 20;
+ error = resp->data.substr( pos, resp->data.find( "\"", pos ) - pos );
+ error = utils::text::trim(
+ utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( error ) ) );
+
+ }
+
+ resp->error_number = error_num;
+ resp->error_text = error;
+ parent->Log(" ! ! Received Facebook error: %d -- %s", error_num, error.c_str());
+ // client_notify( ... );
+ resp->code = HTTP_CODE_FAKE_ERROR;
+ return false;
+ }
+ } catch (const std::exception &e) {
+ parent->Log(" @ @ validate_response: Exception: %s",e.what());
+ return false;
+ }
+
+ return true;
+}
+
+bool facebook_client::handle_entry( std::string method )
+{
+ parent->Log(" >> Entering %s()", method.c_str());
+ return true;
+}
+
+bool facebook_client::handle_success( std::string method )
+{
+ parent->Log(" << Quitting %s()", method.c_str());
+ reset_error();
+ return true;
+}
+
+bool facebook_client::handle_error( std::string method, bool force_disconnect )
+{
+ bool result;
+ increment_error();
+ parent->Log("!!!!! %s(): Something with Facebook went wrong", method.c_str());
+
+ if ( force_disconnect )
+ result = false;
+ else if ( error_count_ <= (UINT)DBGetContactSettingByte(NULL,parent->m_szModuleName,FACEBOOK_KEY_TIMEOUTS_LIMIT,FACEBOOK_TIMEOUTS_LIMIT))
+ result = true;
+ else
+ result = false;
+
+ if ( result == false )
+ {
+ reset_error();
+ parent->SetStatus(ID_STATUS_OFFLINE);
+ }
+
+ return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+DWORD facebook_client::choose_security_level( int request_type )
+{
+ if (this->https_)
+ {
+ if ( request_type != FACEBOOK_REQUEST_MESSAGES_RECEIVE
+ || DBGetContactSettingByte( NULL, parent->m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL, DEFAULT_FORCE_HTTPS_CHANNEL ) )
+ return NLHRF_SSL;
+ }
+
+ switch ( request_type )
+ {
+ case FACEBOOK_REQUEST_LOGIN:
+ case FACEBOOK_REQUEST_SETUP_MACHINE:
+ return NLHRF_SSL;
+
+// case FACEBOOK_REQUEST_LOGOUT:
+// case FACEBOOK_REQUEST_HOME:
+// case FACEBOOK_REQUEST_BUDDY_LIST:
+// case FACEBOOK_REQUEST_LOAD_FRIENDS:
+// case FACEBOOK_REQUEST_DELETE_FRIEND:
+// case FACEBOOK_REQUEST_ADD_FRIEND:
+// case FACEBOOK_REQUEST_FEEDS:
+// case FACEBOOK_REQUEST_NOTIFICATIONS:
+// case FACEBOOK_REQUEST_RECONNECT:
+// case FACEBOOK_REQUEST_STATUS_SET:
+// case FACEBOOK_REQUEST_MESSAGE_SEND:
+// case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+// case FACEBOOK_REQUEST_VISIBILITY:
+// case FACEBOOK_REQUEST_TABS:
+// case FACEBOOK_REQUEST_ASYNC:
+// case FACEBOOK_REQUEST_TYPING_SEND:
+ default:
+ return ( DWORD )0;
+ }
+}
+
+int facebook_client::choose_method( int request_type )
+{
+ switch ( request_type )
+ {
+ case FACEBOOK_REQUEST_LOGIN:
+ case FACEBOOK_REQUEST_SETUP_MACHINE:
+ case FACEBOOK_REQUEST_BUDDY_LIST:
+ case FACEBOOK_REQUEST_STATUS_SET:
+ case FACEBOOK_REQUEST_MESSAGE_SEND:
+ case FACEBOOK_REQUEST_VISIBILITY:
+ case FACEBOOK_REQUEST_TABS:
+ case FACEBOOK_REQUEST_ASYNC:
+ case FACEBOOK_REQUEST_TYPING_SEND:
+ case FACEBOOK_REQUEST_LOGOUT:
+ case FACEBOOK_REQUEST_DELETE_FRIEND:
+ case FACEBOOK_REQUEST_ADD_FRIEND:
+ return REQUEST_POST;
+
+// case FACEBOOK_REQUEST_HOME:
+// case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+// case FACEBOOK_REQUEST_FEEDS:
+// case FACEBOOK_REQUEST_NOTIFICATIONS:
+// case FACEBOOK_REQUEST_RECONNECT:
+// case FACEBOOK_REQUEST_LOAD_FRIENDS:
+ default:
+ return REQUEST_GET;
+ }
+}
+
+std::string facebook_client::choose_proto( int request_type )
+{
+ if (this->https_) {
+ if ( request_type != FACEBOOK_REQUEST_MESSAGES_RECEIVE
+ || DBGetContactSettingByte( NULL, parent->m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL, DEFAULT_FORCE_HTTPS_CHANNEL ) )
+ return HTTP_PROTO_SECURE;
+ }
+
+ switch ( request_type )
+ {
+// case FACEBOOK_REQUEST_LOGOUT:
+// case FACEBOOK_REQUEST_HOME:
+// case FACEBOOK_REQUEST_FEEDS:
+// case FACEBOOK_REQUEST_NOTIFICATIONS:
+// case FACEBOOK_REQUEST_RECONNECT:
+// case FACEBOOK_REQUEST_BUDDY_LIST:
+// case FACEBOOK_REQUEST_LOAD_FRIENDS:
+// case FACEBOOK_REQUEST_STATUS_SET:
+// case FACEBOOK_REQUEST_MESSAGE_SEND:
+// case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+// case FACEBOOK_REQUEST_VISIBILITY:
+// case FACEBOOK_REQUEST_TABS:
+// case FACEBOOK_REQUEST_ASYNC:
+// case FACEBOOK_REQUEST_TYPING_SEND:
+// case FACEBOOK_REQUEST_DELETE_FRIEND:
+// case FACEBOOK_REQUEST_ADD_FRIEND:
+ default:
+ return HTTP_PROTO_REGULAR;
+
+ case FACEBOOK_REQUEST_LOGIN:
+ case FACEBOOK_REQUEST_SETUP_MACHINE:
+ return HTTP_PROTO_SECURE;
+ }
+}
+
+std::string facebook_client::choose_server( int request_type, std::string* data, std::string* get_data )
+{
+ switch ( request_type )
+ {
+ case FACEBOOK_REQUEST_LOGIN:
+ return FACEBOOK_SERVER_LOGIN;
+
+ case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+ {
+ std::string server = FACEBOOK_SERVER_CHAT;
+ if (!this->chat_channel_jslogger_.empty())
+ server = FACEBOOK_SERVER_CHAT2;
+
+ utils::text::replace_first( &server, "%s", "0" );
+ utils::text::replace_first( &server, "%s", this->chat_channel_host_ );
+ return server;
+ }
+
+// case FACEBOOK_REQUEST_LOGOUT:
+// case FACEBOOK_REQUEST_HOME:
+// case FACEBOOK_REQUEST_BUDDY_LIST:
+// case FACEBOOK_REQUEST_LOAD_FRIENDS:
+// case FACEBOOK_REQUEST_FEEDS:
+// case FACEBOOK_REQUEST_NOTIFICATIONS:
+// case FACEBOOK_REQUEST_RECONNECT:
+// case FACEBOOK_REQUEST_STATUS_SET:
+// case FACEBOOK_REQUEST_MESSAGE_SEND:
+// case FACEBOOK_REQUEST_VISIBILITY:
+// case FACEBOOK_REQUEST_TABS:
+// case FACEBOOK_REQUEST_ASYNC:
+// case FACEBOOK_REQUEST_TYPING_SEND:
+// case FACEBOOK_REQUEST_SETUP_MACHINE:
+// case FACEBOOK_REQUEST_DELETE_FRIEND:
+// case FACEBOOK_REQUEST_ADD_FRIEND:
+ default:
+ return FACEBOOK_SERVER_REGULAR;
+ }
+}
+
+std::string facebook_client::choose_action( int request_type, std::string* data, std::string* get_data )
+{
+ switch ( request_type )
+ {
+ case FACEBOOK_REQUEST_LOGIN:
+ return "/login.php?login_attempt=1";
+
+ case FACEBOOK_REQUEST_SETUP_MACHINE:
+ return "/checkpoint/";
+
+ case FACEBOOK_REQUEST_LOGOUT:
+ return "/logout.php";
+
+ case FACEBOOK_REQUEST_HOME:
+ return "/home.php?_fb_noscript=1";
+
+ case FACEBOOK_REQUEST_BUDDY_LIST:
+ return "/ajax/chat/buddy_list.php?__a=1";
+
+ case FACEBOOK_REQUEST_LOAD_FRIENDS:
+ {
+ std::string action = "/ajax/chat/user_info_all.php?__a=1&viewer=%s&__user=%s";
+ utils::text::replace_all( &action, "%s", self_.user_id );
+ return action;
+ }
+
+ case FACEBOOK_REQUEST_DELETE_FRIEND:
+ {
+ return "/ajax/profile/removefriend.php?__a=1";
+ }
+
+ case FACEBOOK_REQUEST_ADD_FRIEND:
+ {
+ return "/ajax/add_friend/action.php?__a=1";
+ }
+
+ case FACEBOOK_REQUEST_FEEDS:
+ {
+ std::string action = "/ajax/intent.php?filter=";
+ action += get_newsfeed_type();
+ action += "&request_type=4&__a=1&newest=%s&ignore_self=true&load_newer=true&__user=%s";
+ std::string newest = utils::conversion::to_string((void*)&this->last_feeds_update_, UTILS_CONV_TIME_T);
+ utils::text::replace_first( &action, "%s", newest );
+ utils::text::replace_first( &action, "%s", self_.user_id );
+ return action;
+ }
+
+ case FACEBOOK_REQUEST_NOTIFICATIONS:
+ {
+ std::string action = "/ajax/notifications/get.php?__a=1&user=%s&time=0&version=2&__user=%s";
+ utils::text::replace_all( &action, "%s", self_.user_id );
+ return action;
+ }
+
+ case FACEBOOK_REQUEST_RECONNECT:
+ {
+ std::string action = "/ajax/presence/reconnect.php?__a=1&reason=%s&fb_dtsg=%s&post_form_id=%s&__user=%s";
+
+ if (this->chat_reconnect_reason_.empty())
+ this->chat_reconnect_reason_ = "6";
+
+ utils::text::replace_first( &action, "%s", this->chat_reconnect_reason_ );
+ utils::text::replace_first( &action, "%s", this->dtsg_ );
+ utils::text::replace_first( &action, "%s", this->post_form_id_ );
+ utils::text::replace_first( &action, "%s", this->self_.user_id );
+ return action;
+ }
+
+ case FACEBOOK_REQUEST_STATUS_SET:
+ return "/ajax/updatestatus.php?__a=1";
+
+ case FACEBOOK_REQUEST_MESSAGE_SEND:
+ return "/ajax/chat/send.php?__a=1";
+
+ case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+ {
+ std::string action = "/x/%s/0/true/p_%s=%s";
+ if (!this->chat_channel_jslogger_.empty()) {
+ action = "/pull?clientid=&channel=p_%s&seq=%s&cb=&state=active";
+ //utils::text::replace_first( &action, "%s", dtsg_ );
+ } else {
+ utils::text::replace_first( &action, "%s", utils::time::unix_timestamp() );
+ }
+
+ utils::text::replace_first( &action, "%s", self_.user_id );
+ utils::text::replace_first( &action, "%s", chat_sequence_num_.empty() ? "0" : chat_sequence_num_ );
+ return action;
+ }
+
+ case FACEBOOK_REQUEST_VISIBILITY:
+ return "/ajax/chat/privacy/visibility.php?__a=1";
+
+ case FACEBOOK_REQUEST_TABS:
+ return "/ajax/chat/tabs.php?__a=1";
+
+ case FACEBOOK_REQUEST_ASYNC:
+ {
+ std::string action = "/ajax/messaging/async.php?__a=1";
+ if (get_data != NULL) {
+ action += "&" + (*get_data);
+ }
+ return action;
+ }
+
+ case FACEBOOK_REQUEST_TYPING_SEND:
+ return "/ajax/messaging/typ.php?__a=1";
+
+ default:
+ return "/?_fb_noscript=1";
+ }
+}
+
+std::string facebook_client::choose_request_url( int request_type, std::string* data, std::string* get_data )
+{
+ std::string url = choose_proto( request_type );
+ url.append( choose_server( request_type, data, get_data ) );
+ url.append( choose_action( request_type, data, get_data ) );
+ return url;
+}
+
+NETLIBHTTPHEADER* facebook_client::get_request_headers( int request_type, int* headers_count )
+{
+ switch ( request_type )
+ {
+ case FACEBOOK_REQUEST_LOGIN:
+ case FACEBOOK_REQUEST_SETUP_MACHINE:
+ case FACEBOOK_REQUEST_BUDDY_LIST:
+ case FACEBOOK_REQUEST_LOAD_FRIENDS:
+ case FACEBOOK_REQUEST_STATUS_SET:
+ case FACEBOOK_REQUEST_MESSAGE_SEND:
+ case FACEBOOK_REQUEST_VISIBILITY:
+ case FACEBOOK_REQUEST_TABS:
+ case FACEBOOK_REQUEST_ASYNC:
+ case FACEBOOK_REQUEST_TYPING_SEND:
+ case FACEBOOK_REQUEST_DELETE_FRIEND:
+ case FACEBOOK_REQUEST_ADD_FRIEND:
+ *headers_count = 5;
+ break;
+
+ case FACEBOOK_REQUEST_HOME:
+ case FACEBOOK_REQUEST_FEEDS:
+ case FACEBOOK_REQUEST_NOTIFICATIONS:
+ case FACEBOOK_REQUEST_RECONNECT:
+ case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+ default:
+ *headers_count = 4;
+ break;
+ }
+
+ NETLIBHTTPHEADER* headers = ( NETLIBHTTPHEADER* )utils::mem::allocate( sizeof( NETLIBHTTPHEADER )*( *headers_count ) );
+
+ switch ( request_type )
+ {
+ case FACEBOOK_REQUEST_LOGIN:
+ case FACEBOOK_REQUEST_SETUP_MACHINE:
+ case FACEBOOK_REQUEST_BUDDY_LIST:
+ case FACEBOOK_REQUEST_LOAD_FRIENDS:
+ case FACEBOOK_REQUEST_STATUS_SET:
+ case FACEBOOK_REQUEST_MESSAGE_SEND:
+ case FACEBOOK_REQUEST_VISIBILITY:
+ case FACEBOOK_REQUEST_TABS:
+ case FACEBOOK_REQUEST_ASYNC:
+ case FACEBOOK_REQUEST_TYPING_SEND:
+ case FACEBOOK_REQUEST_DELETE_FRIEND:
+ case FACEBOOK_REQUEST_ADD_FRIEND:
+ headers[4].szName = "Content-Type";
+ headers[4].szValue = "application/x-www-form-urlencoded; charset=utf-8";
+
+ case FACEBOOK_REQUEST_HOME:
+ case FACEBOOK_REQUEST_RECONNECT:
+ case FACEBOOK_REQUEST_MESSAGES_RECEIVE:
+ default:
+ headers[3].szName = "Cookie";
+ headers[3].szValue = load_cookies( );
+ headers[2].szName = "User-Agent";
+ headers[2].szValue = (char *)g_strUserAgent.c_str( );
+ headers[1].szName = "Accept";
+ headers[1].szValue = "*/*";
+ headers[0].szName = "Accept-Language";
+ headers[0].szValue = "en,en-US;q=0.9";
+ break;
+ }
+
+ return headers;
+}
+
+std::string facebook_client::get_newsfeed_type( )
+{
+ BYTE feed_type = DBGetContactSettingByte(NULL, parent->m_szModuleName, FACEBOOK_KEY_FEED_TYPE, 0);
+ if (feed_type < 0 || feed_type >= SIZEOF(feed_types))
+ feed_type = 0;
+ return feed_types[feed_type].id;
+}
+
+char* facebook_client::load_cookies( )
+{
+ ScopedLock s( cookies_lock_ );
+
+ std::string cookieString = "isfbe=false;";
+
+ if ( !cookies.empty( ) )
+ for ( std::map< std::string, std::string >::iterator iter = cookies.begin(); iter != cookies.end(); ++iter )
+ {
+ cookieString.append( iter->first );
+ cookieString.append( 1, '=' );
+ cookieString.append( iter->second );
+ cookieString.append( 1, ';' );
+ }
+
+ return mir_strdup(cookieString.c_str());
+}
+
+void facebook_client::store_headers( http::response* resp, NETLIBHTTPHEADER* headers, int headersCount )
+{
+ ScopedLock c( cookies_lock_ );
+
+ for ( int i = 0; i < headersCount; i++ )
+ {
+ std::string header_name = headers[i].szName; // TODO: Casting?
+ std::string header_value = headers[i].szValue; // TODO: Casting?
+
+ if ( header_name == "Set-Cookie" )
+ {
+ std::string cookie_name = header_value.substr( 0, header_value.find( "=" ) );
+ std::string cookie_value = header_value.substr( header_value.find( "=" ) + 1, header_value.find( ";" ) - header_value.find( "=" ) - 1 );
+ if ( cookie_value == "deleted" )
+ {
+ parent->Log(" Deleted cookie '%s'", cookie_name.c_str());
+ cookies.erase( cookie_name );
+ } else {
+ parent->Log(" New cookie '%s': %s", cookie_name.c_str(), cookie_value.c_str());
+ cookies[cookie_name] = cookie_value;
+ }
+ }
+ else
+ { // TODO RM: (un)comment
+ //parent->Log("----- Got header '%s': %s", header_name.c_str(), header_value.c_str() );
+ resp->headers[header_name] = header_value;
+ }
+ }
+}
+
+void facebook_client::clear_cookies( )
+{
+ ScopedLock s( cookies_lock_ );
+
+ if ( !cookies.empty( ) )
+ cookies.clear( );
+}
+
+bool facebook_client::login(const std::string &username,const std::string &password)
+{
+ handle_entry( "login" );
+
+ username_ = username;
+ password_ = password;
+
+ // Access homepage to get initial cookies
+ flap( FACEBOOK_REQUEST_HOME, NULL );
+
+ // Prepare login data
+ std::string data = "charset_test=%e2%82%ac%2c%c2%b4%2c%e2%82%ac%2c%c2%b4%2c%e6%b0%b4%2c%d0%94%2c%d0%84&locale=en&email=";
+ data += utils::url::encode( username );
+ data += "&pass=";
+ data += utils::url::encode( password );
+ data += "&pass_placeHolder=Password&login=Login&persistent=1";
+
+ // Send validation
+ http::response resp = flap( FACEBOOK_REQUEST_LOGIN, &data );
+
+ // Process result data
+ validate_response(&resp);
+
+ if ( resp.code == HTTP_CODE_FOUND && resp.headers.find("Location") != resp.headers.end() )
+ {
+ // Check whether some Facebook things are required
+ if ( resp.headers["Location"].find("help.php") != std::string::npos )
+ {
+ client_notify( TranslateT("Login error: Some Facebook things are required.") );
+ parent->Log(" ! ! Login error: Some Facebook things are required.");
+ // return handle_error( "login", FORCE_DISCONNECT );
+ }
+
+ // Check whether setting Machine name is required
+ if ( resp.headers["Location"].find("/checkpoint/") != std::string::npos )
+ {
+ resp = flap( FACEBOOK_REQUEST_SETUP_MACHINE );
+
+ std::string inner_data = "machine_name=MirandaIM&submit[Save%20Device]=Save%20Device";
+ inner_data += "&post_form_id=";
+ inner_data += utils::text::source_get_value(&resp.data, 3, "name=\"post_form_id\"", "value=\"", "\"" );
+
+ inner_data += "&lsd=";
+ inner_data += utils::text::source_get_value(&resp.data, 3, "name=\"lsd\"", "value=\"", "\"" );
+
+ inner_data += "&nh=";
+ inner_data += utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"" );
+
+ resp = flap( FACEBOOK_REQUEST_SETUP_MACHINE, &inner_data );
+ validate_response(&resp);
+ }
+ }
+
+ if ( resp.code == HTTP_CODE_FOUND && resp.headers.find("Location") != resp.headers.end() )
+ {
+ // Check whether HTTPS connection is required and we don't have enabled it
+ if (!this->https_)
+ {
+ if ( resp.headers["Location"].find("https://") != std::string::npos )
+ {
+ client_notify(TranslateT("Your account requires HTTPS connection. Activating."));
+ DBWriteContactSettingByte(NULL, parent->m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS, 1);
+ this->https_ = true;
+ }
+ }
+
+ }
+
+ // Check for Device ID
+ if ( cookies["datr"].length() )
+ DBWriteContactSettingString( NULL, parent->m_szModuleName, FACEBOOK_KEY_DEVICE_ID, cookies["datr"].c_str() );
+
+ switch ( resp.code )
+ {
+ case HTTP_CODE_FAKE_DISCONNECTED:
+ {
+ // When is error only because timeout, try login once more
+ if ( handle_error( "login" ) )
+ return login(username, password);
+ else
+ return false;
+ }
+
+ case HTTP_CODE_OK: // OK page returned, but that is regular login page we don't want in fact
+ {
+ // Check whether captcha code is required
+ if ( resp.data.find("id=\"captcha\"") != std::string::npos )
+ {
+ client_notify( TranslateT("Login error: Captcha code is required. Bad login credentials?") );
+ parent->Log(" ! ! Login error: Captcha code is required.");
+ return handle_error( "login", FORCE_DISCONNECT );
+ }
+
+ // Get error message
+ std::string error_str = utils::text::trim(
+ utils::text::special_expressions_decode(
+ utils::text::remove_html(
+ utils::text::edit_html(
+ utils::text::source_get_value( &resp.data, 2, "id=\"standard_error\">", "</h2>" ) ) ) ) );
+
+ if ( !error_str.length() )
+ error_str = Translate("Unknown login error");
+ parent->Log(" ! ! Login error: %s", error_str.c_str());
+
+ std::string message = Translate("Login error: ") + error_str;
+ TCHAR* tmessage = mir_a2t(message.c_str());
+ client_notify( tmessage );
+ mir_free( tmessage );
+ }
+ case HTTP_CODE_FORBIDDEN: // Forbidden
+ case HTTP_CODE_NOT_FOUND: // Not Found
+ default:
+ return handle_error( "login", FORCE_DISCONNECT );
+
+ case HTTP_CODE_FOUND: // Found and redirected to Home, Logged in, everything is OK
+ if ( cookies.find("c_user") != cookies.end() )
+ {
+ this->self_.user_id = cookies.find("c_user")->second;
+ DBWriteContactSettingString(NULL,parent->m_szModuleName,FACEBOOK_KEY_ID,this->self_.user_id.c_str());
+ parent->Log(" Got self user id: %s", this->self_.user_id.c_str());
+ return handle_success( "login" );
+ } else {
+ client_notify(TranslateT("Login error, probably bad login credentials."));
+ parent->Log(" ! ! Login error, probably bad login credentials.");
+ return handle_error( "login", FORCE_DISCONNECT );
+ }
+ }
+}
+
+bool facebook_client::logout( )
+{
+ if ( DBGetContactSettingByte(NULL, parent->m_szModuleName, FACEBOOK_KEY_DISABLE_LOGOUT, 0) )
+ return true;
+
+ handle_entry( "logout" );
+
+ std::string data = "post_form_id=";
+ data += ( this->post_form_id_.length( ) ) ? this->post_form_id_ : "0";
+ data += "&fb_dtsg=";
+ data += ( this->dtsg_.length( ) ) ? this->dtsg_ : "0";
+ data += "&ref=mb&h=";
+ data += this->logout_hash_;
+
+ http::response resp = flap( FACEBOOK_REQUEST_LOGOUT, &data );
+
+ if (hFcbCon)
+ Netlib_CloseHandle(hFcbCon);
+ hFcbCon = NULL;
+
+ // Process result
+ username_ = password_ = self_.user_id = "";
+
+ switch ( resp.code )
+ {
+ case HTTP_CODE_OK:
+ case HTTP_CODE_FOUND:
+ return handle_success( "logout" );
+
+ default:
+ return false; // Logout not finished properly, but..okay, who cares :P
+ }
+}
+
+bool facebook_client::home( )
+{
+ handle_entry( "home" );
+
+ http::response resp = flap( FACEBOOK_REQUEST_HOME );
+
+ // Process result data
+ validate_response(&resp);
+
+ switch ( resp.code )
+ {
+ case HTTP_CODE_OK:
+ {
+ if ( resp.data.find( "id=\"navAccountName\"" ) != std::string::npos )
+ { // Backup for old fb version
+ // Get real_name
+ this->self_.real_name = utils::text::remove_html( utils::text::special_expressions_decode( utils::text::source_get_value( &resp.data, 2, " id=\"navAccountName\">", "</a" ) ) );
+ DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NAME,this->self_.real_name.c_str());
+ DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NICK,this->self_.real_name.c_str());
+ parent->Log(" Got self real name: %s", this->self_.real_name.c_str());
+ } else if ( resp.data.find("id=\"pageNav\"") != std::string::npos ) {
+ // Get real_name
+ this->self_.real_name = utils::text::remove_html( utils::text::special_expressions_decode( utils::text::source_get_value( &resp.data, 3, " class=\"headerTinymanName\"", ">", "</a" ) ) );
+ DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NAME,this->self_.real_name.c_str());
+ DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NICK,this->self_.real_name.c_str());
+ parent->Log(" Got self real name: %s", this->self_.real_name.c_str());
+ } else {
+ client_notify(TranslateT("Something happened to Facebook. Maybe there was some major update so you should wait for an update."));
+ return handle_error( "home", FORCE_DISCONNECT );
+ }
+
+ // Get avatar
+ std::string avatar = utils::text::source_get_value( &resp.data, 3, "class=\\\"fbxWelcomeBoxImg", "src=\\\"", "\\\"" );
+ if (avatar.empty())
+ avatar = utils::text::source_get_value( &resp.data, 3, "class=\"fbxWelcomeBoxImg", "src=\"", "\"" );
+
+ this->self_.image_url = utils::text::trim( utils::text::special_expressions_decode( avatar ) );
+ parent->Log(" Got self avatar: %s", this->self_.image_url.c_str());
+ parent->CheckAvatarChange(NULL, this->self_.image_url);
+
+ // Get post_form_id
+ this->post_form_id_ = utils::text::source_get_value( &resp.data, 3, "name=\"post_form_id\"", "value=\"", "\"" );
+ parent->Log(" Got self post form id: %s", this->post_form_id_.c_str());
+
+ // Get dtsg
+ this->dtsg_ = utils::text::source_get_value( &resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\"" );
+ parent->Log(" Got self dtsg: %s", this->dtsg_.c_str());
+
+ // Get logout hash
+ this->logout_hash_ = utils::text::source_get_value( &resp.data, 2, "<input type=\"hidden\" autocomplete=\"off\" name=\"h\" value=\"", "\"" );
+ parent->Log(" Got self logout hash: %s", this->logout_hash_.c_str());
+
+ // TODO: DIrectly get that friend requests
+ // Get friend requests count and notify it
+ std::string str_count = utils::text::source_get_value( &resp.data, 2, "<span id=\"requestsCountValue\">", "</span>" );
+ if ( str_count.length() && str_count != std::string( "0" ) )
+ {
+ std::string message = Translate("Got new friend requests: ") + str_count;
+
+ TCHAR* tmessage = mir_a2t(message.c_str());
+ parent->NotifyEvent( parent->m_tszUserName, tmessage, NULL, FACEBOOK_EVENT_OTHER, TEXT(FACEBOOK_URL_REQUESTS) );
+ mir_free( tmessage );
+ }
+
+ if (!DBGetContactSettingByte(NULL,parent->m_szModuleName,FACEBOOK_KEY_PARSE_MESSAGES, DEFAULT_PARSE_MESSAGES))
+ {
+ str_count = utils::text::source_get_value( &resp.data, 2, "<span id=\"messagesCountValue\">", "</span>" );
+ if ( str_count.length() && str_count != std::string( "0" ) )
+ {
+ std::string message = Translate("Got new messages: ") + str_count;
+
+ TCHAR* tmessage = mir_a2t(message.c_str());
+ parent->NotifyEvent( parent->m_tszUserName, tmessage, NULL, FACEBOOK_EVENT_OTHER, TEXT(FACEBOOK_URL_MESSAGES) );
+ mir_free( tmessage );
+ }
+ }
+
+ str_count = utils::text::source_get_value( &resp.data, 2, "<span id=\"notificationsCountValue\">", "</span>" );
+ if ( str_count.length() && str_count != std::string( "0" ) )
+ {
+ // Parse notifications directly to popups
+ ForkThread( &FacebookProto::ProcessNotifications, this->parent, NULL );
+ }
+
+ if (DBGetContactSettingByte(NULL, parent->m_szModuleName, FACEBOOK_KEY_ENABLE_GROUPCHATS, DEFAULT_ENABLE_GROUPCHATS)) {
+ // Get group chats
+ std::string favorites = utils::text::source_get_value( &resp.data, 2, "<div id=\"leftCol\"", "<div id=\"contentCol\"" );
+
+ std::string::size_type pos = 0;
+ while ((pos = favorites.find("href=\"/groups/",pos)) != std::string::npos) {
+ pos += 14;
+ std::string item = favorites.substr(pos, favorites.find("</a>", pos) - pos);
+ std::string id = item.substr(0, item.find("/"));
+
+ if (!id.empty()) {
+ std::string name = utils::text::source_get_value( &item, 3, "class=\"linkWrap", ">", "</div>" );
+ name = utils::text::special_expressions_decode(utils::text::slashu_to_utf8( name ) );
+ parent->Log(" Got new group chat: %s (id: %s)", name.c_str(), id.c_str());
+ if (!name.empty())
+ parent->AddChat(id.c_str(), name.c_str());
+ }
+ }
+ }
+
+ return handle_success( "home" );
+
+ }
+ case HTTP_CODE_FOUND:
+ // Work-around for replica_down, f**king hell what's that?
+ parent->Log(" REPLICA_DOWN is back in force!");
+ return this->home();
+
+ default:
+ return handle_error( "home", FORCE_DISCONNECT );
+ }
+}
+
+bool facebook_client::chat_state( bool online )
+{
+ handle_entry( "chat_state" );
+
+ std::string data = "visibility=";
+ data += ( online ) ? "1" : "0";
+ data += "&window_id=0";
+ data += "&post_form_id=";
+ data += ( post_form_id_.length( ) ) ? post_form_id_ : "0";
+ data += "&post_form_id_source=AsyncRequest";
+ data += "&fb_dtsg=" + this->dtsg_;
+ data += "&lsd=&phstamp=0&__user=";
+ data += self_.user_id;
+ http::response resp = flap( FACEBOOK_REQUEST_VISIBILITY, &data );
+
+ return handle_success( "chat_state" );
+}
+
+bool facebook_client::reconnect( )
+{
+ handle_entry( "reconnect" );
+
+ // Request reconnect
+ http::response resp = flap( FACEBOOK_REQUEST_RECONNECT );
+
+ // Process result data
+ validate_response(&resp);
+
+ switch ( resp.code )
+ {
+ case HTTP_CODE_OK:
+ {
+ this->chat_channel_jslogger_ = utils::text::source_get_value( &resp.data, 2, "\"jslogger_suffix\":\"", "\"" );
+ parent->Log(" Got self channel jslogger: %s", this->chat_channel_jslogger_.c_str());
+
+ this->chat_channel_partition_ = utils::text::source_get_value2( &resp.data, "\"partition\":", ",}" );
+ parent->Log(" Got self channel partition: %s", this->chat_channel_partition_.c_str());
+
+ this->chat_channel_host_ = utils::text::source_get_value( &resp.data, 2, "\"host\":\"", "\"" );
+ parent->Log(" Got self channel host: %s", this->chat_channel_host_.c_str());
+
+ this->chat_sequence_num_ = utils::text::source_get_value2( &resp.data, "\"seq\":", ",}" );
+ parent->Log(" Got self sequence number: %s", this->chat_sequence_num_.c_str());
+
+ if (this->chat_channel_jslogger_.empty()) {
+ if (!atoi(this->chat_channel_host_.substr(0, this->chat_channel_host_.find(".")).c_str())) {
+ this->chat_channel_jslogger_ = "SOMETHING";
+ parent->Log(" Got no jslogger, changed.");
+ }
+ }
+
+ return handle_success( "reconnect" );
+ }
+
+ default:
+ return handle_error( "reconnect", FORCE_DISCONNECT );
+ }
+}
+
+bool facebook_client::buddy_list( )
+{
+ handle_entry( "buddy_list" );
+
+ // Prepare update data
+ std::string data = "user=" + this->self_.user_id + "&fetch_mobile=true&post_form_id=" + this->post_form_id_ + "&fb_dtsg=" + this->dtsg_ + "&lsd=&post_form_id_source=AsyncRequest&__user=" + this->self_.user_id;
+
+ {
+ ScopedLock s(buddies_lock_);
+
+ int counter = 0;
+ for (List::Item< facebook_user >* i = buddies.begin(); i != NULL; i = i->next, counter++ )
+ {
+ data += "&available_user_info_ids[";
+ data += utils::conversion::to_string(&counter, UTILS_CONV_UNSIGNED_NUMBER);
+ data += "]=";
+ data += i->data->user_id;
+ }
+ }
+
+ // Get buddy list
+ http::response resp = flap( FACEBOOK_REQUEST_BUDDY_LIST, &data );
+
+ // Process result data
+ validate_response(&resp);
+
+ switch ( resp.code )
+ {
+ case HTTP_CODE_OK:
+ {
+ std::string* response_data = new std::string( resp.data );
+ ForkThread( &FacebookProto::ProcessBuddyList, this->parent, ( void* )response_data );
+ return handle_success( "buddy_list" );
+ }
+
+ case HTTP_CODE_FAKE_ERROR:
+ case HTTP_CODE_FAKE_DISCONNECTED:
+ default:
+ return handle_error( "buddy_list" );
+ }
+}
+
+bool facebook_client::load_friends( )
+{
+ handle_entry( "load_friends" );
+
+ // Get buddy list
+ http::response resp = flap( FACEBOOK_REQUEST_LOAD_FRIENDS );
+
+ // Process result data
+ validate_response(&resp);
+
+ switch ( resp.code )
+ {
+ case HTTP_CODE_OK:
+ {
+ std::string* response_data = new std::string( resp.data );
+ ForkThread( &FacebookProto::ProcessFriendList, this->parent, ( void* )response_data );
+ return handle_success( "load_friends" );
+ }
+ case HTTP_CODE_FAKE_ERROR:
+ case HTTP_CODE_FAKE_DISCONNECTED:
+ default:
+ return handle_error( "load_friends" );
+ }
+}
+
+bool facebook_client::feeds( )
+{
+ handle_entry( "feeds" );
+
+ // Get feeds
+ http::response resp = flap( FACEBOOK_REQUEST_FEEDS );
+
+ // Process result data
+ validate_response(&resp);
+
+ switch ( resp.code )
+ {
+ case HTTP_CODE_OK:
+ if (resp.data.find("\"num_stories\":0") == std::string::npos) {
+ std::string* response_data = new std::string( resp.data );
+ ForkThread( &FacebookProto::ProcessFeeds, this->parent, ( void* )response_data );
+ }
+ return handle_success( "feeds" );
+
+ case HTTP_CODE_FAKE_ERROR:
+ case HTTP_CODE_FAKE_DISCONNECTED:
+ default:
+ return handle_error( "feeds" );
+ }
+}
+
+bool facebook_client::channel( )
+{
+ handle_entry( "channel" );
+
+ // Get update
+ http::response resp = flap( FACEBOOK_REQUEST_MESSAGES_RECEIVE );
+
+ // Process result data
+ validate_response(&resp);
+
+ if ( resp.code != HTTP_CODE_OK )
+ {
+ // Something went wrong
+ }
+ else if ( resp.data.find( "\"t\":\"continue\"" ) != std::string::npos )
+ {
+ // Everything is OK, no new message received
+ }
+ else if ( resp.data.find( "\"t\":\"fullReload\"" ) != std::string::npos )
+ {
+ // Something went wrong (server flooding?)
+
+ parent->Log("! ! ! Requested full reload");
+
+ this->chat_sequence_num_ = utils::text::source_get_value2( &resp.data, "\"seq\":", ",}" );
+ parent->Log(" Got self sequence number: %s", this->chat_sequence_num_.c_str());
+
+ this->chat_reconnect_reason_ = utils::text::source_get_value2( &resp.data, "\"reason\":", ",}" );
+ parent->Log(" Reconnect reason: %s", this->chat_reconnect_reason_.c_str());
+ }
+ else if ( resp.data.find( "\"t\":\"refresh\"" ) != std::string::npos )
+ {
+ // Something went wrong (server flooding?)
+ parent->Log("! ! ! Requested channel refresh");
+
+ this->chat_reconnect_reason_ = utils::text::source_get_value2( &resp.data, "\"reason\":", ",}" );
+ parent->Log(" Reconnect reason: %s", this->chat_reconnect_reason_.c_str());
+
+ this->chat_sequence_num_ = utils::text::source_get_value2( &resp.data, "\"seq\":", ",}" );
+ parent->Log(" Got self sequence number: %s", this->chat_sequence_num_.c_str());
+
+ return this->reconnect( );
+ } else {
+ // Something has been received, throw to new thread to process
+ std::string* response_data = new std::string( resp.data );
+ ForkThread( &FacebookProto::ProcessMessages, this->parent, ( void* )response_data );
+
+ // Increment sequence number
+ this->chat_sequence_num_ = utils::text::source_get_value2( &resp.data, "\"seq\":", ",}" );
+ parent->Log(" Got self sequence number: %s", this->chat_sequence_num_.c_str());
+ }
+
+ // Return
+ switch ( resp.code )
+ {
+ case HTTP_CODE_OK:
+ return handle_success( "channel" );
+
+ case HTTP_CODE_FAKE_DISCONNECTED:
+ case HTTP_CODE_FAKE_ERROR:
+ default:
+ // Testing workaround for channel change
+ if (!this->chat_channel_jslogger_.empty())
+ this->chat_channel_jslogger_ = "_";
+ else
+ this->chat_channel_jslogger_.clear();
+
+ return handle_error( "channel" );
+ }
+}
+
+bool facebook_client::send_message( std::string message_recipient, std::string message_text, std::string *error_text, bool use_inbox )
+{
+ handle_entry( "send_message" );
+
+ http::response resp;
+
+ if (parent->isInvisible() || use_inbox) {
+ // Use inbox send message when invisible
+ std::string data = "action=send&body=";
+ data += utils::url::encode( message_text );
+ data += "&recipients[0]=";
+ data += message_recipient;
+ data += "&lsd=&fb_dtsg=";
+ data += ( dtsg_.length( ) ) ? dtsg_ : "0";
+ data += "&post_form_id=";
+ data += ( post_form_id_.length( ) ) ? post_form_id_ : "0";
+
+ resp = flap( FACEBOOK_REQUEST_ASYNC, &data );
+ } else {
+ // Use standard send message
+ std::string data = "msg_text=";
+ data += utils::url::encode( message_text );
+ data += "&msg_id=";
+ data += utils::time::mili_timestamp( );
+ data += "%3A";
+ data += utils::time::unix_timestamp( );
+ data += "&to=";
+ data += message_recipient;
+ data += "&__user=";
+ data += this->self_.user_id;
+ data += "&client_time=";
+ data += utils::time::mili_timestamp( );
+ data += "&pvs_time&fb_dtsg=";
+ data += ( dtsg_.length( ) ) ? dtsg_ : "0";
+ data += "&to_offline=false&to_idle=false&lsd&post_form_id_source=AsyncRequest&num_tabs=1";
+ data += "&window_id=0&sidebar_launched=false&sidebar_enabled=false&sidebar_capable=false&sidebar_should_show=false&sidebar_visible=false";
+ data += "&post_form_id=";
+ data += ( post_form_id_.length( ) ) ? post_form_id_ : "0";
+
+ resp = flap( FACEBOOK_REQUEST_MESSAGE_SEND, &data );
+ }
+
+
+ validate_response(&resp);
+ *error_text = resp.error_text;
+
+ switch ( resp.error_number )
+ {
+ case 0: // Everything is OK
+ break;
+
+ //case 1356002: // You are offline - wtf??
+
+ case 1356003: // Contact is offline
+ {
+ HANDLE hContact = parent->ContactIDToHContact( message_recipient );
+ if (hContact != NULL)
+ DBWriteContactSettingWord(hContact,parent->m_szModuleName,"Status",ID_STATUS_OFFLINE);
+ return false;
+ } break;
+
+ case 1356026: // Contact has alternative client
+ {
+ client_notify(TranslateT("Need confirmation for sending messages to other clients.\nOpen facebook website and try to send message to this contact again!"));
+ /*
+ post na url http://www.facebook.com/ajax/chat/post_application_settings.php?__a=1
+
+ enable_and_send Povolit a odeslat
+ to_send AQCoweMPeszBoKpd4iahcOyhmh0kiTYIhv1b5wCtuBiD0AaPVZIdEp3Pf5JMBmQ-9wf0ju-xdi-VRuk0ERk_I7XzI5dVJCs6-B0FExTZhspD-4-kTZLmZI-_M6fIuF2328yMyT3R3UEUmMV8P9MHcZwu-_pS3mOhsaHf6rIVcQ2rocSqLKi03wLKCfg0m8VsptPADWpOI-UNcIo-xl1PAoC1yVnL2wEXEtnF1qI_xFcmlJZ40AOONfIF_LS_lBrGYA-oCWLUK-GLHtQAHjO8aDeNXDU8Jk7Z_ES-_oAHee2PVLHcG_ACHXpasE7Iu3XFLMrdN2hjM96AjPRIf0Vk8gBZzfW_lUspakZmXxMI7iSNQE8lourK_6B3Z1s4UHxDZCNXYuc9gh70nm_xnaxnF9K1bR00s4MltnFjUT_3ypThzA
+ __d 1
+ post_form_id c73ebd9d94b7449c40e6965410fcdcf6
+ fb_dtsg Tb-T9
+ lsd
+ post_form_id_source AsyncRequest
+ */
+ return false;
+ } break;
+
+ default: // Other error
+ return false;
+ }
+
+ switch ( resp.code )
+ {
+ case HTTP_CODE_OK:
+ return handle_success( "send_message" );
+
+ case HTTP_CODE_FAKE_ERROR:
+ case HTTP_CODE_FAKE_DISCONNECTED:
+ default:
+ *error_text = Translate("Timeout when sending message.");
+
+ handle_error( "send_message" );
+ return false;
+ }
+}
+
+void facebook_client::close_chat( std::string message_recipient )
+{
+ // TODO RM: better optimalization for close_chat
+ // add items to list and then checking every x seconds
+/* if ( (::time(NULL) - parent->facy.last_close_chat_time_) < 8 )
+ return;*/
+ // parent->facy.last_close_chat_time_ = ::time(NULL);
+
+ /* Wait some time before close window, because sometimes facebook
+ can't close it so soon. But maybe this didnt help also. */
+ Sleep(300);
+
+ std::string data = "close_chat=";
+ data += message_recipient;
+ data += "&window_id=0";
+ data += "&post_form_id=";
+ data += ( post_form_id_.length( ) ) ? post_form_id_ : "0";
+ data += "&post_form_id_source=AsyncRequest";
+ data += "&fb_dtsg=";
+ data += ( this->dtsg_.length( ) ) ? this->dtsg_ : "0";
+ data += "&__user=";
+ data += self_.user_id;
+
+ http::response resp = flap( FACEBOOK_REQUEST_TABS, &data );
+}
+
+void facebook_client::chat_mark_read( std::string message_recipient )
+{
+ // TODO RM: optimalization?
+
+ std::string data = "action=chatMarkRead&other_user=";
+ data += message_recipient;
+ data += "&post_form_id=";
+ data += ( post_form_id_.length( ) ) ? post_form_id_ : "0";
+ data += "&fb_dtsg=";
+ data += ( this->dtsg_.length( ) ) ? this->dtsg_ : "0";
+ data += "&post_form_id_source=AsyncRequest&lsd=&__user=";
+ data += self_.user_id;
+
+ http::response resp = flap( FACEBOOK_REQUEST_ASYNC, &data );
+}
+
+bool facebook_client::set_status(const std::string &status_text)
+{
+ handle_entry( "set_status" );
+
+ std::string data = "post_form_id_source=AsyncRequest&post_form_id=";
+ data += ( this->post_form_id_.length( ) ) ? this->post_form_id_ : "0";
+ data += "&fb_dtsg=";
+ data += ( this->dtsg_.length( ) ) ? this->dtsg_ : "0";
+ data += "&target_id=";
+ data += this->self_.user_id;
+
+ if ( status_text.length( ) )
+ {
+ data += "&action=PROFILE_UPDATE&app_id=&hey_kid_im_a_composer=true&display_context=profile&_log_display_context=profile&ajax_log=1&status=";
+ data += utils::url::encode( status_text );
+ data += "&profile_id=";
+ data += this->self_.user_id;
+ }
+
+ http::response resp = flap( FACEBOOK_REQUEST_STATUS_SET, &data );
+
+ validate_response(&resp);
+
+ switch ( resp.code )
+ {
+ case HTTP_CODE_OK:
+ return handle_success( "set_status" );
+
+ case HTTP_CODE_FAKE_ERROR:
+ case HTTP_CODE_FAKE_DISCONNECTED:
+ default:
+ return handle_error( "set_status" );
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool facebook_client::save_url(const std::string &url,const std::string &filename, HANDLE &nlc)
+{
+ NETLIBHTTPREQUEST req = {sizeof(req)};
+ NETLIBHTTPREQUEST *resp;
+ req.requestType = REQUEST_GET;
+ req.szUrl = const_cast<char*>(url.c_str());
+ req.flags = NLHRF_HTTP11 | NLHRF_REDIRECT | NLHRF_PERSISTENT | NLHRF_NODUMP;
+ req.nlc = nlc;
+
+ resp = reinterpret_cast<NETLIBHTTPREQUEST*>(CallService( MS_NETLIB_HTTPTRANSACTION,
+ reinterpret_cast<WPARAM>(this->parent->m_hNetlibUser), reinterpret_cast<LPARAM>(&req) ));
+
+ if ( resp )
+ {
+ nlc = resp->nlc;
+ parent->Log( "@@@@@ Saving avatar URL %s to path %s", url.c_str(), filename.c_str() );
+
+ // Create folder if necessary
+ std::string dir = filename.substr(0,filename.rfind('\\'));
+ if(_access(dir.c_str(),0))
+ CallService(MS_UTILS_CREATEDIRTREE, 0, (LPARAM)dir.c_str());
+
+ // Write to file
+ FILE *f = fopen(filename.c_str(),"wb");
+ fwrite(resp->pData,1,resp->dataLength,f);
+ fclose(f);
+
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)resp);
+ return true;
+ } else {
+ nlc = NULL;
+ return false;
+ }
+}
diff --git a/protocols/FacebookRM/connection.cpp b/protocols/FacebookRM/connection.cpp new file mode 100644 index 0000000000..d60b1ec969 --- /dev/null +++ b/protocols/FacebookRM/connection.cpp @@ -0,0 +1,235 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka
+
+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 <http://www.gnu.org/licenses/>.
+
+File name : $HeadURL: http://eternityplugins.googlecode.com/svn/trunk/facebook/connection.cpp $
+Revision : $Revision: 91 $
+Last change by : $Author: n3weRm0re.ewer $
+Last change on : $Date: 2011-01-08 11:10:34 +0100 (so, 08 1 2011) $
+
+*/
+
+#include "common.h"
+
+void FacebookProto::ChangeStatus(void*)
+{
+ ScopedLock s(signon_lock_);
+ ScopedLock b(facy.buddies_lock_);
+
+ int new_status = m_iDesiredStatus;
+ int old_status = m_iStatus;
+
+ if ( new_status == ID_STATUS_OFFLINE )
+ { // Logout
+ LOG("##### Beginning SignOff process");
+
+ m_iStatus = facy.self_.status_id = ID_STATUS_OFFLINE;
+ SetEvent(update_loop_lock_);
+ Netlib_Shutdown(facy.hMsgCon);
+
+ if ( getByte(FACEBOOK_KEY_DISCONNECT_CHAT, DEFAULT_DISCONNECT_CHAT) )
+ facy.chat_state( false );
+
+ facy.logout( );
+
+ deleteSetting( "LogonTS" );
+
+ facy.clear_cookies( );
+ facy.buddies.clear( );
+
+ ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+
+ OnLeaveChat(NULL, NULL);
+
+ SetAllContactStatuses( ID_STATUS_OFFLINE );
+
+ ToggleStatusMenuItems(false);
+
+ if (facy.hMsgCon)
+ Netlib_CloseHandle(facy.hMsgCon);
+ facy.hMsgCon = NULL;
+
+ LOG("##### SignOff complete");
+
+ return;
+ }
+ else if ( old_status == ID_STATUS_OFFLINE )
+ { // Login
+ SYSTEMTIME t;
+ GetLocalTime( &t );
+ Log("[%d.%d.%d] Using Facebook Protocol RM %s", t.wDay, t.wMonth, t.wYear, __VERSION_STRING);
+
+ LOG("***** Beginning SignOn process");
+
+ m_iStatus = facy.self_.status_id = ID_STATUS_CONNECTING;
+ ProtoBroadcastAck(m_szModuleName,0,ACKTYPE_STATUS,ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+
+ ResetEvent(update_loop_lock_);
+
+ if ( NegotiateConnection( ) )
+ {
+ facy.last_feeds_update_ = ::time( NULL );
+
+ facy.home();
+ facy.reconnect();
+
+ facy.load_friends();
+
+ if (getByte(FACEBOOK_KEY_PARSE_MESSAGES, DEFAULT_PARSE_MESSAGES))
+ ForkThread( &FacebookProto::ProcessUnreadMessages, this );
+
+ setDword( "LogonTS", (DWORD)time(NULL) );
+ ForkThread( &FacebookProto::UpdateLoop, this );
+ ForkThread( &FacebookProto::MessageLoop, this );
+
+ if (getByte(FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS))
+ {
+ ForkThread(&FacebookProto::SetAwayMsgWorker, this, NULL);
+ }
+ } else {
+ ProtoBroadcastAck(m_szModuleName,0,ACKTYPE_STATUS,ACKRESULT_FAILED,
+ (HANDLE)old_status,m_iStatus);
+
+ // Set to offline
+ m_iStatus = m_iDesiredStatus = facy.self_.status_id = ID_STATUS_OFFLINE;
+ ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+
+ LOG("***** SignOn failed");
+
+ return;
+ }
+
+ ToggleStatusMenuItems(true);
+ LOG("***** SignOn complete");
+ }
+ else if ( new_status == ID_STATUS_INVISIBLE )
+ {
+ facy.buddies.clear( );
+ this->SetAllContactStatuses( ID_STATUS_OFFLINE );
+ }
+
+ facy.chat_state( m_iDesiredStatus != ID_STATUS_INVISIBLE );
+ facy.buddy_list( );
+
+ m_iStatus = facy.self_.status_id = m_iDesiredStatus;
+ ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+
+ LOG("***** ChangeStatus complete");
+}
+
+/** Return true on success, false on error. */
+bool FacebookProto::NegotiateConnection( )
+{
+ LOG("***** Negotiating connection with Facebook");
+
+ bool error;
+ std::string user, pass;
+ DBVARIANT dbv = {0};
+
+ error = true;
+ if ( !DBGetContactSettingString(NULL,m_szModuleName,FACEBOOK_KEY_LOGIN,&dbv) )
+ {
+ user = dbv.pszVal;
+ DBFreeVariant(&dbv);
+ error = user.empty();
+ }
+ if (error)
+ {
+ NotifyEvent(m_tszUserName,TranslateT("Please enter a username."),NULL,FACEBOOK_EVENT_CLIENT);
+ return false;
+ }
+
+ error = true;
+ if ( !DBGetContactSettingString(NULL,m_szModuleName,FACEBOOK_KEY_PASS,&dbv) )
+ {
+ CallService(MS_DB_CRYPT_DECODESTRING,strlen(dbv.pszVal)+1,
+ reinterpret_cast<LPARAM>(dbv.pszVal));
+ pass = dbv.pszVal;
+ DBFreeVariant(&dbv);
+ error = pass.empty();
+ }
+ if (error)
+ {
+ NotifyEvent(m_tszUserName,TranslateT("Please enter a password."),NULL,FACEBOOK_EVENT_CLIENT);
+ return false;
+ }
+
+ // Load machine name
+ if ( !DBGetContactSettingString(NULL,m_szModuleName,FACEBOOK_KEY_DEVICE_ID,&dbv) )
+ {
+ facy.cookies["datr"] = dbv.pszVal;
+ DBFreeVariant(&dbv);
+ }
+
+ // Get info about secured connection
+ facy.https_ = DBGetContactSettingByte(NULL, m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS, DEFAULT_FORCE_HTTPS ) != 0;
+
+ return facy.login( user, pass );
+}
+
+void FacebookProto::UpdateLoop(void *)
+{
+ time_t tim = ::time(NULL);
+ LOG( ">>>>> Entering Facebook::UpdateLoop[%d]", tim );
+
+ for ( int i = -1; !isOffline(); i = ++i % 6 )
+ {
+ if ( i != -1 ) {
+ if ( !facy.invisible_ )
+ if ( !facy.buddy_list( ) )
+ break;
+ }
+ if ( i == 2 && getByte( FACEBOOK_KEY_EVENT_FEEDS_ENABLE, DEFAULT_EVENT_FEEDS_ENABLE ) )
+ if ( !facy.feeds( ) )
+ break;
+ LOG( "***** FacebookProto::UpdateLoop[%d] going to sleep...", tim );
+ if ( WaitForSingleObjectEx( update_loop_lock_, GetPollRate( ) * 1000, true ) != WAIT_TIMEOUT )
+ break;
+ LOG( "***** FacebookProto::UpdateLoop[%d] waking up...", tim );
+ }
+
+ ResetEvent(update_loop_lock_);
+ LOG( "<<<<< Exiting FacebookProto::UpdateLoop[%d]", tim );
+}
+
+void FacebookProto::MessageLoop(void *)
+{
+ //ScopedLock s(message_loop_lock_); // TODO: Required?
+ time_t tim = ::time(NULL);
+ LOG( ">>>>> Entering Facebook::MessageLoop[%d]", tim );
+
+ while ( facy.channel( ) )
+ {
+ if ( isOffline() )
+ break;
+ LOG( "***** FacebookProto::MessageLoop[%d] refreshing...", tim );
+ }
+
+ LOG( "<<<<< Exiting FacebookProto::MessageLoop[%d]", tim );
+}
+
+BYTE FacebookProto::GetPollRate( )
+{
+ BYTE poll_rate = getByte( FACEBOOK_KEY_POLL_RATE, FACEBOOK_DEFAULT_POLL_RATE );
+
+ return (
+ ( poll_rate >= FACEBOOK_MINIMAL_POLL_RATE &&
+ poll_rate <= FACEBOOK_MAXIMAL_POLL_RATE )
+ ? poll_rate : FACEBOOK_DEFAULT_POLL_RATE );
+}
diff --git a/protocols/FacebookRM/constants.h b/protocols/FacebookRM/constants.h new file mode 100644 index 0000000000..3e0aaacb8e --- /dev/null +++ b/protocols/FacebookRM/constants.h @@ -0,0 +1,122 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+// Version management
+#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 0, 8, 1)
+#define __VERSION_STRING "0.0.8.1"
+
+// Product management
+#define FACEBOOK_NAME "Facebook"
+#define FACEBOOK_URL_HOMEPAGE "http://www.facebook.com"
+#define FACEBOOK_URL_REQUESTS "http://www.facebook.com/n/?reqs.php"
+#define FACEBOOK_URL_MESSAGES "http://www.facebook.com/n/?inbox"
+#define FACEBOOK_URL_NOTIFICATIONS "http://www.facebook.com/n/?notifications.php"
+#define FACEBOOK_URL_PROFILE "http://www.facebook.com/profile.php?id="
+#define FACEBOOK_URL_GROUP "http://www.facebook.com/n/?home.php&sk=group_"
+
+// Connection
+#define FACEBOOK_SERVER_REGULAR "www.facebook.com"
+#define FACEBOOK_SERVER_CHAT "%s.%s.facebook.com"
+#define FACEBOOK_SERVER_CHAT2 "%s-%s.facebook.com"
+#define FACEBOOK_SERVER_LOGIN "login.facebook.com"
+#define FACEBOOK_SERVER_APPS "apps.facebook.com"
+
+// Limits
+#define FACEBOOK_MESSAGE_LIMIT 1024
+#define FACEBOOK_MESSAGE_LIMIT_TEXT "1024"
+#define FACEBOOK_MIND_LIMIT 420
+#define FACEBOOK_MIND_LIMIT_TEXT "420"
+#define FACEBOOK_TIMEOUTS_LIMIT 5
+#define FACEBOOK_GROUP_NAME_LIMIT 100
+
+// Defaults
+#define FACEBOOK_MINIMAL_POLL_RATE 10
+#define FACEBOOK_DEFAULT_POLL_RATE 24 // in seconds
+#define FACEBOOK_MAXIMAL_POLL_RATE 60
+
+#define DEFAULT_FORCE_HTTPS 0
+#define DEFAULT_FORCE_HTTPS_CHANNEL 0
+#define DEFAULT_CLOSE_WINDOWS_ENABLE 0
+#define DEFAULT_SET_MIRANDA_STATUS 0
+#define DEFAULT_LOGGING_ENABLE 0
+#define DEFAULT_SYSTRAY_NOTIFY 0
+#define DEFAULT_DISABLE_STATUS_NOTIFY 0
+#define DEFAULT_BIG_AVATARS 0
+#define DEFAULT_DISCONNECT_CHAT 0
+#define DEFAULT_PARSE_MESSAGES 0
+#define DEFAULT_MAP_STATUSES 0
+#define DEFAULT_LOAD_MOBILE 0
+#define DEFAULT_ENABLE_GROUPCHATS 0
+
+#define DEFAULT_EVENT_NOTIFICATIONS_ENABLE 1
+#define DEFAULT_EVENT_FEEDS_ENABLE 1
+#define DEFAULT_EVENT_OTHER_ENABLE 1
+#define DEFAULT_EVENT_CLIENT_ENABLE 1
+#define DEFAULT_EVENT_COLBACK 0x00ffffff
+#define DEFAULT_EVENT_COLTEXT 0x00000000
+#define DEFAULT_EVENT_TIMEOUT_TYPE 0
+#define DEFAULT_EVENT_TIMEOUT 20
+
+// Event flags
+#define FACEBOOK_EVENT_CLIENT 0x10000000 // Facebook error or info message
+#define FACEBOOK_EVENT_NEWSFEED 0x20000000 // Facebook newsfeed (wall) message
+#define FACEBOOK_EVENT_NOTIFICATION 0x40000000 // Facebook new notification
+#define FACEBOOK_EVENT_OTHER 0x80000000 // Facebook other event - friend requests/new messages
+
+// Facebook request types // TODO: Provide MS_ and release in FB plugin API?
+#define FACEBOOK_REQUEST_LOGIN 100 // connecting physically
+#define FACEBOOK_REQUEST_SETUP_MACHINE 102 // setting machine name
+#define FACEBOOK_REQUEST_LOGOUT 106 // disconnecting physically
+#define FACEBOOK_REQUEST_HOME 110 // getting __post_form_id__ + __fb_dtsg__ + ...
+#define FACEBOOK_REQUEST_BUDDY_LIST 120 // getting regular updates (friends online, ...)
+#define FACEBOOK_REQUEST_LOAD_FRIENDS 121 // getting list of all friends
+#define FACEBOOK_REQUEST_DELETE_FRIEND 122 // deleting friends
+#define FACEBOOK_REQUEST_ADD_FRIEND 123 // adding friends
+#define FACEBOOK_REQUEST_FEEDS 125 // getting feeds
+#define FACEBOOK_REQUEST_NOTIFICATIONS 126 // getting notifications
+#define FACEBOOK_REQUEST_RECONNECT 130 // getting __sequence_num__ and __channel_id__
+#define FACEBOOK_REQUEST_STATUS_SET 251 // setting my "What's on my mind?"
+#define FACEBOOK_REQUEST_MESSAGE_SEND 300 // sending message
+#define FACEBOOK_REQUEST_MESSAGES_RECEIVE 301 // receiving messages
+#define FACEBOOK_REQUEST_TYPING_SEND 304 // sending typing notification
+#define FACEBOOK_REQUEST_VISIBILITY 305 // setting chat visibility
+#define FACEBOOK_REQUEST_TABS 306 // closing message window
+#define FACEBOOK_REQUEST_ASYNC 307 // marking messages read and getting other things
+
+#define FACEBOOK_RECV_MESSAGE 1
+#define FACEBOOK_SEND_MESSAGE 2
+
+// News Feed types
+static const struct
+{
+ const char *name;
+ const char *id;
+} feed_types[] = {
+ { "Most Recent", "lf_" }, //h_chr?
+ { "Wall Posts", "app_2915120374" },
+ { "Top News", "h_nor" }, //h
+ { "Photos", "app_2305272732_2392950137" },
+ { "Links", "app_2309869772" },
+ { "Apps and Games", "appsandgames" },
+};
\ No newline at end of file diff --git a/protocols/FacebookRM/contacts.cpp b/protocols/FacebookRM/contacts.cpp new file mode 100644 index 0000000000..2a2cf4b368 --- /dev/null +++ b/protocols/FacebookRM/contacts.cpp @@ -0,0 +1,263 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+bool FacebookProto::IsMyContact(HANDLE hContact, bool include_chat)
+{
+ const char *proto = reinterpret_cast<char*>( CallService(MS_PROTO_GETCONTACTBASEPROTO,
+ reinterpret_cast<WPARAM>(hContact),0) );
+
+ if( proto && strcmp(m_szModuleName,proto) == 0 )
+ {
+ if( include_chat )
+ return true;
+ else
+ return DBGetContactSettingByte(hContact,m_szModuleName,"ChatRoom",0) == 0;
+ } else {
+ return false;
+ }
+}
+
+HANDLE FacebookProto::ContactIDToHContact(std::string user_id)
+{
+ for(HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ hContact;
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0) )
+ {
+ if(!IsMyContact(hContact))
+ continue;
+
+ DBVARIANT dbv;
+ if( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) )
+ {
+ if( strcmp(user_id.c_str(),dbv.pszVal) == 0 )
+ {
+ DBFreeVariant(&dbv);
+ return hContact;
+ } else {
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+
+ return 0;
+}
+
+HANDLE FacebookProto::AddToContactList(facebook_user* fbu, bool dont_check, const char *new_name)
+{
+ HANDLE hContact;
+
+ if (!dont_check) {
+ // First, check if this contact exists
+ hContact = ContactIDToHContact(fbu->user_id);
+ if( hContact )
+ return hContact;
+ }
+
+ // 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 )
+ {
+ DBWriteContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,fbu->user_id.c_str());
+
+ std::string homepage = FACEBOOK_URL_PROFILE + fbu->user_id;
+ DBWriteContactSettingString(hContact, m_szModuleName,"Homepage", homepage.c_str());
+
+ DBWriteContactSettingString(hContact, m_szModuleName, "MirVer", FACEBOOK_NAME);
+
+ DBDeleteContactSetting(hContact, "CList", "MyHandle");
+
+ DBVARIANT dbv;
+ if( !DBGetContactSettingTString(NULL,m_szModuleName,FACEBOOK_KEY_DEF_GROUP,&dbv) )
+ {
+ DBWriteContactSettingTString(hContact,"CList","Group",dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if (strlen(new_name) > 0) {
+ DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NAME, new_name);
+ DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NICK, new_name);
+ DBWriteContactSettingByte(hContact, m_szModuleName, FACEBOOK_KEY_CONTACT_TYPE, 1); // We suppose he is not on server list
+ }
+
+ if (getByte(FACEBOOK_KEY_DISABLE_STATUS_NOTIFY, 0))
+ CallService(MS_IGNORE_IGNORE, (WPARAM)hContact, (LPARAM)IGNOREEVENT_USERONLINE);
+
+ return hContact;
+ } else {
+ CallService(MS_DB_CONTACT_DELETE,(WPARAM)hContact,0);
+ }
+ }
+
+ return 0;
+}
+
+void FacebookProto::SetAllContactStatuses(int status)
+{
+ for (HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ hContact;
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0))
+ {
+ if (!IsMyContact(hContact))
+ continue;
+
+ if (DBGetContactSettingWord(hContact,m_szModuleName,"Status",ID_STATUS_OFFLINE) == status)
+ continue;
+
+ DBWriteContactSettingWord(hContact,m_szModuleName,"Status",status);
+ }
+}
+
+void FacebookProto::DeleteContactFromServer(void *data)
+{
+ facy.handle_entry( "DeleteContactFromServer" );
+
+ if ( data == NULL )
+ return;
+
+ std::string id = (*(std::string*)data);
+ delete data;
+
+ std::string query = "norefresh=false&post_form_id_source=AsyncRequest&lsd=&fb_dtsg=";
+ query += facy.dtsg_;
+ query += "&post_form_id=";
+ query += facy.post_form_id_;
+ query += "&uid=";
+ query += id;
+ query += "&__user=";
+ query += facy.self_.user_id;
+
+ // Get unread inbox threads
+ http::response resp = facy.flap( FACEBOOK_REQUEST_DELETE_FRIEND, &query );
+
+ // Process result data
+ facy.validate_response(&resp);
+
+ if (resp.data.find("\"success\":true", 0) != std::string::npos) {
+
+ // TODO: do only when operation is successful
+ facebook_user* fbu = facy.buddies.find( id );
+ if (fbu != NULL) {
+ fbu->deleted = true;
+ // TODO: change type of contact in database...
+ DBWriteContactSettingWord(fbu->handle, m_szModuleName, "Status", ID_STATUS_OFFLINE); // set offline status
+
+ // TODO: if not in actual buddies list, search in database...
+ DBWriteContactSettingDword(fbu->handle, m_szModuleName, FACEBOOK_KEY_DELETED, ::time(NULL)); // set deleted time
+ }
+
+ NotifyEvent(TranslateT("Deleting contact"), TranslateT("Contact was sucessfully removed from server."), NULL, FACEBOOK_EVENT_OTHER, NULL);
+ } else {
+ facy.client_notify( TranslateT("Error occured when removing contact from server.") );
+ }
+
+ if (resp.code != HTTP_CODE_OK)
+ facy.handle_error( "DeleteContactFromServer" );
+}
+
+void FacebookProto::AddContactToServer(void *data)
+{
+ facy.handle_entry( "AddContactToServer" );
+
+ if ( data == NULL )
+ return;
+
+ std::string *id = (std::string*)data;
+
+ std::string query = "action=add_friend&how_found=profile_button&ref_param=ts&outgoing_id=&unwanted=&logging_location=&no_flyout_on_click=false&ego_log_data=&post_form_id_source=AsyncRequest&lsd=&fb_dtsg=";
+ query += facy.dtsg_;
+ query += "&post_form_id=";
+ query += facy.post_form_id_;
+ query += "&to_friend=";
+ query += *id;
+ query += "&__user=";
+ query += facy.self_.user_id;
+
+ delete data;
+
+ // Get unread inbox threads
+ http::response resp = facy.flap( FACEBOOK_REQUEST_ADD_FRIEND, &query );
+
+ // Process result data
+ facy.validate_response(&resp);
+
+ if (resp.data.find("\"success\":true", 0) != std::string::npos) {
+ /*facebook_user* fbu = facy.buddies.find( id );
+ if (fbu != NULL) {
+ // TODO: change type of contact in database...
+ // TODO: if not in actual buddies list, search in database...
+ }*/
+
+ NotifyEvent(TranslateT("Adding contact"), TranslateT("Request for friendship was sent successfully."), NULL, FACEBOOK_EVENT_OTHER, NULL);
+ } else {
+ facy.client_notify( TranslateT("Error occured when requesting friendship.") );
+ }
+
+ if (resp.code != HTTP_CODE_OK)
+ facy.handle_error( "AddContactToServer" );
+
+}
+
+
+HANDLE FacebookProto::GetAwayMsg(HANDLE hContact)
+{
+ return 0; // Status messages are disabled
+}
+
+int FacebookProto::OnContactDeleted(WPARAM wparam,LPARAM)
+{
+ HANDLE hContact = (HANDLE)wparam;
+
+ DBVARIANT dbv;
+ TCHAR text[512];
+ if ( !DBGetContactSettingTString(hContact, m_szModuleName, FACEBOOK_KEY_NAME, &dbv) ) {
+ mir_sntprintf(text,SIZEOF(text),TranslateT("Do you want to delete contact '%s' from server list?"),dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ } else if( !DBGetContactSettingTString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) ) {
+ mir_sntprintf(text,SIZEOF(text),TranslateT("Do you want to delete contact '%s' from server list?"),dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if (MessageBox( 0, text, m_tszUserName, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 ) == IDYES) {
+
+ if( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) )
+ {
+ if (!isOffline()) { // TODO: is this needed?
+ std::string* id = new std::string(dbv.pszVal);
+
+ facebook_user* fbu = facy.buddies.find( (*id) );
+ if (fbu != NULL) {
+ fbu->handle = NULL;
+ }
+
+ ForkThread( &FacebookProto::DeleteContactFromServer, this, ( void* )id );
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ }
+
+ return 0;
+}
diff --git a/protocols/FacebookRM/db.h b/protocols/FacebookRM/db.h new file mode 100644 index 0000000000..d928300e59 --- /dev/null +++ b/protocols/FacebookRM/db.h @@ -0,0 +1,96 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+// DB macros
+#define getByte( setting, error ) DBGetContactSettingByte( NULL, m_szModuleName, setting, error )
+#define setByte( setting, value ) DBWriteContactSettingByte( NULL, m_szModuleName, setting, value )
+#define getWord( setting, error ) DBGetContactSettingWord( NULL, m_szModuleName, setting, error )
+#define setWord( setting, value ) DBWriteContactSettingWord( NULL, m_szModuleName, setting, value )
+#define getDword( setting, error ) DBGetContactSettingDword( NULL, m_szModuleName, setting, error )
+#define setDword( setting, value ) DBWriteContactSettingDword( NULL, m_szModuleName, setting, value )
+#define getString( setting, dest ) DBGetContactSettingString( NULL, m_szModuleName, setting, dest )
+#define setString( setting, value ) DBWriteContactSettingString( NULL, m_szModuleName, setting, value )
+#define getTString( setting, dest ) DBGetContactSettingTString( NULL, m_szModuleName, setting, dest )
+#define setTString( setting, value ) DBWriteContactSettingTString( NULL, m_szModuleName, setting, value )
+#define getU8String( setting, dest ) DBGetContactSettingUTF8String( NULL, m_szModuleName, setting, dest )
+#define setU8String( setting, value ) DBWriteContactSettingUTF8String( NULL, m_szModuleName, setting, value )
+#define deleteSetting( setting ) DBDeleteContactSetting( NULL, m_szModuleName, setting )
+
+// DB keys
+#define FACEBOOK_KEY_LOGIN "Email"
+#define FACEBOOK_KEY_ID "ID"
+#define FACEBOOK_KEY_NAME "RealName"
+#define FACEBOOK_KEY_NICK "Nick"
+#define FACEBOOK_KEY_PASS "Password"
+#define FACEBOOK_KEY_UPD_NAMES "UpdateNames"
+#define FACEBOOK_KEY_DEVICE_ID "DeviceID"
+#define FACEBOOK_KEY_AV_URL "AvatarURL"
+#define FACEBOOK_KEY_DELETED "Deleted"
+#define FACEBOOK_KEY_CONTACT_TYPE "ContactType"
+
+#define FACEBOOK_KEY_DEF_GROUP "DefaultGroup"
+#define FACEBOOK_KEY_FORCE_HTTPS "ForceHTTPS"
+#define FACEBOOK_KEY_FORCE_HTTPS_CHANNEL "ForceHTTPSChannel"
+#define FACEBOOK_KEY_CLOSE_WINDOWS_ENABLE "CloseChatEnable"
+#define FACEBOOK_KEY_SET_MIRANDA_STATUS "SetMirandaStatus"
+#define FACEBOOK_KEY_LOGGING_ENABLE "LoggingEnable"
+#define FACEBOOK_KEY_SYSTRAY_NOTIFY "UseSystrayNotify"
+#define FACEBOOK_KEY_DISABLE_STATUS_NOTIFY "DisableStatusNotify"
+#define FACEBOOK_KEY_PARSE_MESSAGES "ParseUnreadMessages"
+#define FACEBOOK_KEY_BIG_AVATARS "UseBigAvatars"
+#define FACEBOOK_KEY_DISCONNECT_CHAT "DisconnectChatEnable"
+#define FACEBOOK_KEY_MAP_STATUSES "MapStatuses"
+#define FACEBOOK_KEY_LOAD_MOBILE "LoadMobile"
+#define FACEBOOK_KEY_ENABLE_GROUPCHATS "GroupchatsEnable"
+
+#define FACEBOOK_KEY_POLL_RATE "PollRate" // [HIDDEN]
+#define FACEBOOK_KEY_TIMEOUTS_LIMIT "TimeoutsLimit" // [HIDDEN]
+#define FACEBOOK_KEY_DISABLE_LOGOUT "DisableLogout" // [HIDDEN]
+#define FACEBOOK_KEY_VALIDATE_RESPONSE "ValidateResponse" // [HIDDEN] - 0 = standard, 1 = always, 2 = never
+
+#define FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE "EventNotificationsEnable"
+#define FACEBOOK_KEY_EVENT_FEEDS_ENABLE "EventFeedsEnable"
+#define FACEBOOK_KEY_EVENT_OTHER_ENABLE "EventOtherEnable"
+#define FACEBOOK_KEY_EVENT_CLIENT_ENABLE "EventClientEnable"
+#define FACEBOOK_KEY_FEED_TYPE "EventFeedsType"
+
+#define FACEBOOK_KEY_EVENT_NOTIFICATIONS_COLBACK "PopupNotificationsColorBack"
+#define FACEBOOK_KEY_EVENT_NOTIFICATIONS_COLTEXT "PopupNotificationsColorText"
+#define FACEBOOK_KEY_EVENT_NOTIFICATIONS_TIMEOUT "PopupNotificationsTimeout"
+#define FACEBOOK_KEY_EVENT_NOTIFICATIONS_DEFAULT "PopupNotificationsColorDefault"
+
+#define FACEBOOK_KEY_EVENT_FEEDS_COLBACK "PopupFeedsColorBack"
+#define FACEBOOK_KEY_EVENT_FEEDS_COLTEXT "PopupFeedsColorText"
+#define FACEBOOK_KEY_EVENT_FEEDS_TIMEOUT "PopupFeedsTimeout"
+#define FACEBOOK_KEY_EVENT_FEEDS_DEFAULT "PopupFeedsColorDefault"
+
+#define FACEBOOK_KEY_EVENT_OTHER_COLBACK "PopupOtherColorBack"
+#define FACEBOOK_KEY_EVENT_OTHER_COLTEXT "PopupOtherColorText"
+#define FACEBOOK_KEY_EVENT_OTHER_TIMEOUT "PopupOtherTimeout"
+#define FACEBOOK_KEY_EVENT_OTHER_DEFAULT "PopupOtherColorDefault"
+
+#define FACEBOOK_KEY_EVENT_CLIENT_COLBACK "PopupClientColorBack"
+#define FACEBOOK_KEY_EVENT_CLIENT_COLTEXT "PopupClientColorText"
+#define FACEBOOK_KEY_EVENT_CLIENT_TIMEOUT "PopupClientTimeout"
+#define FACEBOOK_KEY_EVENT_CLIENT_DEFAULT "PopupClientColorDefault"
diff --git a/protocols/FacebookRM/definitions.h b/protocols/FacebookRM/definitions.h new file mode 100644 index 0000000000..0679c567cf --- /dev/null +++ b/protocols/FacebookRM/definitions.h @@ -0,0 +1,48 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+#define CODE_BLOCK_BEGIN {
+#define CODE_BLOCK_TRY try {
+#define CODE_BLOCK_CATCH } catch(const std::exception &e) {
+#define CODE_BLOCK_INFINITE while( true ) {
+#define CODE_BLOCK_END }
+
+#define FLAG_CONTAINS(x,y) ( ( x & y ) == y )
+#define REMOVE_FLAG(x,y) ( x = ( x & ~y ) )
+
+#define LOG Log
+
+#define LOG_NOTIFY 0
+#define LOG_WARNING 1
+#define LOG_ALERT 2
+#define LOG_FAILURE 3
+#define LOG_CRITICAL 4
+
+#if defined( _UNICODE )
+#define NIIF_INTERN_TCHAR NIIF_INTERN_UNICODE // m_clist.h
+#define mir_tstrdup mir_wstrdup // m_system.h
+#else
+#define NIIF_INTERN_TCHAR 0
+#define mir_tstrdup mir_strdup
+#endif
diff --git a/protocols/FacebookRM/dialogs.cpp b/protocols/FacebookRM/dialogs.cpp new file mode 100644 index 0000000000..721ef35905 --- /dev/null +++ b/protocols/FacebookRM/dialogs.cpp @@ -0,0 +1,486 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+static BOOL LoadDBCheckState(FacebookProto* ppro, HWND hwnd, int idCtrl, const char* szSetting, BYTE bDef)
+{
+ BOOL state = DBGetContactSettingByte(NULL, ppro->m_szModuleName, szSetting, bDef);
+ CheckDlgButton(hwnd, idCtrl, state);
+ return state;
+}
+
+static BOOL StoreDBCheckState(FacebookProto* ppro, HWND hwnd, int idCtrl, const char* szSetting)
+{
+ BOOL state = IsDlgButtonChecked(hwnd, idCtrl);
+ DBWriteContactSettingByte(NULL, ppro->m_szModuleName, szSetting, (BYTE)state);
+ return state;
+}
+
+INT_PTR CALLBACK FBAccountProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
+{
+ FacebookProto *proto;
+
+ switch ( message )
+ {
+
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwnd);
+
+ proto = reinterpret_cast<FacebookProto*>(lparam);
+ SetWindowLong(hwnd,GWLP_USERDATA,lparam);
+
+ DBVARIANT dbv;
+ if( !DBGetContactSettingString(0,proto->ModuleName(),FACEBOOK_KEY_LOGIN,&dbv) )
+ {
+ SetDlgItemTextA(hwnd,IDC_UN,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if ( !DBGetContactSettingString(0,proto->ModuleName(),FACEBOOK_KEY_PASS,&dbv) )
+ {
+ CallService(MS_DB_CRYPT_DECODESTRING,strlen(dbv.pszVal)+1,
+ reinterpret_cast<LPARAM>(dbv.pszVal));
+ SetDlgItemTextA(hwnd,IDC_PW,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if (!proto->isOffline()) {
+ SendMessage(GetDlgItem(hwnd,IDC_UN),EM_SETREADONLY,1,0);
+ SendMessage(GetDlgItem(hwnd,IDC_PW),EM_SETREADONLY,1,0); }
+
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( LOWORD( wparam ) == IDC_NEWACCOUNTLINK )
+ {
+ CallService(MS_UTILS_OPENURL,1,reinterpret_cast<LPARAM>
+ ( FACEBOOK_URL_HOMEPAGE ) );
+ return TRUE;
+ }
+
+ if ( HIWORD( wparam ) == EN_CHANGE && reinterpret_cast<HWND>(lparam) == GetFocus() )
+ {
+ switch(LOWORD(wparam))
+ {
+ case IDC_UN:
+ case IDC_PW:
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ if ( reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY )
+ {
+ proto = reinterpret_cast<FacebookProto*>(GetWindowLong(hwnd,GWLP_USERDATA));
+ char str[128];
+
+ GetDlgItemTextA(hwnd,IDC_UN,str,sizeof(str));
+ DBWriteContactSettingString(0,proto->ModuleName(),FACEBOOK_KEY_LOGIN,str);
+
+ GetDlgItemTextA(hwnd,IDC_PW,str,sizeof(str));
+ CallService(MS_DB_CRYPT_ENCODESTRING,sizeof(str),reinterpret_cast<LPARAM>(str));
+ DBWriteContactSettingString(0,proto->ModuleName(),FACEBOOK_KEY_PASS,str);
+
+ return TRUE;
+ }
+ break;
+
+ }
+
+ return FALSE;
+}
+
+INT_PTR CALLBACK FBMindProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
+{
+ FacebookProto *proto;
+
+ switch(message)
+ {
+
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwnd);
+
+ proto = reinterpret_cast<FacebookProto*>(lparam);
+ SetWindowLong(hwnd,GWLP_USERDATA,lparam);
+ SendDlgItemMessage(hwnd,IDC_MINDMSG,EM_LIMITTEXT,FACEBOOK_MIND_LIMIT,0);
+
+ DBVARIANT dbv = { DBVT_TCHAR };
+
+ if (!DBGetContactSettingTString(NULL,proto->m_szModuleName,FACEBOOK_KEY_NAME,&dbv))
+ {
+ SetWindowText( hwnd, dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+
+ EnableWindow(GetDlgItem( hwnd, IDOK ), FALSE);
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( LOWORD( wparam ) == IDC_MINDMSG && HIWORD( wparam ) == EN_CHANGE )
+ {
+ size_t len = SendDlgItemMessage(hwnd,IDC_MINDMSG,WM_GETTEXTLENGTH,0,0);
+ TCHAR str[4];
+ _sntprintf( str, 4, TEXT( "%d" ), FACEBOOK_MIND_LIMIT-len );
+ SetDlgItemText(hwnd,IDC_CHARACTERS,str);
+
+ EnableWindow(GetDlgItem( hwnd, IDOK ), len > 0);
+
+ return TRUE;
+ }
+ else if ( LOWORD( wparam ) == IDOK )
+ {
+ TCHAR mindMessage[FACEBOOK_MIND_LIMIT+1];
+ proto = reinterpret_cast<FacebookProto*>(GetWindowLong(hwnd,GWLP_USERDATA));
+
+ GetDlgItemText(hwnd,IDC_MINDMSG,mindMessage,SIZEOF(mindMessage));
+ ShowWindow(hwnd,SW_HIDE);
+
+ char *narrow = mir_utf8encodeT(mindMessage);
+ if (proto->last_status_msg_ != narrow) proto->last_status_msg_ = narrow;
+ utils::mem::detract(narrow);
+
+ //char *narrow = mir_t2a_cp(mindMessage,CP_UTF8);
+ ForkThread(&FacebookProto::SetAwayMsgWorker, proto, NULL);
+
+ EndDialog(hwnd, wparam);
+ return TRUE;
+ }
+ else if ( LOWORD( wparam ) == IDCANCEL )
+ {
+ EndDialog(hwnd, wparam);
+ return TRUE;
+ }
+ break;
+
+ }
+
+ return FALSE;
+}
+
+INT_PTR CALLBACK FBOptionsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
+{
+ FacebookProto *proto = reinterpret_cast<FacebookProto*>(GetWindowLong(hwnd,GWLP_USERDATA));
+
+ switch ( message )
+ {
+
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwnd);
+
+ proto = reinterpret_cast<FacebookProto*>(lparam);
+ SetWindowLong(hwnd,GWLP_USERDATA,lparam);
+
+ DBVARIANT dbv;
+ if( !DBGetContactSettingString(0,proto->ModuleName(),FACEBOOK_KEY_LOGIN,&dbv) )
+ {
+ SetDlgItemTextA(hwnd,IDC_UN,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if ( !DBGetContactSettingString(0,proto->ModuleName(),FACEBOOK_KEY_PASS,&dbv) )
+ {
+ CallService(MS_DB_CRYPT_DECODESTRING,strlen(dbv.pszVal)+1,reinterpret_cast<LPARAM>(dbv.pszVal));
+ SetDlgItemTextA(hwnd,IDC_PW,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if (!proto->isOffline())
+ {
+ SendMessage(GetDlgItem(hwnd,IDC_UN),EM_SETREADONLY,TRUE,0);
+ SendMessage(GetDlgItem(hwnd,IDC_PW),EM_SETREADONLY,TRUE,0);
+ }
+
+ SendDlgItemMessage(hwnd, IDC_GROUP, EM_LIMITTEXT, FACEBOOK_GROUP_NAME_LIMIT, 0);
+
+ if( !DBGetContactSettingTString(0,proto->ModuleName(),FACEBOOK_KEY_DEF_GROUP,&dbv) )
+ {
+ SetDlgItemText(hwnd,IDC_GROUP,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ LoadDBCheckState(proto, hwnd, IDC_SET_IGNORE_STATUS, FACEBOOK_KEY_DISABLE_STATUS_NOTIFY, DEFAULT_DISABLE_STATUS_NOTIFY);
+ LoadDBCheckState(proto, hwnd, IDC_BIGGER_AVATARS, FACEBOOK_KEY_BIG_AVATARS, DEFAULT_BIG_AVATARS);
+ LoadDBCheckState(proto, hwnd, IDC_LOAD_MOBILE, FACEBOOK_KEY_LOAD_MOBILE, DEFAULT_LOAD_MOBILE);
+
+ } return TRUE;
+
+ case WM_COMMAND: {
+ if ( LOWORD( wparam ) == IDC_NEWACCOUNTLINK )
+ {
+ CallService(MS_UTILS_OPENURL,1,reinterpret_cast<LPARAM>
+ ( FACEBOOK_URL_HOMEPAGE ) );
+ return TRUE;
+ }
+
+ if ( LOWORD( wparam ) == IDC_SECURE ) {
+ EnableWindow(GetDlgItem(hwnd, IDC_SECURE_CHANNEL), IsDlgButtonChecked(hwnd, IDC_SECURE));
+ }
+
+ if ((LOWORD(wparam)==IDC_UN || LOWORD(wparam)==IDC_PW || LOWORD(wparam)==IDC_GROUP) &&
+ (HIWORD(wparam)!=EN_CHANGE || (HWND)lparam!=GetFocus()))
+ return 0;
+ else
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+
+ } break;
+
+ case WM_NOTIFY:
+ if ( reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY )
+ {
+ char str[128]; TCHAR tstr[128];
+
+ GetDlgItemTextA(hwnd,IDC_UN,str,sizeof(str));
+ DBWriteContactSettingString(0,proto->ModuleName(),FACEBOOK_KEY_LOGIN,str);
+
+ GetDlgItemTextA(hwnd,IDC_PW,str,sizeof(str));
+ CallService(MS_DB_CRYPT_ENCODESTRING,sizeof(str),reinterpret_cast<LPARAM>(str));
+ DBWriteContactSettingString(NULL,proto->m_szModuleName,FACEBOOK_KEY_PASS,str);
+
+ GetDlgItemText(hwnd,IDC_GROUP,tstr,sizeof(tstr));
+ if ( lstrlen( tstr ) > 0 )
+ {
+ DBWriteContactSettingTString(NULL,proto->m_szModuleName,FACEBOOK_KEY_DEF_GROUP,tstr);
+ CallService( MS_CLIST_GROUPCREATE, 0, (LPARAM)tstr );
+ }
+ else
+ DBDeleteContactSetting(NULL,proto->m_szModuleName,FACEBOOK_KEY_DEF_GROUP);
+
+ StoreDBCheckState(proto, hwnd, IDC_SET_IGNORE_STATUS, FACEBOOK_KEY_DISABLE_STATUS_NOTIFY);
+ StoreDBCheckState(proto, hwnd, IDC_BIGGER_AVATARS, FACEBOOK_KEY_BIG_AVATARS);
+ StoreDBCheckState(proto, hwnd, IDC_LOAD_MOBILE, FACEBOOK_KEY_LOAD_MOBILE);
+
+ return TRUE;
+ }
+ break;
+
+ }
+
+ return FALSE;
+}
+
+INT_PTR CALLBACK FBOptionsAdvancedProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
+{
+ FacebookProto *proto = reinterpret_cast<FacebookProto*>(GetWindowLong(hwnd,GWLP_USERDATA));
+
+ switch ( message )
+ {
+
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwnd);
+
+ proto = reinterpret_cast<FacebookProto*>(lparam);
+ SetWindowLong(hwnd,GWLP_USERDATA,lparam);
+
+ LoadDBCheckState(proto, hwnd, IDC_SECURE, FACEBOOK_KEY_FORCE_HTTPS, DEFAULT_FORCE_HTTPS);
+ LoadDBCheckState(proto, hwnd, IDC_SECURE_CHANNEL, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL, DEFAULT_FORCE_HTTPS_CHANNEL);
+ LoadDBCheckState(proto, hwnd, IDC_DISCONNECT_CHAT, FACEBOOK_KEY_DISCONNECT_CHAT, DEFAULT_DISCONNECT_CHAT);
+ LoadDBCheckState(proto, hwnd, IDC_PARSE_UNREAD, FACEBOOK_KEY_PARSE_MESSAGES, DEFAULT_PARSE_MESSAGES);
+ LoadDBCheckState(proto, hwnd, IDC_CLOSE_WINDOWS, FACEBOOK_KEY_CLOSE_WINDOWS_ENABLE, DEFAULT_CLOSE_WINDOWS_ENABLE);
+ LoadDBCheckState(proto, hwnd, IDC_SET_STATUS, FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS);
+ LoadDBCheckState(proto, hwnd, IDC_LOGGING, FACEBOOK_KEY_LOGGING_ENABLE, DEFAULT_LOGGING_ENABLE);
+ LoadDBCheckState(proto, hwnd, IDC_MAP_STATUSES, FACEBOOK_KEY_MAP_STATUSES, DEFAULT_MAP_STATUSES);
+ LoadDBCheckState(proto, hwnd, IDC_GROUPCHATS, FACEBOOK_KEY_ENABLE_GROUPCHATS, DEFAULT_ENABLE_GROUPCHATS);
+
+ EnableWindow(GetDlgItem(hwnd, IDC_SECURE_CHANNEL), IsDlgButtonChecked(hwnd, IDC_SECURE));
+
+ } return TRUE;
+
+ case WM_COMMAND: {
+ if ( LOWORD( wparam ) == IDC_SECURE ) {
+ EnableWindow(GetDlgItem(hwnd, IDC_SECURE_CHANNEL), IsDlgButtonChecked(hwnd, IDC_SECURE));
+ }
+
+ if (LOWORD(wparam) == IDC_SECURE_CHANNEL && IsDlgButtonChecked(hwnd, IDC_SECURE_CHANNEL))
+ MessageBox( hwnd, TranslateT("Note: Make sure you have disabled 'Validate SSL certificates' option in Network options to work properly."), proto->m_tszUserName, MB_OK );
+
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+
+ } break;
+
+ case WM_NOTIFY:
+ if ( reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY )
+ {
+ StoreDBCheckState(proto, hwnd, IDC_SECURE, FACEBOOK_KEY_FORCE_HTTPS);
+ StoreDBCheckState(proto, hwnd, IDC_CLOSE_WINDOWS, FACEBOOK_KEY_CLOSE_WINDOWS_ENABLE);
+ StoreDBCheckState(proto, hwnd, IDC_LOGGING, FACEBOOK_KEY_LOGGING_ENABLE);
+ StoreDBCheckState(proto, hwnd, IDC_SECURE_CHANNEL, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL);
+ StoreDBCheckState(proto, hwnd, IDC_DISCONNECT_CHAT, FACEBOOK_KEY_DISCONNECT_CHAT);
+ StoreDBCheckState(proto, hwnd, IDC_PARSE_UNREAD, FACEBOOK_KEY_PARSE_MESSAGES);
+ StoreDBCheckState(proto, hwnd, IDC_MAP_STATUSES, FACEBOOK_KEY_MAP_STATUSES);
+ StoreDBCheckState(proto, hwnd, IDC_GROUPCHATS, FACEBOOK_KEY_ENABLE_GROUPCHATS);
+
+ BOOL setStatus = IsDlgButtonChecked(hwnd, IDC_SET_STATUS);
+ BOOL setStatusOld = DBGetContactSettingByte(NULL, proto->m_szModuleName, FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS);
+ if (setStatus != setStatusOld)
+ {
+ DBWriteContactSettingByte(NULL, proto->m_szModuleName, FACEBOOK_KEY_SET_MIRANDA_STATUS, setStatus);
+ if (setStatus && proto->isOnline() && DBGetContactSettingByte(NULL, proto->m_szModuleName, FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS))
+ {
+ ForkThread(&FacebookProto::SetAwayMsgWorker, proto, NULL);
+ }
+ }
+
+ return TRUE;
+ }
+ break;
+
+ }
+
+ return FALSE;
+}
+
+
+INT_PTR CALLBACK FBEventsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
+{
+ FacebookProto *proto = reinterpret_cast<FacebookProto*>(GetWindowLong(hwnd,GWLP_USERDATA));
+
+ switch(message)
+ {
+
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwnd);
+
+ proto = reinterpret_cast<FacebookProto*>(lparam);
+ SetWindowLong(hwnd,GWLP_USERDATA,lparam);
+
+ for(size_t i=0; i<SIZEOF(feed_types); i++)
+ {
+ SendDlgItemMessageA(hwnd,IDC_FEED_TYPE,CB_INSERTSTRING,i,
+ reinterpret_cast<LPARAM>(Translate(feed_types[i].name)));
+ }
+ SendDlgItemMessage(hwnd, IDC_FEED_TYPE, CB_SETCURSEL, DBGetContactSettingByte(NULL, proto->m_szModuleName, FACEBOOK_KEY_FEED_TYPE, 0), 0);
+ LoadDBCheckState(proto, hwnd, IDC_SYSTRAY_NOTIFY, FACEBOOK_KEY_SYSTRAY_NOTIFY, DEFAULT_SYSTRAY_NOTIFY);
+
+ LoadDBCheckState(proto, hwnd, IDC_NOTIFICATIONS_ENABLE, FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE);
+ LoadDBCheckState(proto, hwnd, IDC_FEEDS_ENABLE, FACEBOOK_KEY_EVENT_FEEDS_ENABLE, DEFAULT_EVENT_FEEDS_ENABLE);
+ LoadDBCheckState(proto, hwnd, IDC_CLIENT_ENABLE, FACEBOOK_KEY_EVENT_CLIENT_ENABLE, DEFAULT_EVENT_CLIENT_ENABLE);
+ LoadDBCheckState(proto, hwnd, IDC_OTHER_ENABLE, FACEBOOK_KEY_EVENT_OTHER_ENABLE, DEFAULT_EVENT_OTHER_ENABLE);
+
+ SendDlgItemMessage(hwnd, IDC_COLBACK, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_NOTIFICATIONS_COLBACK,DEFAULT_EVENT_COLBACK));
+ SendDlgItemMessage(hwnd, IDC_COLTEXT, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_NOTIFICATIONS_COLTEXT,DEFAULT_EVENT_COLTEXT));
+ SetDlgItemInt(hwnd, IDC_TIMEOUT,DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_NOTIFICATIONS_TIMEOUT, 0),TRUE);
+ SendDlgItemMessage(hwnd, IDC_COLBACK2, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_FEEDS_COLBACK,DEFAULT_EVENT_COLBACK));
+ SendDlgItemMessage(hwnd, IDC_COLTEXT2, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_FEEDS_COLTEXT,DEFAULT_EVENT_COLTEXT));
+ SetDlgItemInt(hwnd, IDC_TIMEOUT2,DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_FEEDS_TIMEOUT, 0),TRUE);
+ SendDlgItemMessage(hwnd, IDC_COLBACK3, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_OTHER_COLBACK,DEFAULT_EVENT_COLBACK));
+ SendDlgItemMessage(hwnd, IDC_COLTEXT3, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_OTHER_COLTEXT,DEFAULT_EVENT_COLTEXT));
+ SetDlgItemInt(hwnd, IDC_TIMEOUT3,DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_OTHER_TIMEOUT, 0),TRUE);
+ SendDlgItemMessage(hwnd, IDC_COLBACK4, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_CLIENT_COLBACK,DEFAULT_EVENT_COLBACK));
+ SendDlgItemMessage(hwnd, IDC_COLTEXT4, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_CLIENT_COLTEXT,DEFAULT_EVENT_COLTEXT));
+ SetDlgItemInt(hwnd, IDC_TIMEOUT4,DBGetContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_CLIENT_TIMEOUT, 0),TRUE);
+
+ LoadDBCheckState(proto, hwnd, IDC_NOTIFICATIONS_DEFAULT, FACEBOOK_KEY_EVENT_NOTIFICATIONS_DEFAULT, 0);
+ LoadDBCheckState(proto, hwnd, IDC_FEEDS_DEFAULT, FACEBOOK_KEY_EVENT_FEEDS_DEFAULT, 0);
+ LoadDBCheckState(proto, hwnd, IDC_CLIENT_DEFAULT, FACEBOOK_KEY_EVENT_CLIENT_DEFAULT, 0);
+ LoadDBCheckState(proto, hwnd, IDC_OTHER_DEFAULT, FACEBOOK_KEY_EVENT_OTHER_DEFAULT, 0);
+
+ SendDlgItemMessage(hwnd, IDC_TIMEOUT, EM_LIMITTEXT, 4, 0);
+ SendDlgItemMessage(hwnd, IDC_TIMEOUT_SPIN, UDM_SETRANGE32, -1, 100);
+ SendDlgItemMessage(hwnd, IDC_TIMEOUT2, EM_LIMITTEXT, 4, 0);
+ SendDlgItemMessage(hwnd, IDC_TIMEOUT_SPIN2, UDM_SETRANGE32, -1, 100);
+ SendDlgItemMessage(hwnd, IDC_TIMEOUT3, EM_LIMITTEXT, 4, 0);
+ SendDlgItemMessage(hwnd, IDC_TIMEOUT_SPIN3, UDM_SETRANGE32, -1, 100);
+ SendDlgItemMessage(hwnd, IDC_TIMEOUT4, EM_LIMITTEXT, 4, 0);
+ SendDlgItemMessage(hwnd, IDC_TIMEOUT_SPIN4, UDM_SETRANGE32, -1, 100);
+
+ } return TRUE;
+
+ case WM_COMMAND: {
+ switch ( LOWORD( wparam ) )
+ {
+ case IDC_PREVIEW:
+ {
+ TCHAR protoName[255];
+ lstrcpy( protoName, proto->m_tszUserName );
+ proto->NotifyEvent( protoName, TranslateT("Sample event"), NULL, FACEBOOK_EVENT_CLIENT );
+ proto->NotifyEvent( protoName, TranslateT("Sample request"), NULL, FACEBOOK_EVENT_OTHER );
+ proto->NotifyEvent( protoName, TranslateT("Sample newsfeed"), NULL, FACEBOOK_EVENT_NEWSFEED );
+ proto->NotifyEvent( protoName, TranslateT("Sample notification"), NULL, FACEBOOK_EVENT_NOTIFICATION );
+ } break;
+
+ case IDC_COLTEXT:
+ case IDC_COLBACK:
+ case IDC_COLTEXT2:
+ case IDC_COLBACK2:
+ case IDC_COLTEXT3:
+ case IDC_COLBACK3:
+ case IDC_COLTEXT4:
+ case IDC_COLBACK4:
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+ // TODO: Required? There's a catching clause below
+ }
+
+ if ((LOWORD(wparam)==IDC_PREVIEW || (HWND)lparam!=GetFocus()))
+ return 0;
+ else
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0); }
+
+ return TRUE;
+
+ case WM_NOTIFY:
+ {
+ if ( reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY )
+ {
+ DBWriteContactSettingByte(NULL, proto->m_szModuleName, FACEBOOK_KEY_FEED_TYPE, SendDlgItemMessage(hwnd, IDC_FEED_TYPE, CB_GETCURSEL, 0, 0));
+
+ StoreDBCheckState(proto, hwnd, IDC_SYSTRAY_NOTIFY, FACEBOOK_KEY_SYSTRAY_NOTIFY);
+
+ StoreDBCheckState(proto, hwnd, IDC_NOTIFICATIONS_ENABLE, FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE);
+ StoreDBCheckState(proto, hwnd, IDC_FEEDS_ENABLE, FACEBOOK_KEY_EVENT_FEEDS_ENABLE);
+ StoreDBCheckState(proto, hwnd, IDC_OTHER_ENABLE, FACEBOOK_KEY_EVENT_OTHER_ENABLE);
+ StoreDBCheckState(proto, hwnd, IDC_CLIENT_ENABLE, FACEBOOK_KEY_EVENT_CLIENT_ENABLE);
+
+ StoreDBCheckState(proto, hwnd, IDC_NOTIFICATIONS_DEFAULT, FACEBOOK_KEY_EVENT_NOTIFICATIONS_DEFAULT);
+ StoreDBCheckState(proto, hwnd, IDC_FEEDS_DEFAULT, FACEBOOK_KEY_EVENT_FEEDS_DEFAULT);
+ StoreDBCheckState(proto, hwnd, IDC_OTHER_DEFAULT, FACEBOOK_KEY_EVENT_OTHER_DEFAULT);
+ StoreDBCheckState(proto, hwnd, IDC_CLIENT_DEFAULT, FACEBOOK_KEY_EVENT_CLIENT_DEFAULT);
+
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_NOTIFICATIONS_COLBACK, SendDlgItemMessage(hwnd,IDC_COLBACK,CPM_GETCOLOUR,0,0));
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_NOTIFICATIONS_COLTEXT, SendDlgItemMessage(hwnd,IDC_COLTEXT,CPM_GETCOLOUR,0,0));
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_NOTIFICATIONS_TIMEOUT, GetDlgItemInt(hwnd,IDC_TIMEOUT,NULL,TRUE));
+
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_FEEDS_COLBACK, SendDlgItemMessage(hwnd,IDC_COLBACK2,CPM_GETCOLOUR,0,0));
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_FEEDS_COLTEXT, SendDlgItemMessage(hwnd,IDC_COLTEXT2,CPM_GETCOLOUR,0,0));
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_FEEDS_TIMEOUT, GetDlgItemInt(hwnd,IDC_TIMEOUT2,NULL,TRUE));
+
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_OTHER_COLBACK, SendDlgItemMessage(hwnd,IDC_COLBACK3,CPM_GETCOLOUR,0,0));
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_OTHER_COLTEXT, SendDlgItemMessage(hwnd,IDC_COLTEXT3,CPM_GETCOLOUR,0,0));
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_OTHER_TIMEOUT, GetDlgItemInt(hwnd,IDC_TIMEOUT3,NULL,TRUE));
+
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_CLIENT_COLBACK, SendDlgItemMessage(hwnd,IDC_COLBACK4,CPM_GETCOLOUR,0,0));
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_CLIENT_COLTEXT, SendDlgItemMessage(hwnd,IDC_COLTEXT4,CPM_GETCOLOUR,0,0));
+ DBWriteContactSettingDword(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_CLIENT_TIMEOUT, GetDlgItemInt(hwnd,IDC_TIMEOUT4,NULL,TRUE));
+ }
+ }
+ return TRUE;
+
+ }
+
+ return FALSE;
+}
diff --git a/protocols/FacebookRM/dialogs.h b/protocols/FacebookRM/dialogs.h new file mode 100644 index 0000000000..1917027546 --- /dev/null +++ b/protocols/FacebookRM/dialogs.h @@ -0,0 +1,29 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+INT_PTR CALLBACK FBAccountProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam );
+INT_PTR CALLBACK FBMindProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam );
+INT_PTR CALLBACK FBOptionsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam );
+INT_PTR CALLBACK FBOptionsAdvancedProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam );
+INT_PTR CALLBACK FBEventsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam );
diff --git a/protocols/FacebookRM/entities.h b/protocols/FacebookRM/entities.h new file mode 100644 index 0000000000..dbe32b8b51 --- /dev/null +++ b/protocols/FacebookRM/entities.h @@ -0,0 +1,136 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+struct facebook_user
+{
+ HANDLE handle;
+
+ std::string user_id;
+ std::string real_name;
+
+ unsigned int status_id;
+ unsigned int gender;
+
+ std::string image_url;
+
+ bool deleted;
+
+ facebook_user( )
+ {
+ this->handle = NULL;
+ this->user_id = this->real_name = this->image_url = "";
+ this->status_id = ID_STATUS_OFFLINE;
+ this->gender = 0;
+ this->deleted = false;
+ }
+
+ facebook_user( facebook_user* fu )
+ {
+ this->handle = fu->handle;
+ this->image_url = fu->image_url;
+ this->real_name = fu->real_name;
+ this->status_id = fu->status_id;
+ this->user_id = fu->user_id;
+ this->gender = fu->gender;
+ this->deleted = fu->deleted;
+ }
+};
+
+struct facebook_message
+{
+ std::string user_id;
+ std::string message_text;
+ std::string sender_name;
+ time_t time;
+
+ facebook_message( )
+ {
+ this->user_id = this->message_text = this->sender_name = "";
+ this->time = 0;
+ }
+
+ facebook_message( const facebook_message& msg )
+ {
+ this->user_id = msg.user_id;
+ this->message_text = msg.message_text;
+ this->sender_name = msg.sender_name;
+ this->time = msg.time;
+ }
+};
+
+struct facebook_notification
+{
+ std::string user_id;
+ std::string text;
+ std::string link;
+
+ facebook_notification( )
+ {
+ this->user_id = this->text = this->link = "";
+ }
+};
+
+struct facebook_newsfeed
+{
+ std::string user_id;
+ std::string title;
+ std::string text;
+ std::string link;
+
+ facebook_newsfeed( )
+ {
+ this->user_id = this->title = this->text = this->link = "";
+ }
+};
+
+
+struct send_chat
+{
+ send_chat(const std::string &chat_id,const std::string &msg) : chat_id(chat_id), msg(msg) {}
+ std::string chat_id;
+ std::string msg;
+};
+
+
+struct send_direct
+{
+ send_direct(HANDLE hContact,const std::string &msg, HANDLE msgid) : hContact(hContact), msg(msg), msgid(msgid) {}
+ HANDLE hContact;
+ std::string msg;
+ HANDLE msgid;
+};
+
+struct send_typing
+{
+ send_typing(HANDLE hContact,const int status) : hContact(hContact), status(status) {}
+ HANDLE hContact;
+ int status;
+};
+
+struct send_messaging
+{
+ send_messaging(const std::string &user_id, const int type) : user_id(user_id), type(type) {}
+ std::string user_id;
+ int type;
+};
diff --git a/protocols/FacebookRM/events.cpp b/protocols/FacebookRM/events.cpp new file mode 100644 index 0000000000..2f93a58335 --- /dev/null +++ b/protocols/FacebookRM/events.cpp @@ -0,0 +1,186 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+int FacebookProto::Log(const char *fmt,...)
+{
+ if ( !getByte( FACEBOOK_KEY_LOGGING_ENABLE, 0 ) )
+ return EXIT_SUCCESS;
+
+ va_list va;
+ char text[65535];
+ ScopedLock s(log_lock_);
+
+ va_start(va,fmt);
+ mir_vsnprintf(text,sizeof(text),fmt,va);
+ va_end(va);
+
+ return utils::debug::log( m_szModuleName, text );
+}
+
+LRESULT CALLBACK PopupDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_COMMAND:
+ {
+ //Get the plugin data (we need the PopUp service to do it)
+ TCHAR* data = (TCHAR*)PUGetPluginData(hwnd);
+ if (data != NULL)
+ {
+ std::string url = mir_t2a_cp(data,CP_UTF8);
+ if ( url.substr(0,4) != "http" )
+ url = FACEBOOK_URL_HOMEPAGE + url; // make absolute url
+
+ CallService(MS_UTILS_OPENURL, (WPARAM) 1, (LPARAM) url.c_str() );
+ }
+
+ // After a click, destroy popup
+ PUDeletePopUp(hwnd);
+ } break;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopUp(hwnd);
+ break;
+
+ case UM_FREEPLUGINDATA:
+ {
+ // After close, free
+ TCHAR* url = (TCHAR*)PUGetPluginData(hwnd);
+ if (url != NULL)
+ mir_free(url);
+ } return FALSE;
+
+ default:
+ break;
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+};
+
+void FacebookProto::NotifyEvent(TCHAR* title, TCHAR* info, HANDLE contact, DWORD flags, TCHAR* szUrl)
+{
+ int ret; int timeout; COLORREF colorBack = 0; COLORREF colorText = 0;
+
+ switch ( flags )
+ {
+ case FACEBOOK_EVENT_CLIENT:
+ if ( !getByte( FACEBOOK_KEY_EVENT_CLIENT_ENABLE, DEFAULT_EVENT_CLIENT_ENABLE ) )
+ goto exit;
+ if ( !getByte( FACEBOOK_KEY_EVENT_CLIENT_DEFAULT, 0 ) )
+ {
+ colorBack = getDword( FACEBOOK_KEY_EVENT_CLIENT_COLBACK, DEFAULT_EVENT_COLBACK );
+ colorText = getDword( FACEBOOK_KEY_EVENT_CLIENT_COLTEXT, DEFAULT_EVENT_COLTEXT );
+ }
+ timeout = getDword( FACEBOOK_KEY_EVENT_CLIENT_TIMEOUT, 0 );
+ flags |= NIIF_WARNING;
+ break;
+
+ case FACEBOOK_EVENT_NEWSFEED:
+ if ( !getByte( FACEBOOK_KEY_EVENT_FEEDS_ENABLE, DEFAULT_EVENT_FEEDS_ENABLE ) )
+ goto exit;
+ if ( !getByte( FACEBOOK_KEY_EVENT_FEEDS_DEFAULT, 0 ) )
+ {
+ colorBack = getDword( FACEBOOK_KEY_EVENT_FEEDS_COLBACK, DEFAULT_EVENT_COLBACK );
+ colorText = getDword( FACEBOOK_KEY_EVENT_FEEDS_COLTEXT, DEFAULT_EVENT_COLTEXT );
+ }
+ timeout = getDword( FACEBOOK_KEY_EVENT_FEEDS_TIMEOUT, 0 );
+ SkinPlaySound( "NewsFeed" );
+ flags |= NIIF_INFO;
+ break;
+
+ case FACEBOOK_EVENT_NOTIFICATION:
+ if ( !getByte( FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE ) )
+ goto exit;
+ if ( !getByte( FACEBOOK_KEY_EVENT_NOTIFICATIONS_DEFAULT, 0 ) )
+ {
+ colorBack = getDword( FACEBOOK_KEY_EVENT_NOTIFICATIONS_COLBACK, DEFAULT_EVENT_COLBACK );
+ colorText = getDword( FACEBOOK_KEY_EVENT_NOTIFICATIONS_COLTEXT, DEFAULT_EVENT_COLTEXT );
+ }
+ timeout = getDword( FACEBOOK_KEY_EVENT_NOTIFICATIONS_TIMEOUT, 0 );
+ SkinPlaySound( "Notification" );
+ flags |= NIIF_INFO;
+ break;
+
+ case FACEBOOK_EVENT_OTHER:
+ if ( !getByte( FACEBOOK_KEY_EVENT_OTHER_ENABLE, DEFAULT_EVENT_OTHER_ENABLE ) )
+ goto exit;
+ if ( !getByte( FACEBOOK_KEY_EVENT_OTHER_DEFAULT, 0 ) )
+ {
+ colorBack = getDword( FACEBOOK_KEY_EVENT_OTHER_COLBACK, DEFAULT_EVENT_COLBACK );
+ colorText = getDword( FACEBOOK_KEY_EVENT_OTHER_COLTEXT, DEFAULT_EVENT_COLTEXT );
+ }
+ timeout = getDword( FACEBOOK_KEY_EVENT_OTHER_TIMEOUT, 0 );
+ SkinPlaySound( "OtherEvent" );
+ flags |= NIIF_INFO;
+ break;
+ }
+
+ if ( !getByte(FACEBOOK_KEY_SYSTRAY_NOTIFY,DEFAULT_SYSTRAY_NOTIFY) )
+ {
+ if (ServiceExists(MS_POPUP_ADDPOPUP))
+ {
+ POPUPDATAT pd;
+ pd.colorBack = colorBack;
+ pd.colorText = colorText;
+ pd.iSeconds = timeout;
+ pd.lchContact = contact;
+ pd.lchIcon = GetIcon(1); // TODO: Icon test
+ pd.PluginData = szUrl;
+ pd.PluginWindowProc = (WNDPROC)PopupDlgProc;
+ lstrcpy(pd.lptzContactName, title);
+ lstrcpy(pd.lptzText, info);
+ ret = PUAddPopUpT(&pd);
+
+ if (ret == 0)
+ return;
+ }
+ } else {
+ if (ServiceExists(MS_CLIST_SYSTRAY_NOTIFY))
+ {
+ MIRANDASYSTRAYNOTIFY err;
+ int niif_flags = flags;
+ REMOVE_FLAG( niif_flags, FACEBOOK_EVENT_CLIENT |
+ FACEBOOK_EVENT_NEWSFEED |
+ FACEBOOK_EVENT_NOTIFICATION |
+ FACEBOOK_EVENT_OTHER );
+ err.szProto = m_szModuleName;
+ err.cbSize = sizeof(err);
+ err.dwInfoFlags = NIIF_INTERN_TCHAR | niif_flags;
+ err.tszInfoTitle = title;
+ err.tszInfo = info;
+ err.uTimeout = 1000 * timeout;
+ ret = CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM) & err);
+
+ if (ret == 0)
+ goto exit;
+ }
+ }
+
+ if (FLAG_CONTAINS(flags, FACEBOOK_EVENT_CLIENT))
+ MessageBox(NULL, info, title, MB_OK | MB_ICONINFORMATION);
+
+exit:
+ if (szUrl != NULL)
+ mir_free(szUrl);
+}
diff --git a/protocols/FacebookRM/facebook.rc b/protocols/FacebookRM/facebook.rc new file mode 100644 index 0000000000..7f66333cbc --- /dev/null +++ b/protocols/FacebookRM/facebook.rc @@ -0,0 +1,302 @@ +// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "constants.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "#include ""constants.h""\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_FACEBOOK ICON "icons/facebook.ico"
+IDI_MIND ICON "icons/mind.ico"
+IDI_ADDFRIEND ICON "icons/addFriend.ico"
+IDI_REMOVEFRIEND ICON "icons/removeFriend.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_FACEBOOKACCOUNT DIALOGEX 0, 0, 186, 134
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LTEXT "E-mail:",IDC_STATIC,0,0,53,12
+ EDITTEXT IDC_UN,54,0,131,12,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,0,16,53,12
+ EDITTEXT IDC_PW,54,16,131,12,ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "Create a new Facebook account",IDC_NEWACCOUNTLINK,
+ "Hyperlink",WS_TABSTOP,0,40,174,12
+END
+
+IDD_MIND DIALOGEX 0, 0, 267, 62
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST
+CAPTION "What's on your mind?"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_MINDMSG,4,4,259,36,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ LTEXT "420",IDC_CHARACTERS,4,48,19,10
+ DEFPUSHBUTTON "Share",IDOK,213,44,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,159,44,50,14
+END
+
+IDD_OPTIONS DIALOGEX 0, 0, 305, 238
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "User Details",IDC_STATIC,7,7,291,60
+ LTEXT "E-mail:",IDC_STATIC,17,19,61,8
+ EDITTEXT IDC_UN,84,17,123,13,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,17,35,61,8
+ EDITTEXT IDC_PW,84,33,123,13,ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "Create a new Facebook account",IDC_NEWACCOUNTLINK,
+ "Hyperlink",WS_TABSTOP,84,52,123,10
+ LTEXT "Default group:",IDC_STATIC,17,85,61,8
+ EDITTEXT IDC_GROUP,84,84,123,13,ES_AUTOHSCROLL
+ CONTROL "Automatically set 'Ignore status change' flag",IDC_SET_IGNORE_STATUS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,101,271,10
+ GROUPBOX "Contacts Settings",IDC_STATIC,7,72,291,70
+ CONTROL "Use bigger avatars",IDC_BIGGER_AVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,114,271,10
+ CONTROL "Load contacts with 'On the Mobile' status",IDC_LOAD_MOBILE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,127,271,10
+END
+
+IDD_OPTIONS_EVENTS DIALOGEX 0, 0, 305, 217
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Event notifications",IDC_STATIC,6,7,293,115
+ CTEXT "Colors",IDC_STATIC,106,14,68,8
+ RTEXT "Back",IDC_STATIC,106,24,31,8
+ LTEXT "Text",IDC_STATIC,143,24,31,8
+ CONTROL "Notifications",IDC_NOTIFICATIONS_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,37,84,8
+ CONTROL "",IDC_COLBACK,"ColourPicker",WS_TABSTOP,113,35,24,13
+ CONTROL "",IDC_COLTEXT,"ColourPicker",WS_TABSTOP,143,35,24,13
+ CONTROL "Default",IDC_NOTIFICATIONS_DEFAULT,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,174,37,63,8
+ CONTROL "News feeds",IDC_FEEDS_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,57,84,8
+ CONTROL "",IDC_COLBACK2,"ColourPicker",WS_TABSTOP,113,55,24,13
+ CONTROL "",IDC_COLTEXT2,"ColourPicker",WS_TABSTOP,143,55,24,13
+ CONTROL "Default",IDC_FEEDS_DEFAULT,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,174,57,63,8
+ CONTROL "Other events",IDC_OTHER_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,77,84,8
+ CONTROL "",IDC_COLBACK3,"ColourPicker",WS_TABSTOP,113,75,24,13
+ CONTROL "",IDC_COLTEXT3,"ColourPicker",WS_TABSTOP,143,75,24,13
+ CONTROL "Default",IDC_OTHER_DEFAULT,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,174,77,63,8
+ CONTROL "Client notifications",IDC_CLIENT_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,97,84,8
+ CONTROL "",IDC_COLBACK4,"ColourPicker",WS_TABSTOP,113,95,24,13
+ CONTROL "",IDC_COLTEXT4,"ColourPicker",WS_TABSTOP,143,95,24,13
+ CONTROL "Default",IDC_CLIENT_DEFAULT,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,174,97,63,8
+ RTEXT "Timeout (sec.)",IDC_STATIC,174,14,113,8
+ RTEXT "(0 = default, -1 = infinite)",IDC_STATIC,174,24,113,8
+ EDITTEXT IDC_TIMEOUT,243,35,34,14,ES_AUTOHSCROLL
+ CONTROL "",IDC_TIMEOUT_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,266,35,11,14
+ EDITTEXT IDC_TIMEOUT2,243,55,34,14,ES_AUTOHSCROLL
+ CONTROL "",IDC_TIMEOUT_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,266,55,11,14
+ EDITTEXT IDC_TIMEOUT3,243,75,34,14,ES_AUTOHSCROLL
+ CONTROL "",IDC_TIMEOUT_SPIN3,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,266,75,11,14
+ EDITTEXT IDC_TIMEOUT4,243,95,34,14,ES_AUTOHSCROLL
+ CONTROL "",IDC_TIMEOUT_SPIN4,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,266,95,11,14
+ PUSHBUTTON "Preview",IDC_PREVIEW,118,182,68,14
+ CONTROL "Use balloon notifications in system tray instead of popups",IDC_SYSTRAY_NOTIFY,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,49,132,208,8
+ LTEXT "News Feed types to notify:",IDC_STATIC,51,155,112,8
+ COMBOBOX IDC_FEED_TYPE,169,153,90,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_OPTIONS_ADVANCED DIALOGEX 0, 0, 305, 238
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Advanced Settings",IDC_STATIC,7,7,291,126
+ CONTROL "Force secure (HTTPS) connection",IDC_SECURE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,32,267,10
+ CONTROL "Post Miranda statuses to Wall",IDC_SET_STATUS,"Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,17,56,267,10
+ CONTROL "Enable logging for debugging purposes",IDC_LOGGING,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,20,267,10
+ CONTROL "Use secure connection also for channel requests",IDC_SECURE_CHANNEL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,44,252,10
+ CONTROL "Also disconnect chat when going to offline",IDC_DISCONNECT_CHAT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,68,267,10
+ CONTROL "Get unread messages on login (EXPERIMENTAL)",IDC_PARSE_UNREAD,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,104,267,10
+ CONTROL "Automatically close chat windows (on website) (NOT WORKING)",IDC_CLOSE_WINDOWS,
+ "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,17,80,267,10
+ CONTROL "Map non-standard statuses to Invisible (instead of Online)",IDC_MAP_STATUSES,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,92,267,10
+ CONTROL "Enable groupchats support (EXPERIMENTAL)",IDC_GROUPCHATS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,116,267,10
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_MIND, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 263
+ VERTGUIDE, 209
+ VERTGUIDE, 213
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 58
+ HORZGUIDE, 40
+ HORZGUIDE, 44
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ VERTGUIDE, 17
+ VERTGUIDE, 78
+ VERTGUIDE, 84
+ VERTGUIDE, 207
+ VERTGUIDE, 288
+ VERTGUIDE, 298
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 231
+ END
+
+ IDD_OPTIONS_EVENTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 6
+ RIGHTMARGIN, 299
+ VERTGUIDE, 22
+ VERTGUIDE, 106
+ VERTGUIDE, 113
+ VERTGUIDE, 137
+ VERTGUIDE, 143
+ VERTGUIDE, 167
+ VERTGUIDE, 174
+ VERTGUIDE, 237
+ VERTGUIDE, 277
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 210
+ HORZGUIDE, 35
+ HORZGUIDE, 37
+ HORZGUIDE, 55
+ HORZGUIDE, 57
+ HORZGUIDE, 75
+ HORZGUIDE, 77
+ HORZGUIDE, 95
+ HORZGUIDE, 97
+ END
+
+ IDD_OPTIONS_ADVANCED, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 298
+ VERTGUIDE, 17
+ VERTGUIDE, 32
+ VERTGUIDE, 119
+ VERTGUIDE, 122
+ VERTGUIDE, 284
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 231
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,0,8,1
+ PRODUCTVERSION 0,9,43,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "Facebook protocol plugin for Miranda IM"
+ VALUE "FileVersion", "0.0.8.1"
+ VALUE "InternalName", "Facebook RM"
+ VALUE "LegalCopyright", "Copyright © 2009-2011 Michal Zelinka, 2011-2012 Robert Pösel"
+ VALUE "OriginalFilename", "facebook.dll"
+ VALUE "ProductName", "Facebook Protocol RM"
+ VALUE "ProductVersion", "0.9.43.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/FacebookRM/facebook_10.sln b/protocols/FacebookRM/facebook_10.sln new file mode 100644 index 0000000000..8f9e54b602 --- /dev/null +++ b/protocols/FacebookRM/facebook_10.sln @@ -0,0 +1,26 @@ +
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "facebook", "facebook_10.vcxproj", "{DADE9455-DC28-465A-9604-2CA28052B9FB}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {DADE9455-DC28-465A-9604-2CA28052B9FB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DADE9455-DC28-465A-9604-2CA28052B9FB}.Debug|Win32.Build.0 = Debug|Win32
+ {DADE9455-DC28-465A-9604-2CA28052B9FB}.Debug|x64.ActiveCfg = Debug|x64
+ {DADE9455-DC28-465A-9604-2CA28052B9FB}.Debug|x64.Build.0 = Debug|x64
+ {DADE9455-DC28-465A-9604-2CA28052B9FB}.Release|Win32.ActiveCfg = Release|Win32
+ {DADE9455-DC28-465A-9604-2CA28052B9FB}.Release|Win32.Build.0 = Release|Win32
+ {DADE9455-DC28-465A-9604-2CA28052B9FB}.Release|x64.ActiveCfg = Release|x64
+ {DADE9455-DC28-465A-9604-2CA28052B9FB}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/protocols/FacebookRM/facebook_10.vcxproj b/protocols/FacebookRM/facebook_10.vcxproj new file mode 100644 index 0000000000..9198e45689 --- /dev/null +++ b/protocols/FacebookRM/facebook_10.vcxproj @@ -0,0 +1,327 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{DADE9455-DC28-465A-9604-2CA28052B9FB}</ProjectGuid>
+ <RootNamespace>facebook</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ <ProjectName>facebook</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <UseOfMfc>Static</UseOfMfc>
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <UseOfMfc>Static</UseOfMfc>
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\$(Configuration)/Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)\$(Configuration)64/Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)\$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\$(Configuration)/Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)\$(Configuration)64/Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)\$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IncludePath)</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IncludePath)</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IncludePath)</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <PreBuildEvent>
+ <Command>
+ </Command>
+ </PreBuildEvent>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>../../include;../../plugins/ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FACEBOOK_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>common.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <GenerateMapFile>true</GenerateMapFile>
+ <MapFileName>$(TargetDir)$(TargetName).map</MapFileName>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>
+ </OptimizeReferences>
+ <EnableCOMDATFolding>
+ </EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>
+ </LinkTimeCodeGeneration>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <PreBuildEvent>
+ <Command>
+ </Command>
+ </PreBuildEvent>
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>../../include;../../plugins/ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;FACEBOOK_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <FunctionLevelLinking>false</FunctionLevelLinking>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>common.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <GenerateMapFile>true</GenerateMapFile>
+ <MapFileName>$(TargetDir)$(TargetName).map</MapFileName>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>
+ </OptimizeReferences>
+ <EnableCOMDATFolding>
+ </EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>
+ </LinkTimeCodeGeneration>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <TargetMachine>MachineX64</TargetMachine>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <PreBuildEvent>
+ <Command>
+ </Command>
+ </PreBuildEvent>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>../../include;../../plugins/ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FACEBOOK_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>common.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <CreateHotpatchableImage>false</CreateHotpatchableImage>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>
+ </AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapFileName>$(TargetDir)$(TargetName).map</MapFileName>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalDependencies>uuid.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ <ProjectReference>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ </ProjectReference>
+ <Manifest>
+ <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).embed.manifest</OutputManifestFile>
+ </Manifest>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <PreBuildEvent>
+ <Command>
+ </Command>
+ </PreBuildEvent>
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>../../include;../../plugins/ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;FACEBOOK_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>common.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <FloatingPointModel>Strict</FloatingPointModel>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <CreateHotpatchableImage>false</CreateHotpatchableImage>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>
+ </AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <MapFileName>$(TargetDir)$(TargetName).map</MapFileName>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <TargetMachine>MachineX64</TargetMachine>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalDependencies>uuid.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="avatars.cpp" />
+ <ClCompile Include="chat.cpp" />
+ <ClCompile Include="communication.cpp" />
+ <ClCompile Include="connection.cpp" />
+ <ClCompile Include="contacts.cpp" />
+ <ClCompile Include="dialogs.cpp" />
+ <ClCompile Include="events.cpp" />
+ <ClCompile Include="http.cpp" />
+ <ClCompile Include="json.cpp" />
+ <ClCompile Include="main.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="messages.cpp" />
+ <ClCompile Include="process.cpp" />
+ <ClCompile Include="proto.cpp" />
+ <ClCompile Include="stubs.cpp" />
+ <ClCompile Include="theme.cpp" />
+ <ClCompile Include="utils.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="JSON_CAJUN\elements.h" />
+ <ClInclude Include="JSON_CAJUN\reader.h" />
+ <ClInclude Include="JSON_CAJUN\visitor.h" />
+ <ClInclude Include="JSON_CAJUN\writer.h" />
+ <ClInclude Include="avatars.h" />
+ <ClInclude Include="client.h" />
+ <ClInclude Include="common.h" />
+ <ClInclude Include="constants.h" />
+ <ClInclude Include="db.h" />
+ <ClInclude Include="definitions.h" />
+ <ClInclude Include="dialogs.h" />
+ <ClInclude Include="entities.h" />
+ <ClInclude Include="http.h" />
+ <ClInclude Include="json.h" />
+ <ClInclude Include="list.hpp" />
+ <ClInclude Include="proto.h" />
+ <ClInclude Include="theme.h" />
+ <ClInclude Include="utils.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="icons\addFriend.ico" />
+ <None Include="icons\removeFriend.ico" />
+ <None Include="JSON_CAJUN\elements.inl" />
+ <None Include="JSON_CAJUN\reader.inl" />
+ <None Include="JSON_CAJUN\writer.inl" />
+ <None Include="icons\facebook.ico" />
+ <None Include="icons\mind.ico" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="facebook.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/protocols/FacebookRM/facebook_10.vcxproj.filters b/protocols/FacebookRM/facebook_10.vcxproj.filters new file mode 100644 index 0000000000..fc92cf1075 --- /dev/null +++ b/protocols/FacebookRM/facebook_10.vcxproj.filters @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Source Files\JSON_CAJUN">
+ <UniqueIdentifier>{7cc935fb-209f-455a-93b3-d3346104ae5b}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="avatars.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="communication.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="connection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="contacts.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dialogs.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="events.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="http.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="json.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="messages.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="process.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="proto.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stubs.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="theme.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="chat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="JSON_CAJUN\elements.h">
+ <Filter>Source Files\JSON_CAJUN</Filter>
+ </ClInclude>
+ <ClInclude Include="JSON_CAJUN\reader.h">
+ <Filter>Source Files\JSON_CAJUN</Filter>
+ </ClInclude>
+ <ClInclude Include="JSON_CAJUN\visitor.h">
+ <Filter>Source Files\JSON_CAJUN</Filter>
+ </ClInclude>
+ <ClInclude Include="JSON_CAJUN\writer.h">
+ <Filter>Source Files\JSON_CAJUN</Filter>
+ </ClInclude>
+ <ClInclude Include="avatars.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="client.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="common.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="constants.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="db.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="definitions.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="dialogs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="entities.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="http.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="json.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="list.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="proto.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="utils.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Resource Files</Filter>
+ </ClInclude>
+ <ClInclude Include="theme.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="JSON_CAJUN\elements.inl">
+ <Filter>Source Files\JSON_CAJUN</Filter>
+ </None>
+ <None Include="JSON_CAJUN\reader.inl">
+ <Filter>Source Files\JSON_CAJUN</Filter>
+ </None>
+ <None Include="JSON_CAJUN\writer.inl">
+ <Filter>Source Files\JSON_CAJUN</Filter>
+ </None>
+ <None Include="icons\facebook.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="icons\mind.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="icons\addFriend.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="icons\removeFriend.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="facebook.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project>
\ No newline at end of file diff --git a/protocols/FacebookRM/http.cpp b/protocols/FacebookRM/http.cpp new file mode 100644 index 0000000000..853e6b8c2f --- /dev/null +++ b/protocols/FacebookRM/http.cpp @@ -0,0 +1,23 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
diff --git a/protocols/FacebookRM/http.h b/protocols/FacebookRM/http.h new file mode 100644 index 0000000000..1dd4174549 --- /dev/null +++ b/protocols/FacebookRM/http.h @@ -0,0 +1,102 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+#define HTTP_PROTO_REGULAR "http://"
+#define HTTP_PROTO_SECURE "https://"
+
+#define HTTP_CODE_CONTINUE 100
+#define HTTP_CODE_SWITCHING_PROTOCOLS 101
+#define HTTP_CODE_PROCESSING 102
+#define HTTP_CODE_OK 200
+#define HTTP_CODE_CREATED 201
+#define HTTP_CODE_ACCEPTED 202
+#define HTTP_CODE_NON_AUTHORITATIVE_INFORMATION 203
+#define HTTP_CODE_NO_CONTENT 204
+#define HTTP_CODE_RESET_CONTENT 205
+#define HTTP_CODE_PARTIAL_CONTENT 206
+#define HTTP_CODE_MULTI_STATUS 207
+#define HTTP_CODE_MULTIPLE_CHOICES 300
+#define HTTP_CODE_MOVED_PERMANENTLY 301
+#define HTTP_CODE_FOUND 302
+#define HTTP_CODE_SEE_OTHER 303
+#define HTTP_CODE_NOT_MODIFIED 304
+#define HTTP_CODE_USE_PROXY 305
+#define HTTP_CODE_SWITCH_PROXY 306
+#define HTTP_CODE_TEMPORARY_REDIRECT 307
+#define HTTP_CODE_BAD_REQUEST 400
+#define HTTP_CODE_UNAUTHORIZED 401
+#define HTTP_CODE_PAYMENT_REQUIRED 402
+#define HTTP_CODE_FORBIDDEN 403
+#define HTTP_CODE_NOT_FOUND 404
+#define HTTP_CODE_METHOD_NOT_ALLOWED 405
+#define HTTP_CODE_NOT_ACCEPTABLE 406
+#define HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED 407
+#define HTTP_CODE_REQUEST_TIMEOUT 408
+#define HTTP_CODE_CONFLICT 409
+#define HTTP_CODE_GONE 410
+#define HTTP_CODE_LENGTH_REQUIRED 411
+#define HTTP_CODE_PRECONDITION_REQUIRED 412
+#define HTTP_CODE_REQUEST_ENTITY_TOO_LARGE 413
+#define HTTP_CODE_REQUEST_URI_TOO_LONG 414
+#define HTTP_CODE_UNSUPPORTED_MEDIA_TYPE 415
+#define HTTP_CODE_REQUESTED_RANGE_NOT_SATISFIABLE 416
+#define HTTP_CODE_EXPECTATION_FAILED 417
+#define HTTP_CODE_UNPROCESSABLE_ENTITY 422
+#define HTTP_CODE_LOCKED 423
+#define HTTP_CODE_FAILED_DEPENDENCY 424
+#define HTTP_CODE_UNORDERED_COLLECTION 425
+#define HTTP_CODE_UPGRADE_REQUIRED 426
+#define HTTP_CODE_RETRY_WITH 449
+#define HTTP_CODE_INTERNAL_SERVER_ERROR 500
+#define HTTP_CODE_NOT_IMPLEMENTED 501
+#define HTTP_CODE_BAD_GATEWAY 502
+#define HTTP_CODE_SERVICE_UNAVAILABLE 503
+#define HTTP_CODE_GATEWAY_TIMEOUT 504
+#define HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED 505
+#define HTTP_CODE_VARIANT_ALSO_NEGOTIATES 506
+#define HTTP_CODE_INSUFFICIENT_STORAGE 507
+#define HTTP_CODE_BANDWIDTH_LIMIT_EXCEEDED 509
+#define HTTP_CODE_NOT_EXTENDED 510
+
+#define HTTP_CODE_FAKE_DISCONNECTED 0
+#define HTTP_CODE_FAKE_ERROR 1
+
+namespace http
+{
+ enum method
+ {
+ get,
+ post
+ };
+
+ struct response
+ {
+ response() : code(0), error_number(0) {}
+ int code;
+ unsigned int error_number;
+ std::string error_text;
+ std::map< std::string, std::string > headers;
+ std::string data;
+ };
+}
diff --git a/protocols/FacebookRM/icons/addFriend.ico b/protocols/FacebookRM/icons/addFriend.ico Binary files differnew file mode 100644 index 0000000000..d8879d15bb --- /dev/null +++ b/protocols/FacebookRM/icons/addFriend.ico diff --git a/protocols/FacebookRM/icons/facebook.ico b/protocols/FacebookRM/icons/facebook.ico Binary files differnew file mode 100644 index 0000000000..c57c0342fa --- /dev/null +++ b/protocols/FacebookRM/icons/facebook.ico diff --git a/protocols/FacebookRM/icons/mind.ico b/protocols/FacebookRM/icons/mind.ico Binary files differnew file mode 100644 index 0000000000..f158842429 --- /dev/null +++ b/protocols/FacebookRM/icons/mind.ico diff --git a/protocols/FacebookRM/icons/removeFriend.ico b/protocols/FacebookRM/icons/removeFriend.ico Binary files differnew file mode 100644 index 0000000000..9639a9c728 --- /dev/null +++ b/protocols/FacebookRM/icons/removeFriend.ico diff --git a/protocols/FacebookRM/json.cpp b/protocols/FacebookRM/json.cpp new file mode 100644 index 0000000000..4293f336f9 --- /dev/null +++ b/protocols/FacebookRM/json.cpp @@ -0,0 +1,537 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+#include "JSON_CAJUN/reader.h"
+#include "JSON_CAJUN/writer.h"
+#include "JSON_CAJUN/elements.h"
+
+int facebook_json_parser::parse_buddy_list( void* data, List::List< facebook_user >* buddy_list )
+{
+ using namespace json;
+
+ try
+ {
+ facebook_user* current = NULL;
+ std::string buddyData = static_cast< std::string* >( data )->substr( 9 );
+ std::istringstream sDocument( buddyData );
+ Object objDocument;
+ Reader::Read(objDocument, sDocument);
+
+ const Object& objRoot = objDocument;
+/* const Array& wasAvailableIDs = objRoot["payload"]["buddy_list"]["wasAvailableIDs"];
+
+ for ( Array::const_iterator itWasAvailable( wasAvailableIDs.Begin() );
+ itWasAvailable != wasAvailableIDs.End(); ++itWasAvailable)
+ {
+ const Number& member = *itWasAvailable;
+ char was_id[32];
+ lltoa( member.Value(), was_id, 10 );
+
+ current = buddy_list->find( std::string( was_id ) );
+ if ( current != NULL )
+ current->status_id = ID_STATUS_OFFLINE;
+ }*/ // Facebook removed support for "wasAvailableIDs"
+
+ // Set all contacts in map to offline
+ for ( List::Item< facebook_user >* i = buddy_list->begin( ); i != NULL; i = i->next ) {
+ i->data->status_id = ID_STATUS_OFFLINE;
+ }
+
+ // Find mobile friends
+ if (DBGetContactSettingByte(NULL,proto->m_szModuleName,FACEBOOK_KEY_LOAD_MOBILE, DEFAULT_LOAD_MOBILE)) {
+ const Array& mobileFriends = objRoot["payload"]["buddy_list"]["mobile_friends"];
+
+ for ( Array::const_iterator buddy( mobileFriends.Begin() ); buddy != mobileFriends.End(); ++buddy) {
+ const Number& member = *buddy;
+ char was_id[32];
+ lltoa( member.Value(), was_id, 10 );
+
+ std::string id = was_id;
+ if (!id.empty()) {
+ current = buddy_list->find( id );
+
+ if ( current == NULL) {
+ buddy_list->insert( std::make_pair( id, new facebook_user( ) ) );
+ current = buddy_list->find( id );
+ current->user_id = id;
+ }
+
+ current->status_id = ID_STATUS_ONTHEPHONE;
+ }
+ }
+ }
+
+ const Object& nowAvailableList = objRoot["payload"]["buddy_list"]["nowAvailableList"];
+ // Find now awailable contacts
+ for (Object::const_iterator itAvailable(nowAvailableList.Begin());
+ itAvailable != nowAvailableList.End(); ++itAvailable)
+ {
+ const Object::Member& member = *itAvailable;
+ const Object& objMember = member.element;
+ const Boolean idle = objMember["i"]; // In new version of Facebook "i" means "offline"
+
+ current = buddy_list->find( member.name );
+ if ( current == NULL) {
+ if (idle) continue; // Just little optimalization
+
+ buddy_list->insert( std::make_pair( member.name, new facebook_user( ) ) );
+ current = buddy_list->find( member.name );
+ current->user_id = current->real_name = member.name;
+ }
+
+ current->status_id = (idle ? ID_STATUS_OFFLINE : ID_STATUS_ONLINE);
+ }
+
+ const Object& userInfosList = objRoot["payload"]["buddy_list"]["userInfos"];
+ // Get aditional informations about contacts (if available)
+ for (Object::const_iterator itUserInfo(userInfosList.Begin());
+ itUserInfo != userInfosList.End(); ++itUserInfo)
+ {
+ const Object::Member& member = *itUserInfo;
+
+ current = buddy_list->find( member.name );
+ if ( current == NULL )
+ continue;
+
+ const Object& objMember = member.element;
+ const String& realName = objMember["name"];
+ const String& imageUrl = objMember["thumbSrc"];
+
+ current->real_name = utils::text::slashu_to_utf8(
+ utils::text::special_expressions_decode( realName.Value( ) ) );
+ current->image_url = utils::text::slashu_to_utf8(
+ utils::text::special_expressions_decode( imageUrl.Value( ) ) );
+ }
+ }
+ catch (Reader::ParseException& e)
+ {
+ proto->Log( "!!!!! Caught json::ParseException: %s", e.what() );
+ proto->Log( " Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1 );
+ }
+ catch (const Exception& e)
+ {
+ proto->Log( "!!!!! Caught json::Exception: %s", e.what() );
+ }
+ catch (const std::exception& e)
+ {
+ proto->Log( "!!!!! Caught std::exception: %s", e.what() );
+ }
+
+ return EXIT_SUCCESS;
+}
+
+int facebook_json_parser::parse_friends( void* data, std::map< std::string, facebook_user* >* friends )
+{
+ using namespace json;
+
+ try
+ {
+ std::string buddyData = static_cast< std::string* >( data )->substr( 9 );
+ std::istringstream sDocument( buddyData );
+ Object objDocument;
+ Reader::Read(objDocument, sDocument);
+
+ const Object& objRoot = objDocument;
+ const Object& payload = objRoot["payload"];
+
+ for ( Object::const_iterator payload_item( payload.Begin() ); payload_item != payload.End(); ++payload_item)
+ {
+ const Object::Member& member = *payload_item;
+
+ const Object& objMember = member.element;
+
+ const String& realName = objMember["name"];
+ const String& imageUrl = objMember["thumbSrc"];
+ //const String& vanity = objMember["vanity"];
+ const Number& gender = objMember["gender"];
+
+ facebook_user *fbu = new facebook_user();
+
+ fbu->user_id = member.name;
+ fbu->real_name = utils::text::slashu_to_utf8(
+ utils::text::special_expressions_decode( realName.Value() ) );
+ fbu->image_url = utils::text::slashu_to_utf8(
+ utils::text::special_expressions_decode( imageUrl.Value() ) );
+
+ if (gender.Value() == 1) {
+ fbu->gender = 70; // female
+ } else if (gender.Value() == 2) {
+ fbu->gender = 77; // male
+ }
+
+ friends->insert( std::make_pair( member.name, fbu ) );
+ }
+ }
+ catch (Reader::ParseException& e)
+ {
+ proto->Log( "!!!!! Caught json::ParseException: %s", e.what() );
+ proto->Log( " Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1 );
+ }
+ catch (const Exception& e)
+ {
+ proto->Log( "!!!!! Caught json::Exception: %s", e.what() );
+ }
+ catch (const std::exception& e)
+ {
+ proto->Log( "!!!!! Caught std::exception: %s", e.what() );
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+int facebook_json_parser::parse_notifications( void *data, std::vector< facebook_notification* > *notifications )
+{
+ using namespace json;
+
+ try
+ {
+ std::string notificationsData = static_cast< std::string* >( data )->substr( 9 );
+ std::istringstream sDocument( notificationsData );
+ Object objDocument;
+ Reader::Read(objDocument, sDocument);
+
+ const Object& objRoot = objDocument;
+ const Object& payload = objRoot["payload"]["notifications"];
+
+ for ( Object::const_iterator payload_item( payload.Begin() ); payload_item != payload.End(); ++payload_item)
+ {
+ const Object::Member& member = *payload_item;
+
+ const Object& objMember = member.element;
+
+ const String& content = objMember["markup"];
+ const Number& unread = objMember["unread"];
+
+ if (unread.Value() == 0) // ignore old notifications
+ continue;
+
+ std::string text = utils::text::slashu_to_utf8(
+ utils::text::special_expressions_decode( content.Value() ) );
+
+ facebook_notification* notification = new facebook_notification( );
+
+ notification->text = utils::text::remove_html( utils::text::source_get_value(&text, 1, "<abbr") );
+ notification->link = utils::text::source_get_value(&text, 3, "<a ", "href=\"", "\"");
+
+ notifications->push_back( notification );
+ }
+
+ }
+ catch (Reader::ParseException& e)
+ {
+ proto->Log( "!!!!! Caught json::ParseException: %s", e.what() );
+ proto->Log( " Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1 );
+ }
+ catch (const Exception& e)
+ {
+ proto->Log( "!!!!! Caught json::Exception: %s", e.what() );
+ }
+ catch (const std::exception& e)
+ {
+ proto->Log( "!!!!! Caught std::exception: %s", e.what() );
+ }
+
+ return EXIT_SUCCESS;
+}
+
+int facebook_json_parser::parse_messages( void* data, std::vector< facebook_message* >* messages, std::vector< facebook_notification* >* notifications )
+{
+ using namespace json;
+
+ try
+ {
+ std::string messageData = static_cast< std::string* >( data )->substr( 9 );
+ std::istringstream sDocument( messageData );
+ Object objDocument;
+ Reader::Read(objDocument, sDocument);
+
+ const Object& objRoot = objDocument;
+ const Array& messagesArray = objRoot["ms"];
+
+ std::string last_msg = "";
+
+ for (Array::const_iterator itMessage(messagesArray.Begin());
+ itMessage != messagesArray.End(); ++itMessage)
+ {
+ const Object& objMember = *itMessage;
+
+ const String& type = objMember["type"];
+
+ if ( type.Value( ) == "msg" || type.Value() == "offline_msg" ) // direct message
+ {
+ const Number& from = objMember["from"];
+ char was_id[32];
+ lltoa( from.Value(), was_id, 10 );
+
+ const Object& messageContent = objMember["msg"];
+ const String& text = messageContent["text"];
+ //"tab_type":"friend", objMember["tab_type"]
+
+ //const Number& time_sent = messageContent["time"];
+// proto->Log("????? Checking time %15.2f > %15.2f", time_sent.Value(), proto->facy.last_message_time_);
+
+ if ((messageContent.Find("truncated") != messageContent.End())
+ && (((const Number &)messageContent["truncated"]).Value() == 1)) {
+ // If we got truncated message, we can ignore it, because we should get it again as "messaging" type
+ std::string msg = "????? We got truncated message so we ignore it\n";
+ msg += utils::text::special_expressions_decode(utils::text::slashu_to_utf8(text.Value()));
+ proto->Log(msg.c_str());
+ } else if (last_msg != text.Value()) {
+ last_msg = text.Value();
+
+ facebook_message* message = new facebook_message( );
+ message->message_text = utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( text.Value( ) ) );
+ message->time = ::time( NULL ); // TODO: use real time from facebook
+ message->user_id = was_id;
+
+ messages->push_back( message );
+ } else {
+ std::string msg = "????? Got duplicit message?\n";
+ msg += utils::text::special_expressions_decode(utils::text::slashu_to_utf8(text.Value()));
+ proto->Log(msg.c_str());
+ }
+ }
+ else if ( type.Value( ) == "messaging" ) // inbox message (multiuser or direct)
+ {
+ const String& type = objMember["event"];
+
+ if (type.Value() == "deliver") {
+ const Object& messageContent = objMember["message"];
+
+ const Number& from = messageContent["sender_fbid"];
+ char was_id[32];
+ lltoa( from.Value(), was_id, 10 );
+
+
+ // Ignore if message is from self user
+ if (was_id == proto->facy.self_.user_id)
+ continue;
+
+
+ const String& text = messageContent["body"];
+ //std::string tid = ((const String&)messageContent["tid"]).Value();
+
+ const String& sender_name = messageContent["sender_name"];
+
+ std::string row = ((const String &)objMember["thread_row"]).Value();
+
+ //const Number& time_sent = messageContent["timestamp"];
+
+ //proto->Log("????? Checking time %15.2f > %15.2f", time_sent.Value(), proto->facy.last_message_time_);
+
+ if (last_msg != text.Value()) {
+ last_msg = text.Value();
+
+ facebook_message* message = new facebook_message( );
+ message->message_text = utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( text.Value( ) ) );
+
+ message->sender_name = utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( sender_name.Value( ) ) );
+
+ message->time = ::time( NULL ); // TODO: user real time from facebook
+ message->user_id = was_id; // TODO: Check if we have contact with this ID in friendlist and then do something different?
+
+ if (row.find("uiSplitPic",0) != std::string::npos) {
+ // This is multiuser message
+
+ std::string authors = utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( row ) );
+ authors = utils::text::source_get_value(&authors, 2, "<strong class=\"authors\">", "<");
+
+ const String& to_id = messageContent["tid"];
+
+ std::string popup_text = message->sender_name;
+ popup_text += ": ";
+ popup_text += message->message_text;
+
+ std::string title = Translate("Multichat");
+ title += ": ";
+ title += authors;
+
+ std::string url = "/?action=read&sk=inbox&page&query&tid=";
+ url += to_id.Value();
+
+ proto->Log(" Got multichat message");
+
+ TCHAR* szTitle = mir_a2t_cp(title.c_str(), CP_UTF8);
+ TCHAR* szText = mir_a2t_cp(popup_text.c_str(), CP_UTF8);
+ TCHAR* szUrl = mir_a2t_cp(url.c_str(), CP_UTF8);
+ proto->NotifyEvent(szTitle,szText,NULL,FACEBOOK_EVENT_OTHER, szUrl);
+ mir_free(szTitle);
+ mir_free(szText);
+
+ } else {
+ messages->push_back( message );
+ }
+ } else {
+ std::string msg = "????? Got duplicit inbox message?\n";
+ msg += utils::text::special_expressions_decode(utils::text::slashu_to_utf8(text.Value()));
+ proto->Log(msg.c_str());
+ }
+ }
+ }
+ else if ( type.Value( ) == "group_msg" ) // chat message
+ {
+ if (!DBGetContactSettingByte(NULL,proto->m_szModuleName,FACEBOOK_KEY_ENABLE_GROUPCHATS, DEFAULT_ENABLE_GROUPCHATS))
+ continue;
+
+ const String& from_name = objMember["from_name"];
+
+ const Number& to = objMember["to"];
+ char group_id[32];
+ lltoa( to.Value(), group_id, 10 );
+
+ const Number& from = objMember["from"];
+ char was_id[32];
+ lltoa( from.Value(), was_id, 10 );
+
+ const Object& messageContent = objMember["msg"];
+ const String& text = messageContent["text"];
+
+ std::string msg = utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( text.Value( ) ) );
+
+ std::string name = utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( from_name.Value( ) ) );
+
+ // Add contact into chat, if isn't there already
+ if (!proto->IsChatContact(group_id, was_id))
+ proto->AddChatContact(group_id, was_id, name.c_str());
+
+ // Add message into chat
+ proto->UpdateChat(group_id, was_id, name.c_str(), msg.c_str());
+ }
+ else if ( type.Value( ) == "thread_msg" ) // multiuser message
+ {
+ const String& from_name = objMember["from_name"];
+ const String& to_name = objMember["to_name"]["__html"];
+ const String& to_id = objMember["to"];
+
+ const Number& from = objMember["from"];
+ char was_id[32];
+ lltoa( from.Value(), was_id, 10 );
+
+ // Ignore if message is from self user
+ if (was_id == proto->facy.self_.user_id)
+ continue;
+
+ const Object& messageContent = objMember["msg"];
+ const String& text = messageContent["text"];
+
+
+ last_msg = text.Value();
+
+
+ std::string popup_text = utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( from_name.Value( ) ) );
+ popup_text += ": ";
+ popup_text += utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( text.Value( ) ) );
+
+ std::string title = Translate("Multichat");
+ title += ": ";
+ title += utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( to_name.Value( ) ) );
+
+ std::string url = "/?action=read&sk=inbox&page&query&tid=";
+ url += to_id.Value();
+
+ proto->Log(" Got multichat message");
+
+ TCHAR* szTitle = mir_a2t_cp(title.c_str(), CP_UTF8);
+ TCHAR* szText = mir_a2t_cp(popup_text.c_str(), CP_UTF8);
+ TCHAR* szUrl = mir_a2t_cp(url.c_str(), CP_UTF8);
+ proto->NotifyEvent(szTitle,szText,NULL,FACEBOOK_EVENT_OTHER, szUrl);
+ mir_free(szTitle);
+ mir_free(szText);
+ }
+ else if ( type.Value( ) == "app_msg" ) // event notification
+ {
+ if (!DBGetContactSettingByte(NULL, proto->m_szModuleName, FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE))
+ continue;
+
+ const String& text = objMember["response"]["payload"]["title"];
+ const String& link = objMember["response"]["payload"]["link"];
+ // TODO RM: include additional text of notification if exits? (e.g. comment text)
+ //const String& text2 = objMember["response"]["payload"]["alert"]["text"];
+
+ const Number& time_sent = objMember["response"]["payload"]["alert"]["time_sent"];
+ if (time_sent.Value() > proto->facy.last_notification_time_) // Check agains duplicit notifications
+ {
+ proto->facy.last_notification_time_ = time_sent.Value();
+
+ facebook_notification* notification = new facebook_notification( );
+ notification->text = utils::text::remove_html(
+ utils::text::special_expressions_decode(
+ utils::text::slashu_to_utf8( text.Value( ) ) ) );
+
+ notification->link = utils::text::special_expressions_decode( link.Value( ) );
+
+ notifications->push_back( notification );
+ }
+ }
+ else if ( type.Value( ) == "typ" ) // chat typing notification
+ {
+ const Number& from = objMember["from"];
+ char user_id[32];
+ lltoa( from.Value(), user_id, 10 );
+
+ facebook_user fbu;
+ fbu.user_id = user_id;
+
+ HANDLE hContact = proto->AddToContactList(&fbu);
+
+ if ( DBGetContactSettingWord(hContact,proto->m_szModuleName,"Status", 0) == ID_STATUS_OFFLINE )
+ DBWriteContactSettingWord(hContact,proto->m_szModuleName,"Status",ID_STATUS_ONLINE);
+
+ const Number& state = objMember["st"];
+ if (state.Value() == 1)
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)60);
+ else
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF);
+ }
+ else if ( type.Value( ) == "visibility" ) // change of chat status
+ {
+ const Boolean visibility = objMember["visibility"];
+ proto->Log(" Requested chat switch to %s", visibility ? "Online" : "Offline");
+ proto->SetStatus( visibility ? ID_STATUS_ONLINE : ID_STATUS_INVISIBLE );
+ }
+ else
+ continue;
+ }
+ }
+ catch (Reader::ParseException& e)
+ {
+ proto->Log( "!!!!! Caught json::ParseException: %s", e.what() );
+ proto->Log( " Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1 );
+ }
+ catch (const Exception& e)
+ {
+ proto->Log ( "!!!!! Caught json::Exception: %s", e.what() );
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/protocols/FacebookRM/json.h b/protocols/FacebookRM/json.h new file mode 100644 index 0000000000..c83e1ef4f6 --- /dev/null +++ b/protocols/FacebookRM/json.h @@ -0,0 +1,42 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+// Parser front-end
+
+#define lltoa _i64toa
+
+class facebook_json_parser
+{
+public:
+ FacebookProto* proto;
+ int parse_buddy_list( void*, List::List< facebook_user >* );
+ int parse_friends( void*, std::map< std::string, facebook_user* >* );
+ int parse_notifications( void*, std::vector< facebook_notification* >* );
+ int parse_messages( void*, std::vector< facebook_message* >*, std::vector< facebook_notification* >* );
+
+ facebook_json_parser( FacebookProto* proto )
+ {
+ this->proto = proto;
+ }
+};
diff --git a/protocols/FacebookRM/list.hpp b/protocols/FacebookRM/list.hpp new file mode 100644 index 0000000000..597a2b413e --- /dev/null +++ b/protocols/FacebookRM/list.hpp @@ -0,0 +1,195 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+namespace List
+{
+ template< typename T > class Item
+ {
+ public:
+ std::string key;
+ T* data;
+ Item< T >* prev;
+ Item< T >* next;
+
+ Item( )
+ {
+ this->data = NULL;
+ this->prev = NULL;
+ this->next = NULL;
+ }
+
+ ~Item( )
+ {
+ delete this->data;
+ }
+ };
+
+ template< typename T > class List
+ {
+ private:
+ Item< T >* first;
+ Item< T >* last;
+ unsigned int count;
+
+ public:
+ List( )
+ {
+ this->first = this->last = NULL;
+ this->count = 0;
+ }
+
+ ~List( )
+ {
+ this->clear( );
+ }
+
+ Item< T >* begin( )
+ {
+ return first;
+ }
+
+ Item< T >* end( )
+ {
+ return last;
+ }
+
+ unsigned int size( )
+ {
+ return count;
+ }
+
+ bool empty( )
+ {
+ return ( this->first == NULL );
+ }
+
+ void insert( Item< T >* item )
+ {
+ if ( this->empty( ) )
+ {
+ this->first = this->last = item;
+ this->count = 1;
+ } else { // TODO: key sorting/comparation
+ item->next = this->first;
+ this->first->prev = item;
+ this->first = item;
+ this->count++;
+ }
+ }
+
+ void insert( std::pair< std::string, T* > item )
+ {
+ Item<T>* ins = new Item<T>;
+ ins->key = item.first;
+ ins->data = item.second;
+ this->insert( ins );
+ }
+ void erase( std::string key )
+ {
+ Item< T >* help = this->first;
+ while ( help != NULL )
+ {
+ if ( help->key.compare( key ) != 0 )
+ help = help->next;
+ else
+ {
+ if ( help == this->first )
+ {
+ this->first = help->next;
+ if ( this->first != NULL )
+ this->first->prev = NULL;
+ else
+ this->last = NULL;
+ }
+ else if ( help == this->last )
+ {
+ this->last = help->prev;
+ if ( this->last != NULL )
+ this->last->next = NULL;
+ else
+ this->first = NULL;
+ }
+ else
+ {
+ help->prev->next = help->next;
+ help->next->prev = help->prev;
+ }
+ if (help != NULL)
+ {
+ this->count--;
+ delete help;
+ }
+ break;
+ }
+ }
+ }
+
+ void erase( Item< T >* item )
+ {
+ if (item != NULL)
+ erase( item->key );
+ }
+
+ T* find( std::string key )
+ {
+ Item< T >* help = this->begin( );
+ while ( help != NULL )
+ {
+ if ( help->key.compare( key ) != 0 )
+ help = help->next;
+ else
+ return help->data;
+ }
+ return NULL;
+ }
+
+ T* at( const unsigned int item )
+ {
+ if (item >= this->count)
+ return NULL;
+ Item< T >* help = this->begin( );
+ for ( unsigned int i = 0; i < item; i++ )
+ help = help->next;
+ return help->item;
+ }
+
+ T* operator[]( const unsigned int item )
+ {
+ return at( item );
+ }
+
+ void clear( )
+ {
+ Item< T >* help;
+ while ( this->first != NULL )
+ {
+ help = this->first;
+ this->first = this->first->next;
+ delete help;
+ }
+ this->last = NULL;
+ this->count = 0;
+ }
+ };
+};
diff --git a/protocols/FacebookRM/main.cpp b/protocols/FacebookRM/main.cpp new file mode 100644 index 0000000000..f7995fc1ce --- /dev/null +++ b/protocols/FacebookRM/main.cpp @@ -0,0 +1,213 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+// TODO: Make following as "globals" structure?
+PLUGINLINK *pluginLink;
+MM_INTERFACE mmi;
+LIST_INTERFACE li;
+CLIST_INTERFACE* pcli;
+UTF8_INTERFACE utfi;
+MD5_INTERFACE md5i;
+int hLangpack;
+
+HINSTANCE g_hInstance;
+std::string g_strUserAgent;
+DWORD g_mirandaVersion;
+
+PLUGININFOEX pluginInfo = {
+ sizeof(PLUGININFOEX),
+ #ifdef _WIN64
+ "Facebook Protocol RM x64",
+ #else
+ "Facebook Protocol RM",
+ #endif
+ __VERSION_DWORD,
+ "Provides basic support for Facebook Chat protocol. [Built: "__DATE__" "__TIME__"]",
+ "Michal Zelinka, Robert Posel",
+ "robyer@seznam.cz",
+ "(c) 2009-11 Michal Zelinka, 2011-12 Robert Posel",
+ "http://code.google.com/p/robyer/",
+ UNICODE_AWARE, //not transient
+ 0, //doesn't replace anything built-in
+ #ifdef _WIN64
+ // {8808C20C-5404-48A6-8390-232AAE5E793A}
+ { 0x8808c20c, 0x5404, 0x48a6, { 0x83, 0x90, 0x23, 0x2a, 0xae, 0x5e, 0x79, 0x3a } }
+ #else
+ // {8432B009-FF32-4727-AAE6-A9035038FD58}
+ { 0x8432b009, 0xff32, 0x4727, { 0xaa, 0xe6, 0xa9, 0x3, 0x50, 0x38, 0xfd, 0x58 } }
+ #endif
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// Protocol instances
+static int compare_protos(const FacebookProto *p1, const FacebookProto *p2)
+{
+ return _tcscmp(p1->m_tszUserName, p2->m_tszUserName);
+}
+
+OBJLIST<FacebookProto> g_Instances(1, compare_protos);
+
+DWORD WINAPI DllMain(HINSTANCE hInstance,DWORD,LPVOID)
+{
+ g_hInstance = hInstance;
+ return TRUE;
+}
+
+extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ if(mirandaVersion > PLUGIN_MAKE_VERSION(0,10,0,0) &&
+ mirandaVersion < PLUGIN_MAKE_VERSION(0,10,0,2))
+ {
+ MessageBox(0,_T("The Facebook protocol plugin cannot be loaded. ")
+ _T("It requires Miranda IM 0.10 alpha build #2 or later."),_T("Miranda"),
+ MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST);
+ return NULL;
+ }
+ else if(mirandaVersion < PLUGIN_MAKE_VERSION(0,9,43,0))
+ {
+ MessageBox(0,_T("The Facebook protocol plugin cannot be loaded. ")
+ _T("It requires Miranda IM 0.9.43 or later."),_T("Miranda"),
+ MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST);
+ return NULL;
+ }
+
+ g_mirandaVersion = mirandaVersion;
+ return &pluginInfo;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Interface information
+
+static const MUUID interfaces[] = {MIID_PROTOCOL, MIID_LAST};
+extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
+{
+ return interfaces;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Load
+
+static PROTO_INTERFACE* protoInit(const char *proto_name,const TCHAR *username )
+{
+ FacebookProto *proto = new FacebookProto(proto_name,username);
+ g_Instances.insert(proto);
+ return proto;
+}
+
+static int protoUninit(PROTO_INTERFACE* proto)
+{
+ g_Instances.remove(( FacebookProto* )proto);
+ return EXIT_SUCCESS;
+}
+
+int OnModulesLoaded(WPARAM,LPARAM)
+{
+ if ( ServiceExists( MS_UPDATE_REGISTER ) )
+ {
+ Update upd = {sizeof(upd)};
+ char curr_version[30];
+
+ upd.szComponentName = pluginInfo.shortName;
+ upd.szUpdateURL = UPDATER_AUTOREGISTER;
+ upd.szBetaVersionURL = "http://robyer.info/miranda/facebookRM/version.html";
+ upd.szBetaChangelogURL = "http://robyer.info/miranda/facebookRM/changelog.html";
+ upd.pbBetaVersionPrefix = reinterpret_cast<BYTE*>("Facebook RM ");
+ upd.cpbBetaVersionPrefix = (int)strlen(reinterpret_cast<char*>(upd.pbBetaVersionPrefix));
+ #ifdef _WIN64
+ upd.szBetaUpdateURL = "http://robyer.info/stahni/facebookRM_x64.zip";
+ #else
+ upd.szBetaUpdateURL = "http://robyer.info/stahni/facebookRM.zip";
+ #endif
+ upd.pbVersion = reinterpret_cast<BYTE*>(CreateVersionStringPluginEx(&pluginInfo,curr_version) );
+ upd.cpbVersion = (int)strlen(reinterpret_cast<char*>(upd.pbVersion));
+ CallService(MS_UPDATE_REGISTER,0,(LPARAM)&upd);
+ }
+
+ return 0;
+}
+
+static HANDLE g_hEvents[1];
+
+extern "C" int __declspec(dllexport) Load(PLUGINLINK *link)
+{
+ pluginLink = link;
+ mir_getMMI(&mmi);
+ mir_getLI(&li);
+ mir_getUTFI(&utfi);
+ mir_getMD5I(&md5i);
+ mir_getLP(&pluginInfo);
+
+ pcli = reinterpret_cast<CLIST_INTERFACE*>( CallService(
+ MS_CLIST_RETRIEVE_INTERFACE,0,reinterpret_cast<LPARAM>(g_hInstance)) );
+
+ PROTOCOLDESCRIPTOR pd = { 0 };
+ pd.cbSize = sizeof(pd);
+ pd.szName = "Facebook";
+ pd.type = PROTOTYPE_PROTOCOL;
+ pd.fnInit = protoInit;
+ pd.fnUninit = protoUninit;
+ CallService(MS_PROTO_REGISTERMODULE,0,reinterpret_cast<LPARAM>(&pd));
+
+ g_hEvents[0] = HookEvent(ME_SYSTEM_MODULESLOADED,OnModulesLoaded);
+
+ InitIcons();
+ InitContactMenus();
+
+ // Init native User-Agent
+ {
+ std::stringstream agent;
+// DWORD mir_ver = ( DWORD )CallService( MS_SYSTEM_GETVERSION, NULL, NULL );
+ agent << "MirandaIM/";
+ agent << (( g_mirandaVersion >> 24) & 0xFF);
+ agent << ".";
+ agent << (( g_mirandaVersion >> 16) & 0xFF);
+ agent << ".";
+ agent << (( g_mirandaVersion >> 8) & 0xFF);
+ agent << ".";
+ agent << (( g_mirandaVersion ) & 0xFF);
+ #ifdef _WIN64
+ agent << " Facebook Protocol RM x64/";
+ #else
+ agent << " Facebook Protocol RM/";
+ #endif
+ agent << __VERSION_STRING;
+ g_strUserAgent = agent.str( );
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Unload
+
+extern "C" int __declspec(dllexport) Unload(void)
+{
+ UninitContactMenus();
+ for(size_t i=1; i<SIZEOF(g_hEvents); i++)
+ UnhookEvent(g_hEvents[i]);
+
+ g_Instances.destroy();
+
+ return 0;
+}
diff --git a/protocols/FacebookRM/messages.cpp b/protocols/FacebookRM/messages.cpp new file mode 100644 index 0000000000..d6873d60e4 --- /dev/null +++ b/protocols/FacebookRM/messages.cpp @@ -0,0 +1,163 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+int FacebookProto::RecvMsg(HANDLE hContact, PROTORECVEVENT *pre)
+{
+ DBVARIANT dbv;
+
+ if( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) )
+ {
+ ForkThread( &FacebookProto::MessagingWorker, this, new send_messaging(dbv.pszVal, FACEBOOK_RECV_MESSAGE ) );
+ DBFreeVariant(&dbv);
+ }
+
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF);
+
+ CCSDATA ccs = { hContact,PSR_MESSAGE,0,reinterpret_cast<LPARAM>(pre) };
+ return CallService(MS_PROTO_RECVMSG,0,reinterpret_cast<LPARAM>(&ccs));
+}
+
+void FacebookProto::SendMsgWorker(void *p)
+{
+ if(p == NULL)
+ return;
+
+// ScopedLock s( facy.send_message_lock_, 500 );
+
+ send_direct *data = static_cast<send_direct*>(p);
+
+ DBVARIANT dbv;
+
+ if ( !isOnline( ) )
+ {
+ ProtoBroadcastAck(m_szModuleName, data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, data->msgid, (LPARAM)Translate("You cannot send messages when you are offline."));
+ }
+ else if( !DBGetContactSettingString(data->hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) )
+ {
+ int retries = 5;
+ std::string error_text = "";
+ bool result = false;
+ while (!result && retries > 0) {
+ result = facy.send_message(dbv.pszVal, data->msg, &error_text, retries % 2 == 0 );
+ retries--;
+ }
+ if (result) {
+ ProtoBroadcastAck(m_szModuleName,data->hContact,ACKTYPE_MESSAGE,ACKRESULT_SUCCESS, data->msgid,0);
+ MessagingWorker( new send_messaging(dbv.pszVal, FACEBOOK_SEND_MESSAGE ) );
+ } else {
+ char *err = mir_utf8decodeA(error_text.c_str());
+ ProtoBroadcastAck(m_szModuleName,data->hContact,ACKTYPE_MESSAGE,ACKRESULT_FAILED, data->msgid,(LPARAM)err);
+ }
+ DBFreeVariant(&dbv);
+ }
+
+ delete data;
+}
+
+void FacebookProto::SendChatMsgWorker(void *p)
+{
+ if(p == NULL)
+ return;
+
+ send_chat *data = static_cast<send_chat*>(p);
+ std::string err_message = "";
+
+ facy.send_message(data->chat_id, data->msg, &err_message, false );
+
+ delete data;
+}
+
+int FacebookProto::SendMsg(HANDLE hContact, int flags, const char *msg)
+{
+ // TODO: msg comes as Unicode (retyped wchar_t*), why should we convert it as ANSI to UTF-8? o_O
+ if ( flags & PREF_UNICODE )
+ msg = mir_utf8encode(msg);
+
+ facy.msgid_ = (facy.msgid_ % 1024)+1;
+ ForkThread( &FacebookProto::SendMsgWorker, this,new send_direct(hContact,msg,(HANDLE)facy.msgid_) );
+ return facy.msgid_;
+}
+
+int FacebookProto::UserIsTyping(HANDLE hContact,int type)
+{
+ if (hContact && isOnline())
+ ForkThread(&FacebookProto::SendTypingWorker, this,new send_typing(hContact,type));
+
+ return 0;
+}
+
+void FacebookProto::SendTypingWorker(void *p)
+{
+ if(p == NULL)
+ return;
+
+ send_typing *typing = static_cast<send_typing*>(p);
+
+ // TODO RM: maybe better send typing optimalization
+ facy.is_typing_ = (typing->status == PROTOTYPE_SELFTYPING_ON);
+ SleepEx( 2000, true );
+
+ if ( !facy.is_typing_ == (typing->status == PROTOTYPE_SELFTYPING_ON) )
+ {
+ delete typing;
+ return;
+ }
+
+ DBVARIANT dbv;
+ if( !DBGetContactSettingString(typing->hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) )
+ {
+ std::string data = "typ=";
+ data += ( typing->status == PROTOTYPE_SELFTYPING_ON ) ? "1" : "0"; // PROTOTYPE_SELFTYPING_OFF
+ data += "&to=";
+ data += dbv.pszVal;
+ data += "&source=mercury-chat";
+ data += "&fb_dtsg=" + facy.dtsg_;
+ data += "&post_form_id=";
+ data += ( facy.post_form_id_.length( ) ) ? facy.post_form_id_ : "0";
+ data += "&post_form_id_source=AsyncRequest&lsd=&phstamp=0&__user=";
+ data += facy.self_.user_id;
+
+ http::response resp = facy.flap( FACEBOOK_REQUEST_TYPING_SEND, &data );
+
+ DBFreeVariant(&dbv);
+ }
+
+ delete typing;
+}
+
+void FacebookProto::MessagingWorker(void *p)
+{
+ if (p == NULL)
+ return;
+
+ send_messaging *data = static_cast<send_messaging*>(p);
+
+ if (data->type == FACEBOOK_RECV_MESSAGE)
+ facy.chat_mark_read( data->user_id );
+
+// if ( DBGetContactSettingByte(NULL, m_szModuleName, FACEBOOK_KEY_CLOSE_WINDOWS_ENABLE, DEFAULT_CLOSE_WINDOWS_ENABLE ) )
+// facy.close_chat( data->user_id );
+
+ delete data;
+}
diff --git a/protocols/FacebookRM/process.cpp b/protocols/FacebookRM/process.cpp new file mode 100644 index 0000000000..4136e1b323 --- /dev/null +++ b/protocols/FacebookRM/process.cpp @@ -0,0 +1,646 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+void FacebookProto::ProcessBuddyList( void* data )
+{
+ if ( data == NULL )
+ return;
+
+ ScopedLock s( facy.buddies_lock_ );
+
+ std::string* resp = (std::string*)data;
+
+ if ( isOffline() )
+ goto exit;
+
+ LOG("***** Starting processing buddy list");
+
+ CODE_BLOCK_TRY
+
+ facebook_json_parser* p = new facebook_json_parser( this );
+ p->parse_buddy_list( data, &facy.buddies );
+ delete p;
+
+ for ( List::Item< facebook_user >* i = facy.buddies.begin( ); i != NULL; )
+ {
+ LOG(" Now %s: %s", (i->data->status_id == ID_STATUS_OFFLINE ? "offline" : "online"), i->data->real_name.c_str());
+
+ facebook_user* fbu;
+
+ if ( i->data->status_id == ID_STATUS_OFFLINE || i->data->deleted )
+ {
+ fbu = i->data;
+
+ if (fbu->handle && !fbu->deleted)
+ DBWriteContactSettingWord(fbu->handle, m_szModuleName, "Status", ID_STATUS_OFFLINE);
+
+ std::string to_delete( i->key );
+ i = i->next;
+ facy.buddies.erase( to_delete );
+ } else {
+ fbu = i->data;
+ i = i->next;
+
+ if (!fbu->handle) { // just been added
+ fbu->handle = AddToContactList(fbu);
+
+ if (!fbu->real_name.empty()) {
+ DBWriteContactSettingUTF8String(fbu->handle,m_szModuleName,FACEBOOK_KEY_NAME,fbu->real_name.c_str());
+ DBWriteContactSettingUTF8String(fbu->handle,m_szModuleName,FACEBOOK_KEY_NICK,fbu->real_name.c_str());
+ }
+ }
+
+ if (DBGetContactSettingWord(fbu->handle,m_szModuleName,"Status", 0) != fbu->status_id ) {
+ DBWriteContactSettingWord(fbu->handle,m_szModuleName,"Status", fbu->status_id );
+ }
+
+ if (DBGetContactSettingByte(fbu->handle,m_szModuleName,FACEBOOK_KEY_CONTACT_TYPE, 0)) {
+ DBDeleteContactSetting(fbu->handle,m_szModuleName,FACEBOOK_KEY_CONTACT_TYPE); // Set type "on server-list" contact
+ }
+
+ // Wasn't contact removed from "server-list" someday?
+ if ( DBGetContactSettingDword(fbu->handle, m_szModuleName, FACEBOOK_KEY_DELETED, 0) ) {
+ DBDeleteContactSetting(fbu->handle, m_szModuleName, FACEBOOK_KEY_DELETED);
+
+ std::string url = FACEBOOK_URL_PROFILE + fbu->user_id;
+
+ TCHAR* szTitle = mir_a2t_cp(fbu->real_name.c_str(), CP_UTF8);
+ TCHAR* szUrl = mir_a2t_cp(url.c_str(), CP_UTF8);
+ NotifyEvent(szTitle, TranslateT("Contact is back on server-list."), fbu->handle, FACEBOOK_EVENT_OTHER, szUrl);
+ mir_free( szTitle );
+ // mir_free( szUrl ); // url is free'd in popup procedure
+ }
+
+ // Check avatar change
+ CheckAvatarChange(fbu->handle, fbu->image_url);
+ }
+ }
+
+ LOG("***** Buddy list processed");
+
+ CODE_BLOCK_CATCH
+
+ LOG("***** Error processing buddy list: %s", e.what());
+
+ CODE_BLOCK_END
+
+exit:
+ delete resp;
+}
+
+void FacebookProto::ProcessFriendList( void* data )
+{
+ if ( data == NULL )
+ return;
+
+ std::string* resp = (std::string*)data;
+
+ LOG("***** Starting processing friend list");
+
+ CODE_BLOCK_TRY
+
+ std::map<std::string, facebook_user*> friends;
+
+ facebook_json_parser* p = new facebook_json_parser( this );
+ p->parse_friends( data, &friends );
+ delete p;
+
+
+ // Check and update old contacts
+ for(HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ hContact;
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0) )
+ {
+ if(!IsMyContact(hContact))
+ continue;
+
+ DBVARIANT dbv;
+ facebook_user *fbu;
+ if( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) ) {
+ std::string id = dbv.pszVal;
+ DBFreeVariant(&dbv);
+
+ std::map< std::string, facebook_user* >::iterator iter;
+
+ if ((iter = friends.find(id)) != friends.end()) {
+ // Found contact, update it and remove from map
+ fbu = iter->second;
+
+ DBVARIANT dbv;
+ bool update_required = true;
+
+ // TODO RM: remove, because contacts cant change it, so its only for "first run"
+ // - but what with contacts, that was added after logon?
+ // Update gender
+ if ( DBGetContactSettingByte(hContact, m_szModuleName, "Gender", 0) != fbu->gender )
+ DBWriteContactSettingByte(hContact, m_szModuleName, "Gender", fbu->gender);
+
+ // TODO: Remove in next version
+ if( !DBGetContactSettingString(hContact, m_szModuleName, "MirVer", &dbv) ) {
+ update_required = strcmp( dbv.pszVal, FACEBOOK_NAME ) != 0;
+ DBFreeVariant(&dbv);
+ }
+ if (update_required) {
+ DBWriteContactSettingString(hContact, m_szModuleName, "MirVer", FACEBOOK_NAME);
+ }
+
+ // Update real name
+ if ( !DBGetContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NAME, &dbv) )
+ {
+ update_required = strcmp( dbv.pszVal, fbu->real_name.c_str() ) != 0;
+ DBFreeVariant(&dbv);
+ }
+ if ( update_required )
+ {
+ DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NAME, fbu->real_name.c_str());
+ DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NICK, fbu->real_name.c_str());
+ }
+
+ if (DBGetContactSettingByte(fbu->handle,m_szModuleName,FACEBOOK_KEY_CONTACT_TYPE, 0)) {
+ DBDeleteContactSetting(fbu->handle,m_szModuleName,FACEBOOK_KEY_CONTACT_TYPE); // Has type "on server-list" contact
+ }
+
+ // Wasn't contact removed from "server-list" someday?
+ if ( DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, 0) ) {
+ DBDeleteContactSetting(hContact, m_szModuleName, FACEBOOK_KEY_DELETED);
+
+ std::string url = FACEBOOK_URL_PROFILE + fbu->user_id;
+
+ TCHAR* szTitle = mir_a2t_cp(fbu->real_name.c_str(), CP_UTF8);
+ TCHAR* szUrl = mir_a2t_cp(url.c_str(), CP_UTF8);
+ NotifyEvent(szTitle, TranslateT("Contact is back on server-list."), hContact, FACEBOOK_EVENT_OTHER, szUrl);
+ mir_free( szTitle );
+ // mir_free( szUrl ); // url is free'd in popup procedure
+ }
+
+ // Check avatar change
+ CheckAvatarChange(hContact, fbu->image_url);
+
+ delete fbu;
+ friends.erase(iter);
+ } else {
+ // Contact was removed from "server-list", notify it
+
+ // Wasnt we already been notified about this contact?
+ if ( !DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, 0)
+ && !DBGetContactSettingByte(hContact, m_szModuleName, FACEBOOK_KEY_CONTACT_TYPE, 0) ) { // And is this contact "on-server" contact?
+
+ DBWriteContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, ::time(NULL));
+
+ std::string contactname = id;
+ if ( !DBGetContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NAME, &dbv) ) {
+ contactname = dbv.pszVal;
+ DBFreeVariant(&dbv);
+ }
+
+ std::string url = FACEBOOK_URL_PROFILE + id;
+
+ TCHAR* szTitle = mir_a2t_cp(contactname.c_str(), CP_UTF8);
+ TCHAR* szUrl = mir_a2t_cp(url.c_str(), CP_UTF8);
+ NotifyEvent(szTitle, TranslateT("Contact is no longer on server-list."), hContact, FACEBOOK_EVENT_OTHER, szUrl);
+ mir_free( szTitle );
+ // mir_free( szUrl ); // url is free'd in popup procedure
+ }
+ }
+ }
+ }
+
+ // Check remain contacts in map and add it to contact list
+ for ( std::map< std::string, facebook_user* >::iterator iter = friends.begin(); iter != friends.end(); ++iter )
+ {
+ facebook_user *fbu = iter->second;
+
+ HANDLE hContact = AddToContactList(fbu, true); // This contact is surely new
+
+ DBWriteContactSettingByte(hContact, m_szModuleName, "Gender", fbu->gender );
+ DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NAME, fbu->real_name.c_str());
+ DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NICK, fbu->real_name.c_str());
+ DBWriteContactSettingString(hContact, m_szModuleName, FACEBOOK_KEY_AV_URL, fbu->image_url.c_str());
+// DBWriteContactSettingWord(hContact, m_szModuleName, "Status", ID_STATUS_OFFLINE );
+ }
+
+ LOG("***** Friend list processed");
+
+ CODE_BLOCK_CATCH
+
+ LOG("***** Error processing friend list: %s", e.what());
+
+ CODE_BLOCK_END
+
+ delete resp;
+}
+
+void FacebookProto::ProcessUnreadMessages( void* )
+{
+ facy.handle_entry( "messages" );
+
+ std::string get_data = "sk=inbox&query=is%3Aunread";
+
+ std::string data = "post_form_id=";
+ data += ( facy.post_form_id_.length( ) ) ? facy.post_form_id_ : "0";
+ data += "&fb_dtsg=" + facy.dtsg_;
+ data += "&post_form_id_source=AsyncRequest&lsd=&phstamp=";
+ data += utils::time::mili_timestamp();
+ data += "&__user=";
+ data += facy.self_.user_id;
+
+ // Get unread inbox threads
+ http::response resp = facy.flap( FACEBOOK_REQUEST_ASYNC, &data, &get_data );
+
+ // sk=inbox, sk=other
+
+ // Process result data
+ facy.validate_response(&resp);
+
+ if (resp.code != HTTP_CODE_OK) {
+ facy.handle_error( "messages" );
+ return;
+ }
+
+ std::string threadlist = utils::text::slashu_to_utf8(resp.data);
+
+ std::string::size_type pos = 0;
+
+ while ( ( pos = threadlist.find( "<li class=\\\"threadRow noDraft unread", pos ) ) != std::string::npos )
+ {
+ std::string::size_type pos2 = threadlist.find( "/li>", pos );
+ std::string thread_content = threadlist.substr( pos, pos2 - pos );
+
+ pos = pos2;
+
+ get_data = "sk=inbox&query=is%3Aunread&thread_query=is%3Aunread&action=read&tid=";
+ get_data += utils::text::source_get_value( &thread_content, 2, "id=\\\"", "\\\"" );
+
+ resp = facy.flap( FACEBOOK_REQUEST_ASYNC, &data, &get_data );
+ // TODO: move this to new thread...
+
+ facy.validate_response(&resp);
+
+ if (resp.code != HTTP_CODE_OK) {
+ LOG(" !! !! Error when getting messages list");
+ continue;
+ }
+
+ std::string messageslist = utils::text::slashu_to_utf8(resp.data);
+
+ std::string user_id = utils::text::source_get_value( &messageslist, 2, "single_thread_id\":", "," );
+ if (user_id.empty()) {
+ LOG(" !! !! Thread id is empty - this is groupchat message."); // TODO: remove as this is not such 'error'
+ continue;
+ }
+
+ facebook_user fbu;
+ fbu.user_id = user_id;
+
+ HANDLE hContact = AddToContactList(&fbu);
+ // TODO: if contact is newly added, get his user info
+ // TODO: maybe create new "receiveMsg" function and use it for offline and channel messages?
+
+ pos2 = 0;
+ while ( ( pos2 = messageslist.find( "class=\\\"MessagingMessage ", pos2 ) ) != std::string::npos ) {
+ pos2 += 8;
+ std::string strclass = messageslist.substr(pos2, messageslist.find("\\\"", pos2) - pos2);
+
+ if (strclass.find("MessagingMessageUnread") == std::string::npos)
+ continue; // ignoring old messages
+
+ //std::string::size_type pos3 = messageslist.find( "/li>", pos2 ); // TODO: ne proti tomuhle li, protože i pÅ™Ãlohy majà li...
+ std::string::size_type pos3 = messageslist.find( "class=\\\"MessagingMessage ", pos2 );
+ std::string messagesgroup = messageslist.substr( pos2, pos3 - pos2 );
+
+ DWORD timestamp = NULL;
+ std::string strtime = utils::text::source_get_value( &messagesgroup, 2, "data-utime=\\\"", "\\\"" );
+ if (!utils::conversion::from_string<DWORD>(timestamp, strtime, std::dec)) {
+ timestamp = static_cast<DWORD>(::time(NULL));
+ }
+
+ pos3 = 0;
+ while ( ( pos3 = messagesgroup.find( "class=\\\"content noh", pos3 ) ) != std::string::npos )
+ {
+
+ std::string message_attachments = "";
+ std::string::size_type pos4 = 0;
+ if ((pos4 = messagesgroup.find( "class=\\\"attachments\\\"", pos4)) != std::string::npos) {
+ std::string attachments = messagesgroup.substr( pos4, messagesgroup.find("<\\/ul", pos4) - pos4 );
+
+ pos4 = 0;
+ while ( ( pos4 = attachments.find("<li", pos4) ) != std::string::npos ) {
+ std::string attachment = attachments.substr( pos4, attachments.find("<\\/li>", pos4) - pos4 );
+ std::string link = utils::text::source_get_value( &attachment, 4, "<a class=", "attachment", "href=\\\"", "\\\"" );
+
+ link = utils::text::trim(
+ utils::text::special_expressions_decode( link ) );
+
+ // or first: std::string name = utils::text::source_get_value( &attachment, 4, "<a class=", "attachment", ">", "<\\/a>" );
+ std::string name = utils::text::trim(
+ utils::text::special_expressions_decode(
+ utils::text::remove_html( attachment ) ) );
+
+ if (link.find("/ajax/messaging/attachments/photo/dialog.php?uri=") != std::string::npos) {
+ link = link.substr(49);
+ link = utils::url::decode(link);
+ }
+
+ message_attachments += "< " + name + " > " + FACEBOOK_URL_HOMEPAGE;
+ message_attachments += link + "\r\n";
+
+ pos4++;
+ }
+
+ }
+
+ std::string message_text = messagesgroup.substr(pos3, messagesgroup.find( "<\\/div", pos3 ) + 6 - pos3);
+ message_text = utils::text::source_get_value( &message_text, 2, "\\\">", "<\\/div" );
+ message_text = utils::text::trim(
+ utils::text::special_expressions_decode(
+ utils::text::remove_html( message_text ) ) );
+
+ if (!message_attachments.empty()) {
+ if (!message_text.empty())
+ message_text += "\r\n\r\n";
+
+ message_text += Translate("Attachments:");
+ message_text += "\r\n" + message_attachments;
+ }
+
+ PROTORECVEVENT recv = {0};
+ CCSDATA ccs = {0};
+
+ recv.flags = PREF_UTF;
+ recv.szMessage = const_cast<char*>(message_text.c_str());
+ recv.timestamp = timestamp;
+
+ ccs.hContact = hContact;
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.lParam = reinterpret_cast<LPARAM>(&recv);
+ CallService(MS_PROTO_CHAINRECV,0,reinterpret_cast<LPARAM>(&ccs));
+
+ pos3++;
+ }
+
+ }
+
+ }
+
+}
+
+void FacebookProto::ProcessMessages( void* data )
+{
+ if ( data == NULL )
+ return;
+
+ std::string* resp = (std::string*)data;
+
+ if ( isOffline() )
+ goto exit;
+
+ LOG("***** Starting processing messages");
+
+ CODE_BLOCK_TRY
+
+ std::vector< facebook_message* > messages;
+ std::vector< facebook_notification* > notifications;
+
+ facebook_json_parser* p = new facebook_json_parser( this );
+ p->parse_messages( data, &messages, ¬ifications );
+ delete p;
+
+ for(std::vector<facebook_message*>::size_type i=0; i<messages.size( ); i++)
+ {
+ if ( messages[i]->user_id != facy.self_.user_id )
+ {
+ LOG(" Got message: %s", messages[i]->message_text.c_str());
+ facebook_user fbu;
+ fbu.user_id = messages[i]->user_id;
+
+ HANDLE hContact = AddToContactList(&fbu, false, messages[i]->sender_name.c_str());
+
+ // TODO: if contact is newly added, get his user info
+ // TODO: maybe create new "receiveMsg" function and use it for offline and channel messages?
+
+ PROTORECVEVENT recv = {0};
+ CCSDATA ccs = {0};
+
+ recv.flags = PREF_UTF;
+ recv.szMessage = const_cast<char*>(messages[i]->message_text.c_str());
+ recv.timestamp = static_cast<DWORD>(messages[i]->time);
+
+ ccs.hContact = hContact;
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.lParam = reinterpret_cast<LPARAM>(&recv);
+ CallService(MS_PROTO_CHAINRECV,0,reinterpret_cast<LPARAM>(&ccs));
+ }
+ delete messages[i];
+ }
+ messages.clear();
+
+ for(std::vector<facebook_notification*>::size_type i=0; i<notifications.size( ); i++)
+ {
+ LOG(" Got notification: %s", notifications[i]->text.c_str());
+ TCHAR* szTitle = mir_a2t_cp(this->m_szModuleName, CP_UTF8);
+ TCHAR* szText = mir_a2t_cp(notifications[i]->text.c_str(), CP_UTF8);
+ TCHAR* szUrl = mir_a2t_cp(notifications[i]->link.c_str(), CP_UTF8);
+ NotifyEvent( szTitle, szText, ContactIDToHContact(notifications[i]->user_id), FACEBOOK_EVENT_NOTIFICATION, szUrl );
+ mir_free( szTitle );
+ mir_free( szText );
+// mir_free( szUrl ); // URL is free'd in popup procedure
+
+ delete notifications[i];
+ }
+ notifications.clear();
+
+ LOG("***** Messages processed");
+
+ CODE_BLOCK_CATCH
+
+ LOG("***** Error processing messages: %s", e.what());
+
+ CODE_BLOCK_END
+
+exit:
+ delete resp;
+}
+
+void FacebookProto::ProcessNotifications( void* )
+{
+ if ( isOffline() )
+ return;
+
+ if (!getByte( FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE ))
+ return;
+
+ facy.handle_entry( "notifications" );
+
+ // Get notifications
+ http::response resp = facy.flap( FACEBOOK_REQUEST_NOTIFICATIONS );
+
+ // Process result data
+ facy.validate_response(&resp);
+
+ if (resp.code != HTTP_CODE_OK) {
+ facy.handle_error( "notifications" );
+ return;
+ }
+
+
+ // Process notifications
+ LOG("***** Starting processing notifications");
+
+ CODE_BLOCK_TRY
+
+ std::vector< facebook_notification* > notifications;
+
+ facebook_json_parser* p = new facebook_json_parser( this );
+ p->parse_notifications( &(resp.data), ¬ifications );
+ delete p;
+
+ for(std::vector<facebook_notification*>::size_type i=0; i<notifications.size( ); i++)
+ {
+ LOG(" Got notification: %s", notifications[i]->text.c_str());
+ TCHAR* szTitle = mir_a2t_cp(this->m_szModuleName, CP_UTF8);
+ TCHAR* szText = mir_a2t_cp(notifications[i]->text.c_str(), CP_UTF8);
+ TCHAR* szUrl = mir_a2t_cp(notifications[i]->link.c_str(), CP_UTF8);
+ NotifyEvent( szTitle, szText, ContactIDToHContact(notifications[i]->user_id), FACEBOOK_EVENT_NOTIFICATION, szUrl );
+ mir_free( szTitle );
+ mir_free( szText );
+// mir_free( szUrl ); // URL is free'd in popup procedure
+
+ delete notifications[i];
+ }
+ notifications.clear();
+
+ LOG("***** Notifications processed");
+
+ CODE_BLOCK_CATCH
+
+ LOG("***** Error processing notifications: %s", e.what());
+
+ CODE_BLOCK_END
+}
+
+
+void FacebookProto::ProcessFeeds( void* data )
+{
+ if ( data == NULL )
+ return;
+
+ std::string* resp = (std::string*)data;
+
+ if (!isOnline())
+ goto exit;
+
+ CODE_BLOCK_TRY
+
+ LOG("***** Starting processing feeds");
+
+ std::vector< facebook_newsfeed* > news;
+
+ std::string::size_type pos = 0;
+ UINT limit = 0;
+
+ *resp = utils::text::slashu_to_utf8(*resp);
+ *resp = utils::text::source_get_value(resp, 2, "\"html\":\"", ">\"");
+
+ while ( ( pos = resp->find( "<div class=\\\"mainWrapper\\\"", pos ) ) != std::string::npos && limit <= 25 )
+ {
+ std::string::size_type pos2 = resp->find( "<div class=\\\"mainWrapper\\\"", pos+5 );
+ if (pos2 == std::string::npos)
+ pos2 = resp->length();
+
+ std::string post = resp->substr( pos, pos2 - pos );
+ pos += 5;
+
+ std::string post_header = utils::text::source_get_value(&post, 4, "<h6 class=", "uiStreamHeadline", ">", "<\\/h6>");
+ std::string post_message = utils::text::source_get_value(&post, 3, "<h6 class=\\\"uiStreamMessage\\\"", ">", "<\\/h6>");
+ std::string post_link = utils::text::source_get_value(&post, 3, "<span class=\\\"uiStreamSource\\\"", ">", "<\\/span>");
+ std::string post_attach = utils::text::source_get_value(&post, 4, "<div class=", "uiStreamAttachments", ">", "<form");
+
+ // in title keep only name, end of events like "X shared link" put into message
+ pos2 = post_header.find("<\\/a>") + 5;
+ post_message = post_header.substr(pos2, post_header.length() - pos2) + post_message;
+ post_header = post_header.substr(0, pos2);
+
+ // append attachement to message (if any)
+ post_message += utils::text::trim( post_attach );
+
+ facebook_newsfeed* nf = new facebook_newsfeed;
+
+ nf->title = utils::text::trim(
+ utils::text::special_expressions_decode(
+ utils::text::remove_html( post_header ) ) );
+
+ nf->user_id = utils::text::source_get_value( &post_header, 2, "user.php?id=", "\\\"" );
+
+ nf->link = utils::text::special_expressions_decode(
+ utils::text::source_get_value( &post_link, 2, "href=\\\"", "\\\">" ) );
+
+ nf->text = utils::text::trim(
+ utils::text::special_expressions_decode(
+ utils::text::remove_html(
+ utils::text::edit_html( post_message ) ) ) );
+
+ if ( !nf->title.length() || !nf->text.length() )
+ {
+ delete nf;
+ continue;
+ }
+
+ if (nf->text.length() > 500)
+ {
+ nf->text = nf->text.substr(0, 500);
+ nf->text += "...";
+ }
+
+ news.push_back( nf );
+ pos++;
+ limit++;
+ }
+
+ for(std::vector<facebook_newsfeed*>::size_type i=0; i<news.size( ); i++)
+ {
+ LOG(" Got newsfeed: %s %s", news[i]->title.c_str(), news[i]->text.c_str());
+ TCHAR* szTitle = mir_a2t_cp(news[i]->title.c_str(), CP_UTF8);
+ TCHAR* szText = mir_a2t_cp(news[i]->text.c_str(), CP_UTF8);
+ TCHAR* szUrl = mir_a2t_cp(news[i]->link.c_str(), CP_UTF8);
+ NotifyEvent(szTitle,szText,this->ContactIDToHContact(news[i]->user_id),FACEBOOK_EVENT_NEWSFEED, szUrl);
+ mir_free(szTitle);
+ mir_free(szText);
+// mir_free(szUrl); // URL is free'd in popup procedure
+ delete news[i];
+ }
+ news.clear();
+
+ this->facy.last_feeds_update_ = ::time(NULL);
+
+ LOG("***** Feeds processed");
+
+ CODE_BLOCK_CATCH
+
+ LOG("***** Error processing feeds: %s", e.what());
+
+ CODE_BLOCK_END
+
+exit:
+ delete resp;
+}
diff --git a/protocols/FacebookRM/proto.cpp b/protocols/FacebookRM/proto.cpp new file mode 100644 index 0000000000..692de07521 --- /dev/null +++ b/protocols/FacebookRM/proto.cpp @@ -0,0 +1,502 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+FacebookProto::FacebookProto(const char* proto_name,const TCHAR* username)
+{
+ m_iVersion = 2;
+ m_szProtoName = mir_strdup( proto_name );
+ m_szModuleName = mir_strdup( proto_name );
+ m_tszUserName = mir_tstrdup( username );
+
+ facy.parent = this;
+
+ signon_lock_ = CreateMutex( NULL, FALSE, NULL );
+ avatar_lock_ = CreateMutex( NULL, FALSE, NULL );
+ log_lock_ = CreateMutex( NULL, FALSE, NULL );
+ update_loop_lock_ = CreateEvent( NULL, FALSE, FALSE, NULL);
+ facy.buddies_lock_ = CreateMutex( NULL, FALSE, NULL );
+ facy.send_message_lock_ = CreateMutex( NULL, FALSE, NULL );
+ facy.fcb_conn_lock_ = CreateMutex( NULL, FALSE, NULL );
+
+ CreateProtoService(m_szModuleName, PS_CREATEACCMGRUI, &FacebookProto::SvcCreateAccMgrUI, this);
+ CreateProtoService(m_szModuleName, PS_GETMYAWAYMSG, &FacebookProto::GetMyAwayMsg, this);
+ CreateProtoService(m_szModuleName, PS_GETMYAVATAR, &FacebookProto::GetMyAvatar, this);
+ CreateProtoService(m_szModuleName, PS_GETAVATARINFO, &FacebookProto::GetAvatarInfo, this);
+ CreateProtoService(m_szModuleName, PS_GETAVATARCAPS, &FacebookProto::GetAvatarCaps, this);
+
+ CreateProtoService(m_szModuleName, PS_JOINCHAT, &FacebookProto::OnJoinChat, this);
+ CreateProtoService(m_szModuleName, PS_LEAVECHAT, &FacebookProto::OnLeaveChat, this);
+
+ HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &FacebookProto::OnBuildStatusMenu, this);
+ HookProtoEvent(ME_OPT_INITIALISE, &FacebookProto::OnOptionsInit, this);
+ HookProtoEvent(ME_GC_EVENT, &FacebookProto::OnChatOutgoing, this);
+ HookProtoEvent(ME_IDLE_CHANGED, &FacebookProto::OnIdleChanged, this);
+
+ // Create standard network connection
+ TCHAR descr[512];
+ NETLIBUSER nlu = {sizeof(nlu)};
+ nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR;
+ nlu.szSettingsModule = m_szModuleName;
+ char module[512];
+ mir_snprintf(module,SIZEOF(module),"%sAv",m_szModuleName);
+ nlu.szSettingsModule = module;
+ mir_sntprintf(descr,SIZEOF(descr),TranslateT("%s server connection"),m_tszUserName);
+ nlu.ptszDescriptiveName = descr;
+ m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER,0,(LPARAM)&nlu);
+ if(m_hNetlibUser == NULL)
+ MessageBox(NULL,TranslateT("Unable to get Netlib connection for Facebook"),m_tszUserName,MB_OK);
+
+ facy.set_handle(m_hNetlibUser);
+
+ SkinAddNewSoundExT( "Notification", m_tszUserName, LPGENT( "Notification" ) );
+ SkinAddNewSoundExT( "NewsFeed", m_tszUserName, LPGENT( "News Feed" ) );
+ SkinAddNewSoundExT( "OtherEvent", m_tszUserName, LPGENT( "Other Event" ) );
+
+ char *profile = Utils_ReplaceVars("%miranda_avatarcache%");
+ def_avatar_folder_ = std::string(profile)+"\\"+m_szModuleName;
+ mir_free(profile);
+ hAvatarFolder_ = FoldersRegisterCustomPath(m_szModuleName, "Avatars", def_avatar_folder_.c_str());
+
+ // Set all contacts offline -- in case we crashed
+ SetAllContactStatuses( ID_STATUS_OFFLINE );
+}
+
+FacebookProto::~FacebookProto( )
+{
+ Netlib_CloseHandle( m_hNetlibUser );
+
+ WaitForSingleObject( signon_lock_, IGNORE );
+ WaitForSingleObject( avatar_lock_, IGNORE );
+ WaitForSingleObject( log_lock_, IGNORE );
+ WaitForSingleObject( facy.buddies_lock_, IGNORE );
+ WaitForSingleObject( facy.send_message_lock_, IGNORE );
+
+ CloseHandle( signon_lock_ );
+ CloseHandle( avatar_lock_ );
+ CloseHandle( log_lock_ );
+ CloseHandle( update_loop_lock_ );
+ //CloseHandle( this->message_loop_lock_ );
+ CloseHandle( facy.buddies_lock_ );
+ CloseHandle( facy.send_message_lock_ );
+ CloseHandle( facy.fcb_conn_lock_ );
+
+ mir_free( m_tszUserName );
+ mir_free( m_szModuleName );
+ mir_free( m_szProtoName );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+DWORD_PTR FacebookProto::GetCaps( int type, HANDLE hContact )
+{
+ switch(type)
+ {
+ case PFLAGNUM_1: // TODO: Other caps available: PF1_BASICSEARCH, PF1_SEARCHBYEMAIL
+ if ( getByte( FACEBOOK_KEY_SET_MIRANDA_STATUS, 0 ) )
+ return PF1_IM | PF1_CHAT | PF1_SERVERCLIST | PF1_MODEMSG;
+ else
+ return PF1_IM | PF1_CHAT | PF1_SERVERCLIST | PF1_MODEMSGRECV;
+ case PFLAGNUM_2:
+ return PF2_ONLINE | PF2_INVISIBLE | PF2_ONTHEPHONE | PF2_IDLE; // | PF2_SHORTAWAY;
+ case PFLAGNUM_3:
+ if ( getByte( FACEBOOK_KEY_SET_MIRANDA_STATUS, 0 ) )
+ return PF2_ONLINE; // | PF2_SHORTAWAY;
+ else
+ return 0;
+ case PFLAGNUM_4:
+ return PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_SUPPORTIDLE | PF4_IMSENDUTF | PF4_AVATARS | PF4_SUPPORTTYPING | PF4_NOAUTHDENYREASON | PF4_IMSENDOFFLINE;
+ case PFLAGNUM_5:
+ return PF2_ONTHEPHONE;
+ case PFLAG_MAXLENOFMESSAGE:
+ return FACEBOOK_MESSAGE_LIMIT;
+ case PFLAG_UNIQUEIDTEXT:
+ return (int) "Facebook ID";
+ case PFLAG_UNIQUEIDSETTING:
+ return (int) FACEBOOK_KEY_ID;
+ }
+ return 0;
+}
+
+HICON FacebookProto::GetIcon(int index)
+{
+ if(LOWORD(index) == PLI_PROTOCOL)
+ {
+ HICON ico = (HICON)CallService(MS_SKIN2_GETICON,0,(LPARAM)"Facebook_facebook");
+ return CopyIcon(ico);
+ } else {
+ return 0;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+int FacebookProto::SetStatus( int new_status )
+{
+ LOG("===== Beginning SetStatus process");
+
+ // Routing statuses not supported by Facebook
+ switch ( new_status )
+ {
+ case ID_STATUS_INVISIBLE:
+ case ID_STATUS_OFFLINE:
+ m_iDesiredStatus = new_status;
+ break;
+
+ // TODO RM: needed/useful?
+ case ID_STATUS_CONNECTING:
+ m_iDesiredStatus = ID_STATUS_OFFLINE;
+ break;
+
+ case ID_STATUS_IDLE:
+ default:
+ m_iDesiredStatus = ID_STATUS_INVISIBLE;
+ if (DBGetContactSettingByte(NULL,m_szModuleName,FACEBOOK_KEY_MAP_STATUSES, DEFAULT_MAP_STATUSES))
+ break;
+ case ID_STATUS_ONLINE:
+ case ID_STATUS_FREECHAT:
+ m_iDesiredStatus = ID_STATUS_ONLINE;
+ break;
+ }
+
+ if ( m_iStatus == ID_STATUS_CONNECTING )
+ {
+ LOG("===== Status is connecting, no change");
+ return 0;
+ }
+
+ if ( m_iStatus == m_iDesiredStatus)
+ {
+ LOG("===== Statuses are same, no change");
+ return 0;
+ }
+
+ facy.invisible_ = ( new_status == ID_STATUS_INVISIBLE );
+
+ ForkThread( &FacebookProto::ChangeStatus, this );
+
+ return 0;
+}
+
+int FacebookProto::SetAwayMsg( int status, const PROTOCHAR *msg )
+{
+ if (!msg)
+ {
+ last_status_msg_.clear();
+ return 0;
+ }
+
+ char *narrow = mir_utf8encodeT(msg);
+ if (last_status_msg_ != narrow) last_status_msg_ = narrow;
+ utils::mem::detract(narrow);
+
+ if (isOnline() && getByte(FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS))
+ {
+ ForkThread(&FacebookProto::SetAwayMsgWorker, this, NULL);
+ }
+ return 0;
+}
+
+void FacebookProto::SetAwayMsgWorker(void *)
+{
+ if ( !last_status_msg_.empty() )
+ facy.set_status( last_status_msg_ );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SERVICES
+
+int FacebookProto::GetMyAwayMsg( WPARAM wParam, LPARAM lParam )
+{
+ DBVARIANT dbv = { DBVT_TCHAR };
+ if ( !getTString( "StatusMsg", &dbv ) && lstrlen( dbv.ptszVal ) != 0 )
+ {
+ int res = (lParam & SGMA_UNICODE) ? (INT_PTR)mir_t2u(dbv.ptszVal) : (INT_PTR)mir_t2a(dbv.ptszVal);
+ DBFreeVariant( &dbv );
+ return res;
+ } else {
+ return 0;
+ }
+}
+
+int FacebookProto::OnIdleChanged( WPARAM wParam, LPARAM lParam )
+{
+ if (m_iStatus == ID_STATUS_INVISIBLE || m_iStatus <= ID_STATUS_OFFLINE)
+ return 0;
+
+ bool bIdle = (lParam & IDF_ISIDLE) != 0;
+ bool bPrivacy = (lParam & IDF_PRIVACY) != 0;
+
+ if (facy.is_idle_ && !bIdle)
+ {
+ facy.is_idle_ = false;
+ SetStatus(m_iDesiredStatus);
+ }
+ else if (!facy.is_idle_ && bIdle && !bPrivacy && m_iDesiredStatus != ID_STATUS_INVISIBLE)
+ {
+ facy.is_idle_ = true;
+ SetStatus(ID_STATUS_IDLE);
+ }
+
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+int FacebookProto::OnEvent(PROTOEVENTTYPE event,WPARAM wParam,LPARAM lParam)
+{
+ switch(event)
+ {
+ case EV_PROTO_ONLOAD:
+ return OnModulesLoaded(wParam,lParam);
+
+ case EV_PROTO_ONEXIT:
+ return OnPreShutdown(wParam,lParam);
+
+ case EV_PROTO_ONOPTIONS:
+ return OnOptionsInit(wParam,lParam);
+
+ case EV_PROTO_ONCONTACTDELETED:
+ return OnContactDeleted(wParam,lParam);
+ }
+
+ return 1;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// EVENTS
+
+int FacebookProto::SvcCreateAccMgrUI(WPARAM wParam,LPARAM lParam)
+{
+ return (int)CreateDialogParam(g_hInstance,MAKEINTRESOURCE(IDD_FACEBOOKACCOUNT),
+ (HWND)lParam, FBAccountProc, (LPARAM)this );
+}
+
+int FacebookProto::OnModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ // Register group chat
+ GCREGISTER gcr = {sizeof(gcr)};
+ gcr.dwFlags = 0; //GC_ACKMSG;
+ gcr.pszModule = m_szModuleName;
+ gcr.pszModuleDispName = m_szModuleName;
+ gcr.iMaxText = FACEBOOK_MESSAGE_LIMIT;
+ gcr.nColors = 0;
+ gcr.pColors = NULL;
+ CallService(MS_GC_REGISTER,0,reinterpret_cast<LPARAM>(&gcr));
+
+ return 0;
+}
+
+int FacebookProto::OnPreShutdown(WPARAM wParam,LPARAM lParam)
+{
+ SetStatus( ID_STATUS_OFFLINE );
+ return 0;
+}
+
+int FacebookProto::OnPrebuildContactMenu(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hContact = reinterpret_cast<HANDLE>(wParam);
+ if(IsMyContact(hContact/*, true*/)) {
+ bool hide = (DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, 0)
+ || DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_CONTACT_TYPE, 0) );
+ ShowContactMenus(true, hide);
+ }
+
+ return 0;
+}
+
+int FacebookProto::OnOptionsInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = {sizeof(odp)};
+ odp.hInstance = g_hInstance;
+ odp.ptszTitle = m_tszUserName;
+ odp.dwInitParam = LPARAM(this);
+ odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE;
+
+ odp.position = 271828;
+ odp.ptszGroup = LPGENT("Network");
+ odp.ptszTab = LPGENT("Account");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS);
+ odp.pfnDlgProc = FBOptionsProc;
+ CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+
+ odp.position = 271829;
+ odp.ptszTab = LPGENT("Advanced");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_ADVANCED);
+ odp.pfnDlgProc = FBOptionsAdvancedProc;
+ CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+
+ odp.position = 271830;
+ if(ServiceExists(MS_POPUP_ADDPOPUPT))
+ odp.ptszGroup = LPGENT("Popups");
+ odp.ptszTab = LPGENT("Events");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_EVENTS);
+ odp.pfnDlgProc = FBEventsProc;
+ CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+
+ return 0;
+}
+
+int FacebookProto::OnBuildStatusMenu(WPARAM wParam,LPARAM lParam)
+{
+ char text[200];
+ strcpy(text,m_szModuleName);
+ char *tDest = text+strlen(text);
+
+ HGENMENU hRoot;
+ CLISTMENUITEM mi = {sizeof(mi)};
+ mi.pszService = text;
+
+ hRoot = MO_GetProtoRootMenu(m_szModuleName);
+ if (hRoot == NULL)
+ {
+ mi.popupPosition = 500085000;
+ mi.hParentMenu = HGENMENU_ROOT;
+ mi.flags = CMIF_ICONFROMICOLIB | CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED | ( this->isOnline() ? 0 : CMIF_GRAYED );
+ mi.icolibItem = GetIconHandle( "facebook" );
+ mi.ptszName = m_tszUserName;
+ hRoot = m_hMenuRoot = reinterpret_cast<HGENMENU>( CallService(
+ MS_CLIST_ADDPROTOMENUITEM,0,reinterpret_cast<LPARAM>(&mi)) );
+ } else {
+ if ( m_hMenuRoot )
+ CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )m_hMenuRoot, 0 );
+ m_hMenuRoot = NULL;
+ }
+
+ mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP | ( this->isOnline() ? 0 : CMIF_GRAYED );
+ mi.position = 201001;
+
+ CreateProtoService(m_szModuleName,"/Mind",&FacebookProto::OnMind,this);
+ strcpy(tDest,"/Mind");
+ mi.hParentMenu = hRoot;
+ mi.pszName = LPGEN("Mind...");
+ mi.icolibItem = GetIconHandle("mind");
+ m_hStatusMind = reinterpret_cast<HGENMENU>( CallService(
+ MS_CLIST_ADDPROTOMENUITEM,0,reinterpret_cast<LPARAM>(&mi)) );
+
+ CreateProtoService(m_szModuleName,"/VisitProfile",&FacebookProto::VisitProfile,this);
+ strcpy(tDest,"/VisitProfile");
+ mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP;
+ mi.pszName = LPGEN("Visit Profile");
+ mi.icolibItem = GetIconHandle("homepage");
+ // TODO RM: remember and properly free in destructor?
+ /*m_hStatusMind = */reinterpret_cast<HGENMENU>( CallService(
+ MS_CLIST_ADDPROTOMENUITEM,0,reinterpret_cast<LPARAM>(&mi)) );
+
+ return 0;
+}
+
+int FacebookProto::OnMind(WPARAM,LPARAM)
+{
+ HWND hDlg = CreateDialogParam( g_hInstance, MAKEINTRESOURCE( IDD_MIND ),
+ ( HWND )0, FBMindProc, reinterpret_cast<LPARAM>( this ) );
+ ShowWindow( hDlg, SW_SHOW );
+ return FALSE;
+}
+
+int FacebookProto::VisitProfile(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hContact = reinterpret_cast<HANDLE>(wParam);
+
+ DBVARIANT dbv;
+ if( wParam != 0 && !DBGetContactSettingString(hContact,m_szModuleName,"Homepage",&dbv) )
+ {
+ CallService(MS_UTILS_OPENURL,1,reinterpret_cast<LPARAM>(dbv.pszVal));
+ DBFreeVariant(&dbv);
+ } else {
+ // self contact, probably
+ // TODO: why isn't wParam == 0 when is status menu moved to main menu?
+ CallService(MS_UTILS_OPENURL,1,reinterpret_cast<LPARAM>(FACEBOOK_URL_PROFILE));
+ return 0;
+ }
+
+ return 0;
+}
+
+int FacebookProto::RemoveFriend(WPARAM wParam,LPARAM lParam)
+{
+ if (wParam == NULL)
+ { // self contact
+ // CallService(MS_UTILS_OPENURL,1,reinterpret_cast<LPARAM>(FACEBOOK_URL_PROFILE));
+ return 0;
+ }
+
+ if (isOffline())
+ return 0;
+
+ if (MessageBox( 0, TranslateT("Are you sure?"), TranslateT("Delete contact from server list"), MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 ) != IDYES)
+ return 0;
+
+ HANDLE hContact = reinterpret_cast<HANDLE>(wParam);
+
+ DBVARIANT dbv;
+ if( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) )
+ {
+ if (!isOffline()) {
+ std::string* id = new std::string(dbv.pszVal);
+ ForkThread( &FacebookProto::DeleteContactFromServer, this, ( void* )id );
+ DBFreeVariant(&dbv);
+
+ if ( !DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, 0) )
+ DBWriteContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, ::time(NULL));
+ }
+ }
+
+ return 0;
+}
+
+int FacebookProto::AddFriend(WPARAM wParam,LPARAM lParam)
+{
+ if (wParam == NULL)
+ { // self contact
+// CallService(MS_UTILS_OPENURL,1,reinterpret_cast<LPARAM>(FACEBOOK_URL_PROFILE));
+ return 0;
+ }
+
+ if (isOffline())
+ return 0;
+
+ HANDLE hContact = reinterpret_cast<HANDLE>(wParam);
+
+ DBVARIANT dbv;
+ if( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) )
+ {
+ if (!isOffline()) {
+ std::string* id = new std::string(dbv.pszVal);
+ ForkThread( &FacebookProto::AddContactToServer, this, ( void* )id );
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ return 0;
+}
+
+void FacebookProto::ToggleStatusMenuItems( BOOL bEnable )
+{
+ CLISTMENUITEM clmi = { 0 };
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS | (( bEnable ) ? 0 : CMIF_GRAYED);
+
+ CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuRoot, ( LPARAM )&clmi );
+ CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hStatusMind, ( LPARAM )&clmi );
+}
diff --git a/protocols/FacebookRM/proto.h b/protocols/FacebookRM/proto.h new file mode 100644 index 0000000000..db236b8777 --- /dev/null +++ b/protocols/FacebookRM/proto.h @@ -0,0 +1,208 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+class FacebookProto : public PROTO_INTERFACE
+{
+public:
+ FacebookProto( const char *proto_name, const TCHAR *username );
+ ~FacebookProto( );
+
+ __inline void* operator new( size_t size )
+ {
+ return calloc( 1, size );
+ }
+ __inline void operator delete( void* p )
+ {
+ free( p );
+ }
+
+ inline const char* ModuleName( ) const
+ {
+ return m_szModuleName;
+ }
+
+ inline bool isOnline( )
+ {
+ return ( m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING );
+ }
+
+ inline bool isOffline( )
+ {
+ return ( m_iStatus == ID_STATUS_OFFLINE );
+ }
+
+ inline bool isInvisible( )
+ {
+ return ( m_iStatus == ID_STATUS_INVISIBLE );
+ }
+
+ //PROTO_INTERFACE
+
+ virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr );
+ virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent );
+
+ virtual int __cdecl Authorize( HANDLE hDbEvent );
+ virtual int __cdecl AuthDeny( HANDLE hDbEvent, const PROTOCHAR* szReason );
+ virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* );
+ virtual int __cdecl AuthRequest( HANDLE hContact, const PROTOCHAR* szMessage );
+
+ virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData );
+
+ virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath );
+ virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer );
+ virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason );
+ virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const PROTOCHAR** szFilename );
+
+ virtual DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact = NULL );
+ virtual HICON __cdecl GetIcon( int iconIndex );
+ virtual int __cdecl GetInfo( HANDLE hContact, int infoType );
+
+ virtual HANDLE __cdecl SearchBasic( const PROTOCHAR* id );
+ virtual HANDLE __cdecl SearchByEmail( const PROTOCHAR* email );
+ virtual HANDLE __cdecl SearchByName( const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName );
+ virtual HWND __cdecl SearchAdvanced( HWND owner );
+ virtual HWND __cdecl CreateExtendedSearchUI( HWND owner );
+
+ virtual int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* );
+ virtual int __cdecl RecvFile( HANDLE hContact, PROTOFILEEVENT* );
+ virtual int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* );
+ virtual int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* );
+
+ virtual int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList );
+ virtual HANDLE __cdecl SendFile( HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles );
+ virtual int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg );
+ virtual int __cdecl SendUrl( HANDLE hContact, int flags, const char* url );
+
+ virtual int __cdecl SetApparentMode( HANDLE hContact, int mode );
+ virtual int __cdecl SetStatus( int iNewStatus );
+
+ virtual HANDLE __cdecl GetAwayMsg( HANDLE hContact );
+ virtual int __cdecl RecvAwayMsg( HANDLE hContact, int mode, PROTORECVEVENT* evt );
+ virtual int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg );
+ virtual int __cdecl SetAwayMsg( int iStatus, const PROTOCHAR* msg );
+
+ virtual int __cdecl UserIsTyping( HANDLE hContact, int type );
+
+ virtual int __cdecl OnEvent( PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam );
+
+ ////////////////////////
+
+ // Services
+ int __cdecl GetMyAwayMsg( WPARAM, LPARAM );
+ int __cdecl SetMyAwayMsg( WPARAM, LPARAM );
+ int __cdecl SvcCreateAccMgrUI( WPARAM, LPARAM );
+ int __cdecl GetMyAvatar(WPARAM, LPARAM );
+ int __cdecl GetAvatarInfo(WPARAM, LPARAM );
+ int __cdecl GetAvatarCaps(WPARAM, LPARAM );
+ int __cdecl VisitProfile(WPARAM, LPARAM );
+ int __cdecl RemoveFriend(WPARAM, LPARAM );
+ int __cdecl AddFriend(WPARAM, LPARAM );
+
+ // Events
+ int __cdecl OnModulesLoaded(WPARAM, LPARAM);
+ int __cdecl OnOptionsInit(WPARAM, LPARAM);
+ int __cdecl OnBuildStatusMenu(WPARAM,LPARAM);
+ int __cdecl OnContactDeleted(WPARAM,LPARAM);
+ int __cdecl OnMind(WPARAM,LPARAM);
+ int __cdecl OnPreShutdown(WPARAM,LPARAM);
+ int __cdecl OnPrebuildContactMenu(WPARAM,LPARAM);
+ int __cdecl OnIdleChanged(WPARAM,LPARAM);
+ int __cdecl OnChatOutgoing(WPARAM,LPARAM);
+ int __cdecl OnJoinChat(WPARAM,LPARAM);
+ int __cdecl OnLeaveChat(WPARAM,LPARAM);
+
+ // Loops
+ bool NegotiateConnection();
+ BYTE GetPollRate();
+ void __cdecl MessageLoop(void*);
+ void __cdecl UpdateLoop(void*);
+
+ // Processing threads
+ void __cdecl ProcessBuddyList(void*);
+ void __cdecl ProcessFriendList(void*);
+ void __cdecl ProcessMessages(void*);
+ void __cdecl ProcessUnreadMessages(void*);
+ void __cdecl ProcessFeeds(void*);
+ void __cdecl ProcessNotifications(void*);
+
+ // Worker threads
+ void __cdecl SignOn(void*);
+ void __cdecl ChangeStatus(void*);
+ void __cdecl SignOff(void*);
+ void __cdecl SetAwayMsgWorker(void*);
+ void __cdecl UpdateAvatarWorker(void*);
+ void __cdecl SendMsgWorker(void*);
+ void __cdecl SendChatMsgWorker(void*);
+ void __cdecl SendTypingWorker(void*);
+ void __cdecl MessagingWorker(void*);
+ void __cdecl DeleteContactFromServer(void*);
+ void __cdecl AddContactToServer(void*);
+
+ // Contacts handling
+ bool IsMyContact(HANDLE, bool include_chat = false);
+ HANDLE ContactIDToHContact(std::string);
+ HANDLE AddToContactList(facebook_user*, bool dont_check = false, const char *new_name = "");
+ void SetAllContactStatuses(int);
+
+ // Chats handling
+ void AddChat(const char *id, const char *name);
+ void UpdateChat(const char *chat_id, const char *id, const char *name, const char *message);
+ bool IsChatContact(const char *chat_id, const char *id);
+ void AddChatContact(const char *chat_id, const char *id, const char *name);
+ void RemoveChatContact(const char *chat_id, const char *id);
+ void SetChatStatus(const char *chat_id, int status);
+ char *GetChatUsers(const char *chat_id);
+
+ // Connection client
+ facebook_client facy; // TODO: Refactor to "client" and make dynamic
+
+ // Helpers
+ std::string GetAvatarFolder();
+ bool GetDbAvatarInfo(PROTO_AVATAR_INFORMATION &ai, std::string *url);
+ void CheckAvatarChange(HANDLE hContact, std::string image_url);
+ void ToggleStatusMenuItems( BOOL bEnable );
+
+ // Handles, Locks
+ HGENMENU m_hMenuRoot;
+ HANDLE m_hStatusMind;
+
+ HANDLE signon_lock_;
+ HANDLE avatar_lock_;
+ HANDLE log_lock_;
+ HANDLE update_loop_lock_;
+ //HANDLE message_loop_lock_;
+
+ HANDLE m_hNetlibUser;
+
+ std::string last_status_msg_;
+ std::string def_avatar_folder_;
+ HANDLE hAvatarFolder_;
+ std::vector<HANDLE> avatar_queue;
+
+ static void CALLBACK APC_callback(ULONG_PTR p);
+
+ // Information providing
+ int Log(const char *fmt,...);
+ void NotifyEvent(TCHAR* title, TCHAR* info, HANDLE contact, DWORD flags, TCHAR* url=NULL);
+};
diff --git a/protocols/FacebookRM/resource.h b/protocols/FacebookRM/resource.h new file mode 100644 index 0000000000..14ff2d1e6b --- /dev/null +++ b/protocols/FacebookRM/resource.h @@ -0,0 +1,69 @@ +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by facebook.rc
+//
+#define IDI_FACEBOOK 101
+#define IDI_MIND 102
+#define IDI_ADDFRIEND 103
+#define IDI_REMOVEFRIEND 104
+#define IDD_FACEBOOKACCOUNT 111
+#define IDD_MIND 112
+#define IDD_OPTIONS 113
+#define IDD_OPTIONS_EVENTS 114
+#define IDD_OPTIONS_ADVANCED 115
+#define IDC_UN 1001
+#define IDC_PW 1002
+#define IDC_NEWACCOUNTLINK 1003
+#define IDC_MINDMSG 1012
+#define IDC_CHARACTERS 1013
+#define IDC_GROUP 1021
+#define IDC_SECURE 1024
+#define IDC_SET_IGNORE_STATUS 1025
+#define IDC_SECURE_CHANNEL 1026
+#define IDC_LOGGING 1027
+#define IDC_DISCONNECT_CHAT 1028
+#define IDC_PARSE_UNREAD 1029
+#define IDC_BIGGER_AVATARS 1030
+#define IDC_CLOSE_WINDOWS 1031
+#define IDC_MAP_STATUSES 1032
+#define IDC_LOAD_MOBILE 1033
+#define IDC_GROUPCHATS 1034
+#define IDC_NOTIFICATIONS_ENABLE 1041
+#define IDC_FEEDS_ENABLE 1042
+#define IDC_OTHER_ENABLE 1043
+#define IDC_CLIENT_ENABLE 1044
+#define IDC_COLBACK 1051
+#define IDC_COLTEXT 1052
+#define IDC_COLBACK2 1053
+#define IDC_COLTEXT2 1054
+#define IDC_COLBACK3 1055
+#define IDC_COLTEXT3 1056
+#define IDC_COLBACK4 1057
+#define IDC_COLTEXT4 1058
+#define IDC_NOTIFICATIONS_DEFAULT 1071
+#define IDC_FEEDS_DEFAULT 1072
+#define IDC_OTHER_DEFAULT 1073
+#define IDC_CLIENT_DEFAULT 1074
+#define IDC_TIMEOUT 1081
+#define IDC_TIMEOUT_SPIN 1082
+#define IDC_TIMEOUT2 1083
+#define IDC_TIMEOUT_SPIN2 1084
+#define IDC_TIMEOUT3 1085
+#define IDC_TIMEOUT_SPIN3 1086
+#define IDC_TIMEOUT4 1087
+#define IDC_TIMEOUT_SPIN4 1088
+#define IDC_SYSTRAY_NOTIFY 1098
+#define IDC_PREVIEW 1099
+#define IDC_SET_STATUS 1126
+#define IDC_FEED_TYPE 1201
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 121
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1202
+#define _APS_NEXT_SYMED_VALUE 131
+#endif
+#endif
diff --git a/protocols/FacebookRM/stubs.cpp b/protocols/FacebookRM/stubs.cpp new file mode 100644 index 0000000000..4cf01cd4c8 --- /dev/null +++ b/protocols/FacebookRM/stubs.cpp @@ -0,0 +1,155 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+HANDLE FacebookProto::AddToList(int flags, PROTOSEARCHRESULT* psr)
+{
+ return 0;
+};
+
+HANDLE FacebookProto::AddToListByEvent(int flags,int iContact,HANDLE hDbEvent)
+{
+ return 0;
+};
+
+int FacebookProto::Authorize(HANDLE hContact)
+{
+ return 0;
+}
+
+int FacebookProto::AuthDeny(HANDLE hContact,const PROTOCHAR *reason)
+{
+ return 0;
+}
+
+int FacebookProto::AuthRecv(HANDLE hContact,PROTORECVEVENT *)
+{
+ return 0;
+}
+
+int FacebookProto::AuthRequest(HANDLE hContact,const PROTOCHAR *message)
+{
+ return 0;
+}
+
+HANDLE FacebookProto::ChangeInfo(int type,void *info_data)
+{
+ MessageBoxA(0,"ChangeInfo","",0);
+ return 0;
+}
+
+HANDLE FacebookProto::FileAllow(HANDLE hContact,HANDLE hTransfer,const PROTOCHAR *path)
+{
+ return 0;
+}
+
+int FacebookProto::FileCancel(HANDLE hContact,HANDLE hTransfer)
+{
+ return 0;
+}
+
+int FacebookProto::FileDeny(HANDLE hContact,HANDLE hTransfer,const PROTOCHAR *reason)
+{
+ return 0;
+}
+
+int FacebookProto::FileResume(HANDLE hTransfer,int *action,const PROTOCHAR **filename)
+{
+ return 0;
+}
+
+int FacebookProto::GetInfo( HANDLE hContact, int infoType )
+{
+ // TODO: Most probably some ProtoAck should be here instead
+ return 1;
+}
+
+HANDLE FacebookProto::SearchBasic( const PROTOCHAR* id )
+{
+ return 0;
+}
+
+HANDLE FacebookProto::SearchByEmail( const PROTOCHAR* email )
+{
+ return 0;
+}
+
+HANDLE FacebookProto::SearchByName( const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName )
+{
+ return 0;
+}
+
+HWND FacebookProto::SearchAdvanced(HWND owner)
+{
+ return 0;
+}
+
+HWND FacebookProto::CreateExtendedSearchUI(HWND owner)
+{
+ return 0;
+}
+
+int FacebookProto::RecvContacts(HANDLE hContact,PROTORECVEVENT *)
+{
+ return 0;
+}
+
+int FacebookProto::RecvFile(HANDLE hContact,PROTORECVFILET *)
+{
+ return 0;
+}
+
+int FacebookProto::RecvUrl(HANDLE hContact,PROTORECVEVENT *)
+{
+ return 0;
+}
+
+int FacebookProto::SendContacts(HANDLE hContact,int flags,int nContacts,HANDLE *hContactsList)
+{
+ return 0;
+}
+
+HANDLE FacebookProto::SendFile(HANDLE hContact,const PROTOCHAR *desc, PROTOCHAR **files)
+{
+ return 0;
+}
+
+int FacebookProto::SendUrl(HANDLE hContact,int flags,const char *url)
+{
+ return 0;
+}
+
+int FacebookProto::SetApparentMode(HANDLE hContact,int mode)
+{
+ return 0;
+}
+
+int FacebookProto::RecvAwayMsg(HANDLE hContact,int mode,PROTORECVEVENT *evt)
+{
+ return 0;
+}
+
+int FacebookProto::SendAwayMsg(HANDLE hContact,HANDLE hProcess,const char *msg)
+{
+ return 0;
+}
diff --git a/protocols/FacebookRM/theme.cpp b/protocols/FacebookRM/theme.cpp new file mode 100644 index 0000000000..7bc62a2317 --- /dev/null +++ b/protocols/FacebookRM/theme.cpp @@ -0,0 +1,196 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+extern OBJLIST<FacebookProto> g_Instances;
+
+struct
+{
+ const char* name;
+ char* descr;
+ int defIconID;
+ const char* section;
+}
+static const icons[] =
+{
+ { "facebook", LPGEN("Facebook Icon"), IDI_FACEBOOK },
+ { "mind", LPGEN("Mind"), IDI_MIND },
+ { "removeFriend", LPGEN("Remove from server"), IDI_REMOVEFRIEND },
+ { "addFriend", LPGEN("Request friendship"), IDI_ADDFRIEND },
+
+ { "homepage", LPGEN("Visit Profile"), 0, "core_main_2" },
+};
+
+static HANDLE hIconLibItem[SIZEOF(icons)];
+
+// TODO: uninit
+void InitIcons(void)
+{
+ TCHAR szFile[MAX_PATH];
+ GetModuleFileName(g_hInstance, szFile, SIZEOF(szFile));
+
+ char setting_name[100];
+ char section_name[100];
+
+ SKINICONDESC sid = {0};
+ sid.cbSize = sizeof(SKINICONDESC);
+ sid.ptszDefaultFile = szFile;
+ sid.cx = sid.cy = 16;
+ sid.pszName = setting_name;
+ sid.pszSection = section_name;
+ sid.flags = SIDF_PATH_TCHAR;
+
+ for (int i=0; i<SIZEOF(icons); i++)
+ {
+ if(icons[i].defIconID)
+ {
+ mir_snprintf(setting_name,sizeof(setting_name),"%s_%s","Facebook",icons[i].name);
+
+ if (icons[i].section)
+ {
+ mir_snprintf(section_name,sizeof(section_name),"%s/%s/%s",LPGEN("Protocols"),
+ LPGEN("Facebook"), icons[i].section);
+ } else {
+ mir_snprintf(section_name,sizeof(section_name),"%s/%s",LPGEN("Protocols"),
+ LPGEN("Facebook"));
+ }
+
+ sid.pszDescription = (char*)icons[i].descr;
+ sid.iDefaultIndex = -icons[i].defIconID;
+ hIconLibItem[i] = (HANDLE)CallService(MS_SKIN2_ADDICON,0,(LPARAM)&sid);
+ } else { // External icons
+ hIconLibItem[i] = (HANDLE)CallService(MS_SKIN2_GETICONHANDLE,0,
+ (LPARAM)icons[i].section);
+ }
+ }
+}
+
+HANDLE GetIconHandle(const char* name)
+{
+ for(size_t i=0; i<SIZEOF(icons); i++)
+ {
+ if(strcmp(icons[i].name,name) == 0)
+ return hIconLibItem[i];
+ }
+ return 0;
+}
+
+char *GetIconDescription(const char* name)
+{
+ for(size_t i=0; i<SIZEOF(icons); i++)
+ {
+ if(strcmp(icons[i].name,name) == 0)
+ return icons[i].descr;
+ }
+ return "";
+}
+
+// Contact List menu stuff
+HANDLE g_hMenuItems[4];
+
+// Helper functions
+static FacebookProto * GetInstanceByHContact(HANDLE hContact)
+{
+ char *proto = reinterpret_cast<char*>( CallService(MS_PROTO_GETCONTACTBASEPROTO,
+ reinterpret_cast<WPARAM>(hContact),0) );
+ if(!proto)
+ return 0;
+
+ for(int i=0; i<g_Instances.getCount(); i++)
+ if(!strcmp(proto,g_Instances[i].m_szModuleName))
+ return &g_Instances[i];
+
+ return 0;
+}
+
+template<int (__cdecl FacebookProto::*Fcn)(WPARAM,LPARAM)>
+INT_PTR GlobalService(WPARAM wParam,LPARAM lParam)
+{
+ FacebookProto *proto = GetInstanceByHContact(reinterpret_cast<HANDLE>(wParam));
+ return proto ? (proto->*Fcn)(wParam,lParam) : 0;
+}
+
+static int PrebuildContactMenu(WPARAM wParam,LPARAM lParam)
+{
+ ShowContactMenus(false);
+
+ FacebookProto *proto = GetInstanceByHContact(reinterpret_cast<HANDLE>(wParam));
+ return proto ? proto->OnPrebuildContactMenu(wParam,lParam) : 0;
+}
+
+HANDLE hHookPreBuildMenu,sVisitProfile,sAddFriend,sRemoveFriend;
+void InitContactMenus()
+{
+ hHookPreBuildMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU,PrebuildContactMenu);
+
+ CLISTMENUITEM mi = {sizeof(mi)};
+ mi.flags = CMIF_ICONFROMICOLIB;
+
+ mi.position=-2000006000;
+ mi.icolibItem = GetIconHandle("homepage");
+ mi.pszName = GetIconDescription("homepage");
+ mi.pszService = "FacebookProto/VisitProfile";
+ sVisitProfile = CreateServiceFunction(mi.pszService,GlobalService<&FacebookProto::VisitProfile>);
+ g_hMenuItems[1] = reinterpret_cast<HANDLE>(
+ CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi) );
+
+ mi.position=-2000006000;
+ mi.icolibItem = GetIconHandle("removeFriend");
+ mi.pszName = GetIconDescription("removeFriend");
+ mi.pszService = "FacebookProto/RemoveFriend";
+ sRemoveFriend = CreateServiceFunction(mi.pszService,GlobalService<&FacebookProto::RemoveFriend>);
+ g_hMenuItems[2] = reinterpret_cast<HANDLE>(
+ CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi) );
+
+ mi.position=-2000006000;
+ mi.icolibItem = GetIconHandle("addFriend");
+ mi.pszName = GetIconDescription("addFriend");
+ mi.pszService = "FacebookProto/AddFriend";
+ sAddFriend = CreateServiceFunction(mi.pszService,GlobalService<&FacebookProto::AddFriend>);
+ g_hMenuItems[3] = reinterpret_cast<HANDLE>(
+ CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi) );
+}
+
+void UninitContactMenus()
+{
+ for(size_t i=0; i<SIZEOF(g_hMenuItems); i++)
+ CallService(MS_CLIST_REMOVECONTACTMENUITEM,(WPARAM)g_hMenuItems[i],0);
+ UnhookEvent(hHookPreBuildMenu);
+ DestroyServiceFunction(sVisitProfile);
+ DestroyServiceFunction(sRemoveFriend);
+ DestroyServiceFunction(sAddFriend);
+}
+
+void ShowContactMenus(bool show, bool deleted)
+{
+ for(size_t i=0; i<SIZEOF(g_hMenuItems); i++)
+ {
+ CLISTMENUITEM item = { sizeof(item) };
+ item.flags = CMIM_FLAGS;
+ if(!show || (i == 3 && !deleted) || (i == 2 && deleted)) // 2 = REMOVE CONTACT; 3 = ADD CONTACT
+ item.flags |= CMIF_HIDDEN;
+
+ CallService(MS_CLIST_MODIFYMENUITEM,reinterpret_cast<WPARAM>(g_hMenuItems[i]),
+ reinterpret_cast<LPARAM>(&item));
+ }
+}
diff --git a/protocols/FacebookRM/theme.h b/protocols/FacebookRM/theme.h new file mode 100644 index 0000000000..4330c35dce --- /dev/null +++ b/protocols/FacebookRM/theme.h @@ -0,0 +1,30 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+void InitIcons(void);
+HANDLE GetIconHandle(const char *name);
+
+void InitContactMenus(void);
+void UninitContactMenus(void);
+void ShowContactMenus(bool show, bool deleted = false);
diff --git a/protocols/FacebookRM/utils.cpp b/protocols/FacebookRM/utils.cpp new file mode 100644 index 0000000000..5440757450 --- /dev/null +++ b/protocols/FacebookRM/utils.cpp @@ -0,0 +1,417 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+
+std::string utils::url::encode(const std::string &s)
+{
+ char *encoded = reinterpret_cast<char*>(CallService( MS_NETLIB_URLENCODE,
+ 0,reinterpret_cast<LPARAM>(s.c_str()) ));
+ std::string ret = encoded;
+ HeapFree(GetProcessHeap(),0,encoded);
+
+ return ret;
+}
+
+std::string utils::url::decode(std::string data)
+{
+ // TODO: Better and universal method?
+ utils::text::replace_all( &data, "%2F", "/" );
+ utils::text::replace_all( &data, "%3F", "?" );
+ utils::text::replace_all( &data, "%3D", "=" );
+ utils::text::replace_all( &data, "%26", "&" );
+
+ return data;
+}
+
+std::string utils::time::unix_timestamp( )
+{
+ time_t in = ::time( NULL );
+ return utils::conversion::to_string( ( void* )&in, UTILS_CONV_TIME_T );
+}
+
+std::string utils::time::mili_timestamp( )
+{
+ SYSTEMTIME st;
+ std::string timestamp = utils::time::unix_timestamp();
+ GetSystemTime(&st);
+ timestamp.append(utils::conversion::to_string( ( void* )&st.wMilliseconds, UTILS_CONV_UNSIGNED_NUMBER ));
+ return timestamp;
+}
+
+std::string utils::conversion::to_string( void* data, WORD type )
+{
+ std::stringstream out;
+
+ switch ( type )
+ {
+ case UTILS_CONV_BOOLEAN:
+ out << (data ? "true" : "false");
+
+ case UTILS_CONV_TIME_T:
+ out << (*( time_t* )data);
+ break;
+
+ case UTILS_CONV_SIGNED_NUMBER:
+ out << (*( signed int* )data);
+ break;
+
+ case UTILS_CONV_UNSIGNED_NUMBER:
+ out << (*( unsigned int* )data);
+ break;
+ }
+
+ return out.str( );
+}
+
+void utils::text::replace_first( std::string* data, std::string from, std::string to )
+{
+ std::string::size_type position = data->find(from);
+ if ( position != std::string::npos )
+ {
+ data->replace( position, from.size(), to );
+ }
+}
+
+void utils::text::replace_all( std::string* data, std::string from, std::string to )
+{
+ std::string::size_type position = 0;
+
+ while ( ( position = data->find( from, position ) ) != std::string::npos )
+ {
+ data->replace( position, from.size(), to );
+ position++;
+ }
+}
+
+unsigned int utils::text::count_all( std::string* data, std::string term )
+{
+ unsigned int count = 0;
+ std::string::size_type position = 0;
+
+ while ( ( position = data->find( term, position ) ) != std::string::npos )
+ {
+ count++;
+ position++;
+ }
+
+ return count;
+}
+
+std::string utils::text::special_expressions_decode( std::string data )
+{
+ utils::text::replace_all( &data, "&", "&" );
+ utils::text::replace_all( &data, """, "\"" );
+ utils::text::replace_all( &data, "'", "'" );
+ utils::text::replace_all( &data, "@", "@" );
+ utils::text::replace_all( &data, "<", "<" );
+ utils::text::replace_all( &data, ">", ">" );
+
+ utils::text::replace_all( &data, "♥", "\xE2\x99\xA5" ); // direct byte replacement
+// utils::text::replace_all( &data, "♥", "\\u2665" ); // indirect slashu replacement
+
+ utils::text::replace_all( &data, "\\/", "/" );
+ utils::text::replace_all( &data, "\\\\", "\\" );
+
+ // TODO: Add more to comply general usage
+ // http://www.utexas.edu/learn/html/spchar.html
+ // http://www.webmonkey.com/reference/Special_Characters
+ // http://www.degraeve.com/reference/specialcharacters.php
+ // http://www.chami.com/tips/internet/050798i.html
+ // http://www.w3schools.com/tags/ref_entities.asp
+ // http://www.natural-innovations.com/wa/doc-charset.html
+ // http://webdesign.about.com/library/bl_htmlcodes.htm
+
+ return data;
+}
+
+std::string utils::text::edit_html( std::string data )
+{
+ std::string::size_type end = 0;
+ std::string::size_type start = 0;
+ std::string new_string = "";
+
+ while ( end != std::string::npos )
+ {
+ end = data.find( "<span class=\\\"text_exposed_hide", start );
+ if ( end != std::string::npos )
+ {
+ new_string += data.substr( start, end - start );
+ start = data.find( "<\\/span", end );
+ } else {
+ new_string += data.substr( start, data.length() - start );
+ }
+ }
+
+ start = end = 0;
+ data = new_string;
+ new_string = "";
+
+ while ( end != std::string::npos )
+ {
+ end = data.find( "<span class=\\\"uiTooltipText", start );
+ if ( end != std::string::npos )
+ {
+ new_string += data.substr( start, end - start );
+ start = data.find( "<\\/span", end );
+ } else {
+ new_string += data.substr( start, data.length() - start );
+ }
+ }
+
+ // Remove "Translate" link
+ start = end = 0;
+ data = new_string;
+ new_string = "";
+ while ( end != std::string::npos )
+ {
+ end = data.find( "translate_story_link\\\">", start );
+ if ( end != std::string::npos )
+ {
+ new_string += data.substr( start, end - start );
+ start = data.find( "<\\/div", end );
+ } else {
+ new_string += data.substr( start, data.length() - start );
+ }
+ }
+
+ // Append newline after attachement title
+ start = new_string.find( "class=\\\"uiAttachmentTitle", 0 );
+ if ( start != std::string::npos )
+ {
+ data = new_string.substr( 0, start );
+ data = utils::text::trim( data );
+
+ start = new_string.find( ">", start );
+ if ( start != std::string::npos )
+ new_string.insert(start+1, "\n\n");
+
+ start = new_string.find( "<\\/div>", start );
+ if ( start != std::string::npos )
+ new_string.insert(start, "\n");
+ }
+
+ // Append newline between attachement link and description
+ start = new_string.find( "uiAttachmentDesc", 0 );
+ if ( start != std::string::npos )
+ {
+ start = new_string.find( ">", start );
+ if ( start != std::string::npos )
+ new_string.insert(start+1, "\n");
+
+ start = new_string.find( "<\\/div>", start );
+ if ( start != std::string::npos )
+ new_string.insert(start, "\n");
+ }
+
+ utils::text::replace_all( &new_string, "<br \\/>", "\n" );
+ utils::text::replace_all( &new_string, "\n\n\n", "\n\n" );
+ //utils::text::replace_all( &new_string, "\\t", "" );
+ //utils::text::replace_all( &new_string, "\\n", "" );
+ return new_string;
+}
+
+
+std::string utils::text::remove_html( std::string data )
+{
+ std::string new_string = "";
+
+ for ( std::string::size_type i = 0; i < data.length( ); i++ )
+ {
+ if ( data.at(i) == '<' && data.at(i+1) != ' ' )
+ {
+ i = data.find( ">", i );
+ if (i == std::string::npos)
+ break;
+
+ continue;
+ }
+
+ new_string += data.at(i);
+ }
+
+ return new_string;
+}
+
+std::string utils::text::slashu_to_utf8( std::string data )
+{
+ std::string new_string = "";
+
+ for ( std::string::size_type i = 0; i < data.length( ); i++ )
+ {
+ if ( data.at(i) == '\\' && (i+1) < data.length( ) && data.at(i+1) == 'u' )
+ {
+ unsigned int udn = strtol( data.substr( i + 2, 4 ).c_str(), NULL, 16 );
+
+ if ( udn >= 128 && udn <= 2047 )
+ { // U+0080 .. U+07FF
+ new_string += ( char )( 192 + ( udn / 64 ) );
+ new_string += ( char )( 128 + ( udn % 64 ) );
+ }
+ else if ( udn >= 2048 && udn <= 65535 )
+ { // U+0800 .. U+FFFF
+ new_string += ( char )( 224 + ( udn / 4096 ) );
+ new_string += ( char )( 128 + ( ( udn / 64 ) % 64 ) );
+ new_string += ( char )( 128 + ( udn % 64 ) );
+ }
+ else if ( udn <= 127 )
+ { // U+0000 .. U+007F (should not appear)
+ new_string += ( char )udn;
+ }
+
+ i += 5;
+ continue;
+ }
+
+ new_string += data.at(i);
+ }
+
+ return new_string;
+}
+
+std::string utils::text::trim( std::string data )
+{
+ std::string spaces = " \t\r\n"; // TODO: include "nbsp"?
+ std::string::size_type begin = data.find_first_not_of( spaces );
+ std::string::size_type end = data.find_last_not_of( spaces ) + 1;
+
+ return (begin != std::string::npos) ? data.substr( begin, end - begin ) : "";
+}
+
+void utils::text::explode(std::string str, std::string separator, std::vector<std::string>* results)
+{
+ std::string::size_type pos;
+ pos = str.find_first_of(separator);
+ while (pos != std::string::npos) {
+ if (pos > 0) {
+ results->push_back(str.substr(0,pos));
+ }
+ str = str.substr(pos+1);
+ pos = str.find_first_of(separator);
+ }
+ if (str.length() > 0) {
+ results->push_back(str);
+ }
+}
+
+std::string utils::text::source_get_value( std::string* data, unsigned int argument_count, ... )
+{
+ va_list arg;
+ std::string ret;
+ std::string::size_type start = 0, end = 0;
+
+ va_start( arg, argument_count );
+
+ for ( unsigned int i = argument_count; i > 0; i-- )
+ {
+ if ( i == 1 )
+ {
+ end = data->find( va_arg( arg, char* ), start );
+ if ( start == std::string::npos || end == std::string::npos )
+ break;
+ ret = data->substr( start, end - start );
+ } else {
+ std::string term = va_arg( arg, char* );
+ start = data->find( term, start );
+ if ( start == std::string::npos )
+ break;
+ start += term.length();
+ }
+ }
+
+ va_end( arg );
+ return ret;
+}
+
+std::string utils::text::source_get_value2( std::string* data, const char *term, const char *endings)
+{
+ std::string::size_type start = 0, end = 0;
+ std::string ret;
+
+ start = data->find(term);
+ if (start != std::string::npos) {
+ start += strlen(term);
+
+ end = data->find_first_of(endings, start);
+ if (end != std::string::npos) {
+ ret = data->substr( start, end - start );
+ }
+ }
+
+ return ret;
+}
+
+int utils::number::random( )
+{
+ srand( ::time( NULL ) );
+ return rand( );
+}
+
+int utils::debug::log(std::string file_name, std::string text)
+{
+ char szFile[MAX_PATH];
+ GetModuleFileNameA(g_hInstance, szFile, SIZEOF(szFile));
+ std::string path = szFile;
+ path = path.substr( 0, path.rfind( "\\" ) );
+ path = path.substr( 0, path.rfind( "\\" ) + 1 );
+ path = path + file_name.c_str() + ".txt";
+
+ SYSTEMTIME time;
+ GetLocalTime( &time );
+
+ std::ofstream out( path.c_str(), std::ios_base::out | std::ios_base::app | std::ios_base::ate );
+ out << "[" << (time.wHour < 10 ? "0" : "") << time.wHour << ":" << (time.wMinute < 10 ? "0" : "") << time.wMinute << ":" << (time.wSecond < 10 ? "0" : "") << time.wSecond << "] " << text << std::endl;
+ out.close( );
+
+ return EXIT_SUCCESS;
+}
+
+void __fastcall utils::mem::detract(char** str )
+{
+ utils::mem::detract( ( void** )str );
+}
+
+void __fastcall utils::mem::detract(void** p)
+{
+ utils::mem::detract((void*)(*p));
+}
+
+void __fastcall utils::mem::detract(void* p)
+{
+ mir_free(p);
+}
+
+void* __fastcall utils::mem::allocate(size_t size)
+{
+ return mir_calloc(size);
+}
+
+int ext_to_format(const std::string &ext)
+{
+ for(size_t i=0; i<SIZEOF(formats); i++)
+ {
+ if(ext == formats[i].ext)
+ return formats[i].fmt;
+ }
+
+ return PA_FORMAT_UNKNOWN;
+}
diff --git a/protocols/FacebookRM/utils.h b/protocols/FacebookRM/utils.h new file mode 100644 index 0000000000..868aeb84bc --- /dev/null +++ b/protocols/FacebookRM/utils.h @@ -0,0 +1,160 @@ +/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2009-11 Michal Zelinka, 2011-12 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#pragma once
+
+// C++ bool type
+#define UTILS_CONV_BOOLEAN 0x0001 // true | false
+// signed regular numbers
+#define UTILS_CONV_SIGNED_NUMBER 0x0010 // 1234 | -1234
+// unsigned regular numbers
+#define UTILS_CONV_UNSIGNED_NUMBER 0x0020 // 1234
+// miscellaneous
+#define UTILS_CONV_TIME_T 0x0040 // 1234567890
+
+template<typename T>
+void CreateProtoService(const char *module,const char *service,
+ int (__cdecl T::*serviceProc)(WPARAM,LPARAM),T *self)
+{
+ char temp[MAX_PATH*2];
+
+ mir_snprintf(temp,sizeof(temp),"%s%s",module,service);
+ CreateServiceFunctionObj(temp,( MIRANDASERVICEOBJ )*(void**)&serviceProc, self );
+}
+
+template<typename T>
+void HookProtoEvent(const char* evt, int (__cdecl T::*eventProc)(WPARAM,LPARAM), T *self)
+{
+ ::HookEventObj(evt,(MIRANDAHOOKOBJ)*(void**)&eventProc,self);
+}
+
+template<typename T>
+HANDLE ForkThreadEx(void (__cdecl T::*thread)(void*),T *self,void *data = 0)
+{
+ return reinterpret_cast<HANDLE>( mir_forkthreadowner(
+ (pThreadFuncOwner)*(void**)&thread,self,data,0));
+}
+
+template<typename T>
+void ForkThread(void (__cdecl T::*thread)(void*),T *self,void *data = 0)
+{
+ CloseHandle(ForkThreadEx(thread,self,data));
+}
+
+namespace utils
+{
+ namespace url
+ {
+ std::string encode(const std::string &s);
+ std::string decode(std::string data);
+ };
+
+ namespace time
+ {
+ std::string unix_timestamp( );
+ std::string mili_timestamp( );
+ };
+
+ namespace number
+ {
+ int random( );
+ };
+
+ namespace text
+ {
+ void replace_first( std::string* data, std::string from, std::string to );
+ void replace_all( std::string* data, std::string from, std::string to );
+ unsigned int count_all( std::string* data, std::string term );
+ std::string special_expressions_decode( std::string data );
+ std::string edit_html( std::string data );
+ std::string remove_html( std::string data );
+ std::string slashu_to_utf8( std::string data );
+ std::string trim( std::string data );
+ std::string source_get_value( std::string* data, unsigned int argument_count, ... );
+ std::string source_get_value2( std::string* data, const char *term, const char *endings);
+ void explode(std::string str, std::string separator, std::vector<std::string>* results);
+ };
+
+ namespace conversion
+ {
+ std::string to_string( void*, WORD type );
+
+ template <class T>
+ bool from_string(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&)) {
+ std::istringstream iss(s);
+ return !(iss >> f >> t).fail();
+ }
+ };
+
+ namespace debug
+ {
+ int log(std::string file_name, std::string text);
+ };
+
+ namespace mem
+ {
+ void __fastcall detract(char** str );
+ void __fastcall detract(void** p);
+ void __fastcall detract(void* p);
+ void* __fastcall allocate(size_t size);
+ };
+};
+
+class ScopedLock
+{
+public:
+ ScopedLock(HANDLE h, int t = INFINITE) : handle_(h), timeout_(t)
+ {
+ WaitForSingleObject(handle_,timeout_);
+ }
+ ~ScopedLock()
+ {
+ if(handle_)
+ ReleaseMutex(handle_);
+ }
+ void Unlock()
+ {
+ ReleaseMutex(handle_);
+ handle_ = 0;
+ }
+private:
+ HANDLE handle_;
+ int timeout_;
+};
+
+static const struct
+{
+ char *ext;
+ int fmt;
+} formats[] = {
+ { ".png", PA_FORMAT_PNG },
+ { ".jpg", PA_FORMAT_JPEG },
+ { ".jpeg", PA_FORMAT_JPEG },
+ { ".ico", PA_FORMAT_ICON },
+ { ".bmp", PA_FORMAT_BMP },
+ { ".gif", PA_FORMAT_GIF },
+};
+
+int ext_to_format(const std::string &ext);
+
+void MB( const char* m );
+void MBI( int a );
|