diff --git a/AUTHORS b/AUTHORS index 039f330dc4..888814e7de 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,6 +24,7 @@ Developers: carlomorgantinizynga CCLabelTTF supports for shadow and stroke + Adding CCLabelTTF::createWithFontDefinition. James Gregory (j4m3z0r, Zynga) Maintainer of Emscripten port. @@ -183,6 +184,7 @@ Developers: Simpler, correct handling of spritesheet sources for CCScale9Sprite. Clean up linked libraries for android. JavaScript debugger improved and bugfixed. + Fix flags for debugger server socket. Nicolas Gramlich (nicolasgramlich, Zynga) fixed CCDirector to use CCLabelBMFont instead of CCLabelTTF diff --git a/CHANGELOG b/CHANGELOG index 4002d73d77..9584fc46ef 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +cocos2d-x-3.0alpha0-pre @Jul.24 2013 +[all platforms] + Feature #XXXX: Add support for std::function<> in CCMemuItem and CCCallFunc + + cocos2d-2.1rc0-x-2.1.3 @May.01 2013 [all platforms] Bug #1853: use SHELLOPTS instead of "-o igncr" for Android Eclipse project diff --git a/CocosDenshion/android/opensl/OpenSLEngine.cpp b/CocosDenshion/android/opensl/OpenSLEngine.cpp index 101bf59790..28d83fe448 100644 --- a/CocosDenshion/android/opensl/OpenSLEngine.cpp +++ b/CocosDenshion/android/opensl/OpenSLEngine.cpp @@ -289,7 +289,8 @@ bool initAudioPlayer(AudioPlayer* player, const char* filename) if(fp){ SLDataLocator_URI loc_fd = {SL_DATALOCATOR_URI , (SLchar*)filename}; SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; - (player->audioSrc) = {&loc_fd, &format_mime}; + player->audioSrc.pLocator = &loc_fd; + player->audioSrc.pFormat = &format_mime; return createAudioPlayerBySource(player); } LOGD("file not found! Stop preload file: %s", filename); diff --git a/CocosDenshion/proj.tizen/.cproject b/CocosDenshion/proj.tizen/.cproject index 255f35d585..fde412fa0d 100644 --- a/CocosDenshion/proj.tizen/.cproject +++ b/CocosDenshion/proj.tizen/.cproject @@ -24,12 +24,12 @@ - + @@ -57,14 +56,15 @@ + - + @@ -89,12 +88,11 @@ - + diff --git a/cocos2dx/actions/CCActionInstant.h b/cocos2dx/actions/CCActionInstant.h index 4bc1822687..be9918f8a8 100644 --- a/cocos2dx/actions/CCActionInstant.h +++ b/cocos2dx/actions/CCActionInstant.h @@ -30,6 +30,7 @@ THE SOFTWARE. #include #include +#include "CCStdC.h" #include "ccTypeInfo.h" #include "CCAction.h" @@ -213,7 +214,7 @@ public: : m_pSelectorTarget(NULL) , m_nScriptHandler(0) , m_pCallFunc(NULL) - , _function(NULL) + , _function(nullptr) { } virtual ~CCCallFunc(); diff --git a/cocos2dx/cocoa/CCData.h b/cocos2dx/cocoa/CCData.h index 6fa2657ce7..1279b9839a 100644 --- a/cocos2dx/cocoa/CCData.h +++ b/cocos2dx/cocoa/CCData.h @@ -7,7 +7,7 @@ NS_CC_BEGIN -class CCData : public CCObject +class CC_DLL CCData : public CCObject { public: CCData(unsigned char *pBytes, const unsigned long nSize); diff --git a/cocos2dx/cocos2d.cpp b/cocos2dx/cocos2d.cpp index 2a8e582497..d109164fe1 100644 --- a/cocos2dx/cocos2d.cpp +++ b/cocos2dx/cocos2d.cpp @@ -30,7 +30,7 @@ NS_CC_BEGIN const char* cocos2dVersion() { - return "2.1rc0-x-2.1.3"; + return "3.0-alpha0-pre"; } NS_CC_END diff --git a/cocos2dx/label_nodes/CCLabelTTF.cpp b/cocos2dx/label_nodes/CCLabelTTF.cpp index dd375118b1..436094bef6 100644 --- a/cocos2dx/label_nodes/CCLabelTTF.cpp +++ b/cocos2dx/label_nodes/CCLabelTTF.cpp @@ -96,6 +96,18 @@ CCLabelTTF* CCLabelTTF::create(const char *string, const char *fontName, float f return NULL; } +CCLabelTTF * CCLabelTTF::createWithFontDefinition(const char *string, ccFontDefinition &textDefinition) +{ + CCLabelTTF *pRet = new CCLabelTTF(); + if(pRet && pRet->initWithStringAndTextDefinition(string, textDefinition)) + { + pRet->autorelease(); + return pRet; + } + CC_SAFE_DELETE(pRet); + return NULL; +} + bool CCLabelTTF::init() { return this->initWithString("", "Helvetica", 12); diff --git a/cocos2dx/label_nodes/CCLabelTTF.h b/cocos2dx/label_nodes/CCLabelTTF.h index a5f950d5c3..487a89b0c2 100644 --- a/cocos2dx/label_nodes/CCLabelTTF.h +++ b/cocos2dx/label_nodes/CCLabelTTF.h @@ -70,6 +70,10 @@ public: const CCSize& dimensions, CCTextAlignment hAlignment, CCVerticalTextAlignment vAlignment); + + /** Create a lable with string and a font definition*/ + static CCLabelTTF * createWithFontDefinition(const char *string, ccFontDefinition &textDefinition); + /** initializes the CCLabelTTF with a font name and font size */ bool initWithString(const char *string, const char *fontName, float fontSize); diff --git a/cocos2dx/menu_nodes/CCMenuItem.cpp b/cocos2dx/menu_nodes/CCMenuItem.cpp index c828c62a8a..03512418bf 100644 --- a/cocos2dx/menu_nodes/CCMenuItem.cpp +++ b/cocos2dx/menu_nodes/CCMenuItem.cpp @@ -52,7 +52,7 @@ const unsigned int kDisableTag = 0x3; CCMenuItem* CCMenuItem::create() { - return CCMenuItem::create((const ccMenuCallback&)NULL); + return CCMenuItem::create((const ccMenuCallback&)nullptr); } // XXX deprecated @@ -161,6 +161,7 @@ bool CCMenuItem::isSelected() return m_bSelected; } +// XXX deprecated void CCMenuItem::setTarget(CCObject *target, SEL_MenuHandler selector) { _target = target; @@ -227,7 +228,7 @@ CCMenuItemLabel * CCMenuItemLabel::create(CCNode*label, const ccMenuCallback& ca CCMenuItemLabel* CCMenuItemLabel::create(CCNode *label) { CCMenuItemLabel *pRet = new CCMenuItemLabel(); - pRet->initWithLabel(label, (const ccMenuCallback&) NULL); + pRet->initWithLabel(label, (const ccMenuCallback&) nullptr); pRet->autorelease(); return pRet; } @@ -334,7 +335,7 @@ void CCMenuItemLabel::setEnabled(bool enabled) CCMenuItemAtlasFont * CCMenuItemAtlasFont::create(const char *value, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap) { - return CCMenuItemAtlasFont::create(value, charMapFile, itemWidth, itemHeight, startCharMap, (const ccMenuCallback&)NULL); + return CCMenuItemAtlasFont::create(value, charMapFile, itemWidth, itemHeight, startCharMap, (const ccMenuCallback&)nullptr); } // XXX: deprecated @@ -427,11 +428,12 @@ CCMenuItemFont * CCMenuItemFont::create(const char *value, const ccMenuCallback& CCMenuItemFont * CCMenuItemFont::create(const char *value) { CCMenuItemFont *pRet = new CCMenuItemFont(); - pRet->initWithString(value, (const ccMenuCallback&)NULL); + pRet->initWithString(value, (const ccMenuCallback&)nullptr); pRet->autorelease(); return pRet; } +// XXX: deprecated bool CCMenuItemFont::initWithString(const char *value, CCObject* target, SEL_MenuHandler selector) { CCAssert( value != NULL && strlen(value) != 0, "Value length must be greater than 0"); @@ -571,7 +573,7 @@ void CCMenuItemSprite::setDisabledImage(CCNode* pImage) CCMenuItemSprite * CCMenuItemSprite::create(CCNode* normalSprite, CCNode* selectedSprite, CCNode* disabledSprite) { - return CCMenuItemSprite::create(normalSprite, selectedSprite, disabledSprite, (const ccMenuCallback&)NULL); + return CCMenuItemSprite::create(normalSprite, selectedSprite, disabledSprite, (const ccMenuCallback&)nullptr); } // XXX deprecated @@ -726,12 +728,12 @@ CCMenuItemImage* CCMenuItemImage::create() bool CCMenuItemImage::init(void) { - return initWithNormalImage(NULL, NULL, NULL, (const ccMenuCallback&)NULL); + return initWithNormalImage(NULL, NULL, NULL, (const ccMenuCallback&)nullptr); } CCMenuItemImage * CCMenuItemImage::create(const char *normalImage, const char *selectedImage) { - return CCMenuItemImage::create(normalImage, selectedImage, NULL, (const ccMenuCallback&)NULL); + return CCMenuItemImage::create(normalImage, selectedImage, NULL, (const ccMenuCallback&)nullptr); } // XXX deprecated @@ -773,7 +775,7 @@ CCMenuItemImage * CCMenuItemImage::create(const char *normalImage, const char *s CCMenuItemImage * CCMenuItemImage::create(const char *normalImage, const char *selectedImage, const char *disabledImage) { CCMenuItemImage *pRet = new CCMenuItemImage(); - if (pRet && pRet->initWithNormalImage(normalImage, selectedImage, disabledImage, (const ccMenuCallback&)NULL)) + if (pRet && pRet->initWithNormalImage(normalImage, selectedImage, disabledImage, (const ccMenuCallback&)nullptr)) { pRet->autorelease(); return pRet; @@ -846,6 +848,7 @@ CCArray* CCMenuItemToggle::getSubItems() return m_pSubItems; } +// XXX: deprecated CCMenuItemToggle * CCMenuItemToggle::createWithTarget(CCObject* target, SEL_MenuHandler selector, CCArray* menuItems) { CCMenuItemToggle *pRet = new CCMenuItemToggle(); @@ -864,6 +867,25 @@ CCMenuItemToggle * CCMenuItemToggle::createWithTarget(CCObject* target, SEL_Menu return pRet; } +CCMenuItemToggle * CCMenuItemToggle::createWithCallback(const ccMenuCallback &callback, CCArray* menuItems) +{ + CCMenuItemToggle *pRet = new CCMenuItemToggle(); + pRet->CCMenuItem::initWithCallback(callback); + pRet->m_pSubItems = CCArray::create(); + pRet->m_pSubItems->retain(); + + for (unsigned int z=0; z < menuItems->count(); z++) + { + CCMenuItem* menuItem = (CCMenuItem*)menuItems->objectAtIndex(z); + pRet->m_pSubItems->addObject(menuItem); + } + + pRet->m_uSelectedIndex = UINT_MAX; + pRet->setSelectedIndex(0); + return pRet; +} + +// XXX: deprecated CCMenuItemToggle * CCMenuItemToggle::createWithTarget(CCObject* target, SEL_MenuHandler selector, CCMenuItem* item, ...) { va_list args; @@ -875,6 +897,17 @@ CCMenuItemToggle * CCMenuItemToggle::createWithTarget(CCObject* target, SEL_Menu return pRet; } +CCMenuItemToggle * CCMenuItemToggle::createWithCallback(const ccMenuCallback &callback, CCMenuItem* item, ...) +{ + va_list args; + va_start(args, item); + CCMenuItemToggle *pRet = new CCMenuItemToggle(); + pRet->initWithCallback(callback, item, args); + pRet->autorelease(); + va_end(args); + return pRet; +} + CCMenuItemToggle * CCMenuItemToggle::create() { CCMenuItemToggle *pRet = new CCMenuItemToggle(); @@ -883,14 +916,22 @@ CCMenuItemToggle * CCMenuItemToggle::create() return pRet; } +// XXX: deprecated bool CCMenuItemToggle::initWithTarget(CCObject* target, SEL_MenuHandler selector, CCMenuItem* item, va_list args) { - CCMenuItem::initWithTarget(target, selector); + _target = target; + CC_SAFE_RETAIN(_target); + return initWithCallback(std::bind( selector, target, std::placeholders::_1), item, args); +} + +bool CCMenuItemToggle::initWithCallback(const ccMenuCallback &callback, CCMenuItem *item, va_list args) +{ + CCMenuItem::initWithCallback(callback); this->m_pSubItems = CCArray::create(); this->m_pSubItems->retain(); int z = 0; CCMenuItem *i = item; - while(i) + while(i) { z++; m_pSubItems->addObject(i); @@ -911,7 +952,7 @@ CCMenuItemToggle* CCMenuItemToggle::create(CCMenuItem *item) bool CCMenuItemToggle::initWithItem(CCMenuItem *item) { - CCMenuItem::initWithCallback((const ccMenuCallback&)NULL); + CCMenuItem::initWithCallback((const ccMenuCallback&)nullptr); setSubItems(CCArray::create()); if (item) diff --git a/cocos2dx/menu_nodes/CCMenuItem.h b/cocos2dx/menu_nodes/CCMenuItem.h index ca34e8d08c..1ed8c52def 100644 --- a/cocos2dx/menu_nodes/CCMenuItem.h +++ b/cocos2dx/menu_nodes/CCMenuItem.h @@ -71,7 +71,7 @@ public: , m_bEnabled(false) , m_nScriptTapHandler(0) , _target(NULL) - , _callback(NULL) + , _callback(nullptr) {} virtual ~CCMenuItem(); @@ -374,12 +374,12 @@ public: /** creates a menu item from a CCArray with a target selector */ CC_DEPRECATED_ATTRIBUTE static CCMenuItemToggle * createWithTarget(CCObject* target, SEL_MenuHandler selector, CCArray* menuItems); /** creates a menu item from a CCArray with a callable object */ - static CCMenuItemToggle * createWithTarget(const ccMenuCallback& callback, CCArray* menuItems); + static CCMenuItemToggle * createWithCallback(const ccMenuCallback& callback, CCArray* menuItems); /** creates a menu item from a list of items with a target/selector */ CC_DEPRECATED_ATTRIBUTE static CCMenuItemToggle* createWithTarget(CCObject* target, SEL_MenuHandler selector, CCMenuItem* item, ...); /** creates a menu item from a list of items with a callable object */ - static CCMenuItemToggle* createWithTarget(const ccMenuCallback& callback, CCMenuItem* item, ...); + static CCMenuItemToggle* createWithCallback(const ccMenuCallback& callback, CCMenuItem* item, ...); /** creates a menu item with no target/selector and no items */ static CCMenuItemToggle* create(); @@ -387,7 +387,7 @@ public: /** initializes a menu item from a list of items with a target selector */ CC_DEPRECATED_ATTRIBUTE bool initWithTarget(CCObject* target, SEL_MenuHandler selector, CCMenuItem* item, va_list args); /** initializes a menu item from a list of items with a callable object */ - bool initWithTarget(const ccMenuCallback& callback, CCMenuItem* item, va_list args); + bool initWithCallback(const ccMenuCallback& callback, CCMenuItem* item, va_list args); /** creates a menu item with a item */ static CCMenuItemToggle* create(CCMenuItem *item); diff --git a/cocos2dx/platform/CCEGLViewProtocol.cpp b/cocos2dx/platform/CCEGLViewProtocol.cpp index 976684246f..458a814561 100644 --- a/cocos2dx/platform/CCEGLViewProtocol.cpp +++ b/cocos2dx/platform/CCEGLViewProtocol.cpp @@ -166,7 +166,7 @@ void CCEGLViewProtocol::setScissorInPoints(float x , float y , float w , float h bool CCEGLViewProtocol::isScissorEnabled() { - return glIsEnabled(GL_SCISSOR_TEST); + return (GL_FALSE == glIsEnabled(GL_SCISSOR_TEST)) ? false : true; } CCRect CCEGLViewProtocol::getScissorRect() diff --git a/cocos2dx/platform/android/CCFileUtilsAndroid.cpp b/cocos2dx/platform/android/CCFileUtilsAndroid.cpp index 2bcf2397ea..5340f61d78 100644 --- a/cocos2dx/platform/android/CCFileUtilsAndroid.cpp +++ b/cocos2dx/platform/android/CCFileUtilsAndroid.cpp @@ -118,10 +118,11 @@ unsigned char* CCFileUtilsAndroid::getFileData(const char* pszFileName, const ch return 0; } - if (pszFileName[0] != '/') + string fullPath = fullPathForFilename(pszFileName); + + if (fullPath[0] != '/') { //CCLOG("GETTING FILE RELATIVE DATA: %s", pszFileName); - string fullPath = fullPathForFilename(pszFileName); pData = s_pZipFile->getFileData(fullPath.c_str(), pSize); } else @@ -130,7 +131,7 @@ unsigned char* CCFileUtilsAndroid::getFileData(const char* pszFileName, const ch { // read rrom other path than user set it //CCLOG("GETTING FILE ABSOLUTE DATA: %s", pszFileName); - FILE *fp = fopen(pszFileName, pszMode); + FILE *fp = fopen(fullPath.c_str(), pszMode); CC_BREAK_IF(!fp); unsigned long size; diff --git a/cocos2dx/platform/android/java/project.properties b/cocos2dx/platform/android/java/project.properties index 4a46b9d1c9..cd0ca122a3 100644 --- a/cocos2dx/platform/android/java/project.properties +++ b/cocos2dx/platform/android/java/project.properties @@ -12,4 +12,4 @@ android.library=true # Project target. -target=android-17 +target=android-8 diff --git a/cocos2dx/platform/android/java/src/org/cocos2dx/lib/Cocos2dxETCLoader.java b/cocos2dx/platform/android/java/src/org/cocos2dx/lib/Cocos2dxETCLoader.java index a21cd23af2..fd4cd81954 100644 --- a/cocos2dx/platform/android/java/src/org/cocos2dx/lib/Cocos2dxETCLoader.java +++ b/cocos2dx/platform/android/java/src/org/cocos2dx/lib/Cocos2dxETCLoader.java @@ -65,7 +65,6 @@ public class Cocos2dxETCLoader { texture = ETC1Util.createTexture(inputStream); inputStream.close(); - assetManager.close(); } catch (Exception e) { Log.d("Cocos2dx", "Unable to create texture for " + filePath); @@ -73,24 +72,29 @@ public class Cocos2dxETCLoader { } if (texture != null) { + boolean ret = true; + try { - int width = texture.getWidth(); - int height = texture.getHeight(); + final int width = texture.getWidth(); + final int height = texture.getHeight(); + final int length = texture.getData().remaining(); - final byte[] data = new byte[width * height * 3]; + final byte[] data = new byte[length]; final ByteBuffer buf = ByteBuffer.wrap(data); buf.order(ByteOrder.nativeOrder()); buf.put(texture.getData()); nativeSetTextureInfo(width, height, - data); + data, + length); } catch (Exception e) { Log.d("invoke native function error", e.toString()); + ret = false; } - return true; + return ret; } else { return false; } @@ -100,5 +104,6 @@ public class Cocos2dxETCLoader { Cocos2dxETCLoader.context = context; } - private static native void nativeSetTextureInfo(final int width, final int height, final byte[] data); + private static native void nativeSetTextureInfo(final int width, final int height, final byte[] data, + final int dataLength); } diff --git a/cocos2dx/platform/tizen/CCGL.h b/cocos2dx/platform/tizen/CCGL.h index b034370bd8..5bbffbf198 100644 --- a/cocos2dx/platform/tizen/CCGL.h +++ b/cocos2dx/platform/tizen/CCGL.h @@ -29,8 +29,6 @@ THE SOFTWARE. #include using namespace Tizen::Graphics::Opengl; -typedef char GLchar; - #define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES #define glClearDepth glClearDepthf diff --git a/cocos2dx/platform/tizen/CCStdC.h b/cocos2dx/platform/tizen/CCStdC.h index 8e983e6f74..92c5eafdac 100644 --- a/cocos2dx/platform/tizen/CCStdC.h +++ b/cocos2dx/platform/tizen/CCStdC.h @@ -30,6 +30,7 @@ THE SOFTWARE. #include #include #include +#include #include #ifndef MIN @@ -40,4 +41,6 @@ THE SOFTWARE. #define MAX(x,y) (((x) < (y)) ? (y) : (x)) #endif // MAX +#define nullptr __null + #endif // __CC_STD_C_H__ diff --git a/cocos2dx/proj.mac/cocos2dx.xcodeproj/project.pbxproj.REMOVED.git-id b/cocos2dx/proj.mac/cocos2dx.xcodeproj/project.pbxproj.REMOVED.git-id index 39afd547af..15cc6a0584 100644 --- a/cocos2dx/proj.mac/cocos2dx.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/cocos2dx/proj.mac/cocos2dx.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -0b4fa0b87348ffa5b356628b5dd4907d0f8e7b86 \ No newline at end of file +4f421e1ed8425f53876db5971e3deac238edb4d3 \ No newline at end of file diff --git a/cocos2dx/proj.tizen/.cproject b/cocos2dx/proj.tizen/.cproject index 987b801a5b..476d53feb0 100644 --- a/cocos2dx/proj.tizen/.cproject +++ b/cocos2dx/proj.tizen/.cproject @@ -30,12 +30,12 @@ - + @@ -65,14 +64,15 @@ + - + @@ -102,12 +101,11 @@ - + diff --git a/cocos2dx/sprite_nodes/CCSprite.cpp b/cocos2dx/sprite_nodes/CCSprite.cpp index 900a2bf97c..336130abe5 100644 --- a/cocos2dx/sprite_nodes/CCSprite.cpp +++ b/cocos2dx/sprite_nodes/CCSprite.cpp @@ -554,17 +554,13 @@ void CCSprite::draw(void) if (m_pobTexture != NULL) { ccGLBindTexture2D( m_pobTexture->getName() ); + ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); } else { ccGLBindTexture2D(0); + ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_Color ); } - - // - // Attributes - // - - ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); #define kQuadSize sizeof(m_sQuad.bl) #ifdef EMSCRIPTEN @@ -578,10 +574,13 @@ void CCSprite::draw(void) int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); - // texCoods - diff = offsetof( ccV3F_C4B_T2F, texCoords); - glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); - + if (m_pobTexture != NULL) + { + // texCoods + diff = offsetof( ccV3F_C4B_T2F, texCoords); + glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); + } + // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); diff --git a/cocos2dx/textures/CCTextureCache.cpp b/cocos2dx/textures/CCTextureCache.cpp index 589eba1e44..c22207f1d9 100644 --- a/cocos2dx/textures/CCTextureCache.cpp +++ b/cocos2dx/textures/CCTextureCache.cpp @@ -232,6 +232,7 @@ CCDictionary* CCTextureCache::snapshotTextures() { pRet->setObject(pElement->getObject(), pElement->getStrKey()); } + pRet->autorelease(); return pRet; } diff --git a/cocos2dx/textures/CCTextureETC.cpp b/cocos2dx/textures/CCTextureETC.cpp index a6189aa19b..bd3464b408 100644 --- a/cocos2dx/textures/CCTextureETC.cpp +++ b/cocos2dx/textures/CCTextureETC.cpp @@ -81,11 +81,11 @@ static unsigned int sLength = 0; extern "C" { - JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxETCLoader_nativeSetTextureInfo(JNIEnv* env, jobject thiz, jint width, jint height, jbyteArray data) + JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxETCLoader_nativeSetTextureInfo(JNIEnv* env, jobject thiz, jint width, jint height, jbyteArray data, jint dataLength) { sWidth = (unsigned int)width; sHeight = (unsigned int)height; - sLength = sWidth * sHeight * 3; + sLength = dataLength; sData = new unsigned char[sLength]; env->GetByteArrayRegion(data, 0, sLength, (jbyte*)sData); } diff --git a/extensions/CCBReader/CCBReader.cpp b/extensions/CCBReader/CCBReader.cpp index 42a5efd1d5..44df950e6b 100644 --- a/extensions/CCBReader/CCBReader.cpp +++ b/extensions/CCBReader/CCBReader.cpp @@ -621,7 +621,7 @@ CCNode * CCBReader::readNodeGraph(CCNode * pParent) { // Read properties ccNodeLoader->parseProperties(node, pParent, this); - bool isCCBFileNode = dynamic_cast(node); + bool isCCBFileNode = (NULL == dynamic_cast(node)) ? false : true; // Handle sub ccb files (remove middle node) if (isCCBFileNode) { diff --git a/extensions/GUI/CCControlExtension/CCControlColourPicker.cpp b/extensions/GUI/CCControlExtension/CCControlColourPicker.cpp index e96ddbdf58..984f459b5b 100644 --- a/extensions/GUI/CCControlExtension/CCControlColourPicker.cpp +++ b/extensions/GUI/CCControlExtension/CCControlColourPicker.cpp @@ -46,24 +46,9 @@ CCControlColourPicker::CCControlColourPicker() CCControlColourPicker::~CCControlColourPicker() { - if (m_background) - { - m_background->removeFromParentAndCleanup(true); - } - - if (m_huePicker) - { - m_huePicker->removeFromParentAndCleanup(true); - } - - if (m_colourPicker) - { - m_colourPicker->removeFromParentAndCleanup(true); - } - - m_background = NULL; - m_huePicker = NULL; - m_colourPicker = NULL; + CC_SAFE_RELEASE(m_background); + CC_SAFE_RELEASE(m_huePicker); + CC_SAFE_RELEASE(m_colourPicker); } bool CCControlColourPicker::init() @@ -94,7 +79,8 @@ bool CCControlColourPicker::init() // Add image m_background=CCControlUtils::addSpriteToTargetWithPosAndAnchor("menuColourPanelBackground.png", spriteSheet, CCPointZero, ccp(0.5f, 0.5f)); - + CC_SAFE_RETAIN(m_background); + CCPoint backgroundPointZero = ccpSub(m_background->getPosition(), ccp (m_background->getContentSize().width / 2, m_background->getContentSize().height / 2)); // Setup panels diff --git a/extensions/network/WebSocket.cpp b/extensions/network/WebSocket.cpp index b12f5d3922..6c34de6e88 100644 --- a/extensions/network/WebSocket.cpp +++ b/extensions/network/WebSocket.cpp @@ -557,6 +557,8 @@ int WebSocket::onSocketCallback(struct libwebsocket_context *ctx, CC_SAFE_DELETE(data); CC_SAFE_DELETE_ARRAY(buf); } + + CC_SAFE_DELETE(subThreadMsg); } _wsHelper->_subThreadWsMessageQueue->clear(); diff --git a/extensions/proj.tizen/.cproject b/extensions/proj.tizen/.cproject index 67b2850444..ccbb1ef2f5 100644 --- a/extensions/proj.tizen/.cproject +++ b/extensions/proj.tizen/.cproject @@ -30,18 +30,19 @@ - + @@ -69,14 +69,15 @@ + - + @@ -108,12 +108,11 @@ - + diff --git a/external/libwebsockets/tizen/include/libwebsockets.h b/external/libwebsockets/tizen/include/libwebsockets.h new file mode 100644 index 0000000000..28e649c67e --- /dev/null +++ b/external/libwebsockets/tizen/include/libwebsockets.h @@ -0,0 +1,977 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef __LIBWEBSOCKET_H__ +#define __LIBWEBSOCKET_H__ + +#ifdef __cplusplus +extern "C" { +#include +#endif + +#ifdef WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include "../win32port/win32helpers/websock-w32.h" + +#include "../win32port/win32helpers/gettimeofday.h" + +#define strcasecmp stricmp +#define getdtablesize() 30000 + +typedef int ssize_t; + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#endif + +#else // NOT WIN32 +#include +#include +#endif + +#include + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#define CONTEXT_PORT_NO_LISTEN 0 +#define MAX_MUX_RECURSION 2 + +enum lws_log_levels { + LLL_ERR = 1 << 0, + LLL_WARN = 1 << 1, + LLL_NOTICE = 1 << 2, + LLL_INFO = 1 << 3, + LLL_DEBUG = 1 << 4, + LLL_PARSER = 1 << 5, + LLL_HEADER = 1 << 6, + LLL_EXT = 1 << 7, + LLL_CLIENT = 1 << 8, + LLL_LATENCY = 1 << 9, + + LLL_COUNT = 10 /* set to count of valid flags */ +}; + +LWS_EXTERN void _lws_log(int filter, const char *format, ...); + +/* notice, warn and log are always compiled in */ +#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) +#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) +#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) +/* + * weaker logging can be deselected at configure time using --disable-debug + * that gets rid of the overhead of checking while keeping _warn and _err + * active + */ +#ifdef _DEBUG + +#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) +#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) +#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) +#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) +#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) +#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) +#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) +LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); + +#else /* no debug */ + +#define lwsl_info(...) +#define lwsl_debug(...) +#define lwsl_parser(...) +#define lwsl_header(...) +#define lwsl_ext(...) +#define lwsl_client(...) +#define lwsl_latency(...) +#define lwsl_hexdump(a, b) + +#endif + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, + LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + LWS_CALLBACK_HTTP_WRITEABLE, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + LWS_CALLBACK_PROTOCOL_INIT, + LWS_CALLBACK_PROTOCOL_DESTROY, + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_SET_MODE_POLL_FD, + LWS_CALLBACK_CLEAR_MODE_POLL_FD, +}; + +#ifndef LWS_NO_EXTENSIONS +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, + LWS_EXT_CALLBACK_PAYLOAD_TX, + LWS_EXT_CALLBACK_PAYLOAD_RX, +}; +#endif + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ + WSI_TOKEN_EXTENSIONS, + + /* client receives these */ + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + WSI_TOKEN_MUXURL, + + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +/* + * From RFC 6455 + 1000 + + 1000 indicates a normal closure, meaning that the purpose for + which the connection was established has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g., an + endpoint that understands only text data MAY send this if it + receives a binary message). + + 1004 + + Reserved. The specific meaning might be defined in the future. + + 1005 + + 1005 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that no status + code was actually present. + + 1006 + + 1006 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed abnormally, e.g., without sending or + receiving a Close control frame. + + 1007 + + 1007 indicates that an endpoint is terminating the connection + because it has received data within a message that was not + consistent with the type of the message (e.g., non-UTF-8 [RFC3629] + data within a text message). + + 1008 + + 1008 indicates that an endpoint is terminating the connection + because it has received a message that violates its policy. This + is a generic status code that can be returned when there is no + other more suitable status code (e.g., 1003 or 1009) or if there + is a need to hide specific details about the policy. + + 1009 + + 1009 indicates that an endpoint is terminating the connection + because it has received a message that is too big for it to + process. + + 1010 + + 1010 indicates that an endpoint (client) is terminating the + connection because it has expected the server to negotiate one or + more extension, but the server didn't return them in the response + message of the WebSocket handshake. The list of extensions that + are needed SHOULD appear in the /reason/ part of the Close frame. + Note that this status code is not used by the server, because it + can fail the WebSocket handshake instead. + + 1011 + + 1011 indicates that a server is terminating the connection because + it encountered an unexpected condition that prevented it from + fulfilling the request. + + 1015 + + 1015 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed due to a failure to perform a TLS handshake + (e.g., the server certificate can't be verified). +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_RESERVED = 1004, + LWS_CLOSE_STATUS_NO_STATUS = 1005, + LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, + LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, + LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, + LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, + LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, + LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, + LWS_CLOSE_STATUS_TLS_FAILURE = 1015, +}; + +struct libwebsocket; +struct libwebsocket_context; +/* needed even with extensions disabled for create context */ +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * This callback is the way the user controls what is served. All the + * protocol detail is hidden and handled by the library. + * + * For each connection / session there is user data allocated that is + * pointed to by "user". You set the size of this user data area when + * the library is initialized with libwebsocket_create_server. + * + * You get an opportunity to initialize user data when called back with + * LWS_CALLBACK_ESTABLISHED reason. + * + * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the + * client user code to examine the http headers + * and decide to reject the connection. If the + * content in the headers is interesting to the + * client (url, etc) it needs to copy it out at + * this point since it will be destroyed before + * the CLIENT_ESTABLISHED call + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, it can be found at *in and + * is len bytes long + * + * LWS_CALLBACK_HTTP: an http request has come from a client that is not + * asking to upgrade the connection to a websocket + * one. This is a chance to serve http content, + * for example, to send a script to the client + * which will then open the websockets connection. + * @in points to the URI path requested and + * libwebsockets_serve_http_file() makes it very + * simple to send back a file to the client. + * Normally after sending the file you are done + * with the http connection, since the rest of the + * activity will come by websockets from the script + * that was delivered by http, so you will want to + * return 1; to close and free up the connection. + * That's important because it uses a slot in the + * total number of client connections allowed set + * by MAX_CLIENTS. + * + * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol + * link now. + * + * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down + * http link has completed. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @in contains the connection + * socket's descriptor. Return non-zero to terminate + * the connection before sending or receiving anything. + * Because this happens immediately after the network connection + * from the client, there's no websocket protocol selected yet so + * this callback is issued only to protocol 0. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to an array of struct lws_tokens, you can + * use the header enums lws_token_indexes from libwebsockets.h + * to check for and read the supported header presence and + * content before deciding to allow the handshake to proceed or + * to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can + * do initial setup / allocations etc + * + * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating + * this protocol won't get used at all after this callback, the + * context is getting destroyed. Take the opportunity to + * deallocate everything that was allocated by the protocol. + * + * The next four reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. This callback happens when a socket needs to be + * added to the polling loop: @in contains the fd, and + * @len is the events bitmap (like, POLLIN). If you are using the + * internal polling loop (the "service" callback), you can just + * ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @in is + * the socket desricptor. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_SET_MODE_POLL_FD: This callback happens when libwebsockets + * wants to modify the events for the socket descriptor in @in. + * The handler should OR @len on to the events member of the pollfd + * struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + * + * LWS_CALLBACK_CLEAR_MODE_POLL_FD: This callback occurs when libwebsockets + * wants to modify the events for the socket descriptor in @in. + * The handler should AND ~@len on to the events member of the + * pollfd struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + */ +LWS_EXTERN int callback(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +#ifndef LWS_NO_EXTENSIONS +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_EXTERN int extension_callback(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); +#endif + +/** + * struct libwebsocket_protocols - List of protocols and handlers server + * supports. + * @name: Protocol name that must match the one given in the client + * Javascript new WebSocket(url, 'protocol') name + * @callback: The service callback used for this protocol. It allows the + * service action for an entire protocol to be encapsulated in + * the protocol-specific callback + * @per_session_data_size: Each new connection using this protocol gets + * this much memory allocated on connection establishment and + * freed on connection takedown. A pointer to this per-connection + * allocation is passed into the callback in the 'user' parameter + * @rx_buffer_size: if you want atomic frames delivered to the callback, you + * should set this to the size of the biggest legal frame that + * you support. If the frame size is exceeded, there is no + * error, but the buffer will spill to the user callback when + * full, which you can detect by using + * libwebsockets_remaining_packet_payload(). Notice that you + * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING + * and post-padding are automatically also allocated on top. + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @protocol_index: which protocol we are starting from zero + * + * This structure represents one protocol supported by the server. An + * array of these structures is passed to libwebsocket_create_server() + * allows as many protocols as you like to be handled by one server. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + size_t rx_buffer_size; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int protocol_index; +}; + +#ifndef LWS_NO_EXTENSIONS +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this extension that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void *per_context_private_data; +}; +#endif + +/** + * struct lws_context_creation_info: parameters to create context with + * + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client + * @iface: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @protocols: Array of structures listing supported protocols and a protocol- + * specific callback for each one. The list is ended with an + * entry that has a NULL callback pointer. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports. If you configured with + * --without-extensions, you should give NULL here. + * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored + * @ssl_ca_filepath: CA certificate filepath or NULL + * @ssl_cipher_list: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * @user: optional user pointer that can be recovered via the context + * pointer using libwebsocket_context_user + * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to + * all libwebsocket sockets, client or server + * @ka_probes: if ka_time was nonzero, after the timeout expires how many + * times to try to get a response from the peer before giving up + * and killing the connection + * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes + * attempt + */ + +struct lws_context_creation_info { + int port; + const char *iface; + struct libwebsocket_protocols *protocols; + struct libwebsocket_extension *extensions; + const char *ssl_cert_filepath; + const char *ssl_private_key_filepath; + const char *ssl_ca_filepath; + const char *ssl_cipher_list; + int gid; + int uid; + unsigned int options; + void *user; + int ka_time; + int ka_probes; + int ka_interval; + +}; + +LWS_EXTERN +void lws_set_log_level(int level, + void (*log_emit_function)(int level, const char *line)); + +LWS_EXTERN void +lwsl_emit_syslog(int level, const char *line); + +LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info); + +LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct pollfd *pollfd); + +LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * So for example you need this kind of code to use libwebsocket_write with a + * 128-byte payload + * + * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING]; + * + * // fill your part of the buffer... for example here it's all zeros + * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128); + * + * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 4 + +LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type); +LWS_EXTERN int +libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_EXTERN unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi); + +LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_EXTERN void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_EXTERN int +lws_daemonize(const char *_lock_path); + +LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_EXTERN int +lws_frame_is_binary(struct libwebsocket *wsi); + +LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_EXTERN const char * +lws_get_library_version(void); + +/* access to headers... only valid while headers valid */ + +LWS_EXTERN int +lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_EXTERN int +lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h); + +/* + * Note: this is not normally needed as a user api. It's provided in case it is + * useful when integrating with other app poll loop service code. + */ + +LWS_EXTERN int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_NO_EXTENSIONS +LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/libwebsockets/tizen/lib/x86/libwebsockets.a.REMOVED.git-id b/external/libwebsockets/tizen/lib/x86/libwebsockets.a.REMOVED.git-id new file mode 100644 index 0000000000..7e29b6b4fa --- /dev/null +++ b/external/libwebsockets/tizen/lib/x86/libwebsockets.a.REMOVED.git-id @@ -0,0 +1 @@ +2e9ff412352827591ef1389f336b01d179260293 \ No newline at end of file diff --git a/plugin/plugins/flurry/proj.ios/PluginFlurry.xcodeproj/project.pbxproj b/plugin/plugins/flurry/proj.ios/PluginFlurry.xcodeproj/project.pbxproj index ddb972429a..100d81b80c 100644 --- a/plugin/plugins/flurry/proj.ios/PluginFlurry.xcodeproj/project.pbxproj +++ b/plugin/plugins/flurry/proj.ios/PluginFlurry.xcodeproj/project.pbxproj @@ -187,10 +187,7 @@ DSTROOT = /tmp/libPluginFlurry.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "PluginFlurry-Prefix.pch"; - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../protocols/include", - "$(SRCROOT)/../../../protocols/platform/ios", - ); + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../protocols/platform/ios"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/../platform/ios\"", @@ -209,10 +206,7 @@ DSTROOT = /tmp/libPluginFlurry.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "PluginFlurry-Prefix.pch"; - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../protocols/include", - "$(SRCROOT)/../../../protocols/platform/ios", - ); + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../protocols/platform/ios"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/../platform/ios\"", diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/FHSTwitterEngine.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/FHSTwitterEngine.h new file mode 100755 index 0000000000..4f9352bbea --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/FHSTwitterEngine.h @@ -0,0 +1,385 @@ +// +// FHSTwitterEngine.h +// FHSTwitterEngine +// +// Created by Nathaniel Symer on 8/22/12. +// Copyright (C) 2012 Nathaniel Symer. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// +// +// //// FHSTwitterEngine Version 1.6.1 //// +// Modified OAuthConsumer Version 1.2.2 +// +// + + +// +// FHSTwitterEngine +// The synchronous Twitter engine that doesn’t suck!! +// + +// FHSTwitterEngine is Synchronous +// That means you will have to thread. Boo Hoo. + +// Setup +// Just add the FHSTwitterEngine folder to you project. + +// USAGE +// See README.markdown + +// +// NOTE TO CONTRIBUTORS +// Use NSJSONSerialization with removeNull(). Life is easy that way. +// + + +#import + +// These are for the dispatch_async() calls that you use to get around the synchronous-ness +#define GCDBackgroundThread dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) +#define GCDMainThread dispatch_get_main_queue() + +// oEmbed align modes +typedef enum { + FHSTwitterEngineAlignModeLeft, + FHSTwitterEngineAlignModeRight, + FHSTwitterEngineAlignModeCenter, + FHSTwitterEngineAlignModeNone +} FHSTwitterEngineAlignMode; + +// Image sizes +typedef enum { + FHSTwitterEngineImageSizeMini, // 24px by 24px + FHSTwitterEngineImageSizeNormal, // 48x48 + FHSTwitterEngineImageSizeBigger, // 73x73 + FHSTwitterEngineImageSizeOriginal // original size of image +} FHSTwitterEngineImageSize; + +typedef enum { + FHSTwitterEngineResultTypeMixed, + FHSTwitterEngineResultTypeRecent, + FHSTwitterEngineResultTypePopular +} FHSTwitterEngineResultType; + +// Remove NSNulls from NSDictionary and NSArray +// Credit for this function goes to Conrad Kramer +id removeNull(id rootObject); + +extern NSString * const FHSProfileBackgroundColorKey; +extern NSString * const FHSProfileLinkColorKey; +extern NSString * const FHSProfileSidebarBorderColorKey; +extern NSString * const FHSProfileSidebarFillColorKey; +extern NSString * const FHSProfileTextColorKey; + +extern NSString * const FHSProfileNameKey; +extern NSString * const FHSProfileURLKey; +extern NSString * const FHSProfileLocationKey; +extern NSString * const FHSProfileDescriptionKey; + +@protocol FHSTwitterEngineAccessTokenDelegate + +- (void)storeAccessToken:(NSString *)accessToken; +- (NSString *)loadAccessToken; + +@end + +@class OAToken; +@class OAConsumer; +@class OAMutableURLRequest; + +@interface FHSTwitterEngine : NSObject + +// +// REST API +// + +// statuses/update +- (NSError *)postTweet:(NSString *)tweetString; +- (NSError *)postTweet:(NSString *)tweetString inReplyTo:(NSString *)inReplyToString; + +// statuses/home_timeline +- (id)getHomeTimelineSinceID:(NSString *)sinceID count:(int)count; + +// help/test +- (id)testService; + +// blocks/create +- (NSError *)block:(NSString *)username; + +// blocks/destroy +- (NSError *)unblock:(NSString *)username; + +// users/lookup +- (id)lookupUsers:(NSArray *)users areIDs:(BOOL)areIDs; + +// users/search +- (id)searchUsersWithQuery:(NSString *)q andCount:(int)count; + +// account/update_profile_image +- (NSError *)setProfileImageWithImageAtPath:(NSString *)file; +- (NSError *)setProfileImageWithImageData:(NSData *)data; + +// account/settings GET and POST +// See FHSTwitterEngine.m For details +- (id)getUserSettings; +- (NSError *)updateSettingsWithDictionary:(NSDictionary *)settings; + +// account/update_profile +// See FHSTwitterEngine.m for details +- (NSError *)updateUserProfileWithDictionary:(NSDictionary *)settings; + +// account/update_profile_background_image +- (NSError *)setProfileBackgroundImageWithImageData:(NSData *)data tiled:(BOOL)isTiled; +- (NSError *)setProfileBackgroundImageWithImageAtPath:(NSString *)file tiled:(BOOL)isTiled; +- (NSError *)setUseProfileBackgroundImage:(BOOL)shouldUseProfileBackgroundImage; + +// account/update_profile_colors +// See FHSTwitterEngine.m for details +// If the dictionary is nil, FHSTwitterEngine resets the values +- (NSError *)updateProfileColorsWithDictionary:(NSDictionary *)dictionary; + +// account/rate_limit_status +- (id)getRateLimitStatus; + +// favorites/create, favorites/destroy +- (NSError *)markTweet:(NSString *)tweetID asFavorite:(BOOL)flag; + +// favorites/list +- (id)getFavoritesForUser:(NSString *)user isID:(BOOL)isID andCount:(int)count; +- (id)getFavoritesForUser:(NSString *)user isID:(BOOL)isID andCount:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID; + +// account/verify_credentials +- (id)verifyCredentials; + +// friendships/create +- (NSError *)followUser:(NSString *)user isID:(BOOL)isID; + +// friendships/destroy +- (NSError *)unfollowUser:(NSString *)user isID:(BOOL)isID; + +// friendships/lookup +- (id)lookupFriendshipStatusForUsers:(NSArray *)users areIDs:(BOOL)areIDs; + +// friendships/incoming +- (id)getPendingIncomingFollowers; + +// friendships/outgoing +- (id)getPendingOutgoingFollowers; + +// friendships/update +- (NSError *)enableRetweets:(BOOL)enableRTs andDeviceNotifs:(BOOL)devNotifs forUser:(NSString *)user isID:(BOOL)isID; + +// friendships/no_retweet_ids +- (id)getNoRetweetIDs; + +// help/tos +- (id)getTermsOfService; + +// help/privacy +- (id)getPrivacyPolicy; + +// direct_messages +- (id)getDirectMessages:(int)count; + +// direct_messages/destroy +- (NSError *)deleteDirectMessage:(NSString *)messageID; + +// direct_messages/sent +- (id)getSentDirectMessages:(int)count; + +// direct_messages/new +- (NSError *)sendDirectMessage:(NSString *)body toUser:(NSString *)user isID:(BOOL)isID; + +// direct_messages/show +- (id)showDirectMessage:(NSString *)messageID; + +// users/report_spam +- (NSError *)reportUserAsSpam:(NSString *)user isID:(BOOL)isID; + +// help/configuration +- (id)getConfiguration; + +// help/languages +- (id)getLanguages; + +// blocks/blocking/ids +- (id)listBlockedIDs; + +// blocks/blocking +- (id)listBlockedUsers; + +// blocks/exists +- (id)authenticatedUserIsBlocking:(NSString *)user isID:(BOOL)isID; + +// users/profile_image +- (id)getProfileImageForUsername:(NSString *)username andSize:(FHSTwitterEngineImageSize)size; + +// statuses/user_timeline +- (id)getTimelineForUser:(NSString *)user isID:(BOOL)isID count:(int)count; +- (id)getTimelineForUser:(NSString *)user isID:(BOOL)isID count:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID; + +// statuses/retweet +- (NSError *)retweet:(NSString *)identifier; + +// statuses/oembed +- (id)oembedTweet:(NSString *)identifier maxWidth:(float)maxWidth alignmentMode:(FHSTwitterEngineAlignMode)alignmentMode; + +// statuses/show +- (id)getDetailsForTweet:(NSString *)identifier; + +// statuses/destroy +- (NSError *)destroyTweet:(NSString *)identifier; + +// statuses/update_with_media +- (NSError *)postTweet:(NSString *)tweetString withImageData:(NSData *)theData; +- (NSError *)postTweet:(NSString *)tweetString withImageData:(NSData *)theData inReplyTo:(NSString *)irt; + +// statuses/mentions_timeline +- (id)getMentionsTimelineWithCount:(int)count; +- (id)getMentionsTimelineWithCount:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID; + +// statuses/retweets_of_me +- (id)getRetweetedTimelineWithCount:(int)count; +- (id)getRetweetedTimelineWithCount:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID; + +// statuses/retweets +- (id)getRetweetsForTweet:(NSString *)identifier count:(int)count; + +// lists/list +- (id)getListsForUser:(NSString *)user isID:(BOOL)isID; + +// lists/statuses +- (id)getTimelineForListWithID:(NSString *)listID count:(int)count; +- (id)getTimelineForListWithID:(NSString *)listID count:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID; +- (id)getTimelineForListWithID:(NSString *)listID count:(int)count excludeRetweets:(BOOL)excludeRetweets excludeReplies:(BOOL)excludeReplies; +- (id)getTimelineForListWithID:(NSString *)listID count:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID excludeRetweets:(BOOL)excludeRetweets excludeReplies:(BOOL)excludeReplies; + +// lists/members/create_all +- (NSError *)addUsersToListWithID:(NSString *)listID users:(NSArray *)users; + +// lists/members/destroy_all +- (NSError *)removeUsersFromListWithID:(NSString *)listID users:(NSArray *)users; + +// lists/members +- (id)listUsersInListWithID:(NSString *)listID; + +// lists/update +- (NSError *)setModeOfListWithID:(NSString *)listID toPrivate:(BOOL)isPrivate; +- (NSError *)changeNameOfListWithID:(NSString *)listID toName:(NSString *)newName; +- (NSError *)changeDescriptionOfListWithID:(NSString *)listID toDescription:(NSString *)newName; + +// lists/show +- (id)getListWithID:(NSString *)listID; + +// lists/create +- (NSError *)createListWithName:(NSString *)name isPrivate:(BOOL)isPrivate description:(NSString *)description; + +// tweets/search +- (id)searchTweetsWithQuery:(NSString *)q count:(int)count resultType:(FHSTwitterEngineResultType)resultType unil:(NSDate *)untilDate sinceID:(NSString *)sinceID maxID:(NSString *)maxID; + +// followers/ids +- (id)getFollowersIDs; + +// followers/list +- (id)listFollowersForUser:(NSString *)user isID:(BOOL)isID withCursor:(NSString *)cursor; + +// friends/ids +- (id)getFriendsIDs; + +// friends/list +- (id)listFriendsForUser:(NSString *)user isID:(BOOL)isID withCursor:(NSString *)cursor; + +// +// Login and Auth +// + +// XAuth login +- (NSError *)getXAuthAccessTokenForUsername:(NSString *)username password:(NSString *)password; + +// OAuth login +- (void)showOAuthLoginControllerFromViewController:(UIViewController *)sender; +- (void)showOAuthLoginControllerFromViewController:(UIViewController *)sender withCompletion:(void(^)(BOOL success))completionBlock; + +// Access Token Mangement +- (void)clearAccessToken; +- (void)loadAccessToken; +- (BOOL)isAuthorized; + +// Clear Keys +- (void)clearConsumer; + +// sendRequest methods, use these for every request +- (NSError *)sendPOSTRequest:(OAMutableURLRequest *)request withParameters:(NSArray *)params; +- (id)sendGETRequest:(OAMutableURLRequest *)request withParameters:(NSArray *)params; + +// +// Misc Methods +// + +// Date parser +- (NSDate *)getDateFromTwitterCreatedAt:(NSString *)twitterDate; + +// id list generator - returns an array of id/username list strings +- (NSArray *)generateRequestStringsFromArray:(NSArray *)array; + +// Temporaryily set keys +// if you don't want your keys in memory, simply use +// this method. You will have to use it before +// making any API calls. +- (void)temporarilySetConsumerKey:(NSString *)consumerKey andSecret:(NSString *)consumerSecret; + +// Use to set the consumer key when using the singleton +- (void)permanentlySetConsumerKey:(NSString *)consumerKey andSecret:(NSString *)consumerSecret; + +// Singleton, NEVER use the -init method. Ever. ++ (FHSTwitterEngine *)sharedEngine; + +// Determines your internet status ++ (BOOL)isConnectedToInternet; + +// Determines if entities should be included +@property (nonatomic, assign) BOOL includeEntities; + +// Logged in user's username +@property (nonatomic, retain) NSString *loggedInUsername; + +// Logged in user's Twitter ID +@property (nonatomic, retain) NSString *loggedInID; + +// Will be called to store the accesstoken +@property (nonatomic, assign) id delegate; + +// Access Token +@property (nonatomic, retain) OAToken *accessToken; + +@end + +@interface NSData (Base64) ++ (NSData *)dataWithBase64EncodedString:(NSString *)string; +- (id)initWithBase64EncodedString:(NSString *)string; +- (NSString *)base64EncodingWithLineLength:(unsigned int)lineLength; +@end + +@interface NSString (FHSTwitterEngine) +- (NSString *)fhs_trimForTwitter; +- (NSString *)fhs_stringWithRange:(NSRange)range; +- (BOOL)fhs_isNumeric; +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/FHSTwitterEngine.m b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/FHSTwitterEngine.m new file mode 100755 index 0000000000..a4cf011feb --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/FHSTwitterEngine.m @@ -0,0 +1,2242 @@ +// +// FHSTwitterEngine.m +// FHSTwitterEngine +// +// Created by Nathaniel Symer on 8/22/12. +// Copyright (C) 2012 Nathaniel Symer. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "FHSTwitterEngine.h" + +#import "OAuthConsumer.h" +#import +#import +#import +#import +#import +#import + +NSString * const FHSProfileBackgroundColorKey = @"profile_background_color"; +NSString * const FHSProfileLinkColorKey = @"profile_link_color"; +NSString * const FHSProfileSidebarBorderColorKey = @"profile_sidebar_border_color"; +NSString * const FHSProfileSidebarFillColorKey = @"profile_sidebar_fill_color"; +NSString * const FHSProfileTextColorKey = @"profile_text_color"; + +NSString * const FHSProfileNameKey = @"name"; +NSString * const FHSProfileURLKey = @"url"; +NSString * const FHSProfileLocationKey = @"location"; +NSString * const FHSProfileDescriptionKey = @"description"; + + +static NSString * const errorFourhundred = @"Bad Request: The request you are trying to make has missing or bad parameters."; + +static NSString * const authBlockKey = @"FHSTwitterEngineOAuthCompletion"; + +static FHSTwitterEngine *sharedInstance = nil; + +id removeNull(id rootObject) { + if ([rootObject isKindOfClass:[NSDictionary class]]) { + NSMutableDictionary *sanitizedDictionary = [NSMutableDictionary dictionaryWithDictionary:rootObject]; + [rootObject enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + id sanitized = removeNull(obj); + if (!sanitized) { + [sanitizedDictionary setObject:@"" forKey:key]; + } else { + [sanitizedDictionary setObject:sanitized forKey:key]; + } + }]; + return [NSMutableDictionary dictionaryWithDictionary:sanitizedDictionary]; + } + + if ([rootObject isKindOfClass:[NSArray class]]) { + NSMutableArray *sanitizedArray = [NSMutableArray arrayWithArray:rootObject]; + [rootObject enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + id sanitized = removeNull(obj); + if (!sanitized) { + [sanitizedArray replaceObjectAtIndex:[sanitizedArray indexOfObject:obj] withObject:@""]; + } else { + [sanitizedArray replaceObjectAtIndex:[sanitizedArray indexOfObject:obj] withObject:sanitized]; + } + }]; + return [NSMutableArray arrayWithArray:sanitizedArray]; + } + + if ([rootObject isKindOfClass:[NSNull class]]) { + return (id)nil; + } else { + return rootObject; + } +} + +NSError * getBadRequestError() { + return [NSError errorWithDomain:errorFourhundred code:400 userInfo:nil]; +} + +NSError * getNilReturnLengthError() { + return [NSError errorWithDomain:@"Twitter successfully processed the request, but did not return any content" code:204 userInfo:nil]; +} + +@interface FHSTwitterEngineController : UIViewController + +@property (nonatomic, retain) UINavigationBar *navBar; +@property (nonatomic, retain) UIView *blockerView; +@property (nonatomic, retain) UIToolbar *pinCopyBar; + +//@property (nonatomic, retain) FHSTwitterEngine *engine; +@property (nonatomic, retain) UIWebView *theWebView; +@property (nonatomic, retain) OAToken *requestToken; + +//- (id)initWithEngine:(FHSTwitterEngine *)theEngine; +- (NSString *)locatePin; +- (void)showPinCopyPrompt; + +@end + +@interface FHSTwitterEngine() + +// Login stuff +- (NSString *)getRequestTokenString; + +// General Get request sender +- (id)sendRequest:(NSURLRequest *)request; + +// These are here to obfuscate them from prying eyes +@property (retain, nonatomic) OAConsumer *consumer; +@property (assign, nonatomic) BOOL shouldClearConsumer; +@property (retain, nonatomic) NSDateFormatter *dateFormatter; + +@end + +@implementation NSString (FHSTwitterEngine) + +- (NSString *)fhs_trimForTwitter { + NSString *string = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + return (string.length > 140)?[string substringToIndex:140]:string; +} + +- (NSString *)fhs_stringWithRange:(NSRange)range { + return [[self substringFromIndex:range.location]substringToIndex:range.length]; +} + +- (BOOL)fhs_isNumeric { + const char *raw = (const char *)[self UTF8String]; + + for (int i = 0; i < strlen(raw); i++) { + if (raw[i] < '0' || raw[i] > '9') { + return NO; + } + } + return YES; +} + +@end + +@implementation FHSTwitterEngine + +static NSString * const url_search_tweets = @"https://api.twitter.com/1.1/search/tweets.json"; + +static NSString * const url_users_search = @"https://api.twitter.com/1.1/users/search.json"; +static NSString * const url_users_show = @"https://api.twitter.com/1.1/users/show.json"; +static NSString * const url_users_report_spam = @"https://api.twitter.com/1.1/users/report_spam.json"; +static NSString * const url_users_lookup = @"https://api.twitter.com/1.1/users/lookup.json"; + +static NSString * const url_lists_create = @"https://api.twitter.com/1.1/lists/create.json"; +static NSString * const url_lists_show = @"https://api.twitter.com/1.1/lists/show.json"; +static NSString * const url_lists_update = @"https://api.twitter.com/1.1/lists/update.json"; +static NSString * const url_lists_members = @"https://api.twitter.com/1.1/lists/members.json"; +static NSString * const url_lists_members_destroy_all = @"https://api.twitter.com/1.1/lists/members/destroy_all.json"; +static NSString * const url_lists_members_create_all = @"https://api.twitter.com/1.1/lists/members/create_all.json"; +static NSString * const url_lists_statuses = @"https://api.twitter.com/1.1/lists/statuses.json"; +static NSString * const url_lists_list = @"https://api.twitter.com/1.1/lists/list.json"; + +static NSString * const url_statuses_home_timeline = @"https://api.twitter.com/1.1/statuses/home_timeline.json"; +static NSString * const url_statuses_update = @"https://api.twitter.com/1.1/statuses/update.json"; +static NSString * const url_statuses_retweets_of_me = @"https://api.twitter.com/1.1/statuses/retweets_of_me.json"; +static NSString * const url_statuses_user_timeline = @"https://api.twitter.com/1.1/statuses/user_timeline.json"; +static NSString * const url_statuses_metions_timeline = @"https://api.twitter.com/1.1/statuses/mentions_timeline.json"; +static NSString * const url_statuses_update_with_media = @"https://api.twitter.com/1.1/statuses/update_with_media.json"; +static NSString * const url_statuses_destroy = @"https://api.twitter.com/1.1/statuses/destroy.json"; +static NSString * const url_statuses_show = @"https://api.twitter.com/1.1/statuses/show.json"; +static NSString * const url_statuses_oembed = @"https://api.twitter.com/1.1/statuses/oembed.json"; + +static NSString * const url_blocks_exists = @"https://api.twitter.com/1.1/blocks/exists.json"; +static NSString * const url_blocks_blocking = @"https://api.twitter.com/1.1/blocks/blocking.json"; +static NSString * const url_blocks_blocking_ids = @"https://api.twitter.com/1.1/blocks/blocking/ids.json"; +static NSString * const url_blocks_destroy = @"https://api.twitter.com/1.1/blocks/destroy.json"; +static NSString * const url_blocks_create = @"https://api.twitter.com/1.1/blocks/create.json"; + +static NSString * const url_help_languages = @"https://api.twitter.com/1.1/help/languages.json"; +static NSString * const url_help_configuration = @"https://api.twitter.com/1.1/help/configuration.json"; +static NSString * const url_help_privacy = @"https://api.twitter.com/1.1/help/privacy.json"; +static NSString * const url_help_tos = @"https://api.twitter.com/1.1/help/tos.json"; +static NSString * const url_help_test = @"https://api.twitter.com/1.1/help/test.json"; + +static NSString * const url_direct_messages_show = @"https://api.twitter.com/1.1/direct_messages/show.json"; +static NSString * const url_direct_messages_new = @"https://api.twitter.com/1.1/direct_messages/new.json"; +static NSString * const url_direct_messages_sent = @"https://api.twitter.com/1.1/direct_messages/sent.json"; +static NSString * const url_direct_messages_destroy = @"https://api.twitter.com/1.1/direct_messages/destroy.json"; +static NSString * const url_direct_messages = @"https://api.twitter.com/1.1/direct_messages.json"; + +static NSString * const url_friendships_no_retweets_ids = @"https://api.twitter.com/1.1/friendships/no_retweets/ids.json"; +static NSString * const url_friendships_update = @"https://api.twitter.com/1.1/friendships/update.json"; +static NSString * const url_friendships_outgoing = @"https://api.twitter.com/1.1/friendships/outgoing.json"; +static NSString * const url_friendships_incoming = @"https://api.twitter.com/1.1/friendships/incoming.json"; +static NSString * const url_friendships_lookup = @"https://api.twitter.com/1.1/friendships/lookup.json"; +static NSString * const url_friendships_destroy = @"https://api.twitter.com/1.1/friendships/destroy.json"; +static NSString * const url_friendships_create = @"https://api.twitter.com/1.1/friendships/create.json"; + +static NSString * const url_account_verify_credentials = @"https://api.twitter.com/1.1/account/verify_credentials.json"; +static NSString * const url_account_update_profile_colors = @"https://api.twitter.com/1.1/account/update_profile_colors.json"; +static NSString * const url_account_update_profile_background_image = @"https://api.twitter.com/1.1/account/update_profile_background_image.json"; +static NSString * const url_account_update_profile_image = @"https://api.twitter.com/1.1/account/update_profile_image.json"; +static NSString * const url_account_settings = @"https://api.twitter.com/1.1/account/settings.json"; +static NSString * const url_account_update_profile = @"https://api.twitter.com/1.1/account/update_profile.json"; + +static NSString * const url_favorites_list = @"https://api.twitter.com/1.1/favorites/list.json"; +static NSString * const url_favorites_create = @"https://api.twitter.com/1.1/favorites/create.json"; +static NSString * const url_favorites_destroy = @"https://api.twitter.com/1.1/favorites/destroy.json"; + +static NSString * const url_application_rate_limit_status = @"https://api.twitter.com/1.1/application/rate_limit_status.json"; + +static NSString * const url_followers_ids = @"https://api.twitter.com/1.1/followers/ids.json"; +static NSString * const url_followers_list = @"https://api.twitter.com/1.1/followers/list.json"; + +static NSString * const url_friends_ids = @"https://api.twitter.com/1.1/friends/ids.json"; +static NSString * const url_friends_list = @"https://api.twitter.com/1.1/friends/list.json"; + +- (id)listFollowersForUser:(NSString *)user isID:(BOOL)isID withCursor:(NSString *)cursor { + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_friends_list]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *skipstatusP = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + OARequestParameter *include_entitiesP = [OARequestParameter requestParameterWithName:@"include_entities" value:self.includeEntities?@"true":@"false"]; + OARequestParameter *screen_nameP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + OARequestParameter *cursorP = [OARequestParameter requestParameterWithName:@"cursor" value:cursor]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:include_entitiesP, skipstatusP, screen_nameP, cursorP, nil]]; +} + +- (id)listFriendsForUser:(NSString *)user isID:(BOOL)isID withCursor:(NSString *)cursor { + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_friends_list]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *skipstatusP = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + OARequestParameter *include_entitiesP = [OARequestParameter requestParameterWithName:@"include_entities" value:self.includeEntities?@"true":@"false"]; + OARequestParameter *screen_nameP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + OARequestParameter *cursorP = [OARequestParameter requestParameterWithName:@"cursor" value:cursor]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:include_entitiesP, skipstatusP, screen_nameP, cursorP, nil]]; +} + +- (id)searchUsersWithQuery:(NSString *)q andCount:(int)count { + + if (count == 0) { + return nil; + } + + if (q.length == 0) { + return getBadRequestError(); + } + + if (q.length > 1000) { + q = [q substringToIndex:1000]; + } + + NSURL *baseURL = [NSURL URLWithString:url_users_search]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *include_entitiesP = [OARequestParameter requestParameterWithName:@"include_entities" value:self.includeEntities?@"true":@"false"]; + OARequestParameter *countP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + OARequestParameter *qP = [OARequestParameter requestParameterWithName:@"q" value:q]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:include_entitiesP, countP, qP, nil]]; +} + +- (id)searchTweetsWithQuery:(NSString *)q count:(int)count resultType:(FHSTwitterEngineResultType)resultType unil:(NSDate *)untilDate sinceID:(NSString *)sinceID maxID:(NSString *)maxID { + + if (count == 0) { + return nil; + } + + if (q.length == 0) { + return getBadRequestError(); + } + + if (q.length > 1000) { + q = [q substringToIndex:1000]; + } + + NSURL *baseURL = [NSURL URLWithString:url_search_tweets]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *include_entitiesP = [OARequestParameter requestParameterWithName:@"include_entities" value:self.includeEntities?@"true":@"false"]; + OARequestParameter *countP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + OARequestParameter *untilP = [OARequestParameter requestParameterWithName:@"until" value:nil]; + OARequestParameter *result_typeP = [OARequestParameter requestParameterWithName:@"result_type" value:nil]; + OARequestParameter *qP = [OARequestParameter requestParameterWithName:@"q" value:q]; + + [self.dateFormatter setDateFormat:@"YYYY-MM-DD"]; + NSString *untilString = [self.dateFormatter stringFromDate:untilDate]; + [self.dateFormatter setDateFormat:@"EEE MMM dd HH:mm:ss ZZZZ yyyy"]; + + untilP.value = untilString; + + if (resultType == FHSTwitterEngineResultTypeMixed) { + result_typeP.value = @"mixed"; + } else if (resultType == FHSTwitterEngineResultTypeRecent) { + result_typeP.value = @"recent"; + } else if (resultType == FHSTwitterEngineResultTypePopular) { + result_typeP.value = @"popular"; + } + + NSMutableArray *params = [NSMutableArray arrayWithObjects:countP, include_entitiesP, qP, nil]; + + if (maxID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"max_id" value:maxID]]; + } + + if (sinceID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"since_id" value:sinceID]]; + } + + return [self sendGETRequest:request withParameters:params]; +} + +- (NSError *)createListWithName:(NSString *)name isPrivate:(BOOL)isPrivate description:(NSString *)description { + + if (name.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_create]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *nameP = [OARequestParameter requestParameterWithName:@"name" value:name]; + OARequestParameter *isPrivateP = [OARequestParameter requestParameterWithName:@"mode" value:isPrivate?@"private":@"public"]; + + NSMutableArray *params = [NSMutableArray arrayWithObjects:nameP, isPrivateP, nil]; + + if (description.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"description" value:description]]; + } + + return [self sendPOSTRequest:request withParameters:params]; +} + +- (id)getListWithID:(NSString *)listID { + + if (listID.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_show]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *listIDP = [OARequestParameter requestParameterWithName:@"list_id" value:listID]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:listIDP, nil]]; +} + +- (NSError *)changeDescriptionOfListWithID:(NSString *)listID toDescription:(NSString *)newName { + + if (listID.length == 0) { + return getBadRequestError(); + } + + if (newName.length == 0 ) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_update]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *listIDP = [OARequestParameter requestParameterWithName:@"list_id" value:listID]; + OARequestParameter *nameP = [OARequestParameter requestParameterWithName:@"description" value:newName]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:listIDP, nameP, nil]]; +} + +- (NSError *)changeNameOfListWithID:(NSString *)listID toName:(NSString *)newName { + + if (listID.length == 0) { + return getBadRequestError(); + } + + if (newName.length == 0 ) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_update]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *listIDP = [OARequestParameter requestParameterWithName:@"list_id" value:listID]; + OARequestParameter *nameP = [OARequestParameter requestParameterWithName:@"name" value:newName]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:listIDP, nameP, nil]]; +} + +- (NSError *)setModeOfListWithID:(NSString *)listID toPrivate:(BOOL)isPrivate { + + if (listID.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_update]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *listIDP = [OARequestParameter requestParameterWithName:@"list_id" value:listID]; + OARequestParameter *isPrivateP = [OARequestParameter requestParameterWithName:@"mode" value:isPrivate?@"private":@"public"]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:listIDP, isPrivateP, nil]]; +} + +- (id)listUsersInListWithID:(NSString *)listID { + + if (listID.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_members]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *listIDP = [OARequestParameter requestParameterWithName:@"list_id" value:listID]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:listIDP, nil]]; +} + +- (NSError *)removeUsersFromListWithID:(NSString *)listID users:(NSArray *)users { + + if (users.count == 0) { + return getBadRequestError(); + } + + if (users.count > 100) { + return getBadRequestError(); + } + + if (listID.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_members_destroy_all]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *screen_name = [OARequestParameter requestParameterWithName:@"screen_name" value:[users componentsJoinedByString:@","]]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:screen_name, nil]]; +} + +- (NSError *)addUsersToListWithID:(NSString *)listID users:(NSArray *)users { + + if (users.count == 0) { + return getBadRequestError(); + } + + if (users.count > 100) { + return getBadRequestError(); + } + + if (listID.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_members_create_all]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *screen_name = [OARequestParameter requestParameterWithName:@"screen_name" value:[users componentsJoinedByString:@","]]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:screen_name, nil]]; +} + +- (id)getTimelineForListWithID:(NSString *)listID count:(int)count { + return [self getTimelineForListWithID:listID count:count sinceID:nil maxID:nil]; +} + +- (id)getTimelineForListWithID:(NSString *)listID count:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID { + return [self getTimelineForListWithID:listID count:count sinceID:sinceID maxID:maxID excludeRetweets:YES excludeReplies:YES]; +} + +- (id)getTimelineForListWithID:(NSString *)listID count:(int)count excludeRetweets:(BOOL)excludeRetweets excludeReplies:(BOOL)excludeReplies { + return [self getTimelineForListWithID:listID count:count sinceID:nil maxID:nil excludeRetweets:excludeRetweets excludeReplies:excludeReplies]; +} + +- (id)getTimelineForListWithID:(NSString *)listID count:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID excludeRetweets:(BOOL)excludeRetweets excludeReplies:(BOOL)excludeReplies { + + if (count == 0) { + return nil; + } + + if (listID.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_statuses]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *countP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + OARequestParameter *excludeRepliesP = [OARequestParameter requestParameterWithName:@"exclude_replies" value:excludeReplies?@"true":@"false"]; + OARequestParameter *includeRTsP = [OARequestParameter requestParameterWithName:@"include_rts" value:excludeRetweets?@"false":@"true"]; + OARequestParameter *listIDP = [OARequestParameter requestParameterWithName:@"list_id" value:listID]; + + NSMutableArray *params = [NSMutableArray arrayWithObjects:countP, excludeRepliesP, includeRTsP, listIDP, nil]; + + if (sinceID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"since_id" value:sinceID]]; + } + + if (maxID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"max_id" value:maxID]]; + } + + return [self sendGETRequest:request withParameters:params]; +} + +- (id)getListsForUser:(NSString *)user isID:(BOOL)isID { + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_lists_list]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *userP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:userP, nil]]; +} + +- (id)getRetweetsForTweet:(NSString *)identifier count:(int)count { + + if (count == 0) { + return nil; + } + + if (identifier.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.twitter.com/1.1/statuses/retweets/%@.json",identifier]]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *identifierP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:identifierP, nil]]; +} + +- (id)getRetweetedTimelineWithCount:(int)count { + return [self getRetweetedTimelineWithCount:count sinceID:nil maxID:nil]; +} + +- (id)getRetweetedTimelineWithCount:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID { + + if (count == 0) { + return nil; + } + + NSURL *baseURL = [NSURL URLWithString:url_statuses_retweets_of_me]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *countP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + OARequestParameter *excludeRepliesP = [OARequestParameter requestParameterWithName:@"exclude_replies" value:@"false"]; + OARequestParameter *includeRTsP = [OARequestParameter requestParameterWithName:@"include_rts" value:@"true"]; + + NSMutableArray *params = [NSMutableArray array]; + [params addObject:countP]; + [params addObject:excludeRepliesP]; + [params addObject:includeRTsP]; + + if (sinceID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"since_id" value:sinceID]]; + } + + if (maxID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"max_id" value:maxID]]; + } + + return [self sendGETRequest:request withParameters:params]; +} + +- (id)getMentionsTimelineWithCount:(int)count { + return [self getMentionsTimelineWithCount:count sinceID:nil maxID:nil]; +} + +- (id)getMentionsTimelineWithCount:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID { + + if (count == 0) { + return nil; + } + + NSURL *baseURL = [NSURL URLWithString:url_statuses_metions_timeline]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *countP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + OARequestParameter *excludeRepliesP = [OARequestParameter requestParameterWithName:@"exclude_replies" value:@"false"]; + OARequestParameter *includeRTsP = [OARequestParameter requestParameterWithName:@"include_rts" value:@"true"]; + + NSMutableArray *params = [NSMutableArray array]; + [params addObject:countP]; + [params addObject:excludeRepliesP]; + [params addObject:includeRTsP]; + + if (sinceID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"since_id" value:sinceID]]; + } + + if (maxID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"max_id" value:maxID]]; + } + + return [self sendGETRequest:request withParameters:params]; +} + +- (NSError *)postTweet:(NSString *)tweetString withImageData:(NSData *)theData { + return [self postTweet:tweetString withImageData:theData inReplyTo:nil]; +} + +- (NSError *)postTweet:(NSString *)tweetString withImageData:(NSData *)theData inReplyTo:(NSString *)irt { + + if (tweetString.length == 0) { + return getBadRequestError(); + } + + if (theData.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_statuses_update_with_media]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *statusP = [OARequestParameter requestParameterWithName:@"status" value:tweetString]; + OARequestParameter *mediaP = [OARequestParameter requestParameterWithName:@"media_data[]" value:[theData base64EncodingWithLineLength:0]]; + + NSMutableArray *params = [NSMutableArray arrayWithObjects:statusP, mediaP, nil]; + + if (irt.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"in_reply_to_status_id" value:irt]]; + } + + return [self sendPOSTRequest:request withParameters:params]; +} + +- (NSError *)destroyTweet:(NSString *)identifier { + + if (identifier.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_statuses_destroy]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *identifierP = [OARequestParameter requestParameterWithName:@"id" value:identifier]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:identifierP, nil]]; +} + +- (id)getDetailsForTweet:(NSString *)identifier { + + if (identifier.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_statuses_show]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *identifierP = [OARequestParameter requestParameterWithName:@"id" value:identifier]; + OARequestParameter *includeMyRetweet = [OARequestParameter requestParameterWithName:@"include_my_retweet" value:@"true"]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:includeMyRetweet, identifierP, nil]]; +} + +- (id)oembedTweet:(NSString *)identifier maxWidth:(float)maxWidth alignmentMode:(FHSTwitterEngineAlignMode)alignmentMode { + + if (identifier.length == 0) { + return getBadRequestError(); + } + + NSString *language = [[NSLocale preferredLanguages]objectAtIndex:0]; + NSString *alignment = [[NSArray arrayWithObjects:@"left", @"right", @"center", @"none", nil]objectAtIndex:alignmentMode]; + + NSURL *baseURL = [NSURL URLWithString:url_statuses_oembed]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *identifierP = [OARequestParameter requestParameterWithName:@"id" value:identifier]; + OARequestParameter *maxWidthP = [OARequestParameter requestParameterWithName:@"maxwidth" value:[NSString stringWithFormat:@"%f",maxWidth]]; + OARequestParameter *languageP= [OARequestParameter requestParameterWithName:@"lang" value:language]; + OARequestParameter *alignmentP = [OARequestParameter requestParameterWithName:@"align" value:alignment]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:identifierP, maxWidthP, languageP,alignmentP, nil]]; +} + +- (NSError *)retweet:(NSString *)identifier { + + if (identifier.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.twitter.com/1.1/statuses/retweet/%@.json",identifier]]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + return [self sendPOSTRequest:request withParameters:nil]; +} + +- (id)getTimelineForUser:(NSString *)user isID:(BOOL)isID count:(int)count { + return [self getTimelineForUser:user isID:isID count:count sinceID:nil maxID:nil]; +} + +- (id)getTimelineForUser:(NSString *)user isID:(BOOL)isID count:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID { + + if (count == 0) { + return nil; + } + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_statuses_user_timeline]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *countP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + OARequestParameter *userP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + OARequestParameter *excludeRepliesP = [OARequestParameter requestParameterWithName:@"exclude_replies" value:@"false"]; + OARequestParameter *includeRTsP = [OARequestParameter requestParameterWithName:@"include_rts" value:@"true"]; + + NSMutableArray *params = [NSMutableArray array]; + [params addObject:countP]; + [params addObject:userP]; + [params addObject:excludeRepliesP]; + [params addObject:includeRTsP]; + + if (sinceID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"since_id" value:sinceID]]; + } + + if (maxID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"max_id" value:maxID]]; + } + + return [self sendGETRequest:request withParameters:params]; +} + +- (id)getProfileImageForUsername:(NSString *)username andSize:(FHSTwitterEngineImageSize)size { + + if (username.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_users_show]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *usernameP = [OARequestParameter requestParameterWithName:@"screen_name" value:username]; + + NSArray *params = [NSArray arrayWithObjects:usernameP, nil]; + + id userShowReturn = [self sendGETRequest:request withParameters:params]; + + if ([userShowReturn isKindOfClass:[NSError class]]) { + return [NSError errorWithDomain:[(NSError *)userShowReturn domain] code:[(NSError *)userShowReturn code] userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]]; + } else if ([userShowReturn isKindOfClass:[NSDictionary class]]) { + NSString *url = [userShowReturn objectForKey:@"profile_image_url"]; // normal + + if (size == 0) { // mini + url = [url stringByReplacingOccurrencesOfString:@"_normal" withString:@"_mini"]; + } else if (size == 2) { // bigger + url = [url stringByReplacingOccurrencesOfString:@"_normal" withString:@"_bigger"]; + } else if (size == 3) { // original + url = [url stringByReplacingOccurrencesOfString:@"_normal" withString:@""]; + } + + id ret = [self sendRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; + + if ([ret isKindOfClass:[NSData class]]) { + return [UIImage imageWithData:(NSData *)ret]; + } + + return ret; + } + + return [NSError errorWithDomain:@"Bad Request: The request you attempted to make messed up royally." code:400 userInfo:nil]; +} + +- (id)authenticatedUserIsBlocking:(NSString *)user isID:(BOOL)isID { + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_blocks_exists]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *userP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + OARequestParameter *skipstatusP = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + + id obj = [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:skipstatusP, userP, nil]]; + + if ([obj isKindOfClass:[NSError class]]) { + return obj; + } else if ([obj isKindOfClass:[NSDictionary class]]) { + if ([[obj objectForKey:@"error"]isEqualToString:@"You are not blocking this user."]) { + return @"NO"; + } else { + return @"YES"; + } + } + + return getBadRequestError(); +} + +- (id)listBlockedUsers { + NSURL *baseURL = [NSURL URLWithString:url_blocks_blocking]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *skipstatusP = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:skipstatusP, nil]]; +} + +- (id)listBlockedIDs { + NSURL *baseURL = [NSURL URLWithString:url_blocks_blocking_ids]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *stringifyIDsP = [OARequestParameter requestParameterWithName:@"stringify_ids" value:@"true"]; + + id object = [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:stringifyIDsP, nil]]; + + if ([object isKindOfClass:[NSDictionary class]]) { + return [(NSDictionary *)object objectForKey:@"ids"]; + } + return object; +} + +- (id)getLanguages { + NSURL *baseURL = [NSURL URLWithString:url_help_languages]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + return [self sendGETRequest:request withParameters:nil]; +} + +- (id)getConfiguration { + NSURL *baseURL = [NSURL URLWithString:url_help_configuration]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + return [self sendGETRequest:request withParameters:nil]; +} + +- (NSError *)reportUserAsSpam:(NSString *)user isID:(BOOL)isID { + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_users_report_spam]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *userP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:userP, nil]]; +} + +- (id)showDirectMessage:(NSString *)messageID { + + if (messageID.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_direct_messages_show]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *id_ = [OARequestParameter requestParameterWithName:@"id" value:messageID]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:id_, nil]]; +} + +- (NSError *)sendDirectMessage:(NSString *)body toUser:(NSString *)user isID:(BOOL)isID { + + if (user.length == 0) { + return getBadRequestError(); + } + + if (body.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_direct_messages_new]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *bodyP = [OARequestParameter requestParameterWithName:@"text" value:[body fhs_trimForTwitter]]; + OARequestParameter *userP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:userP, bodyP, nil]]; +} + +- (id)getSentDirectMessages:(int)count { + + if (count == 0) { + return nil; + } + + NSURL *baseURL = [NSURL URLWithString:url_direct_messages_sent]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *countP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:countP, nil]]; +} + +- (NSError *)deleteDirectMessage:(NSString *)messageID { + + if (messageID.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_direct_messages_destroy]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *identitifierP = [OARequestParameter requestParameterWithName:@"id" value:messageID]; + OARequestParameter *includeEntitiesP = [OARequestParameter requestParameterWithName:@"include_entities" value:self.includeEntities?@"true":@"false"]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:identitifierP, includeEntitiesP, nil]]; +} + +- (id)getDirectMessages:(int)count { + + if (count == 0) { + return nil; + } + + NSURL *baseURL = [NSURL URLWithString:url_direct_messages]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *countP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + OARequestParameter *skipStatusP = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:countP, skipStatusP, nil]]; +} + +- (id)getPrivacyPolicy { + NSURL *baseURL = [NSURL URLWithString:url_help_privacy]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + + id object = [self sendGETRequest:request withParameters:nil]; + + if ([object isKindOfClass:[NSDictionary class]]) { + NSDictionary *dict = (NSDictionary *)object; + if ([dict.allKeys containsObject:@"privacy"]) { + return [dict objectForKey:@"privacy"]; + } + } + return object; +} + +- (id)getTermsOfService { + NSURL *baseURL = [NSURL URLWithString:url_help_tos]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + + id object = [self sendGETRequest:request withParameters:nil]; + + if ([object isKindOfClass:[NSDictionary class]]) { + NSDictionary *dict = (NSDictionary *)object; + if ([dict.allKeys containsObject:@"tos"]) { + return [dict objectForKey:@"tos"]; + } + } + return object; +} + +- (id)getNoRetweetIDs { + NSURL *baseURL = [NSURL URLWithString:url_friendships_no_retweets_ids]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *stringifyIDsP = [OARequestParameter requestParameterWithName:@"stringify_ids" value:@"true"]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:stringifyIDsP, nil]]; +} + +- (NSError *)enableRetweets:(BOOL)enableRTs andDeviceNotifs:(BOOL)devNotifs forUser:(NSString *)user isID:(BOOL)isID { + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_friendships_update]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *userP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + OARequestParameter *retweetsP = [OARequestParameter requestParameterWithName:@"retweets" value:enableRTs?@"true":@"false"]; + OARequestParameter *deviceP = [OARequestParameter requestParameterWithName:@"device" value:devNotifs?@"true":@"false"]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:userP, retweetsP, deviceP, nil]]; +} + +- (id)getPendingOutgoingFollowers { + NSURL *baseURL = [NSURL URLWithString:url_friendships_outgoing]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *stringifyIDsP = [OARequestParameter requestParameterWithName:@"stringify_ids" value:@"true"]; + + id object = [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:stringifyIDsP, nil]]; + + if ([object isKindOfClass:[NSDictionary class]]) { + NSDictionary *dict = (NSDictionary *)object; + if ([dict.allKeys containsObject:@"ids"]) { + return [dict objectForKey:@"ids"]; + } + } + return object; +} + +- (id)getPendingIncomingFollowers { + NSURL *baseURL = [NSURL URLWithString:url_friendships_incoming]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *stringifyIDsP = [OARequestParameter requestParameterWithName:@"stringify_ids" value:@"true"]; + + id object = [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:stringifyIDsP, nil]]; + + if ([object isKindOfClass:[NSDictionary class]]) { + NSDictionary *dict = (NSDictionary *)object; + if ([dict.allKeys containsObject:@"ids"]) { + return [dict objectForKey:@"ids"]; + } + } + return object; +} + +- (id)lookupFriendshipStatusForUsers:(NSArray *)users areIDs:(BOOL)areIDs { + + if (users.count == 0) { + return nil; + } + + NSMutableArray *returnedDictionaries = [NSMutableArray array]; + NSArray *reqStrings = [self generateRequestStringsFromArray:users]; + + NSURL *baseURL = [NSURL URLWithString:url_friendships_lookup]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + + for (NSString *reqString in reqStrings) { + OARequestParameter *userP = [OARequestParameter requestParameterWithName:areIDs?@"user_id":@"screen_name" value:reqString]; + + id retObj = [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:userP, nil]]; + + if ([retObj isKindOfClass:[NSArray class]]) { + [returnedDictionaries addObjectsFromArray:(NSArray *)retObj]; + } else if ([retObj isKindOfClass:[NSError class]]) { + return retObj; + } + } + return returnedDictionaries; +} + +- (NSError *)unfollowUser:(NSString *)user isID:(BOOL)isID { + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_friendships_destroy]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *userP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:userP, nil]]; +} + +- (NSError *)followUser:(NSString *)user isID:(BOOL)isID { + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_friendships_create]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *userP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:userP, nil]]; +} + +- (id)verifyCredentials { + NSURL *baseURL = [NSURL URLWithString:url_account_verify_credentials]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + return [self sendGETRequest:request withParameters:nil]; +} + +- (id)getFavoritesForUser:(NSString *)user isID:(BOOL)isID andCount:(int)count { + return [self getFavoritesForUser:user isID:isID andCount:count sinceID:nil maxID:nil]; +} + +- (id)getFavoritesForUser:(NSString *)user isID:(BOOL)isID andCount:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID { + if (count == 0) { + return nil; + } + + if (user.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_favorites_list]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *countP = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d",count]]; + OARequestParameter *userP = [OARequestParameter requestParameterWithName:isID?@"user_id":@"screen_name" value:user]; + OARequestParameter *includeEntitiesP = [OARequestParameter requestParameterWithName:@"include_entities" value:self.includeEntities?@"true":@"false"]; + + NSMutableArray *params = [NSMutableArray arrayWithObjects:countP, userP, includeEntitiesP, nil]; + + if (sinceID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"since_id" value:sinceID]]; + } + + if (maxID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"max_id" value:maxID]]; + } + + return [self sendGETRequest:request withParameters:params]; +} + +- (NSError *)markTweet:(NSString *)tweetID asFavorite:(BOOL)flag { + + if (tweetID.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:flag?url_favorites_create:url_favorites_destroy]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *idP = [OARequestParameter requestParameterWithName:@"id" value:tweetID]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:idP, nil]]; +} + +- (id)getRateLimitStatus { + NSURL *baseURL = [NSURL URLWithString:url_application_rate_limit_status]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + return [self sendGETRequest:request withParameters:nil]; +} + +- (NSError *)updateProfileColorsWithDictionary:(NSDictionary *)dictionary { + + // profile_background_color - hex color + // profile_link_color - hex color + // profile_sidebar_border_color - hex color + // profile_sidebar_fill_color - hex color + // profile_text_color - hex color + + NSString *profile_background_color = nil; + NSString *profile_link_color = nil; + NSString *profile_sidebar_border_color = nil; + NSString *profile_sidebar_fill_color = nil; + NSString *profile_text_color = nil; + + if (!dictionary) { + profile_background_color = @"C0DEED"; + profile_link_color = @"0084B4"; + profile_sidebar_border_color = @"C0DEED"; + profile_sidebar_fill_color = @"DDEEF6"; + profile_text_color = @"333333"; + } else { + profile_background_color = [dictionary objectForKey:FHSProfileBackgroundColorKey]; + profile_link_color = [dictionary objectForKey:FHSProfileLinkColorKey]; + profile_sidebar_border_color = [dictionary objectForKey:FHSProfileSidebarBorderColorKey]; + profile_sidebar_fill_color = [dictionary objectForKey:FHSProfileSidebarFillColorKey]; + profile_text_color = [dictionary objectForKey:FHSProfileTextColorKey]; + } + + NSURL *baseURL = [NSURL URLWithString:url_account_update_profile_colors]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *skipStatus = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + + NSMutableArray *params = [NSMutableArray arrayWithObjects:skipStatus, nil]; + + if (profile_background_color.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"profile_background_color" value:profile_background_color]]; + } + + if (profile_link_color.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"profile_link_color" value:profile_link_color]]; + } + + if (profile_sidebar_border_color.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"profile_sidebar_border_color" value:profile_sidebar_border_color]]; + } + + if (profile_sidebar_fill_color.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"profile_sidebar_fill_color" value:profile_sidebar_fill_color]]; + } + + if (profile_text_color.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"profile_text_color" value:profile_text_color]]; + } + + return [self sendPOSTRequest:request withParameters:params]; +} + +- (NSError *)setUseProfileBackgroundImage:(BOOL)shouldUseBGImg { + NSURL *baseURL = [NSURL URLWithString:url_account_update_profile_background_image]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *skipStatus = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + OARequestParameter *useImage = [OARequestParameter requestParameterWithName:@"profile_use_background_image" value:shouldUseBGImg?@"true":@"false"]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:skipStatus, useImage, nil]]; +} + +- (NSError *)setProfileBackgroundImageWithImageData:(NSData *)data tiled:(BOOL)isTiled { + if (data.length == 0) { + return getBadRequestError(); + } + + if (data.length >= 800000) { + return [NSError errorWithDomain:@"The image you are trying to upload is too large." code:422 userInfo:nil]; + } + + NSURL *baseURL = [NSURL URLWithString:url_account_update_profile_background_image]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *tiled = [OARequestParameter requestParameterWithName:@"tiled" value:isTiled?@"true":@"false"]; + OARequestParameter *skipStatus = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + OARequestParameter *useImage = [OARequestParameter requestParameterWithName:@"profile_use_background_image" value:@"true"]; + OARequestParameter *image = [OARequestParameter requestParameterWithName:@"image" value:[data base64EncodingWithLineLength:0]]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:tiled, skipStatus, useImage, image, nil]]; +} + +- (NSError *)setProfileBackgroundImageWithImageAtPath:(NSString *)file tiled:(BOOL)isTiled { + return [self setProfileBackgroundImageWithImageData:[NSData dataWithContentsOfFile:file] tiled:isTiled]; +} + +- (NSError *)setProfileImageWithImageData:(NSData *)data { + if (data.length == 0) { + return getBadRequestError(); + } + + if (data.length >= 700000) { + return [NSError errorWithDomain:@"The image you are trying to upload is too large." code:422 userInfo:nil]; + } + + NSURL *baseURL = [NSURL URLWithString:url_account_update_profile_image]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *skipStatus = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + OARequestParameter *image = [OARequestParameter requestParameterWithName:@"image" value:[data base64EncodingWithLineLength:0]]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:image, skipStatus, nil]]; +} + +- (NSError *)setProfileImageWithImageAtPath:(NSString *)file { + return [self setProfileImageWithImageData:[NSData dataWithContentsOfFile:file]]; +} + +- (id)getUserSettings { + NSURL *baseURL = [NSURL URLWithString:url_account_settings]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + return [self sendGETRequest:request withParameters:nil]; +} + +- (NSError *)updateUserProfileWithDictionary:(NSDictionary *)settings { + + if (!settings) { + return getBadRequestError(); + } + + // all of the values are just non-normalized strings. They appear: + + // setting - length in characters + // name - 20 + // url - 100 + // location - 30 + // description - 160 + + NSString *name = [settings objectForKey:FHSProfileNameKey]; + NSString *url = [settings objectForKey:FHSProfileURLKey]; + NSString *location = [settings objectForKey:FHSProfileLocationKey]; + NSString *description = [settings objectForKey:FHSProfileDescriptionKey]; + + NSURL *baseURL = [NSURL URLWithString:url_account_update_profile]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *skipStatus = [OARequestParameter requestParameterWithName:@"skip_status" value:@"true"]; + + NSMutableArray *params = [NSMutableArray arrayWithObjects:skipStatus, nil]; + + if (name.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"name" value:name]]; + } + + if (url.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"url" value:url]]; + } + + if (location.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"location" value:location]]; + } + + if (description.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"description" value:description]]; + } + + return [self sendPOSTRequest:request withParameters:params]; +} + +- (NSError *)updateSettingsWithDictionary:(NSDictionary *)settings { + + if (!settings) { + return getBadRequestError(); + } + + // Dictionary with keys: + // All strings... You could have guessed that. + // sleep_time_enabled - true/false + // start_sleep_time - UTC time + // end_sleep_time - UTC time + // time_zone - Europe/Copenhagen, Pacific/Tongatapu + // lang - en, it, es + + NSString *sleep_time_enabled = [settings objectForKey:@"sleep_time_enabled"]; + NSString *start_sleep_time = [settings objectForKey:@"start_sleep_time"]; + NSString *end_sleep_time = [settings objectForKey:@"end_sleep_time"]; + NSString *time_zone = [settings objectForKey:@"time_zone"]; + NSString *lang = [settings objectForKey:@"lang"]; + + NSURL *baseURL = [NSURL URLWithString:url_account_settings]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + + NSMutableArray *params = [NSMutableArray array]; + + if (sleep_time_enabled.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"sleep_time_enabled" value:sleep_time_enabled]]; + } + + if (start_sleep_time.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"start_sleep_time" value:start_sleep_time]]; + } + + if (end_sleep_time.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"end_sleep_time" value:end_sleep_time]]; + } + + if (time_zone.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"time_zone" value:time_zone]]; + } + + if (lang.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"lang" value:lang]]; + } + + return [self sendPOSTRequest:request withParameters:params]; +} + +- (id)lookupUsers:(NSArray *)users areIDs:(BOOL)areIDs { + + if (users.count == 0) { + return nil; + } + + if (users.count > 100) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_users_lookup]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *usernames = [OARequestParameter requestParameterWithName:areIDs?@"user_id":@"screen_name" value:[users componentsJoinedByString:@","]]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:usernames, nil]]; +} + +- (NSError *)unblock:(NSString *)username { + + if (username.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_blocks_destroy]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *usernameP = [OARequestParameter requestParameterWithName:@"screen_name" value:username]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:usernameP, nil]]; +} + +- (NSError *)block:(NSString *)username { + + if (username.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_blocks_create]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *usernameP = [OARequestParameter requestParameterWithName:@"screen_name" value:username]; + return [self sendPOSTRequest:request withParameters:[NSArray arrayWithObjects:usernameP, nil]]; +} + +- (id)testService { + NSURL *baseURL = [NSURL URLWithString:url_help_test]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + + id retValue = [self sendGETRequest:request withParameters:nil]; + + if ([retValue isKindOfClass:[NSString class]]) { + if ([(NSString *)retValue isEqualToString:@"ok"]) { + return @"YES"; + } else { + return @"NO"; + } + } else if ([retValue isKindOfClass:[NSError class]]) { + return retValue; + } + + return getBadRequestError(); +} + +- (id)getHomeTimelineSinceID:(NSString *)sinceID count:(int)count { + + if (count == 0) { + return nil; + } + + NSURL *baseURL = [NSURL URLWithString:url_statuses_home_timeline]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *countParam = [OARequestParameter requestParameterWithName:@"count" value:[NSString stringWithFormat:@"%d", count]]; + + NSMutableArray *params = [NSMutableArray arrayWithObjects:countParam, nil]; + + if (sinceID.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"since_id" value:sinceID]]; + } + + return [self sendGETRequest:request withParameters:params]; +} + +- (NSError *)postTweet:(NSString *)tweetString inReplyTo:(NSString *)inReplyToString { + + if (tweetString.length == 0) { + return getBadRequestError(); + } + + NSURL *baseURL = [NSURL URLWithString:url_statuses_update]; + OARequestParameter *status = [OARequestParameter requestParameterWithName:@"status" value:[tweetString fhs_trimForTwitter]]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + + NSMutableArray *params = [NSMutableArray arrayWithObjects:status, nil]; + + if (inReplyToString.length > 0) { + [params addObject:[OARequestParameter requestParameterWithName:@"in_reply_to_status_id" value:inReplyToString]]; + } + + return [self sendPOSTRequest:request withParameters:params]; +} + +- (NSError *)postTweet:(NSString *)tweetString { + return [self postTweet:tweetString inReplyTo:nil]; +} + +- (id)getFollowersIDs { + NSURL *baseURL = [NSURL URLWithString:url_followers_ids]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *param = [OARequestParameter requestParameterWithName:@"screen_name" value:self.loggedInUsername]; + OARequestParameter *stringify_ids = [OARequestParameter requestParameterWithName:@"stringify_ids" value:@"true"]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:param, stringify_ids, nil]]; +} + +- (id)getFriendsIDs { + NSURL *baseURL = [NSURL URLWithString:url_friends_ids]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken]; + OARequestParameter *param = [OARequestParameter requestParameterWithName:@"screen_name" value:self.loggedInUsername]; + OARequestParameter *stringify_ids = [OARequestParameter requestParameterWithName:@"stringify_ids" value:@"true"]; + return [self sendGETRequest:request withParameters:[NSArray arrayWithObjects:param, stringify_ids, nil]]; +} + +- (id)init { + self = [super init]; + if (self) { + // Twitter API datestamps are UTC + // Don't question this code. + self.dateFormatter = [[[NSDateFormatter alloc]init]autorelease]; + _dateFormatter.locale = [[[NSLocale alloc]initWithLocaleIdentifier:@"en_US"]autorelease]; + _dateFormatter.dateStyle = NSDateFormatterLongStyle; + _dateFormatter.formatterBehavior = NSDateFormatterBehavior10_4; + _dateFormatter.dateFormat = @"EEE MMM dd HH:mm:ss ZZZZ yyyy"; + } + return self; +} + +// The shared* class method ++ (FHSTwitterEngine *)sharedEngine { + @synchronized (self) { + if (sharedInstance == nil) { + [[self alloc]init]; + } + } + return sharedInstance; +} + +// Override stuff to make sure that the singleton is never dealloc'd. Fun. ++ (id)allocWithZone:(NSZone *)zone { + @synchronized(self) { + if (sharedInstance == nil) { + sharedInstance = [super allocWithZone:zone]; + return sharedInstance; + } + } + return nil; +} + +- (id)retain { + return self; +} + +- (oneway void)release { + // Do nothing +} + +- (id)autorelease { + return self; +} + +- (NSUInteger)retainCount { + return NSUIntegerMax; +} + +- (NSArray *)generateRequestStringsFromArray:(NSArray *)array { + + NSString *initialString = [array componentsJoinedByString:@","]; + + if (array.count <= 100) { + return [NSArray arrayWithObjects:initialString, nil]; + } + + int offset = 0; + int remainder = fmod(array.count, 100); + int numberOfStrings = (array.count-remainder)/100; + + NSMutableArray *reqStrs = [NSMutableArray array]; + + for (int i = 1; i <= numberOfStrings; ++i) { + NSString *ninetyNinththItem = (NSString *)[array objectAtIndex:(i*100)-1]; + NSRange range = [initialString rangeOfString:ninetyNinththItem]; + int endOffset = range.location+range.length; + NSRange rangeOfAString = NSMakeRange(offset, endOffset-offset); + offset = endOffset; + NSString *endResult = [initialString fhs_stringWithRange:rangeOfAString]; + + if ([[endResult substringToIndex:1]isEqualToString:@","]) { + endResult = [endResult substringFromIndex:1]; + } + + [reqStrs addObject:endResult]; + } + + NSString *remainderString = [initialString stringByReplacingOccurrencesOfString:[reqStrs componentsJoinedByString:@","] withString:@""]; + + if ([[remainderString substringToIndex:1]isEqualToString:@","]) { + remainderString = [remainderString substringFromIndex:1]; + } + + [reqStrs addObject:remainderString]; + + return reqStrs; +} + +// +// XAuth +// + +- (NSError *)getXAuthAccessTokenForUsername:(NSString *)username password:(NSString *)password { + + if (password.length == 0) { + return [NSError errorWithDomain:@"Bad Request: The request you are trying to make is missing parameters." code:400 userInfo:nil]; + } + + if (username.length == 0) { + return [NSError errorWithDomain:@"Bad Request: The request you are trying to make is missing parameters." code:400 userInfo:nil]; + } + + NSURL *baseURL = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:nil]; + OARequestParameter *x_auth_mode = [OARequestParameter requestParameterWithName:@"x_auth_mode" value:@"client_auth"]; + OARequestParameter *x_auth_username = [OARequestParameter requestParameterWithName:@"x_auth_username" value:username]; + OARequestParameter *x_auth_password = [OARequestParameter requestParameterWithName:@"x_auth_password" value:password]; + [request setHTTPMethod:@"POST"]; + + [request setParameters:[NSArray arrayWithObjects:x_auth_mode, x_auth_username, x_auth_password, nil]]; + [request prepare]; + + if (self.shouldClearConsumer) { + self.shouldClearConsumer = NO; + self.consumer = nil; + } + + id ret = [self sendRequest:request]; + + if ([ret isKindOfClass:[NSError class]]) { + return ret; + } + + NSString *httpBody = [[[NSString alloc]initWithData:(NSData *)ret encoding:NSUTF8StringEncoding]autorelease]; + + if (httpBody.length > 0) { + [self storeAccessToken:httpBody]; + } else { + [self storeAccessToken:nil]; + return [NSError errorWithDomain:@"Twitter messed up and did not return anything for some reason. Please try again later." code:500 userInfo:nil]; + } + return nil; +} + +// +// sendRequest: +// + +- (id)sendRequest:(NSURLRequest *)request { + + NSHTTPURLResponse *response = nil; + NSError *error = nil; + + NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; + + if (error) { + return error; + } + + if (response == nil) { + return error; + } + + if (response.statusCode >= 304) { + return error; + } + + if (data.length == 0) { + return error; + } + + return data; +} + + +- (NSError *)sendPOSTRequest:(OAMutableURLRequest *)request withParameters:(NSArray *)params { + + if (![self isAuthorized]) { + [self loadAccessToken]; + if (![self isAuthorized]) { + return [NSError errorWithDomain:@"You are not authorized via OAuth" code:401 userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]]; + } + } + + [request setHTTPMethod:@"POST"]; + [request setParameters:params]; + [request prepare]; + + if (_shouldClearConsumer) { + self.shouldClearConsumer = NO; + self.consumer = nil; + } + + id retobj = [self sendRequest:request]; + + if (retobj == nil) { + return getNilReturnLengthError(); + } + + if ([retobj isKindOfClass:[NSError class]]) { + return retobj; + } + + id parsedJSONResponse = removeNull([NSJSONSerialization JSONObjectWithData:(NSData *)retobj options:NSJSONReadingMutableContainers error:nil]); + + if ([parsedJSONResponse isKindOfClass:[NSDictionary class]]) { + NSString *errorMessage = [parsedJSONResponse objectForKey:@"error"]; + NSArray *errorArray = [parsedJSONResponse objectForKey:@"errors"]; + if (errorMessage.length > 0) { + return [NSError errorWithDomain:errorMessage code:[[parsedJSONResponse objectForKey:@"code"]intValue] userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]]; + } else if (errorArray.count > 0) { + if (errorArray.count > 1) { + return [NSError errorWithDomain:@"Multiple Errors" code:1337 userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]]; + } else { + NSDictionary *theError = [errorArray objectAtIndex:0]; + return [NSError errorWithDomain:[theError objectForKey:@"message"] code:[[theError objectForKey:@"code"]integerValue] userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]]; + } + } + } + + return nil; +} + +- (id)sendGETRequest:(OAMutableURLRequest *)request withParameters:(NSArray *)params { + + if (![self isAuthorized]) { + [self loadAccessToken]; + if (![self isAuthorized]) { + return [NSError errorWithDomain:@"You are not authorized via OAuth" code:401 userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]]; + } + } + + [request setHTTPMethod:@"GET"]; + [request setParameters:params]; + [request prepare]; + + if (_shouldClearConsumer) { + self.shouldClearConsumer = NO; + self.consumer = nil; + } + + id retobj = [self sendRequest:request]; + + if (retobj == nil) { + return getNilReturnLengthError(); + } + + if ([retobj isKindOfClass:[NSError class]]) { + return retobj; + } + + id parsedJSONResponse = removeNull([NSJSONSerialization JSONObjectWithData:(NSData *)retobj options:NSJSONReadingMutableContainers error:nil]); + + if ([parsedJSONResponse isKindOfClass:[NSDictionary class]]) { + NSString *errorMessage = [parsedJSONResponse objectForKey:@"error"]; + NSArray *errorArray = [parsedJSONResponse objectForKey:@"errors"]; + if (errorMessage.length > 0) { + return [NSError errorWithDomain:errorMessage code:[[parsedJSONResponse objectForKey:@"code"]intValue] userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]]; + } else if (errorArray.count > 0) { + if (errorArray.count > 1) { + return [NSError errorWithDomain:@"Multiple Errors" code:1337 userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]]; + } else { + NSDictionary *theError = [errorArray objectAtIndex:0]; + return [NSError errorWithDomain:[theError objectForKey:@"message"] code:[[theError objectForKey:@"code"]integerValue] userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]]; + } + } + } + + return parsedJSONResponse; +} + + +// +// OAuth +// + +- (NSString *)getRequestTokenString { + NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/request_token"]; + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:url consumer:self.consumer token:nil]; + [request setHTTPMethod:@"POST"]; + [request prepare]; + + id retobj = [self sendRequest:request]; + + if ([retobj isKindOfClass:[NSData class]]) { + return [[[NSString alloc]initWithData:(NSData *)retobj encoding:NSUTF8StringEncoding]autorelease]; + } + + return nil; +} + +- (BOOL)finishAuthWithRequestToken:(OAToken *)reqToken { + + NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"]; + + OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:url consumer:self.consumer token:reqToken]; + [request setHTTPMethod:@"POST"]; + [request prepare]; + + if (_shouldClearConsumer) { + self.shouldClearConsumer = NO; + self.consumer = nil; + } + + id retobj = [self sendRequest:request]; + + if ([retobj isKindOfClass:[NSError class]]) { + return NO; + } + + NSString *response = [[[NSString alloc]initWithData:(NSData *)retobj encoding:NSUTF8StringEncoding]autorelease]; + + if (response.length == 0) { + return NO; + } + + [self storeAccessToken:response]; + + return YES; +} + +// +// Access Token Management +// + +- (void)loadAccessToken { + + NSString *savedHttpBody = nil; + + if (self.delegate && [self.delegate respondsToSelector:@selector(loadAccessToken)]) { + savedHttpBody = [self.delegate loadAccessToken]; + } else { + savedHttpBody = [[NSUserDefaults standardUserDefaults]objectForKey:@"SavedAccessHTTPBody"]; + } + + self.accessToken = [OAToken tokenWithHTTPResponseBody:savedHttpBody]; + self.loggedInUsername = [self extractValueForKey:@"screen_name" fromHTTPBody:savedHttpBody]; + self.loggedInID = [self extractValueForKey:@"user_id" fromHTTPBody:savedHttpBody]; +} + +- (void)storeAccessToken:(NSString *)accessTokenZ { + self.accessToken = [OAToken tokenWithHTTPResponseBody:accessTokenZ]; + self.loggedInUsername = [self extractValueForKey:@"screen_name" fromHTTPBody:accessTokenZ]; + self.loggedInID = [self extractValueForKey:@"user_id" fromHTTPBody:accessTokenZ]; + + if ([self.delegate respondsToSelector:@selector(storeAccessToken:)]) { + [self.delegate storeAccessToken:accessTokenZ]; + } else { + [[NSUserDefaults standardUserDefaults]setObject:accessTokenZ forKey:@"SavedAccessHTTPBody"]; + } +} + +- (NSString *)extractValueForKey:(NSString *)target fromHTTPBody:(NSString *)body { + if (body.length == 0) { + return nil; + } + + if (target.length == 0) { + return nil; + } + + NSArray *tuples = [body componentsSeparatedByString:@"&"]; + if (tuples.count < 1) { + return nil; + } + + for (NSString *tuple in tuples) { + NSArray *keyValueArray = [tuple componentsSeparatedByString:@"="]; + + if (keyValueArray.count >= 2) { + NSString *key = [keyValueArray objectAtIndex:0]; + NSString *value = [keyValueArray objectAtIndex:1]; + + if ([key isEqualToString:target]) { + return value; + } + } + } + + return nil; +} + +- (BOOL)isAuthorized { + if (!self.consumer) { + return NO; + } + + if (self.accessToken.key && self.accessToken.secret) { + if (self.accessToken.key.length > 0 && self.accessToken.secret.length > 0) { + return YES; + } + } + + return NO; +} + +- (void)clearAccessToken { + [self storeAccessToken:@""]; + self.accessToken = nil; + self.loggedInUsername = nil; +} + +- (NSDate *)getDateFromTwitterCreatedAt:(NSString *)twitterDate { + return [self.dateFormatter dateFromString:twitterDate]; +} + +- (void)clearConsumer { + self.consumer = nil; +} + +- (void)permanentlySetConsumerKey:(NSString *)consumerKey andSecret:(NSString *)consumerSecret { + self.shouldClearConsumer = NO; + self.consumer = [OAConsumer consumerWithKey:consumerKey secret:consumerSecret]; +} + +- (void)temporarilySetConsumerKey:(NSString *)consumerKey andSecret:(NSString *)consumerSecret { + self.shouldClearConsumer = YES; + self.consumer = [OAConsumer consumerWithKey:consumerKey secret:consumerSecret]; +} + +- (void)showOAuthLoginControllerFromViewController:(UIViewController *)sender { + [self showOAuthLoginControllerFromViewController:sender withCompletion:nil]; +} + +- (void)showOAuthLoginControllerFromViewController:(UIViewController *)sender withCompletion:(void(^)(BOOL success))block { + FHSTwitterEngineController *vc = [[[FHSTwitterEngineController alloc]init]autorelease]; + vc.modalTransitionStyle = UIModalTransitionStyleCoverVertical; + objc_setAssociatedObject(authBlockKey, "FHSTwitterEngineOAuthCompletion", block, OBJC_ASSOCIATION_COPY_NONATOMIC); + [sender presentModalViewController:vc animated:YES]; +} + ++ (BOOL)isConnectedToInternet { + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress); + if (reachability) { + SCNetworkReachabilityFlags flags; + BOOL worked = SCNetworkReachabilityGetFlags(reachability, &flags); + CFRelease(reachability); + + if (worked) { + + if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) { + return NO; + } + + if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) { + return YES; + } + + + if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0) || (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) { + if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) { + return YES; + } + } + + if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) { + return YES; + } + } + + } + return NO; +} + +- (void)dealloc { + [self setConsumer:nil]; + [self setDateFormatter:nil]; + [self setLoggedInUsername:nil]; + [self setLoggedInID:nil]; + [self setDelegate:nil]; + [self setAccessToken:nil]; + [super dealloc]; +} + +@end + +@implementation FHSTwitterEngineController + +static NSString * const newPinJS = @"var d = document.getElementById('oauth-pin'); if (d == null) d = document.getElementById('oauth_pin'); if (d) { var d2 = d.getElementsByTagName('code'); if (d2.length > 0) d2[0].innerHTML; }"; +static NSString * const oldPinJS = @"var d = document.getElementById('oauth-pin'); if (d == null) d = document.getElementById('oauth_pin'); if (d) d = d.innerHTML; d;"; + +- (void)loadView { + [super loadView]; + [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(pasteboardChanged:) name:UIPasteboardChangedNotification object:nil]; + + self.view = [[[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 460)]autorelease]; + self.view.backgroundColor = [UIColor grayColor]; + self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + self.theWebView = [[[UIWebView alloc]initWithFrame:CGRectMake(0, 44, 320, 416)]autorelease]; + _theWebView.hidden = YES; + _theWebView.delegate = self; + _theWebView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _theWebView.dataDetectorTypes = UIDataDetectorTypeNone; + _theWebView.backgroundColor = [UIColor darkGrayColor]; + + self.navBar = [[[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 44)]autorelease]; + _navBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; + + [self.view addSubview:_theWebView]; + [self.view addSubview:_navBar]; + + self.blockerView = [[[UIView alloc]initWithFrame:CGRectMake(0, 0, 200, 60)]autorelease]; + _blockerView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.8]; + _blockerView.center = CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2); + _blockerView.clipsToBounds = YES; + _blockerView.layer.cornerRadius = 10; + + self.pinCopyBar = [[[UIToolbar alloc]initWithFrame:CGRectMake(0, 44, self.view.bounds.size.width, 44)]autorelease]; + _pinCopyBar.barStyle = UIBarStyleBlackTranslucent; + _pinCopyBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; + _pinCopyBar.items = [NSArray arrayWithObjects:[[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]autorelease], [[[UIBarButtonItem alloc]initWithTitle:@"Select and Copy the PIN" style: UIBarButtonItemStylePlain target:nil action: nil]autorelease], [[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]autorelease], nil]; + + UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 5, _blockerView.bounds.size.width, 15)]; + label.text = @"Please Wait..."; + label.backgroundColor = [UIColor clearColor]; + label.textColor = [UIColor whiteColor]; + label.textAlignment = UITextAlignmentCenter; + label.font = [UIFont boldSystemFontOfSize:15]; + [_blockerView addSubview:label]; + [label release]; + + UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; + spinner.center = CGPointMake(_blockerView.bounds.size.width/2, (_blockerView.bounds.size.height/2)+10); + [_blockerView addSubview:spinner]; + [self.view addSubview:_blockerView]; + [spinner startAnimating]; + [spinner release]; + + UINavigationItem *navItem = [[[UINavigationItem alloc]initWithTitle:@"Twitter Login"]autorelease]; + navItem.leftBarButtonItem = [[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(close)]autorelease]; + [_navBar pushNavigationItem:navItem animated:NO]; + + [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; + + dispatch_async(GCDBackgroundThread, ^{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; + + NSString *reqString = [[FHSTwitterEngine sharedEngine]getRequestTokenString]; + + if (reqString.length == 0) { + [self dismissModalViewControllerAnimated:YES]; + [pool release]; + return; + } + + self.requestToken = [OAToken tokenWithHTTPResponseBody:reqString]; + NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.twitter.com/oauth/authorize?oauth_token=%@",_requestToken.key]]]; + + dispatch_sync(GCDMainThread, ^{ + NSAutoreleasePool *poolTwo = [[NSAutoreleasePool alloc]init]; + [_theWebView loadRequest:request]; + [poolTwo release]; + }); + + [pool release]; + }); +} + +- (void)gotPin:(NSString *)pin { + _requestToken.verifier = pin; + BOOL ret = [[FHSTwitterEngine sharedEngine]finishAuthWithRequestToken:_requestToken]; + + void(^block)(BOOL success) = objc_getAssociatedObject(authBlockKey, "FHSTwitterEngineOAuthCompletion"); + objc_removeAssociatedObjects(authBlockKey); + + if (block) { + block(ret); + } + + [self dismissModalViewControllerAnimated:YES]; +} + +- (void)pasteboardChanged:(NSNotification *)note { + + if (![note.userInfo objectForKey:UIPasteboardChangedTypesAddedKey]) { + return; + } + + NSString *string = [[UIPasteboard generalPasteboard]string]; + + if (string.length != 7 || !string.fhs_isNumeric) { + return; + } + + [self gotPin:string]; +} + +- (NSString *)locatePin { + NSString *pin = [[_theWebView stringByEvaluatingJavaScriptFromString:newPinJS]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + + if (pin.length == 7) { + return pin; + } else { + pin = [[_theWebView stringByEvaluatingJavaScriptFromString:oldPinJS]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + + if (pin.length == 7) { + return pin; + } + } + + return nil; +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView { + _theWebView.userInteractionEnabled = YES; + NSString *authPin = [self locatePin]; + + if (authPin.length > 0) { + [self gotPin:authPin]; + return; + } + + NSString *formCount = [webView stringByEvaluatingJavaScriptFromString:@"document.forms.length"]; + + if ([formCount isEqualToString:@"0"]) { + [self showPinCopyPrompt]; + } + + [UIView beginAnimations:nil context:nil]; + _blockerView.hidden = YES; + [UIView commitAnimations]; + + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; + + _theWebView.hidden = NO; +} + +- (void)showPinCopyPrompt { + if (_pinCopyBar.superview) { + return; + } + + _pinCopyBar.center = CGPointMake(_pinCopyBar.bounds.size.width/2, _pinCopyBar.bounds.size.height/2); + [self.view insertSubview:_pinCopyBar belowSubview:_navBar]; + + [UIView beginAnimations:nil context:nil]; + _pinCopyBar.center = CGPointMake(_pinCopyBar.bounds.size.width/2, _navBar.bounds.size.height+_pinCopyBar.bounds.size.height/2); + [UIView commitAnimations]; +} + +- (void)webViewDidStartLoad:(UIWebView *)webView { + _theWebView.userInteractionEnabled = NO; + [_theWebView setHidden:YES]; + [_blockerView setHidden:NO]; + [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; +} + +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { + + if (strstr([request.URL.absoluteString UTF8String], "denied=")) { + [self dismissModalViewControllerAnimated:YES]; + return NO; + } + + NSData *data = request.HTTPBody; + char *raw = data?(char *)[data bytes]:""; + + if (raw && (strstr(raw, "cancel=") || strstr(raw, "deny="))) { + [self dismissModalViewControllerAnimated:YES]; + return NO; + } + + return YES; +} + +- (void)close { + [self dismissModalViewControllerAnimated:YES]; +} + +- (void)dismissModalViewControllerAnimated:(BOOL)animated { + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; + [[NSNotificationCenter defaultCenter]removeObserver:self]; + [_theWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@""]]]; + [super dismissModalViewControllerAnimated:animated]; +} + +- (void)dealloc { + [self setNavBar:nil]; + [self setBlockerView:nil]; + [self setPinCopyBar:nil]; + [self setTheWebView:nil]; + [self setRequestToken:nil]; + [super dealloc]; +} + +@end + + +static char const encodingTable[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' }; + +@implementation NSData (Base64) + ++ (NSData *)dataWithBase64EncodedString:(NSString *)string { + return [[[NSData alloc]initWithBase64EncodedString:string]autorelease]; +} + +- (id)initWithBase64EncodedString:(NSString *)string { + NSMutableData *mutableData = nil; + + if (string) { + unsigned long ixtext = 0; + unsigned char ch = 0; + unsigned char inbuf[4] = {0,0,0,0}; + unsigned char outbuf[3] = {0,0,0}; + short ixinbuf = 0; + BOOL flignore = NO; + BOOL flendtext = NO; + + NSData *base64Data = [string dataUsingEncoding:NSASCIIStringEncoding]; + const unsigned char *base64Bytes = [base64Data bytes]; + mutableData = [NSMutableData dataWithCapacity:base64Data.length]; + unsigned long lentext = [base64Data length]; + + while (!(ixtext >= lentext)) { + + ch = base64Bytes[ixtext++]; + flignore = NO; + + if ((ch >= 'A') && (ch <= 'Z')) { + ch = ch - 'A'; + } else if ((ch >= 'a') && (ch <= 'z')) { + ch = ch - 'a' + 26; + } else if ((ch >= '0') && (ch <= '9')) { + ch = ch - '0' + 52; + } else if (ch == '+') { + ch = 62; + } else if (ch == '=') { + flendtext = YES; + } else if (ch == '/') { + ch = 63; + } else { + flignore = YES; + } + + if (!flignore) { + short ctcharsinbuf = 3; + BOOL flbreak = NO; + + if (flendtext) { + if (!ixinbuf) { + break; + } + + if (ixinbuf == 1 || ixinbuf == 2) { + ctcharsinbuf = 1; + } else { + ctcharsinbuf = 2; + } + + ixinbuf = 3; + flbreak = YES; + } + + inbuf[ixinbuf++] = ch; + + if (ixinbuf == 4) { + ixinbuf = 0; + outbuf[0] = (inbuf[0] << 2) | ((inbuf[1] & 0x30) >> 4); + outbuf[1] = ((inbuf[1] & 0x0F) << 4) | ((inbuf[2] & 0x3C) >> 2); + outbuf[2] = ((inbuf[2] & 0x03) << 6) | (inbuf[3] & 0x3F); + + for (int i = 0; i < ctcharsinbuf; i++) { + [mutableData appendBytes:&outbuf[i] length:1]; + } + } + + if (flbreak) { + break; + } + } + } + } + + self = [self initWithData:mutableData]; + return self; +} + +- (NSString *)base64EncodingWithLineLength:(unsigned int)lineLength { + + const unsigned char *bytes = [self bytes]; + unsigned long ixtext = 0; + unsigned long lentext = [self length]; + long ctremaining = 0; + unsigned char inbuf[3] = {0,0,0}; + unsigned char outbuf[4] = {0,0,0,0}; + + short charsonline = 0; + short ctcopy = 0; + unsigned long ix = 0; + + NSMutableString *result = [NSMutableString stringWithCapacity:lentext]; + + while (YES) { + ctremaining = lentext-ixtext; + + if (ctremaining <= 0) { + break; + } + + for (int i = 0; i < 3; i++) { + ix = ixtext + i; + inbuf[i] = (ix < lentext)?bytes[ix]:0; + } + + outbuf[0] = (inbuf[0] & 0xFC) >> 2; + outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf[1] & 0xF0) >> 4); + outbuf[2] = ((inbuf[1] & 0x0F) << 2) | ((inbuf[2] & 0xC0) >> 6); + outbuf[3] = inbuf[2] & 0x3F; + + switch (ctremaining) { + case 1: + ctcopy = 2; + break; + case 2: + ctcopy = 3; + break; + default: + ctcopy = 4; + break; + } + + for (int i = 0; i < ctcopy; i++) { + [result appendFormat:@"%c",encodingTable[outbuf[i]]]; + } + + for (int i = ctcopy; i < 4; i++) { + [result appendString:@"="]; + } + + ixtext += 3; + charsonline += 4; + + if (lineLength > 0) { + if (charsonline >= lineLength) { + charsonline = 0; + [result appendString:@"\n"]; + } + } + } + return result; +} + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Categories/NSString+URLEncoding.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Categories/NSString+URLEncoding.h new file mode 100755 index 0000000000..de06fe773c --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Categories/NSString+URLEncoding.h @@ -0,0 +1,34 @@ +// +// NSString+URLEncoding.h +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface NSString (OAURLEncodingAdditions) + +- (NSString *)URLEncodedString; +- (NSString *)URLDecodedString; + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Categories/NSString+URLEncoding.m b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Categories/NSString+URLEncoding.m new file mode 100755 index 0000000000..c4536ae934 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Categories/NSString+URLEncoding.m @@ -0,0 +1,44 @@ +// +// NSString+URLEncoding.m +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSString+URLEncoding.h" + +@implementation NSString (OAURLEncodingAdditions) + +- (NSString *)URLEncodedString { + CFStringRef url = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR("!*'();:@&=+$,/?%#[]"), kCFStringEncodingUTF8); // for some reason, releasing this is disasterous + NSString *result = (NSString *)url; + [result autorelease]; + return result; +} + +- (NSString *)URLDecodedString { + CFStringRef url = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)self, CFSTR(""), kCFStringEncodingUTF8); + NSString *result = (NSString *)url; + [result autorelease]; + return result; +} + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Crytpo/Base64TranscoderFHS.c b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Crytpo/Base64TranscoderFHS.c new file mode 100755 index 0000000000..e222718b46 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Crytpo/Base64TranscoderFHS.c @@ -0,0 +1,225 @@ +/* + * Base64Transcoder.c + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Base64TranscoderFHS.h" + +#include +#include + +const u_int8_t kBase64EncodeTable_[64] = { + /* 0 */ 'A', /* 1 */ 'B', /* 2 */ 'C', /* 3 */ 'D', + /* 4 */ 'E', /* 5 */ 'F', /* 6 */ 'G', /* 7 */ 'H', + /* 8 */ 'I', /* 9 */ 'J', /* 10 */ 'K', /* 11 */ 'L', + /* 12 */ 'M', /* 13 */ 'N', /* 14 */ 'O', /* 15 */ 'P', + /* 16 */ 'Q', /* 17 */ 'R', /* 18 */ 'S', /* 19 */ 'T', + /* 20 */ 'U', /* 21 */ 'V', /* 22 */ 'W', /* 23 */ 'X', + /* 24 */ 'Y', /* 25 */ 'Z', /* 26 */ 'a', /* 27 */ 'b', + /* 28 */ 'c', /* 29 */ 'd', /* 30 */ 'e', /* 31 */ 'f', + /* 32 */ 'g', /* 33 */ 'h', /* 34 */ 'i', /* 35 */ 'j', + /* 36 */ 'k', /* 37 */ 'l', /* 38 */ 'm', /* 39 */ 'n', + /* 40 */ 'o', /* 41 */ 'p', /* 42 */ 'q', /* 43 */ 'r', + /* 44 */ 's', /* 45 */ 't', /* 46 */ 'u', /* 47 */ 'v', + /* 48 */ 'w', /* 49 */ 'x', /* 50 */ 'y', /* 51 */ 'z', + /* 52 */ '0', /* 53 */ '1', /* 54 */ '2', /* 55 */ '3', + /* 56 */ '4', /* 57 */ '5', /* 58 */ '6', /* 59 */ '7', + /* 60 */ '8', /* 61 */ '9', /* 62 */ '+', /* 63 */ '/' +}; + +/* +-1 = Base64 end of data marker. +-2 = White space (tabs, cr, lf, space) +-3 = Noise (all non whitespace, non-base64 characters) +-4 = Dangerous noise +-5 = Illegal noise (null byte) +*/ + +const int8_t kBase64DecodeTable_[128] = { + /* 0x00 */ -5, /* 0x01 */ -3, /* 0x02 */ -3, /* 0x03 */ -3, + /* 0x04 */ -3, /* 0x05 */ -3, /* 0x06 */ -3, /* 0x07 */ -3, + /* 0x08 */ -3, /* 0x09 */ -2, /* 0x0a */ -2, /* 0x0b */ -2, + /* 0x0c */ -2, /* 0x0d */ -2, /* 0x0e */ -3, /* 0x0f */ -3, + /* 0x10 */ -3, /* 0x11 */ -3, /* 0x12 */ -3, /* 0x13 */ -3, + /* 0x14 */ -3, /* 0x15 */ -3, /* 0x16 */ -3, /* 0x17 */ -3, + /* 0x18 */ -3, /* 0x19 */ -3, /* 0x1a */ -3, /* 0x1b */ -3, + /* 0x1c */ -3, /* 0x1d */ -3, /* 0x1e */ -3, /* 0x1f */ -3, + /* ' ' */ -2, /* '!' */ -3, /* '"' */ -3, /* '#' */ -3, + /* '$' */ -3, /* '%' */ -3, /* '&' */ -3, /* ''' */ -3, + /* '(' */ -3, /* ')' */ -3, /* '*' */ -3, /* '+' */ 62, + /* ',' */ -3, /* '-' */ -3, /* '.' */ -3, /* '/' */ 63, + /* '0' */ 52, /* '1' */ 53, /* '2' */ 54, /* '3' */ 55, + /* '4' */ 56, /* '5' */ 57, /* '6' */ 58, /* '7' */ 59, + /* '8' */ 60, /* '9' */ 61, /* ':' */ -3, /* ';' */ -3, + /* '<' */ -3, /* '=' */ -1, /* '>' */ -3, /* '?' */ -3, + /* '@' */ -3, /* 'A' */ 0, /* 'B' */ 1, /* 'C' */ 2, + /* 'D' */ 3, /* 'E' */ 4, /* 'F' */ 5, /* 'G' */ 6, + /* 'H' */ 7, /* 'I' */ 8, /* 'J' */ 9, /* 'K' */ 10, + /* 'L' */ 11, /* 'M' */ 12, /* 'N' */ 13, /* 'O' */ 14, + /* 'P' */ 15, /* 'Q' */ 16, /* 'R' */ 17, /* 'S' */ 18, + /* 'T' */ 19, /* 'U' */ 20, /* 'V' */ 21, /* 'W' */ 22, + /* 'X' */ 23, /* 'Y' */ 24, /* 'Z' */ 25, /* '[' */ -3, + /* '\' */ -3, /* ']' */ -3, /* '^' */ -3, /* '_' */ -3, + /* '`' */ -3, /* 'a' */ 26, /* 'b' */ 27, /* 'c' */ 28, + /* 'd' */ 29, /* 'e' */ 30, /* 'f' */ 31, /* 'g' */ 32, + /* 'h' */ 33, /* 'i' */ 34, /* 'j' */ 35, /* 'k' */ 36, + /* 'l' */ 37, /* 'm' */ 38, /* 'n' */ 39, /* 'o' */ 40, + /* 'p' */ 41, /* 'q' */ 42, /* 'r' */ 43, /* 's' */ 44, + /* 't' */ 45, /* 'u' */ 46, /* 'v' */ 47, /* 'w' */ 48, + /* 'x' */ 49, /* 'y' */ 50, /* 'z' */ 51, /* '{' */ -3, + /* '|' */ -3, /* '}' */ -3, /* '~' */ -3, /* 0x7f */ -3 +}; + +const u_int8_t kBits_00000011_ = 0x03; +const u_int8_t kBits_00001111_ = 0x0F; +const u_int8_t kBits_00110000_ = 0x30; +const u_int8_t kBits_00111100_ = 0x3C; +const u_int8_t kBits_00111111_ = 0x3F; +const u_int8_t kBits_11000000_ = 0xC0; +const u_int8_t kBits_11110000_ = 0xF0; +const u_int8_t kBits_11111100_ = 0xFC; + +size_t EstimateBas64EncodedDataSizeFHS(size_t inDataSize) { + size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4; + theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72; + return(theEncodedDataSize); +} + +size_t EstimateBas64DecodedDataSizeFHS(size_t inDataSize) { + size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3; + //theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72; + return(theDecodedDataSize); +} + +bool Base64EncodeDataFHS(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize) { + + size_t theEncodedDataSize = EstimateBas64EncodedDataSizeFHS(inInputDataSize); + if (*ioOutputDataSize < theEncodedDataSize) { + return false; + } + + *ioOutputDataSize = theEncodedDataSize; + const u_int8_t *theInPtr = (const u_int8_t *)inInputData; + u_int32_t theInIndex = 0, theOutIndex = 0; + for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3) { + outOutputData[theOutIndex++] = kBase64EncodeTable_[(theInPtr[theInIndex] & kBits_11111100_) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable_[(theInPtr[theInIndex] & kBits_00000011_) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000_) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable_[(theInPtr[theInIndex + 1] & kBits_00001111_) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000_) >> 6]; + outOutputData[theOutIndex++] = kBase64EncodeTable_[(theInPtr[theInIndex + 2] & kBits_00111111_) >> 0]; + + if (theOutIndex % 74 == 72) { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } + + const size_t theRemainingBytes = inInputDataSize - theInIndex; + + if (theRemainingBytes == 1) { + outOutputData[theOutIndex++] = kBase64EncodeTable_[(theInPtr[theInIndex] & kBits_11111100_) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable_[(theInPtr[theInIndex] & kBits_00000011_) << 4 | (0 & kBits_11110000_) >> 4]; + outOutputData[theOutIndex++] = '='; + outOutputData[theOutIndex++] = '='; + + if (theOutIndex % 74 == 72) { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } else if (theRemainingBytes == 2) { + outOutputData[theOutIndex++] = kBase64EncodeTable_[(theInPtr[theInIndex] & kBits_11111100_) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable_[(theInPtr[theInIndex] & kBits_00000011_) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000_) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable_[(theInPtr[theInIndex + 1] & kBits_00001111_) << 2 | (0 & kBits_11000000_) >> 6]; + outOutputData[theOutIndex++] = '='; + + if (theOutIndex % 74 == 72) { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } + + return true; +} + +bool Base64DecodeData_(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize) { + + memset(ioOutputData, '.', *ioOutputDataSize); + + size_t theDecodedDataSize = EstimateBas64DecodedDataSizeFHS(inInputDataSize); + if (*ioOutputDataSize < theDecodedDataSize) { + return false; + } + + *ioOutputDataSize = 0; + const u_int8_t *theInPtr = (const u_int8_t *)inInputData; + u_int8_t *theOutPtr = (u_int8_t *)ioOutputData; + size_t theInIndex = 0, theOutIndex = 0; + u_int8_t theOutputOctet; + size_t theSequence = 0; + for (; theInIndex < inInputDataSize; ) { + int8_t theSextet = 0; + + int8_t theCurrentInputOctet = theInPtr[theInIndex]; + theSextet = kBase64DecodeTable_[theCurrentInputOctet]; + + if (theSextet == -1) { + break; + } + + while (theSextet == -2) { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable_[theCurrentInputOctet]; + } + + while (theSextet == -3) { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable_[theCurrentInputOctet]; + } + + if (theSequence == 0) { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100_; + } else if (theSequence == 1) { + theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011_; + theOutPtr[theOutIndex++] = theOutputOctet; + } else if (theSequence == 2) { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000_; + } else if (theSequence == 3) { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111_; + theOutPtr[theOutIndex++] = theOutputOctet; + } else if (theSequence == 4) { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000_; + } else if (theSequence == 5) { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111_; + theOutPtr[theOutIndex++] = theOutputOctet; + } + + theSequence = (theSequence+1)%6; + + if (theSequence != 2 && theSequence != 4) { + theInIndex++; + } + } + *ioOutputDataSize = theOutIndex; + return true; +} diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Crytpo/Base64TranscoderFHS.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Crytpo/Base64TranscoderFHS.h new file mode 100755 index 0000000000..fe03c3ad48 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/Crytpo/Base64TranscoderFHS.h @@ -0,0 +1,36 @@ +/* + * Base64Transcoder.h + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +extern size_t EstimateBas64EncodedDataSizeFHS(size_t inDataSize); +extern size_t EstimateBas64DecodedDataSizeFHS(size_t inDataSize); + +extern bool Base64EncodeDataFHS(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize); +extern bool Base64DecodeDataFHS(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize); + diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAConsumer.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAConsumer.h new file mode 100755 index 0000000000..920169d81e --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAConsumer.h @@ -0,0 +1,38 @@ +// +// OAConsumer.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + +@interface OAConsumer : NSObject + +@property (nonatomic, retain) NSString *key; +@property (nonatomic, retain) NSString *secret; + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; + ++ (OAConsumer *)consumerWithKey:(NSString *)aKey secret:(NSString *)aSecret; + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAConsumer.m b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAConsumer.m new file mode 100755 index 0000000000..4dada114bc --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAConsumer.m @@ -0,0 +1,48 @@ +// +// OAConsumer.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "OAConsumer.h" + +@implementation OAConsumer + ++ (OAConsumer *)consumerWithKey:(NSString *)aKey secret:(NSString *)aSecret { + return [[[[self class]alloc]initWithKey:aKey secret:aSecret]autorelease]; +} + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret { + if (self = [super init]) { + self.key = aKey; + self.secret = aSecret; + } + return self; +} + +- (void)dealloc { + [self setKey:nil]; + [self setSecret:nil]; + [super dealloc]; +} + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAHMAC_SHA1SignatureProvider.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAHMAC_SHA1SignatureProvider.h new file mode 100755 index 0000000000..6c2af1a18c --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAHMAC_SHA1SignatureProvider.h @@ -0,0 +1,38 @@ +// +// OAHMAC_SHA1SignatureProvider.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + +@protocol OASignatureProviding +- (NSString *)name; +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret; +@end + +@interface OAHMAC_SHA1SignatureProvider : NSObject + ++ (OAHMAC_SHA1SignatureProvider *)OAHMAC_SHA1SignatureProvider; + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAHMAC_SHA1SignatureProvider.m b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAHMAC_SHA1SignatureProvider.m new file mode 100755 index 0000000000..44996f2ec5 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAHMAC_SHA1SignatureProvider.m @@ -0,0 +1,60 @@ +// +// OAHMAC_SHA1SignatureProvider.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAHMAC_SHA1SignatureProvider.h" +#import +#include "Base64TranscoderFHS.h" + +@implementation OAHMAC_SHA1SignatureProvider + ++ (OAHMAC_SHA1SignatureProvider *)OAHMAC_SHA1SignatureProvider { + return [[[[self class]alloc]init]autorelease]; +} + +- (NSString *)name { + return @"HMAC-SHA1"; +} + +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret { + + NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding]; + NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding]; + unsigned char result[20]; + CCHmac(kCCHmacAlgSHA1, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], result); + + // Base64 Encoding + + char base64Result[32]; + size_t theResultLength = 32; + Base64EncodeDataFHS(result, 20, base64Result, &theResultLength); + NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength]; + + NSString *base64EncodedResult = [[NSString alloc]initWithData:theData encoding:NSUTF8StringEncoding]; + + return [base64EncodedResult autorelease]; +} + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAMutableURLRequest.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAMutableURLRequest.h new file mode 100755 index 0000000000..e0d0dfd1c4 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAMutableURLRequest.h @@ -0,0 +1,55 @@ +// +// OAMutableURLRequest.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OAConsumer.h" +#import "OAToken.h" +#import "OAHMAC_SHA1SignatureProvider.h" + +@class OAServiceTicket; + +@interface OAMutableURLRequest : NSMutableURLRequest + +@property (nonatomic, assign) NSString *signature; +@property (nonatomic, assign) NSString *nonce; +@property (nonatomic, assign) NSString *timestamp; + ++ (void)fetchDataForRequest:(OAMutableURLRequest *)request withCompletionHandler:(void(^)(OAServiceTicket *, NSData *, NSError *))block; + ++ (OAMutableURLRequest *)requestWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken realm:(NSString *)aRealm signatureProvider:(id)aProvider; + ++ (OAMutableURLRequest *)requestWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken; + +- (id)initWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken realm:(NSString *)aRealm signatureProvider:(id)aProvider; + +- (id)initWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken realm:(NSString *)aRealm signatureProvider:(id)aProvider nonce:(NSString *)aNonce timestamp:(NSString *)aTimestamp; + +- (void)prepare; +- (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)parameterValue; +- (NSArray *)parameters; +- (void)setParameters:(NSArray *)parameters; + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAMutableURLRequest.m b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAMutableURLRequest.m new file mode 100755 index 0000000000..d03e352916 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAMutableURLRequest.m @@ -0,0 +1,296 @@ +// +// OAMutableURLRequest.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAMutableURLRequest.h" +#import "OARequestParameter.h" +#import "OAServiceTicket.h" + +@interface OAMutableURLRequest () +- (void)_generateTimestamp; +- (void)_generateNonce; +- (NSString *)_signatureBaseString; + +@property (nonatomic, retain) OAConsumer *consumer; +@property (nonatomic, retain) OAToken *token; +@property (nonatomic, retain) NSString *realm; +@property (nonatomic, retain) id signatureProvider; +@property (nonatomic, retain) NSMutableDictionary *extraOAuthParameters; + +@end + +@interface NSURL (OABaseAdditions) +- (NSString *)URLStringWithoutQuery; +@end + +@implementation NSURL (OABaseAdditions) + +- (NSString *)URLStringWithoutQuery { + if (self.absoluteString.length == 0) { + return nil; + } + + NSArray *parts = [self.absoluteString componentsSeparatedByString:@"?"]; + return (parts.count == 0)?nil:[parts objectAtIndex:0]; +} + +@end + +@implementation OAMutableURLRequest + ++ (void)fetchDataForRequest:(OAMutableURLRequest *)request withCompletionHandler:(void(^)(OAServiceTicket *, NSData *, NSError *))block { + [request prepare]; + + [NSURLConnection sendAsynchronousRequest:request queue:[[[NSOperationQueue alloc]init]autorelease] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { + OAServiceTicket *ticket = [[[OAServiceTicket alloc]initWithRequest:request response:response didSucceed:(error == nil)]autorelease]; + block(ticket, data, error); + }]; +} + ++ (OAMutableURLRequest *)requestWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken { + return [[[[self class]alloc]initWithURL:aUrl consumer:aConsumer token:aToken realm:nil signatureProvider:nil]autorelease]; +} + ++ (OAMutableURLRequest *)requestWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken realm:(NSString *)aRealm signatureProvider:(id)aProvider { + return [[[[self class]alloc]initWithURL:aUrl consumer:aConsumer token:aToken realm:aRealm signatureProvider:aProvider]autorelease]; +} + +- (id)initWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken realm:(NSString *)aRealm signatureProvider:(id)aProvider { + + self = [super initWithURL:aUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:25]; + + if (self) { + [self setConsumer:aConsumer]; + + // empty token for Unauthorized Request Token transaction + if (aToken == nil) { + [self setToken:[OAToken token]]; + } else { + [self setToken:aToken]; + } + + if (aRealm == nil) { + [self setRealm:@""]; + } else { + [self setRealm:aRealm]; + } + + // default to HMAC-SHA1 + if (aProvider == nil) { + [self setSignatureProvider:[OAHMAC_SHA1SignatureProvider OAHMAC_SHA1SignatureProvider]]; + } else { + [self setSignatureProvider:aProvider]; + } + + [self _generateTimestamp]; + [self _generateNonce]; + } + return self; +} + +// Setting a timestamp and nonce to known values. Can be helpful for testing +- (id)initWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken realm:(NSString *)aRealm signatureProvider:(id)aProvider nonce:(NSString *)aNonce timestamp:(NSString *)aTimestamp { + + self = [super initWithURL:aUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0]; + + if (self) { + [self setConsumer:aConsumer]; + + // empty token for Unauthorized Request Token transaction + if (aToken == nil) { + [self setToken:[OAToken token]]; + } else { + [self setToken:aToken]; + } + + if (aRealm == nil) { + [self setRealm:@""]; + } else { + [self setRealm:aRealm]; + } + + // default to HMAC-SHA1 + if (aProvider == nil) { + [self setSignatureProvider:[OAHMAC_SHA1SignatureProvider OAHMAC_SHA1SignatureProvider]]; + } else { + [self setSignatureProvider:aProvider]; + } + + [self setTimestamp:aTimestamp]; + [self setNonce:aNonce]; + } + return self; +} + +- (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)parameterValue { + + if (!parameterName && !parameterValue) { + NSLog(@"%s There was not parameter name nor value specified.", __PRETTY_FUNCTION__); + return; + } + + if (self.extraOAuthParameters == nil) { + [self setExtraOAuthParameters:[NSMutableDictionary dictionary]]; + } + + [self.extraOAuthParameters setObject:parameterValue forKey:parameterName]; +} + +- (void)prepare { + // sign + // Secrets must be urlencoded before concatenated with '&' + // TODO: if later RSA-SHA1 support is added then a little code redesign is needed + self.signature = [self.signatureProvider signClearText:[self _signatureBaseString] withSecret:[NSString stringWithFormat:@"%@&%@", [self.consumer.secret URLEncodedString], [self.token.secret URLEncodedString]]]; + + // set OAuth headers + NSString *oauthToken; + + if ([self.token.key isEqualToString:@""]) { + oauthToken = @"oauth_callback=\"oob\", "; + } else if (self.token.verifier.length == 0) { + oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", ", [self.token.key URLEncodedString]]; + } else { + oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", oauth_verifier=\"%@\", ", [self.token.key URLEncodedString], [self.token.verifier URLEncodedString]]; + } + + NSMutableString *extraParameters = [NSMutableString string]; + + // Adding the optional parameters in sorted order isn't required by the OAuth spec, but it makes it possible to hard-code expected values in the unit tests. + for (NSString *parameterName in [[self.extraOAuthParameters allKeys]sortedArrayUsingSelector:@selector(compare:)]) { + [extraParameters appendFormat:@", %@=\"%@\"",[parameterName URLEncodedString],[[self.extraOAuthParameters objectForKey:parameterName]URLEncodedString]]; + } + + NSString *oauthHeader = [NSString stringWithFormat:@"OAuth realm=\"%@\", oauth_consumer_key=\"%@\", %@oauth_signature_method=\"%@\", oauth_signature=\"%@\", oauth_timestamp=\"%@\", oauth_nonce=\"%@\", oauth_version=\"1.0\"%@", [self.realm URLEncodedString], [self.consumer.key URLEncodedString], oauthToken, [[self.signatureProvider name] URLEncodedString], [self.signature URLEncodedString], self.timestamp, self.nonce, extraParameters]; + + [self setValue:oauthHeader forHTTPHeaderField:@"Authorization"]; +} + +- (NSArray *)parameters { + + NSString *encodedParameters = nil; + + if ([self.HTTPMethod isEqualToString:@"GET"] || [self.HTTPMethod isEqualToString:@"DELETE"]) { + encodedParameters = self.URL.query; + } else if ([self.HTTPMethod isEqualToString:@"POST"] || [self.HTTPMethod isEqualToString:@"PUT"]) { + encodedParameters = [[[NSString alloc]initWithData:self.HTTPBody encoding:NSASCIIStringEncoding]autorelease]; + } + + if (encodedParameters.length == 0) { + return nil; + } + + NSArray *encodedParameterPairs = [encodedParameters componentsSeparatedByString:@"&"]; + NSMutableArray *requestParameters = [NSMutableArray arrayWithCapacity:16]; + + for (NSString *encodedPair in encodedParameterPairs) { + NSArray *encodedPairElements = [encodedPair componentsSeparatedByString:@"="]; + OARequestParameter *parameter = [OARequestParameter requestParameterWithName:[[encodedPairElements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] value:[[encodedPairElements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + [requestParameters addObject:parameter]; + } + + return requestParameters; +} + +- (void)setParameters:(NSArray *)parameters { + NSMutableString *encodedParameterPairs = [NSMutableString stringWithCapacity:256]; + + int position = 1; + for (OARequestParameter *requestParameter in parameters) { + [encodedParameterPairs appendString:[requestParameter URLEncodedNameValuePair]]; + if (position < parameters.count) { + [encodedParameterPairs appendString:@"&"]; + } + position++; + } + + if ([self.HTTPMethod isEqualToString:@"GET"] || [self.HTTPMethod isEqualToString:@"DELETE"]) { + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", [self.URL URLStringWithoutQuery], encodedParameterPairs]]]; + } else if ([self.HTTPMethod isEqualToString:@"POST"] || [self.HTTPMethod isEqualToString:@"PUT"]) { + NSData *postData = [encodedParameterPairs dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; + [self setHTTPBody:postData]; + [self setValue:[NSString stringWithFormat:@"%d",postData.length] forHTTPHeaderField:@"Content-Length"]; + [self setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + } +} + +- (void)_generateTimestamp { + [self setTimestamp:[NSString stringWithFormat:@"%ld", time(nil)]]; +} + +- (void)_generateNonce { + CFUUIDRef theUUID = CFUUIDCreate(nil); + CFStringRef string = CFUUIDCreateString(nil, theUUID); + CFRelease(theUUID); + [self setNonce:[NSString stringWithString:(NSString *)string]]; + CFRelease(string); +} + +- (NSString *)_signatureBaseString { + // OAuth Spec, Section 9.1.1 "Normalize Request Parameters" + // build a sorted array of both request parameters and OAuth header parameters + NSArray *parameters = [self parameters]; + + NSMutableArray *parameterPairs = [NSMutableArray arrayWithCapacity:(6+parameters.count)]; // 6 being the number of OAuth params in the Signature Base String + + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_consumer_key" value:self.consumer.key]URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_signature_method" value:[self.signatureProvider name]] URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_timestamp" value:self.timestamp]URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_nonce" value:self.nonce]URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_version" value:@"1.0"]URLEncodedNameValuePair]]; + + if (self.token.key.length > 0) { + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_token" value:self.token.key]URLEncodedNameValuePair]]; + if (self.token.verifier.length > 0) { + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_verifier" value:self.token.verifier]URLEncodedNameValuePair]]; + } + } else { + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_callback" value:@"oob"]URLEncodedNameValuePair]]; + } + + for (OARequestParameter *param in parameters) { + [parameterPairs addObject:[param URLEncodedNameValuePair]]; + } + + NSArray *sortedPairs = [parameterPairs sortedArrayUsingSelector:@selector(compare:)]; + NSString *normalizedRequestParameters = [sortedPairs componentsJoinedByString:@"&"]; + + // OAuth Spec, Section 9.1.2 "Concatenate Request Elements" + NSString *ret = [NSString stringWithFormat:@"%@&%@&%@", self.HTTPMethod, [[self.URL URLStringWithoutQuery]URLEncodedString], [normalizedRequestParameters URLEncodedString]]; + return ret; +} + +- (void)dealloc { + [self setExtraOAuthParameters:nil]; + [self setConsumer:nil]; + [self setToken:nil]; + [self setRealm:nil]; + [self setSignatureProvider:nil]; + [self setTimestamp:nil]; + [self setNonce:nil]; + [self setSignature:nil]; + [super dealloc]; +} + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OARequestParameter.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OARequestParameter.h new file mode 100755 index 0000000000..d0808c8173 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OARequestParameter.h @@ -0,0 +1,41 @@ +// +// OARequestParameter.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "NSString+URLEncoding.h" + +@interface OARequestParameter : NSObject + +@property (nonatomic, retain) NSString *name; +@property (nonatomic, retain) NSString *value; + ++ (id)requestParameterWithName:(NSString *)aName value:(NSString *)aValue; +- (id)initWithName:(NSString *)aName value:(NSString *)aValue; +- (NSString *)URLEncodedName; +- (NSString *)URLEncodedValue; +- (NSString *)URLEncodedNameValuePair; + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OARequestParameter.m b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OARequestParameter.m new file mode 100755 index 0000000000..a98427c80e --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OARequestParameter.m @@ -0,0 +1,62 @@ +// +// OARequestParameter.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OARequestParameter.h" + + +@implementation OARequestParameter + ++ (id)requestParameterWithName:(NSString *)aName value:(NSString *)aValue { + return [[[[self class]alloc]initWithName:aName value:aValue]autorelease]; +} + +- (id)initWithName:(NSString *)aName value:(NSString *)aValue { + if (self = [super init]) { + self.name = aName; + self.value = aValue; + } + return self; +} + +- (NSString *)URLEncodedName { + return [self.name URLEncodedString]; +} + +- (NSString *)URLEncodedValue { + return [self.value URLEncodedString]; +} + +- (NSString *)URLEncodedNameValuePair { + return [NSString stringWithFormat:@"%@=%@", [self URLEncodedName], [self URLEncodedValue]]; +} + +- (void)dealloc { + [self setName:nil]; + [self setValue:nil]; + [super dealloc]; +} + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAServiceTicket.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAServiceTicket.h new file mode 100755 index 0000000000..d9d2c1cf20 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAServiceTicket.h @@ -0,0 +1,39 @@ +// +// OAServiceTicket.h +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OAMutableURLRequest.h" + + +@interface OAServiceTicket : NSObject + +@property (nonatomic, retain) OAMutableURLRequest *request; +@property (nonatomic, retain) NSURLResponse *response; +@property (nonatomic, assign) BOOL didSucceed; + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse didSucceed:(BOOL)success; + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAServiceTicket.m b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAServiceTicket.m new file mode 100755 index 0000000000..78fbc9d679 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAServiceTicket.m @@ -0,0 +1,47 @@ +// +// OAServiceTicket.m +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAServiceTicket.h" + + +@implementation OAServiceTicket + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse didSucceed:(BOOL)success { + if (self = [super init]) { + self.request = aRequest; + self.response = aResponse; + self.didSucceed = success; + } + return self; +} + +- (void)dealloc { + [self setRequest:nil]; + [self setResponse:nil]; + [super dealloc]; +} + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAToken.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAToken.h new file mode 100755 index 0000000000..25d29c2419 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAToken.h @@ -0,0 +1,48 @@ +// +// OAToken.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@interface OAToken : NSObject + +@property (nonatomic, retain) NSString *verifier; +@property (nonatomic, retain) NSString *key; +@property (nonatomic, retain) NSString *secret; + +- (NSString *)pin; +- (void)setPin:(NSString *)aPin; + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; +- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; +- (id)initWithHTTPResponseBody:(NSString *)body; + ++ (OAToken *)token; ++ (OAToken *)tokenWithKey:(NSString *)aKey secret:(NSString *)aSecret; ++ (OAToken *)tokenWithHTTPResponseBody:(NSString *)body; ++ (OAToken *)tokenWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; + +- (void)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAToken.m b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAToken.m new file mode 100755 index 0000000000..49dbc6fd00 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAToken.m @@ -0,0 +1,129 @@ +// +// OAToken.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAToken.h" + +@implementation OAToken + ++ (OAToken *)token { + return [[[[self class]alloc]init]autorelease]; +} + ++ (OAToken *)tokenWithKey:(NSString *)aKey secret:(NSString *)aSecret { + return [[[[self class]alloc]initWithKey:aKey secret:aSecret]autorelease]; +} + ++ (OAToken *)tokenWithHTTPResponseBody:(NSString *)body { + return [[[[self class]alloc]initWithHTTPResponseBody:body]autorelease]; +} + ++ (OAToken *)tokenWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix { + return [[[[self class]alloc]initWithUserDefaultsUsingServiceProviderName:provider prefix:prefix]autorelease]; +} + +- (NSString *)pin { + return self.verifier; +} + +- (void)setPin:(NSString *)aPin { + [self setVerifier:aPin]; +} + +- (id)init { + if (self = [super init]) { + self.key = @""; + self.secret = @""; + self.verifier = @""; + } + return self; +} + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret { + if (self = [super init]) { + self.key = aKey; + self.secret = aSecret; + self.verifier = @""; + } + return self; +} + +- (id)initWithHTTPResponseBody:(NSString *)body { + if (self = [super init]) { + + if (body == nil) { + body = @""; + } + + NSArray *pairs = [body componentsSeparatedByString:@"&"]; + + for (NSString *pair in pairs) { + NSArray *elements = [pair componentsSeparatedByString:@"="]; + if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token"]) { + self.key = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_secret"]) { + self.secret = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } + } + self.verifier = @""; + } + + return self; +} + +- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix { + self = [super init]; + if (self) { + NSString *theKey = [[NSUserDefaults standardUserDefaults]stringForKey:[NSString stringWithFormat:@"OAUTH_%@_%@_KEY", prefix, provider]]; + NSString *theSecret = [[NSUserDefaults standardUserDefaults]stringForKey:[NSString stringWithFormat:@"OAUTH_%@_%@_SECRET", prefix, provider]]; + + BOOL nokey = (theKey.length == 0); + BOOL nosecret = (theSecret.length == 0); + + if ((nokey && nosecret) || (nokey || nosecret)) { + return nil; + } + + self.key = theKey; + self.secret = theSecret; + self.verifier = @""; + } + return self; +} + +- (void)dealloc { + [self setVerifier:nil]; + [self setKey:nil]; + [self setSecret:nil]; + [super dealloc]; +} + +- (void)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix { + [[NSUserDefaults standardUserDefaults]setObject:self.key forKey:[NSString stringWithFormat:@"OAUTH_%@_%@_KEY", prefix, provider]]; + [[NSUserDefaults standardUserDefaults]setObject:self.secret forKey:[NSString stringWithFormat:@"OAUTH_%@_%@_SECRET", prefix, provider]]; + [[NSUserDefaults standardUserDefaults]synchronize]; +} + +@end diff --git a/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAuthConsumer.h b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAuthConsumer.h new file mode 100755 index 0000000000..2177df01b6 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/FHSTwitterEngine/OAuthConsumer/OAuthConsumer.h @@ -0,0 +1,37 @@ +// +// OAuthConsumer.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +// +// FHSTwitterEngine OAuthConsumer Version 1.2.2 +// As modified by Nate Symer (@natesymer) +// + +#import +#import "OAToken.h" +#import "OAConsumer.h" +#import "OAMutableURLRequest.h" +#import "OARequestParameter.h" +#import "OAServiceTicket.h" \ No newline at end of file diff --git a/plugin/plugins/twitter/proj.ios/PluginTwitter-Prefix.pch b/plugin/plugins/twitter/proj.ios/PluginTwitter-Prefix.pch new file mode 100644 index 0000000000..343ceb82c8 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/PluginTwitter-Prefix.pch @@ -0,0 +1,8 @@ +// +// Prefix header for all source files of the 'PluginTwitter' target in the 'PluginTwitter' project +// + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/plugin/plugins/twitter/proj.ios/PluginTwitter.xcodeproj/project.pbxproj b/plugin/plugins/twitter/proj.ios/PluginTwitter.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..8d210519d0 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/PluginTwitter.xcodeproj/project.pbxproj @@ -0,0 +1,319 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + FACAD88C1762C1B500D75ADE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FACAD88B1762C1B500D75ADE /* Foundation.framework */; }; + FACAD89F1762C22300D75ADE /* SocialTwitter.m in Sources */ = {isa = PBXBuildFile; fileRef = FACAD89E1762C22300D75ADE /* SocialTwitter.m */; }; + FACAD8BA1762C61A00D75ADE /* FHSTwitterEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = FACAD8A51762C61A00D75ADE /* FHSTwitterEngine.m */; }; + FACAD8BB1762C61A00D75ADE /* NSString+URLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = FACAD8A91762C61A00D75ADE /* NSString+URLEncoding.m */; }; + FACAD8BC1762C61A00D75ADE /* Base64TranscoderFHS.c in Sources */ = {isa = PBXBuildFile; fileRef = FACAD8AB1762C61A00D75ADE /* Base64TranscoderFHS.c */; }; + FACAD8BD1762C61A00D75ADE /* OAConsumer.m in Sources */ = {isa = PBXBuildFile; fileRef = FACAD8AE1762C61A00D75ADE /* OAConsumer.m */; }; + FACAD8BE1762C61A00D75ADE /* OAHMAC_SHA1SignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = FACAD8B01762C61A00D75ADE /* OAHMAC_SHA1SignatureProvider.m */; }; + FACAD8BF1762C61A00D75ADE /* OAMutableURLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = FACAD8B21762C61A00D75ADE /* OAMutableURLRequest.m */; }; + FACAD8C01762C61A00D75ADE /* OARequestParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = FACAD8B41762C61A00D75ADE /* OARequestParameter.m */; }; + FACAD8C11762C61A00D75ADE /* OAServiceTicket.m in Sources */ = {isa = PBXBuildFile; fileRef = FACAD8B61762C61A00D75ADE /* OAServiceTicket.m */; }; + FACAD8C21762C61A00D75ADE /* OAToken.m in Sources */ = {isa = PBXBuildFile; fileRef = FACAD8B81762C61A00D75ADE /* OAToken.m */; }; + FACAD8C41762C64100D75ADE /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FACAD8C31762C64100D75ADE /* UIKit.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + FACAD8861762C1B500D75ADE /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/${PRODUCT_NAME}"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + FACAD8881762C1B500D75ADE /* libPluginTwitter.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPluginTwitter.a; sourceTree = BUILT_PRODUCTS_DIR; }; + FACAD88B1762C1B500D75ADE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + FACAD89D1762C22300D75ADE /* SocialTwitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SocialTwitter.h; sourceTree = ""; }; + FACAD89E1762C22300D75ADE /* SocialTwitter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SocialTwitter.m; sourceTree = ""; }; + FACAD8A41762C61A00D75ADE /* FHSTwitterEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FHSTwitterEngine.h; sourceTree = ""; }; + FACAD8A51762C61A00D75ADE /* FHSTwitterEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FHSTwitterEngine.m; sourceTree = ""; }; + FACAD8A81762C61A00D75ADE /* NSString+URLEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+URLEncoding.h"; sourceTree = ""; }; + FACAD8A91762C61A00D75ADE /* NSString+URLEncoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+URLEncoding.m"; sourceTree = ""; }; + FACAD8AB1762C61A00D75ADE /* Base64TranscoderFHS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Base64TranscoderFHS.c; sourceTree = ""; }; + FACAD8AC1762C61A00D75ADE /* Base64TranscoderFHS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Base64TranscoderFHS.h; sourceTree = ""; }; + FACAD8AD1762C61A00D75ADE /* OAConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAConsumer.h; sourceTree = ""; }; + FACAD8AE1762C61A00D75ADE /* OAConsumer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAConsumer.m; sourceTree = ""; }; + FACAD8AF1762C61A00D75ADE /* OAHMAC_SHA1SignatureProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAHMAC_SHA1SignatureProvider.h; sourceTree = ""; }; + FACAD8B01762C61A00D75ADE /* OAHMAC_SHA1SignatureProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAHMAC_SHA1SignatureProvider.m; sourceTree = ""; }; + FACAD8B11762C61A00D75ADE /* OAMutableURLRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAMutableURLRequest.h; sourceTree = ""; }; + FACAD8B21762C61A00D75ADE /* OAMutableURLRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAMutableURLRequest.m; sourceTree = ""; }; + FACAD8B31762C61A00D75ADE /* OARequestParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OARequestParameter.h; sourceTree = ""; }; + FACAD8B41762C61A00D75ADE /* OARequestParameter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OARequestParameter.m; sourceTree = ""; }; + FACAD8B51762C61A00D75ADE /* OAServiceTicket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAServiceTicket.h; sourceTree = ""; }; + FACAD8B61762C61A00D75ADE /* OAServiceTicket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAServiceTicket.m; sourceTree = ""; }; + FACAD8B71762C61A00D75ADE /* OAToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAToken.h; sourceTree = ""; }; + FACAD8B81762C61A00D75ADE /* OAToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAToken.m; sourceTree = ""; }; + FACAD8B91762C61A00D75ADE /* OAuthConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAuthConsumer.h; sourceTree = ""; }; + FACAD8C31762C64100D75ADE /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + FACAD8CB1762C76800D75ADE /* PluginTwitter-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PluginTwitter-Prefix.pch"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + FACAD8851762C1B500D75ADE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FACAD8C41762C64100D75ADE /* UIKit.framework in Frameworks */, + FACAD88C1762C1B500D75ADE /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + FACAD87D1762C1B500D75ADE = { + isa = PBXGroup; + children = ( + FACAD8CB1762C76800D75ADE /* PluginTwitter-Prefix.pch */, + FACAD8A31762C61A00D75ADE /* FHSTwitterEngine */, + FACAD89D1762C22300D75ADE /* SocialTwitter.h */, + FACAD89E1762C22300D75ADE /* SocialTwitter.m */, + FACAD88A1762C1B500D75ADE /* Frameworks */, + FACAD8891762C1B500D75ADE /* Products */, + ); + sourceTree = ""; + }; + FACAD8891762C1B500D75ADE /* Products */ = { + isa = PBXGroup; + children = ( + FACAD8881762C1B500D75ADE /* libPluginTwitter.a */, + ); + name = Products; + sourceTree = ""; + }; + FACAD88A1762C1B500D75ADE /* Frameworks */ = { + isa = PBXGroup; + children = ( + FACAD8C31762C64100D75ADE /* UIKit.framework */, + FACAD88B1762C1B500D75ADE /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + FACAD8A31762C61A00D75ADE /* FHSTwitterEngine */ = { + isa = PBXGroup; + children = ( + FACAD8A41762C61A00D75ADE /* FHSTwitterEngine.h */, + FACAD8A51762C61A00D75ADE /* FHSTwitterEngine.m */, + FACAD8A61762C61A00D75ADE /* OAuthConsumer */, + ); + path = FHSTwitterEngine; + sourceTree = ""; + }; + FACAD8A61762C61A00D75ADE /* OAuthConsumer */ = { + isa = PBXGroup; + children = ( + FACAD8A71762C61A00D75ADE /* Categories */, + FACAD8AA1762C61A00D75ADE /* Crytpo */, + FACAD8AD1762C61A00D75ADE /* OAConsumer.h */, + FACAD8AE1762C61A00D75ADE /* OAConsumer.m */, + FACAD8AF1762C61A00D75ADE /* OAHMAC_SHA1SignatureProvider.h */, + FACAD8B01762C61A00D75ADE /* OAHMAC_SHA1SignatureProvider.m */, + FACAD8B11762C61A00D75ADE /* OAMutableURLRequest.h */, + FACAD8B21762C61A00D75ADE /* OAMutableURLRequest.m */, + FACAD8B31762C61A00D75ADE /* OARequestParameter.h */, + FACAD8B41762C61A00D75ADE /* OARequestParameter.m */, + FACAD8B51762C61A00D75ADE /* OAServiceTicket.h */, + FACAD8B61762C61A00D75ADE /* OAServiceTicket.m */, + FACAD8B71762C61A00D75ADE /* OAToken.h */, + FACAD8B81762C61A00D75ADE /* OAToken.m */, + FACAD8B91762C61A00D75ADE /* OAuthConsumer.h */, + ); + path = OAuthConsumer; + sourceTree = ""; + }; + FACAD8A71762C61A00D75ADE /* Categories */ = { + isa = PBXGroup; + children = ( + FACAD8A81762C61A00D75ADE /* NSString+URLEncoding.h */, + FACAD8A91762C61A00D75ADE /* NSString+URLEncoding.m */, + ); + path = Categories; + sourceTree = ""; + }; + FACAD8AA1762C61A00D75ADE /* Crytpo */ = { + isa = PBXGroup; + children = ( + FACAD8AB1762C61A00D75ADE /* Base64TranscoderFHS.c */, + FACAD8AC1762C61A00D75ADE /* Base64TranscoderFHS.h */, + ); + path = Crytpo; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + FACAD8871762C1B500D75ADE /* PluginTwitter */ = { + isa = PBXNativeTarget; + buildConfigurationList = FACAD8961762C1B500D75ADE /* Build configuration list for PBXNativeTarget "PluginTwitter" */; + buildPhases = ( + FACAD8841762C1B500D75ADE /* Sources */, + FACAD8851762C1B500D75ADE /* Frameworks */, + FACAD8861762C1B500D75ADE /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PluginTwitter; + productName = PluginTwitter; + productReference = FACAD8881762C1B500D75ADE /* libPluginTwitter.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + FACAD87F1762C1B500D75ADE /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0440; + ORGANIZATIONNAME = zhangbin; + }; + buildConfigurationList = FACAD8821762C1B500D75ADE /* Build configuration list for PBXProject "PluginTwitter" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = FACAD87D1762C1B500D75ADE; + productRefGroup = FACAD8891762C1B500D75ADE /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + FACAD8871762C1B500D75ADE /* PluginTwitter */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + FACAD8841762C1B500D75ADE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FACAD89F1762C22300D75ADE /* SocialTwitter.m in Sources */, + FACAD8BA1762C61A00D75ADE /* FHSTwitterEngine.m in Sources */, + FACAD8BB1762C61A00D75ADE /* NSString+URLEncoding.m in Sources */, + FACAD8BC1762C61A00D75ADE /* Base64TranscoderFHS.c in Sources */, + FACAD8BD1762C61A00D75ADE /* OAConsumer.m in Sources */, + FACAD8BE1762C61A00D75ADE /* OAHMAC_SHA1SignatureProvider.m in Sources */, + FACAD8BF1762C61A00D75ADE /* OAMutableURLRequest.m in Sources */, + FACAD8C01762C61A00D75ADE /* OARequestParameter.m in Sources */, + FACAD8C11762C61A00D75ADE /* OAServiceTicket.m in Sources */, + FACAD8C21762C61A00D75ADE /* OAToken.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + FACAD8941762C1B500D75ADE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; + SDKROOT = iphoneos; + }; + name = Debug; + }; + FACAD8951762C1B500D75ADE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + FACAD8971762C1B500D75ADE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LIBRARY = "libc++"; + DSTROOT = /tmp/PluginTwitter.dst; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "PluginTwitter-Prefix.pch"; + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../protocols/platform/ios"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + FACAD8981762C1B500D75ADE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LIBRARY = "libc++"; + DSTROOT = /tmp/PluginTwitter.dst; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "PluginTwitter-Prefix.pch"; + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../protocols/platform/ios"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + FACAD8821762C1B500D75ADE /* Build configuration list for PBXProject "PluginTwitter" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FACAD8941762C1B500D75ADE /* Debug */, + FACAD8951762C1B500D75ADE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FACAD8961762C1B500D75ADE /* Build configuration list for PBXNativeTarget "PluginTwitter" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FACAD8971762C1B500D75ADE /* Debug */, + FACAD8981762C1B500D75ADE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = FACAD87F1762C1B500D75ADE /* Project object */; +} diff --git a/plugin/plugins/twitter/proj.ios/SocialTwitter.h b/plugin/plugins/twitter/proj.ios/SocialTwitter.h new file mode 100644 index 0000000000..1b7842fca0 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/SocialTwitter.h @@ -0,0 +1,44 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#import "InterfaceSocial.h" + +@interface SocialTwitter : NSObject +{ + +} + +@property BOOL debug; +@property (copy, nonatomic) NSMutableDictionary* mShareInfo; + +/** + * @brief interfaces of protocol : InterfaceSocial + */ +- (void) configDeveloperInfo : (NSMutableDictionary*) cpInfo; +- (void) share: (NSMutableDictionary*) shareInfo; +- (void) setDebugMode: (BOOL) debug; +- (NSString*) getSDKVersion; +- (NSString*) getPluginVersion; + +@end diff --git a/plugin/plugins/twitter/proj.ios/SocialTwitter.m b/plugin/plugins/twitter/proj.ios/SocialTwitter.m new file mode 100644 index 0000000000..e9f82c3866 --- /dev/null +++ b/plugin/plugins/twitter/proj.ios/SocialTwitter.m @@ -0,0 +1,142 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#import "SocialTwitter.h" +#import "FHSTwitterEngine.h" +#import "SocialWrapper.h" + +#define OUTPUT_LOG(...) if (self.debug) NSLog(__VA_ARGS__); + +@implementation SocialTwitter + +@synthesize mShareInfo; +@synthesize debug = __debug; + +- (void) configDeveloperInfo : (NSMutableDictionary*) cpInfo +{ + NSString* appKey = [cpInfo objectForKey:@"TwitterKey"]; + NSString* appSecret = [cpInfo objectForKey:@"TwitterSecret"]; + + if (nil == appKey || nil == appSecret) { + return; + } + + [[FHSTwitterEngine sharedEngine]permanentlySetConsumerKey:appKey andSecret:appSecret]; +} + +- (void) share: (NSMutableDictionary*) shareInfo +{ + self.mShareInfo = shareInfo; + if ([[FHSTwitterEngine sharedEngine]isAuthorized]) + { + [self doShare]; + } else { + UIViewController* controller = [self getCurrentRootViewController]; + [[FHSTwitterEngine sharedEngine]showOAuthLoginControllerFromViewController:controller withCompletion:^(BOOL success) { + if (success) { + [self doShare]; + } else { + [SocialWrapper onShareResult:self withRet:kShareFail withMsg:@"Login Failed"]; + } + }]; + } +} + +- (void) setDebugMode: (BOOL) debug +{ + self.debug = debug; +} + +- (NSString*) getSDKVersion +{ + return @"20130607"; +} + +- (NSString*) getPluginVersion +{ + return @"0.2.0"; +} + +- (void) doShare +{ + if (nil == mShareInfo) { + [SocialWrapper onShareResult:self withRet:kShareFail withMsg:@"Shared info error"]; + return; + } + + NSString* strText = [mShareInfo objectForKey:@"SharedText"]; + NSString* strImagePath = [mShareInfo objectForKey:@"SharedImagePath"]; + + BOOL oldConfig = [UIApplication sharedApplication].networkActivityIndicatorVisible; + [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; + + NSError* returnCode = nil; + if (nil != strImagePath) { + NSData* data = [NSData dataWithContentsOfFile:strImagePath]; + returnCode = [[FHSTwitterEngine sharedEngine] postTweet:strText withImageData:data]; + } else { + returnCode = [[FHSTwitterEngine sharedEngine]postTweet:strText]; + } + [UIApplication sharedApplication].networkActivityIndicatorVisible = oldConfig; + + if (returnCode) { + NSString* strErrorCode = [NSString stringWithFormat:@"ErrorCode %d", returnCode.code]; + [SocialWrapper onShareResult:self withRet:kShareFail withMsg:strErrorCode]; + } else { + [SocialWrapper onShareResult:self withRet:kShareSuccess withMsg:@"Share Succeed"]; + } +} + +- (UIViewController *)getCurrentRootViewController { + + UIViewController *result = nil; + + // Try to find the root view controller programmically + + // Find the top window (that is not an alert view or other window) + UIWindow *topWindow = [[UIApplication sharedApplication] keyWindow]; + if (topWindow.windowLevel != UIWindowLevelNormal) + { + NSArray *windows = [[UIApplication sharedApplication] windows]; + for(topWindow in windows) + { + if (topWindow.windowLevel == UIWindowLevelNormal) + break; + } + } + + UIView *rootView = [[topWindow subviews] objectAtIndex:0]; + id nextResponder = [rootView nextResponder]; + + if ([nextResponder isKindOfClass:[UIViewController class]]) + result = nextResponder; + else if ([topWindow respondsToSelector:@selector(rootViewController)] && topWindow.rootViewController != nil) + result = topWindow.rootViewController; + else + NSAssert(NO, @"Could not find a root view controller."); + + return result; +} + +@end diff --git a/plugin/plugins/umeng/proj.ios/PluginUmeng.xcodeproj/project.pbxproj b/plugin/plugins/umeng/proj.ios/PluginUmeng.xcodeproj/project.pbxproj index 913a504689..ea67c97955 100644 --- a/plugin/plugins/umeng/proj.ios/PluginUmeng.xcodeproj/project.pbxproj +++ b/plugin/plugins/umeng/proj.ios/PluginUmeng.xcodeproj/project.pbxproj @@ -185,10 +185,7 @@ DSTROOT = /tmp/libPluginUmeng.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "PluginUmeng-Prefix.pch"; - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../protocols/include", - "$(SRCROOT)/../../../protocols/platform/ios", - ); + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../protocols/platform/ios"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)\"", @@ -207,10 +204,7 @@ DSTROOT = /tmp/libPluginUmeng.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "PluginUmeng-Prefix.pch"; - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../protocols/include", - "$(SRCROOT)/../../../protocols/platform/ios", - ); + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../protocols/platform/ios"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)\"", diff --git a/plugin/plugins/weibo/proj.ios/PluginWeibo.xcodeproj/project.pbxproj b/plugin/plugins/weibo/proj.ios/PluginWeibo.xcodeproj/project.pbxproj index 6a65f68170..f562040faf 100644 --- a/plugin/plugins/weibo/proj.ios/PluginWeibo.xcodeproj/project.pbxproj +++ b/plugin/plugins/weibo/proj.ios/PluginWeibo.xcodeproj/project.pbxproj @@ -225,14 +225,12 @@ FAE2753F175D9D2B00F5DA8E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "compiler-default"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; DSTROOT = /tmp/PluginWeibo.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "PluginWeibo-Prefix.pch"; - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../protocols/include", - "$(SRCROOT)/../../../protocols/platform/ios", - ); + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../protocols/platform/ios"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -242,14 +240,12 @@ FAE27540175D9D2B00F5DA8E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "compiler-default"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; DSTROOT = /tmp/PluginWeibo.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "PluginWeibo-Prefix.pch"; - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../protocols/include", - "$(SRCROOT)/../../../protocols/platform/ios", - ); + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../protocols/platform/ios"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/plugin/protocols/PluginManager.cpp b/plugin/protocols/PluginManager.cpp index f39a893ca2..2061cb366a 100644 --- a/plugin/protocols/PluginManager.cpp +++ b/plugin/protocols/PluginManager.cpp @@ -80,7 +80,7 @@ PluginProtocol* PluginManager::loadPlugin(const char* name) } else { pRet = PluginFactory::getInstance()->createPlugin(name); - m_pluginsMap["name"] = pRet; + m_pluginsMap[name] = pRet; } } while (false); diff --git a/plugin/protocols/platform/android/PluginJniMacros.h b/plugin/protocols/platform/android/PluginJniMacros.h index 5cba8480f0..86e5f1d449 100644 --- a/plugin/protocols/platform/android/PluginJniMacros.h +++ b/plugin/protocols/platform/android/PluginJniMacros.h @@ -40,12 +40,25 @@ if (PluginJniHelper::getMethodInfo(t \ , funcName \ , paramCode)) \ { \ - if (NULL != param) \ - { \ - ret = t.env->Call##retCode##Method(pData->jobj, t.methodID, param); \ - } else { \ - ret = t.env->Call##retCode##Method(pData->jobj, t.methodID); \ - } \ + ret = t.env->Call##retCode##Method(pData->jobj, t.methodID, param); \ + t.env->DeleteLocalRef(t.classID); \ +} \ +return ret; \ + + +#define CALL_BASERET_JAVA_FUNC(retType, paramCode, retCode, defaultRet) \ +retType ret = defaultRet; \ +return_val_if_fails(funcName != NULL && strlen(funcName) > 0, ret); \ +PluginJavaData* pData = PluginUtils::getPluginJavaData(thiz); \ +return_val_if_fails(pData != NULL, ret); \ + \ +PluginJniMethodInfo t; \ +if (PluginJniHelper::getMethodInfo(t \ + , pData->jclassName.c_str() \ + , funcName \ + , paramCode)) \ +{ \ + ret = t.env->Call##retCode##Method(pData->jobj, t.methodID); \ t.env->DeleteLocalRef(t.classID); \ } \ return ret; \ @@ -88,7 +101,7 @@ if (0 == nParamNum) { \ paramCode = "()"; \ paramCode.append(jRetCode); \ - ret = PluginUtils::callJava##retCode##FuncWithName_oneParam(this, funcName, paramCode.c_str(), NULL); \ + ret = PluginUtils::callJava##retCode##FuncWithName(this, funcName); \ } else \ { \ PluginParam* pRetParam = NULL; \ diff --git a/plugin/protocols/platform/android/PluginProtocol.cpp b/plugin/protocols/platform/android/PluginProtocol.cpp index 71a1e5956f..da853b0b63 100644 --- a/plugin/protocols/platform/android/PluginProtocol.cpp +++ b/plugin/protocols/platform/android/PluginProtocol.cpp @@ -107,7 +107,7 @@ void PluginProtocol::callFuncWithParam(const char* funcName, std::vectorCallVoidMethod(pData->jobj, t.methodID, param); - } else { - t.env->CallVoidMethod(pData->jobj, t.methodID); - } + t.env->CallVoidMethod(pData->jobj, t.methodID, param); + t.env->DeleteLocalRef(t.classID); + } + } + static void callJavaFunctionWithName(PluginProtocol* thiz, const char* funcName) + { + return_if_fails(funcName != NULL && strlen(funcName) > 0); + PluginJavaData* pData = PluginUtils::getPluginJavaData(thiz); + return_if_fails(pData != NULL); + + PluginJniMethodInfo t; + if (PluginJniHelper::getMethodInfo(t + , pData->jclassName.c_str() + , funcName + , "()V")) + { + t.env->CallVoidMethod(pData->jobj, t.methodID); t.env->DeleteLocalRef(t.classID); } } @@ -101,6 +112,25 @@ public: } return ret; } + static const char* callJavaStringFuncWithName(PluginProtocol* thiz, const char* funcName) + { + const char* ret = ""; + return_val_if_fails(funcName != NULL && strlen(funcName) > 0, ret); + PluginJavaData* pData = PluginUtils::getPluginJavaData(thiz); + return_val_if_fails(pData != NULL, ret); + + PluginJniMethodInfo t; + if (PluginJniHelper::getMethodInfo(t + , pData->jclassName.c_str() + , funcName + , "()Ljava/lang/String;")) + { + jstring strRet = (jstring) t.env->CallObjectMethod(pData->jobj, t.methodID); + ret = PluginJniHelper::jstring2string(strRet).c_str(); + t.env->DeleteLocalRef(t.classID); + } + return ret; + } // methods return value is int template @@ -108,6 +138,10 @@ public: { CALL_BASERET_JAVA_FUNC_WITH_PARAM(int, paramCode, param, Int, 0) } + static int callJavaIntFuncWithName(PluginProtocol* thiz, const char* funcName) + { + CALL_BASERET_JAVA_FUNC(int, "()I", Int, 0) + } // methods return value is float template @@ -115,6 +149,10 @@ public: { CALL_BASERET_JAVA_FUNC_WITH_PARAM(float, paramCode, param, Float, 0.0f) } + static float callJavaFloatFuncWithName(PluginProtocol* thiz, const char* funcName) + { + CALL_BASERET_JAVA_FUNC(float, "()F", Float, 0.0f); + } // methods return value is bool template @@ -122,6 +160,10 @@ public: { CALL_BASERET_JAVA_FUNC_WITH_PARAM(bool, paramCode, param, Boolean, false) } + static bool callJavaBoolFuncWithName(PluginProtocol* thiz, const char* funcName) + { + CALL_BASERET_JAVA_FUNC(bool, "()Z", Boolean, false) + } static void outputLog(const char* logTag, const char* pFormat, ...); }; diff --git a/plugin/protocols/platform/ios/PluginOCMacros.h b/plugin/protocols/platform/ios/PluginOCMacros.h index aa7b18a68f..7d82dabc13 100644 --- a/plugin/protocols/platform/ios/PluginOCMacros.h +++ b/plugin/protocols/platform/ios/PluginOCMacros.h @@ -61,7 +61,7 @@ if (NULL == pData) { int nParamNum = params.size(); \ if (0 == nParamNum) \ { \ - ret = PluginUtilsIOS::callOC##retCode##FunctionWithName_oneParam(this, funcName, NULL); \ + ret = PluginUtilsIOS::callOC##retCode##FunctionWithName(this, funcName); \ } else \ { \ PluginParam* pRetParam = NULL; \ diff --git a/plugin/protocols/platform/ios/PluginProtocol.mm b/plugin/protocols/platform/ios/PluginProtocol.mm index 9f4fe4e0e5..84da94d817 100644 --- a/plugin/protocols/platform/ios/PluginProtocol.mm +++ b/plugin/protocols/platform/ios/PluginProtocol.mm @@ -117,7 +117,7 @@ void PluginProtocol::callFuncWithParam(const char* funcName, std::vectorobj; NSString* strFuncName = [NSString stringWithUTF8String:funcName]; - if (param != nil) { - strFuncName = [strFuncName stringByAppendingString:@":"]; - } + strFuncName = [strFuncName stringByAppendingString:@":"]; + SEL selector = NSSelectorFromString(strFuncName); if ([pOCObj respondsToSelector:selector]) { - if (param == nil) { - [pOCObj performSelector:selector]; - } else { - [pOCObj performSelector:selector withObject:param]; - } + [pOCObj performSelector:selector withObject:param]; + } else { + outputLog("Can't find function '%s' in class '%s'", [strFuncName UTF8String], pData->className.c_str()); + } + } else { + PluginUtilsIOS::outputLog("Plugin %s not right initilized", pPlugin->getPluginName()); + } +} + +void PluginUtilsIOS::callOCFunctionWithName(PluginProtocol* pPlugin, const char* funcName) +{ + return_if_fails(funcName != NULL && strlen(funcName) > 0); + + PluginOCData* pData = PluginUtilsIOS::getPluginOCData(pPlugin); + if (pData) { + id pOCObj = pData->obj; + + NSString* strFuncName = [NSString stringWithUTF8String:funcName]; + SEL selector = NSSelectorFromString(strFuncName); + if ([pOCObj respondsToSelector:selector]) { + [pOCObj performSelector:selector]; } else { outputLog("Can't find function '%s' in class '%s'", [strFuncName UTF8String], pData->className.c_str()); } @@ -192,14 +207,33 @@ void PluginUtilsIOS::callOCFunctionWithName_oneParam(PluginProtocol* pPlugin, co int PluginUtilsIOS::callOCIntFunctionWithName_oneParam(PluginProtocol* pPlugin, const char* funcName, id param) { - int ret = (NSInteger)callRetFunction(pPlugin, funcName, param); + NSNumber* num = (NSNumber*) callRetFunctionWithParam(pPlugin, funcName, param); + int ret = [num integerValue]; + return ret; +} + +int PluginUtilsIOS::callOCIntFunctionWithName(PluginProtocol* pPlugin, const char* funcName) +{ + NSNumber* num = (NSNumber*) callRetFunction(pPlugin, funcName); + int ret = [num integerValue]; return ret; } float PluginUtilsIOS::callOCFloatFunctionWithName_oneParam(PluginProtocol* pPlugin, const char* funcName, id param) { float ret = 0.0f; - NSNumber* pRet = (NSNumber*)callRetFunction(pPlugin, funcName, param); + NSNumber* pRet = (NSNumber*)callRetFunctionWithParam(pPlugin, funcName, param); + if (nil != pRet) { + ret = [pRet floatValue]; + } + + return ret; +} + +float PluginUtilsIOS::callOCFloatFunctionWithName(PluginProtocol* pPlugin, const char* funcName) +{ + float ret = 0.0f; + NSNumber* pRet = (NSNumber*)callRetFunction(pPlugin, funcName); if (nil != pRet) { ret = [pRet floatValue]; } @@ -210,7 +244,7 @@ float PluginUtilsIOS::callOCFloatFunctionWithName_oneParam(PluginProtocol* pPlug bool PluginUtilsIOS::callOCBoolFunctionWithName_oneParam(PluginProtocol* pPlugin, const char* funcName, id param) { bool ret = false; - NSNumber* pRet = (NSNumber*)callRetFunction(pPlugin, funcName, param); + NSNumber* pRet = (NSNumber*)callRetFunctionWithParam(pPlugin, funcName, param); if (nil != pRet) { ret = [pRet boolValue]; } @@ -218,18 +252,40 @@ bool PluginUtilsIOS::callOCBoolFunctionWithName_oneParam(PluginProtocol* pPlugin return ret; } +bool PluginUtilsIOS::callOCBoolFunctionWithName(PluginProtocol* pPlugin, const char* funcName) +{ + bool ret = false; + NSNumber* pRet = (NSNumber*)callRetFunction(pPlugin, funcName); + if (nil != pRet) { + ret = [pRet boolValue]; + } + + return ret; +} + const char* PluginUtilsIOS::callOCStringFunctionWithName_oneParam(PluginProtocol* pPlugin, const char* funcName, id param) { const char* ret = ""; - NSString* pRet = (NSString*)callRetFunction(pPlugin, funcName, param); + NSString* pRet = (NSString*)callRetFunctionWithParam(pPlugin, funcName, param); if (nil != pRet) { ret = [pRet UTF8String]; } return ret; } + +const char* PluginUtilsIOS::callOCStringFunctionWithName(PluginProtocol* pPlugin, const char* funcName) +{ + const char* ret = ""; + NSString* pRet = (NSString*)callRetFunction(pPlugin, funcName); + if (nil != pRet) { + ret = [pRet UTF8String]; + } + + return ret; +} -id PluginUtilsIOS::callRetFunction(PluginProtocol* pPlugin, const char* funcName, id param) +id PluginUtilsIOS::callRetFunction(PluginProtocol* pPlugin, const char* funcName) { id ret = nil; return_val_if_fails(funcName != NULL && strlen(funcName) > 0, ret); @@ -239,16 +295,33 @@ id PluginUtilsIOS::callRetFunction(PluginProtocol* pPlugin, const char* funcName id pOCObj = pData->obj; NSString* strFuncName = [NSString stringWithUTF8String:funcName]; - if (param != nil) { - strFuncName = [strFuncName stringByAppendingString:@":"]; - } SEL selector = NSSelectorFromString(strFuncName); if ([pOCObj respondsToSelector:selector]) { - if (param == nil) { - ret = [pOCObj performSelector:selector]; - } else { - ret = [pOCObj performSelector:selector withObject:param]; - } + ret = [pOCObj performSelector:selector]; + } else { + outputLog("Can't find function '%s' in class '%s'", [strFuncName UTF8String], pData->className.c_str()); + } + } else { + PluginUtilsIOS::outputLog("Plugin %s not right initilized", pPlugin->getPluginName()); + } + + return ret; +} + +id PluginUtilsIOS::callRetFunctionWithParam(PluginProtocol* pPlugin, const char* funcName, id param) +{ + id ret = nil; + return_val_if_fails(funcName != NULL && strlen(funcName) > 0, ret); + + PluginOCData* pData = PluginUtilsIOS::getPluginOCData(pPlugin); + if (pData) { + id pOCObj = pData->obj; + + NSString* strFuncName = [NSString stringWithUTF8String:funcName]; + strFuncName = [strFuncName stringByAppendingString:@":"]; + SEL selector = NSSelectorFromString(strFuncName); + if ([pOCObj respondsToSelector:selector]) { + ret = [pOCObj performSelector:selector withObject:param]; } else { outputLog("Can't find function '%s' in class '%s'", [strFuncName UTF8String], pData->className.c_str()); } diff --git a/plugin/protocols/proj.ios/PluginProtocol.xcodeproj/project.pbxproj b/plugin/protocols/proj.ios/PluginProtocol.xcodeproj/project.pbxproj index cdd6ce0a69..27e6cd3d73 100644 --- a/plugin/protocols/proj.ios/PluginProtocol.xcodeproj/project.pbxproj +++ b/plugin/protocols/proj.ios/PluginProtocol.xcodeproj/project.pbxproj @@ -171,7 +171,7 @@ FA09A318168ADBC2008C1C7B /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0440; + LastUpgradeCheck = 0460; ORGANIZATIONNAME = zhangbin; }; buildConfigurationList = FA09A31B168ADBC2008C1C7B /* Build configuration list for PBXProject "PluginProtocol" */; @@ -219,6 +219,9 @@ ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -245,6 +248,9 @@ ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = gnu99; diff --git a/plugin/samples/HelloSocial/proj.ios/HelloSocial.xcodeproj/project.pbxproj b/plugin/samples/HelloSocial/proj.ios/HelloSocial.xcodeproj/project.pbxproj index 013e0d1172..9ab1750a5b 100644 --- a/plugin/samples/HelloSocial/proj.ios/HelloSocial.xcodeproj/project.pbxproj +++ b/plugin/samples/HelloSocial/proj.ios/HelloSocial.xcodeproj/project.pbxproj @@ -35,6 +35,8 @@ D4EF949C15BD2D8E00D803EB /* Icon-114.png in Resources */ = {isa = PBXBuildFile; fileRef = D4EF949B15BD2D8E00D803EB /* Icon-114.png */; }; D4EF949E15BD2D9600D803EB /* Icon-72.png in Resources */ = {isa = PBXBuildFile; fileRef = D4EF949D15BD2D9600D803EB /* Icon-72.png */; }; D4EF94A015BD2D9800D803EB /* Icon-144.png in Resources */ = {isa = PBXBuildFile; fileRef = D4EF949F15BD2D9800D803EB /* Icon-144.png */; }; + FACAD8F61763061F00D75ADE /* libPluginTwitter.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FACAD8F51762DC3A00D75ADE /* libPluginTwitter.a */; }; + FACAD8F81763070D00D75ADE /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FACAD8F71763070D00D75ADE /* SystemConfiguration.framework */; }; FAE27583175DEC8600F5DA8E /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = FAE27580175DEC8600F5DA8E /* background.png */; }; FAE27584175DEC8600F5DA8E /* twitter.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = FAE27581175DEC8600F5DA8E /* twitter.jpeg */; }; FAE27585175DEC8600F5DA8E /* weibo.png in Resources */ = {isa = PBXBuildFile; fileRef = FAE27582175DEC8600F5DA8E /* weibo.png */; }; @@ -46,6 +48,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + FACAD8F41762DC3A00D75ADE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FACAD8ED1762DC3A00D75ADE /* PluginTwitter.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = FACAD8881762C1B500D75ADE; + remoteInfo = PluginTwitter; + }; FAE2757E175DEC0D00F5DA8E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = FAE27577175DEC0C00F5DA8E /* cocos2dx.xcodeproj */; @@ -112,6 +121,8 @@ D4EF949D15BD2D9600D803EB /* Icon-72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon-72.png"; path = "../proj.ios/Icon-72.png"; sourceTree = ""; }; D4EF949F15BD2D9800D803EB /* Icon-144.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon-144.png"; path = "../proj.ios/Icon-144.png"; sourceTree = ""; }; D4F9F37B12E54555005CA6D2 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + FACAD8ED1762DC3A00D75ADE /* PluginTwitter.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = PluginTwitter.xcodeproj; path = ../../../plugins/twitter/proj.ios/PluginTwitter.xcodeproj; sourceTree = ""; }; + FACAD8F71763070D00D75ADE /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; FAE27577175DEC0C00F5DA8E /* cocos2dx.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = cocos2dx.xcodeproj; path = ../../../../cocos2dx/proj.ios/cocos2dx.xcodeproj; sourceTree = ""; }; FAE27580175DEC8600F5DA8E /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background.png; sourceTree = ""; }; FAE27581175DEC8600F5DA8E /* twitter.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = twitter.jpeg; sourceTree = ""; }; @@ -128,6 +139,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + FACAD8F81763070D00D75ADE /* SystemConfiguration.framework in Frameworks */, + FACAD8F61763061F00D75ADE /* libPluginTwitter.a in Frameworks */, FAE275A1175DEEF500F5DA8E /* AudioToolbox.framework in Frameworks */, FAE27598175DEE1900F5DA8E /* libcocos2dx.a in Frameworks */, FAE27599175DEE1900F5DA8E /* libPluginProtocol.a in Frameworks */, @@ -223,6 +236,8 @@ 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { isa = PBXGroup; children = ( + FACAD8F71763070D00D75ADE /* SystemConfiguration.framework */, + FACAD8ED1762DC3A00D75ADE /* PluginTwitter.xcodeproj */, FAE2758F175DED2300F5DA8E /* PluginWeibo.xcodeproj */, FAE27586175DED1700F5DA8E /* PluginProtocol.xcodeproj */, FAE27577175DEC0C00F5DA8E /* cocos2dx.xcodeproj */, @@ -273,6 +288,14 @@ path = ../Resources; sourceTree = ""; }; + FACAD8EE1762DC3A00D75ADE /* Products */ = { + isa = PBXGroup; + children = ( + FACAD8F51762DC3A00D75ADE /* libPluginTwitter.a */, + ); + name = Products; + sourceTree = ""; + }; FAE27578175DEC0C00F5DA8E /* Products */ = { isa = PBXGroup; children = ( @@ -346,6 +369,10 @@ ProductGroup = FAE27587175DED1700F5DA8E /* Products */; ProjectRef = FAE27586175DED1700F5DA8E /* PluginProtocol.xcodeproj */; }, + { + ProductGroup = FACAD8EE1762DC3A00D75ADE /* Products */; + ProjectRef = FACAD8ED1762DC3A00D75ADE /* PluginTwitter.xcodeproj */; + }, { ProductGroup = FAE27590175DED2300F5DA8E /* Products */; ProjectRef = FAE2758F175DED2300F5DA8E /* PluginWeibo.xcodeproj */; @@ -359,6 +386,13 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ + FACAD8F51762DC3A00D75ADE /* libPluginTwitter.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libPluginTwitter.a; + remoteRef = FACAD8F41762DC3A00D75ADE /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; FAE2757F175DEC0D00F5DA8E /* libcocos2dx.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -430,8 +464,8 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; @@ -457,13 +491,13 @@ "\"$(SRCROOT)/../../../protocols/include", ); INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 4.0; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/ios/libraries\""; OTHER_CFLAGS = "-O2"; "OTHER_LDFLAGS[arch=*]" = "-ObjC"; PRODUCT_NAME = HelloSocial; - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + PROVISIONING_PROFILE = "34B6E084-2760-4B9B-94CE-0998083C95F5"; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "34B6E084-2760-4B9B-94CE-0998083C95F5"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; USER_HEADER_SEARCH_PATHS = ""; @@ -475,8 +509,8 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; COPY_PHASE_STRIP = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -500,12 +534,12 @@ "\"$(SRCROOT)/../../../protocols/include", ); INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 4.0; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/ios/libraries\""; "OTHER_LDFLAGS[arch=*]" = "-ObjC"; PRODUCT_NAME = HelloSocial; - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + PROVISIONING_PROFILE = "34B6E084-2760-4B9B-94CE-0998083C95F5"; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "34B6E084-2760-4B9B-94CE-0998083C95F5"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; USER_HEADER_SEARCH_PATHS = ""; @@ -517,12 +551,12 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; GCC_C_LANGUAGE_STANDARD = c99; GCC_VERSION = ""; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; - PROVISIONING_PROFILE = "0C43CFE2-55C4-429A-9A03-BFB76D31630B"; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "0C43CFE2-55C4-429A-9A03-BFB76D31630B"; SDKROOT = iphoneos; VALID_ARCHS = "armv6 armv7 i386"; }; @@ -532,13 +566,13 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; GCC_C_LANGUAGE_STANDARD = c99; GCC_VERSION = ""; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - PROVISIONING_PROFILE = "0C43CFE2-55C4-429A-9A03-BFB76D31630B"; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "DB6844BA-2943-44DB-B10A-3A3F0E8A52B8"; SDKROOT = iphoneos; VALID_ARCHS = "armv6 armv7 i386"; }; diff --git a/samples/Cpp/HelloCpp/proj.tizen/.cproject b/samples/Cpp/HelloCpp/proj.tizen/.cproject index c145fac350..c6b75243bc 100644 --- a/samples/Cpp/HelloCpp/proj.tizen/.cproject +++ b/samples/Cpp/HelloCpp/proj.tizen/.cproject @@ -25,12 +25,12 @@ - + @@ -58,14 +57,15 @@ + - + @@ -96,7 +95,7 @@ - + + - + @@ -99,7 +98,7 @@ - + @@ -65,14 +66,15 @@ + - + @@ -103,7 +104,7 @@ - + diff --git a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj index 3a4146d74a..5509d36bce 100644 --- a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj +++ b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj @@ -129,6 +129,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\libwebsockets\win32\lib\*.*" "$(O + @@ -226,6 +227,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\libwebsockets\win32\lib\*.*" "$(O + diff --git a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters index 68a799d585..bbb5b046cf 100644 --- a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters +++ b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters @@ -513,6 +513,9 @@ Classes\ExtensionsTest\NetworkTest + + Classes + @@ -980,5 +983,8 @@ Classes\ExtensionsTest\NetworkTest + + Classes + \ No newline at end of file diff --git a/samples/Javascript/MoonWarriors/proj.ios/MoonWarriors.xcodeproj/project.pbxproj b/samples/Javascript/MoonWarriors/proj.ios/MoonWarriors.xcodeproj/project.pbxproj index 55e4fcb618..7ef6a64af7 100644 --- a/samples/Javascript/MoonWarriors/proj.ios/MoonWarriors.xcodeproj/project.pbxproj +++ b/samples/Javascript/MoonWarriors/proj.ios/MoonWarriors.xcodeproj/project.pbxproj @@ -633,7 +633,7 @@ PUBLIC_HEADERS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/Headers"; TARGETED_DEVICE_FAMILY = "1,2"; USER_HEADER_SEARCH_PATHS = ""; - VALID_ARCHS = "armv7 armv7s"; + VALID_ARCHS = "armv7 armv7s i386"; WRAPPER_EXTENSION = app; }; name = Debug; @@ -680,7 +680,7 @@ TARGETED_DEVICE_FAMILY = "1,2"; USER_HEADER_SEARCH_PATHS = ""; VALIDATE_PRODUCT = YES; - VALID_ARCHS = "armv7 armv7s"; + VALID_ARCHS = "armv7 armv7s i386"; WRAPPER_EXTENSION = app; }; name = Release; diff --git a/samples/Javascript/TestJavascript/proj.ios/AppController.mm b/samples/Javascript/TestJavascript/proj.ios/AppController.mm index 3e3e5c9474..55052cbae8 100644 --- a/samples/Javascript/TestJavascript/proj.ios/AppController.mm +++ b/samples/Javascript/TestJavascript/proj.ios/AppController.mm @@ -35,6 +35,8 @@ static AppDelegate s_sharedApplication; multiSampling: NO numberOfSamples: 0 ]; + [__glView setMultipleTouchEnabled:YES]; + // Use RootViewController manage EAGLView viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil]; viewController.wantsFullScreenLayout = YES; diff --git a/scripting/javascript/bindings/ScriptingCore.cpp b/scripting/javascript/bindings/ScriptingCore.cpp index d24fac5c54..6aef63aacc 100644 --- a/scripting/javascript/bindings/ScriptingCore.cpp +++ b/scripting/javascript/bindings/ScriptingCore.cpp @@ -1984,15 +1984,16 @@ void* serverEntryPoint(void*) struct addrinfo hints, *result, *rp; int s; memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; // TCP + hints.ai_family = AF_INET; // IPv4 + hints.ai_socktype = SOCK_STREAM; // TCP stream sockets + hints.ai_flags = AI_PASSIVE; // fill in my IP for me - int err; stringstream portstr; portstr << JSB_DEBUGGER_PORT; - const char* tmp = portstr.str().c_str(); - if ((err = getaddrinfo(NULL, tmp, &hints, &result)) != 0) { - printf("error: %s\n", gai_strerror(err)); + + int err; + if ((err = getaddrinfo(NULL, portstr.str().c_str(), &hints, &result)) != 0) { + LOGD("getaddrinfo error : %s\n", gai_strerror(err)); } for (rp = result; rp != NULL; rp = rp->ai_next) { diff --git a/scripting/javascript/bindings/generated b/scripting/javascript/bindings/generated index 71562d8f33..5d0f36f011 160000 --- a/scripting/javascript/bindings/generated +++ b/scripting/javascript/bindings/generated @@ -1 +1 @@ -Subproject commit 71562d8f336df63d6d2dc01fbe0d04e8619ecf62 +Subproject commit 5d0f36f011c4b9ed067fb42dc6529bdb58deb9a5 diff --git a/template/multi-platform-cpp/proj.ios/AppController.mm b/template/multi-platform-cpp/proj.ios/AppController.mm index 18674885a0..0ed0be670a 100644 --- a/template/multi-platform-cpp/proj.ios/AppController.mm +++ b/template/multi-platform-cpp/proj.ios/AppController.mm @@ -35,7 +35,6 @@ static AppDelegate s_sharedApplication; sharegroup: nil multiSampling: NO numberOfSamples: 0]; - [__glView setMultipleTouchEnabled:YES]; // Use RootViewController manage EAGLView viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil]; diff --git a/template/multi-platform-cpp/proj.win32/HelloCpp.vcxproj b/template/multi-platform-cpp/proj.win32/HelloCpp.vcxproj index 28ec791200..a68139f692 100644 --- a/template/multi-platform-cpp/proj.win32/HelloCpp.vcxproj +++ b/template/multi-platform-cpp/proj.win32/HelloCpp.vcxproj @@ -77,7 +77,7 @@ 4267;4251;4244;%(DisableSpecificWarnings) - libExtensions.lib;libcocos2d.lib;libCocosDenshion.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libcurl_imp.lib;pthreadVCE2.lib;%(AdditionalDependencies) + libExtensions.lib;libcocos2d.lib;libCocosDenshion.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libcurl_imp.lib;pthreadVCE2.lib;websockets.lib;%(AdditionalDependencies) $(OutDir)$(ProjectName).exe $(OutDir);%(AdditionalLibraryDirectories) true @@ -88,6 +88,10 @@ + + if not exist "$(OutDir)" mkdir "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" + @@ -104,7 +108,7 @@ 4267;4251;4244;%(DisableSpecificWarnings) - libcocos2d.lib;libCocosDenshion.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libcurl_imp.lib;libExtensions.lib;pthreadVCE2.lib;%(AdditionalDependencies) + libExtensions.lib;libcocos2d.lib;libCocosDenshion.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libcurl_imp.lib;pthreadVCE2.lib;websockets.lib;%(AdditionalDependencies) $(OutDir)$(ProjectName).exe $(OutDir);%(AdditionalLibraryDirectories) true @@ -117,6 +121,10 @@ + + if not exist "$(OutDir)" mkdir "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" + diff --git a/template/multi-platform-js/proj.ios/AppController.mm b/template/multi-platform-js/proj.ios/AppController.mm index ce9bb75462..5910da0d35 100644 --- a/template/multi-platform-js/proj.ios/AppController.mm +++ b/template/multi-platform-js/proj.ios/AppController.mm @@ -28,6 +28,8 @@ static AppDelegate s_sharedApplication; sharegroup: nil multiSampling: NO numberOfSamples: 0 ]; + + [__glView setMultipleTouchEnabled:YES]; // Use RootViewController manage EAGLView viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil]; diff --git a/template/multi-platform-js/proj.win32/HelloJavascript.vcxproj b/template/multi-platform-js/proj.win32/HelloJavascript.vcxproj index 7e7788bdf3..4011e819b9 100644 --- a/template/multi-platform-js/proj.win32/HelloJavascript.vcxproj +++ b/template/multi-platform-js/proj.win32/HelloJavascript.vcxproj @@ -94,10 +94,10 @@ if not exist "$(OutDir)" mkdir "$(OutDir)" xcopy /Y /Q "$(ProjectDir)..\..\..\scripting\javascript\spidermonkey-win32\lib\*.*" "$(OutDir)" - +xcopy /Y /Q "$(ProjectDir)..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" - libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libCocosDenshion.lib;libchipmunk.lib;libJSBinding.lib;libcurl_imp.lib;mozjs.lib;ws2_32.lib;sqlite3.lib;pthreadVCE2.lib;%(AdditionalDependencies) + libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libCocosDenshion.lib;libchipmunk.lib;libJSBinding.lib;libcurl_imp.lib;mozjs.lib;ws2_32.lib;sqlite3.lib;pthreadVCE2.lib;websockets.lib;%(AdditionalDependencies) $(OutDir);%(AdditionalLibraryDirectories) true Windows @@ -148,10 +148,10 @@ xcopy "$(ProjectDir)..\Resources" "$(OutDir)\HelloJavascriptRes\" /e /Y if not exist "$(OutDir)" mkdir "$(OutDir)" xcopy /Y /Q "$(ProjectDir)..\..\..\scripting\javascript\spidermonkey-win32\lib\*.*" "$(OutDir)" - +xcopy /Y /Q "$(ProjectDir)..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" - libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libCocosDenshion.lib;libchipmunk.lib;libJSBinding.lib;libcurl_imp.lib;mozjs.lib;ws2_32.lib;sqlite3.lib;pthreadVCE2.lib;%(AdditionalDependencies) + libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libCocosDenshion.lib;libchipmunk.lib;libJSBinding.lib;libcurl_imp.lib;mozjs.lib;ws2_32.lib;sqlite3.lib;pthreadVCE2.lib;websockets.lib;%(AdditionalDependencies) $(OutDir);%(AdditionalLibraryDirectories) Windows MachineX86 diff --git a/template/multi-platform-lua/proj.ios/AppController.mm b/template/multi-platform-lua/proj.ios/AppController.mm index cbccc23254..2218aac5e4 100644 --- a/template/multi-platform-lua/proj.ios/AppController.mm +++ b/template/multi-platform-lua/proj.ios/AppController.mm @@ -51,6 +51,7 @@ static AppDelegate s_sharedApplication; multiSampling: NO numberOfSamples: 0 ]; + [__glView setMultipleTouchEnabled:YES]; // Use RootViewController manage EAGLView viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil]; viewController.wantsFullScreenLayout = YES; diff --git a/template/multi-platform-lua/proj.win32/HelloLua.vcxproj b/template/multi-platform-lua/proj.win32/HelloLua.vcxproj index ccb952cd36..90da9385fe 100644 --- a/template/multi-platform-lua/proj.win32/HelloLua.vcxproj +++ b/template/multi-platform-lua/proj.win32/HelloLua.vcxproj @@ -79,7 +79,7 @@ MachineX86 true $(OutDir);%(AdditionalLibraryDirectories) - libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libCocosDenshion.lib;liblua.lib;%(AdditionalDependencies) + libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libCocosDenshion.lib;liblua.lib;lua51.lib;websockets.lib;%(AdditionalDependencies) 0x0409 @@ -104,6 +104,10 @@ + + if not exist "$(OutDir)" mkdir "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" + @@ -123,7 +127,7 @@ Windows MachineX86 $(OutDir);%(AdditionalLibraryDirectories) - libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libCocosDenshion.lib;liblua.lib;%(AdditionalDependencies) + libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libCocosDenshion.lib;liblua.lib;lua51.lib;websockets.lib;%(AdditionalDependencies) 0x0409 @@ -148,20 +152,16 @@ + + if not exist "$(OutDir)" mkdir "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" + - - - - - - - - diff --git a/template/multi-platform-lua/proj.win32/HelloLua.vcxproj.filters b/template/multi-platform-lua/proj.win32/HelloLua.vcxproj.filters index 99c727af38..593b960878 100644 --- a/template/multi-platform-lua/proj.win32/HelloLua.vcxproj.filters +++ b/template/multi-platform-lua/proj.win32/HelloLua.vcxproj.filters @@ -15,10 +15,6 @@ win32 - - - - @@ -27,9 +23,5 @@ win32 - - - - \ No newline at end of file diff --git a/tools/tojs/cocos2dx.ini b/tools/tojs/cocos2dx.ini index 4b47d76c41..8d1da651d5 100644 --- a/tools/tojs/cocos2dx.ini +++ b/tools/tojs/cocos2dx.ini @@ -47,7 +47,7 @@ skip = CCNode::[convertToWindowSpace ^setPosition$ getGrid setGLServerState desc CCDirector::[getAccelerometer getKeypadDispatcher getTouchDispatcher setWatcherCallbackFun getOpenGLView getProjection getClassTypeInfo], CCLayer.*::[didAccelerate (g|s)etBlendFunc], CCMenu.*::[.*Target getSubItems create initWithItems alignItemsInRows alignItemsInColumns], - CCMenuItem.*::[create setCallback], + CCMenuItem.*::[create setCallback initWithCallback], CCCopying::[*], CC.*Protocol::[*], CC.*Delegate::[*],