From 8bff3fad476df8f39cdf307b5f491b8f77f8e8ef Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Wed, 25 May 2011 13:06:08 -0400 Subject: [PATCH 01/13] + Most recent version of FBConnect + New fields used by the app delegate for SHKFacebook + ShareKitAppDelegate now propagating appropriate incoming URLs + Replaced SHKFacebookKey and SHKFacebookSecret with SHKFacebookAppID + New version of SHKFacebook based on most recently released FBConnect library + Updated project file --- Classes/Example/ShareKitAppDelegate.m | 30 + Classes/ShareKit/SHKConfig.h | 3 +- .../FBConnect.bundle/images/login.png | Bin 2102 -> 0 bytes .../FBConnect.bundle/images/login2.png | Bin 3843 -> 0 bytes .../FBConnect.bundle/images/login2_down.png | Bin 3728 -> 0 bytes .../FBConnect.bundle/images/login_down.png | Bin 1980 -> 0 bytes .../FBConnect.bundle/images/logout.png | Bin 1661 -> 0 bytes .../FBConnect.bundle/images/logout_down.png | Bin 1551 -> 0 bytes .../Services/Facebook/FBConnect/FBConnect.h | 18 +- .../Facebook/FBConnect/FBConnectGlobal.h | 218 ------ .../Facebook/FBConnect/FBConnectGlobal.m | 45 -- .../images/close.png | Bin .../images/fbicon.png | Bin .../Services/Facebook/FBConnect/FBDialog.h | 73 +- .../Services/Facebook/FBConnect/FBDialog.m | 280 ++++---- .../Facebook/FBConnect/FBFeedDialog.h | 42 -- .../Facebook/FBConnect/FBFeedDialog.m | 85 --- .../Facebook/FBConnect/FBLoginButton.h | 49 -- .../Facebook/FBConnect/FBLoginButton.m | 196 ------ .../Facebook/FBConnect/FBLoginDialog.h | 36 +- .../Facebook/FBConnect/FBLoginDialog.m | 149 ++-- .../Facebook/FBConnect/FBPermissionDialog.h | 31 - .../Facebook/FBConnect/FBPermissionDialog.m | 101 --- .../Services/Facebook/FBConnect/FBRequest.h | 137 ++-- .../Services/Facebook/FBConnect/FBRequest.m | 465 ++++++------ .../Services/Facebook/FBConnect/FBSession.h | 205 ------ .../Services/Facebook/FBConnect/FBSession.m | 301 -------- .../Facebook/FBConnect/FBStreamDialog.h | 62 -- .../Facebook/FBConnect/FBStreamDialog.m | 77 -- .../Facebook/FBConnect/FBXMLHandler.h | 32 - .../Facebook/FBConnect/FBXMLHandler.m | 152 ---- .../Services/Facebook/FBConnect/Facebook.h | 113 +++ .../Services/Facebook/FBConnect/Facebook.m | 660 ++++++++++++++++++ .../Services/Facebook/FBConnect/JSON/JSON.h | 50 ++ .../Facebook/FBConnect/JSON/NSObject+SBJSON.h | 68 ++ .../Facebook/FBConnect/JSON/NSObject+SBJSON.m | 53 ++ .../Facebook/FBConnect/JSON/NSString+SBJSON.h | 58 ++ .../Facebook/FBConnect/JSON/NSString+SBJSON.m | 55 ++ .../Services/Facebook/FBConnect/JSON/SBJSON.h | 75 ++ .../Services/Facebook/FBConnect/JSON/SBJSON.m | 212 ++++++ .../Facebook/FBConnect/JSON/SBJsonBase.h | 86 +++ .../Facebook/FBConnect/JSON/SBJsonBase.m | 78 +++ .../Facebook/FBConnect/JSON/SBJsonParser.h | 87 +++ .../Facebook/FBConnect/JSON/SBJsonParser.m | 475 +++++++++++++ .../Facebook/FBConnect/JSON/SBJsonWriter.h | 129 ++++ .../Facebook/FBConnect/JSON/SBJsonWriter.m | 237 +++++++ .../Services/Facebook/SHKFBStreamDialog.h | 19 - .../Services/Facebook/SHKFBStreamDialog.m | 40 -- .../Sharers/Services/Facebook/SHKFacebook.h | 22 +- .../Sharers/Services/Facebook/SHKFacebook.m | 263 +++---- ShareKit-Info.plist | 13 + ShareKit.xcodeproj/project.pbxproj | 166 ++--- 52 files changed, 3266 insertions(+), 2480 deletions(-) delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2_down.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login_down.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout_down.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m rename Classes/ShareKit/Sharers/Services/Facebook/FBConnect/{FBConnect.bundle => FBDialog.bundle}/images/close.png (100%) rename Classes/ShareKit/Sharers/Services/Facebook/FBConnect/{FBConnect.bundle => FBDialog.bundle}/images/fbicon.png (100%) delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m delete mode 100755 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h delete mode 100755 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/JSON.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m diff --git a/Classes/Example/ShareKitAppDelegate.m b/Classes/Example/ShareKitAppDelegate.m index e905ec41..259a5503 100644 --- a/Classes/Example/ShareKitAppDelegate.m +++ b/Classes/Example/ShareKitAppDelegate.m @@ -9,6 +9,7 @@ #import "ShareKitAppDelegate.h" #import "RootViewController.h" +#import "SHKFacebook.h" #import "SHKReadItLater.h" #import "SHKFacebook.h" @@ -45,6 +46,35 @@ - (void)applicationWillTerminate:(UIApplication *)application // Save data if appropriate } +- (BOOL)handleOpenURL:(NSURL*)url +{ + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + NSNumber *index = [info objectForKey:@"FacebookURLTypeIndex"]; + if (! index) return YES; + + NSArray *urlTypes = [info objectForKey:@"CFBundleURLTypes"]; + if ((! urlTypes) || ([urlTypes count] <= [index integerValue])) return YES; + + NSDictionary *facebookURL = [urlTypes objectAtIndex:[index integerValue]]; + NSString *scheme = [[facebookURL objectForKey:@"CFBundleURLSchemes"] lastObject]; + if ([[url scheme] isEqualToString:scheme]) + return [SHKFacebook handleOpenURL:url]; + return YES; +} + +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation +{ + return [self handleOpenURL:url]; +} + +- (BOOL)application:(UIApplication *)application + handleOpenURL:(NSURL *)url +{ + return [self handleOpenURL:url]; +} #pragma mark - #pragma mark Memory management diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index c2aa3565..9c6a1efb 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -46,8 +46,7 @@ // If SHKFacebookUseSessionProxy is enabled then SHKFacebookSecret is ignored and should be left blank #define SHKFacebookUseSessionProxy NO -#define SHKFacebookKey @"" -#define SHKFacebookSecret @"" +#define SHKFacebookAppID @"" #define SHKFacebookSessionProxyURL @"" // Read It Later - http://readitlaterlist.com/api/?shk diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login.png deleted file mode 100644 index 77bc30c27400597b79ccc126fabd5bcc0fb3a41c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2102 zcmV-62+8+}P)*hL`sNJ)3hS3TI$f|ffT8Va8oI?La8WKP?HeL zfgrVN3wB7sCK%HYY-)q;wY{wO{haB!cOPDx-Sq=ks;W8Y*uMAdJ#*(f-<)&qumVQK zM5-ngNriE$$iyO#Q;9T0>OumDW(II|b@f_{#qzu;iYsWWRj``|+OlkwB&oycbRKJN zZf=PJ?qon48OYnWZ?DUpTl`X9VWnYK-eSEVsuU(qLxO&H*k!*H7`%1KGt~FRFHfC1 z)yTl+KyTTyrOIqJ|E}zj@6FNZO)3Sh835ep3V;5WqkRsC0V zvPF$i6%NY^N;4n~%fgDSIo)mV@2BBzHBZ!nuvDM9KpzZC3PLj|`pkuT!nPFAE`w3n zEJH1XLkiF{D{3LyXvi_35mZvff3+DI1v(9zg8?5xK|j|i#Z#l>s?q8dphtmD&1h!3 z(AqJrD^#t0fGUHm038E5l&%m8yk^2+woJ*p$LZi}Q~8!92?4(wK97U{76cXa1~YUS zmjAb>Kvu{8N(VFpWFjdp%)x6fZbojFk&oByZjAdCk`P)7hv0G9VA2M$qq-D}7tV&; zLs{&mhIf;BgK|x(S1Y_LnoYG@6(m(i|%%bd(74n6yJhR*>X- z{CQn=%*j@xp?*7z8CrC9-^EvE=c1}|2{x>+zz<$M4O!GfrPfkVg0x0rZ74*QhJK4Y zP_i5zv$vR?5hIn2t&Igb91ifmRVppn)MH4HXk#xb{C+=v`u)dIwsanLJb#?}WPjA3 zFlnIqZo=spElAtiy_~-jTSi@#GZ()qkL}kd&yRl)Yj70gGB|IIQa6@$j>qHdF!wXKYIN% z25tRhv*7UIJun)yaoa0L&*Iq~Ysr?y=YGC_6B>Sd5!Y_o(&9Geq!H^pM8QuzxkApH?Cg+tsyI^ZNs`!uvaPT<4&SYP2mxwi z4?edU9)Fn6Gc_6X*t6?l9D4gRbP%vi*k0HkC&DZdw>YC+4%@UCJ#^PSCUwNdiGE{w zaXhOdXQu${!*{6P)>BIHLoIuWg_#&|Ik9^AD*l=G&RpSsPJU#=(={b{uwp*VMcU2F z9k*c}uwtNpfJSSe*NX6ZJxOgDIu*~cjL8GU)cw245P4H9qw0Z$ShaE)^0STj^SSHj zx^FEfkF8?Ga)=s~wXO<9MJYd3we0$-T$pOimmp`W0~R`txnQ*j-bO zhbjy4<~z+0L^Wh8LYvkt!;kmY;Q0HOX-*YAFnM|I6vSx2C~yL$4(?wH6LZ46fW`M4 zz20~m4|sIlm48`r_CiYktLBl zO+kw7iGezPkEv|zXZ!Vj?!SC#KHA#aap}@OQL}y#RxHVm+ctf@7$%hy7M&k&{$v-P z`sP}wwFbnB&4XpLp@EkI8JaY1>d{{L{@T0LJvglulCOW`*m-=b#*HU8lwkduVm`-i zl+E`KMi|ui$BU?Y>Z@q^;Be$gpx~T3b1k85Bi75*x`~?D3}Tt?9-AE5&x>!I!K(*0 zqUqQRe43?^KQwiYvAy?pecbl$>8sp!_8&K~WPTQYLEX|1>2vMZ2h!p;=FG=h#oF51 z9=mzV+;lm5a9}X)$uO2W65Bg=GR&Kumo!Hwiis-x;suf7$XJ!iJ}~6sH$GERv20Gt zYo@bJMP@la>N|1b#DaJqosP8kLFh@Xb-Dv+>+GMleY%p)=L}y@PAG;_TE-2<-d&`S zRa;+6UUg}$%M(!EOve~4rO7qygjBX-F-#d#`;T!KwL~srqa-PB@6=T2#GN~LrY(4O zrsPO~A01Gy(}tl_zSl7WqJlp>E7WdVUS7_+1dTxXgEfr0`uh53y83+2xrG9Q zPsq{J0aM8%(-08>Nhgo^jq+_z(Omtnj~qGj4o&-oXtFM1U^g~4u4!#;{f@`uDW*BK z0^8I@qtV!nM&lQim6d<0tE;<6Q$9fux`c$v$iTKli=!s0s;G)erA%A#B#eH0lxZNU g4hAy&(0>FN0K8&LR2ps7(*OVf07*qoM6N<$f~YXATM diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2.png deleted file mode 100644 index 03e8eba939acaebddd108b1efb168708b9fcdeb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3843 zcmV+e5B%_nP){~+iKvoh= zNPvKmT|rt_S=F`}p|xslr9E1u;k2a|+fxv8fq$P!l0&* zLjNlY4r&2verk3^fHQ#scfo=MQxg*tA5^JSW9eF__)eiAgW_PYEf5GCvDs|TZ{NOs zZy3ln24FJ-@2$7qx+-l%(c1LmKsW_^3O)?iU9?ow#T0@-aB5B=kr*1o>JJF2UzKVmg+&|XMKP#&NueQ245Rtum!_UN_{M6wT&dxOupks0hUFT3VnFebLPMSm!}1J- z*;0g09azdu2tp%>eg(h^eI7_7gbyBq5`f`TN(Y5LhldmW0FIM=eO@>GJ`Zn~G*7g8 z-n2S{;%bFHYXHa2z>HV3@5p71Fm39!RCz1eU7^ny!2Wm}IDzl=U`j~5B0`$hj|I4iH_qpNoxa8GIt2Yhwh1ZFI-v>dZhE8vUO0A8a zP&`gr6r=b#nOKr)Tc=}aU;byai@h&~#}Mf!G%4 z@yj19L|U?$U(Z-sCCe3p(H!H4)7}M(&WGg-N>P}X35U~z`i5q_`{4Izzi)QzGe?dg(IUE=(Ddg7lOGytbV1^`&2!=AcUIQ@PCgXXH(?eln$pQ%S_VLCpnJ$=<=v-q2J{)@6V zZkZZcCd34A@WLfPBzOlnfHsFhAb6fU7X@#4iUu1iZ-v>YL&K?VT$7oGY2~9ZcjkC} z{}9}oCIbPm=7{^*pz#njhWOBXxUyKF?9V!-2iW-O0owYbZ zfbcqcc$Q|Q)fstXzKmx(^Va}d)XWw&#un$`EAz+T)6+H_J>5q(`uS=(z-QEl$z{ZR z5XobWpS<5uM;KIpWsKl9`5j>f-G3f#<1)RoI2YJza}B%XaZVJnvPZwH(J`7%~Te?u&&`P!^b5IYqkIB|jX~1k(2OY>8 zkpQR5hci|mUuh&Dd0bTHxm#%ku@IR1V6vn_XSBdWs}u8QcDf#B6D6a@ZZ4BGRyH|p z9Y{0=kdZ?1BEN}b50fjX5@dTkE+;)BA~PcazJM03-4}(s{u1I!0UV2>0od>JVZxYf z4&INCw2^~*WnR_RdID=AI=WrtY!4RRScH2ku9x{WwWqMDY8PL2H?FDR!70c|k@*{c zw*&j?T8OtKDsS(>W{k`phIJ2r9T}+>e!s2Ljvqa~4eed$h?j^*AHA0cLgHf4FsSbXeh%nfHEN7vwS)h&$!?Pdp>v=QBLT5^j%9~38Vy3LSZvmWck@Ft- z`9CR`dLB40)s*Y*UkIm1kBkg>$49`eK zS!pgDl)=hIXVJ#Tfa&FhXr~Ezwp%4n9b1 zZA1F~)bIc5=kCX@E$i^^3v2Mzo2PQyX=vVe?NhtC4UEc4a|j&TsP=v5j@ii09)Z<& z&B8~At=zsRUZ_P`@dzxNJD$c44cO7`k>kL?I`{fgc-&6hyK*MKUi<6aTyG}-VH$_| zbLs4{JZ7v9>&s%vVw#_oO#7qI#4zXtY+AF3e4`~lf5b6xv3Qg-u)VMAvNCW-w_`vF zAzeqxm6pE2Svd4g#fzTKvplQK)Yo*Mydc`<|zEK*ate1!DCXD9G z-0QnO#mS~KTt>y3tvn++Xg07+!KjxqwNy{a6L)_jW=+gSab6#f_mYvgCO<7)_lg*EO=e8{md!5a*Lj&{JoJrnS>}|o9Mm7PMvcSd zvMg+^K7gqdkNTrl9Bydh&+XWK94i->Vch6k;^pysTi>pgWlS172b0ES;n2~L+?(f& z<-cFsc?4&ho49W!TVs)VFn|NW%iF}=a^Ge-^G04r$`zt41$z#*VC9lB%1-%s>bdQF z=?GHoH-E-xJapd@Y<}Z_Yy_*@SbZiR-_V2*qzzO+q!}s78wjp%c)YW{Wz zXU)l|Huc#Ylv(WX)3^mxQdlf1e9~?2pL_%$W>@6qYWIO={(Jt+Qe@HudE}W7Fl|B( z?zm-2cs%O>AG6QWHOp{5njBK5V|oWDX^3IH*<*|&NY6*e`O91N19VR|iFkVbZ8Sk0 zcxl@q{Pmp%{PB^SLwc&TQSBR+sF!`Tv*r}7irpb$+d}04vm;g<)Hv7xoX4dEJuY09fu<@9_x6B=b_iGN*L~N(pdf0%C>jg^)ra-)Q+2?&RDG&*M&eZ|^Arc?c9Y&n`t@XA_pr8WpO83H*{y46K87 zjKyO=>pnfl<(Cy_;NZbJ)YkqROJVA0GL*oYLo<_orvA_VZ9ng`_S-kn z2A=`lc~N-O^q=)!*)dw|Gvpwm9t0CT@%$cqZ3&xsC73z6NZtUj`{&w28Lx^ATXowc z?0xf5+1OWid=hayre^0#ynYJbfmHFF#|wt^`N0!A@QXF`Q2qS(_-$5Byj0yVfcMJp zD`nn`+YWQy&fSd|m6MD|DwpAh^jzJi)&YLoLx7!rZ7%ALhVIuBf8O-M5P0S11X-8k zr@Od}850YUXfabZt&{a;Hb?-M?2zKnZ)@mtqz+78V{}RoFea}L!OFT>>!kg-fii+l*gheCb z)xho6_PB52q!J?X7>&J&OV3P?S_4Otg*GaMxhY|%or}r0cG$VYuNJYa5o^qNyw3wg zt^}82yX5OweMb?GZ7ietB_59fJTuKg!0&?H>Ahn6l5B6cZrQRWS3U=hmt?OX0bf*K zo5PEP4d*VKf4LM-=4Ub9f0Hhxe=Pome9cyk%i*1)C!eF+9wA%| z7cdZ4RaH&iw{PEFPN%bo?r9XaDKu0_tJU_H&E{j}<>fE0TD59F-Es?pa8iia(J>Gw zhBtNEa8rkyO4;El^gr0C1^P)1RCwC#Tv==z*A+d(;U(xd@ur-_X; zR+2VOyxX#r*rM!cH6>CK_ibi+-y04|$rL4Tjah-emk9YsBcXZkug;%8 ze}sWpWK7%L-M!6hHvhV+X{*~@R7%XNgIAZ;C4xaTm@FkGYe~5!H2Y-A2s znpdH+;l=X$UY8)6MOjvKZ|SmnflL@JukR`Mja_7xVbT?d9*y8=;AbO7t}P>3j`Hy#uXz|h%OmxoYR24E?bge;{XNvS)F6VV6*HPL9& zU9HOl2C!5Bz%t;uF?m-{XlZUB1v?mS+T69s&X5?{f#cziY@&3H?Q_1 z6Bvd(PnKl@co-H@!sf1OxLpp!6Df>O&Eo3yX_&3WFjhZa!gGJ;R~c_QVscuArVJUn>!N>SpXa1 z8JkCfd@C3X_b2F*DU>^msIIVM_)GtN)6M4JBFZbWw~%B3TrkZq58zzzE^q(~3@Ohf z#3CpyG2ofK8(=XRG3AS((r!abLj^io>+rXCF9U*!Pl_x{EM)nMZ#LQN3v+I% z%{oNM6MYh;A`p0c3A`fS{$K?D`55nea%(*rYwYNHq!B|NFJjRk400SUXAy$o1j0#y z*w4lnlvQPB_-E%3k0*)2ZHUAqL=&pf)$ZcFeMU+ zRE9}ZP+nGoa5RZeE{?-Y0n6@jyUMvfyR8^bdjMJzlnD%?5++6#F-OcK8_ZO`m1Kf1 zcVhqa_TX*)jYk5guPTPS%)yUmX2Tern&%mfvG!v7nC&8!1}U;#Kmx8(3)v#kvnB3p z?RhC;ejzyzJ7o|CWV6LatZCu*B`IK>b|cI*=BeojA1~7@QxLJtWi=^uAI%r}O*U9m zdxSLMk$zSVSxqt=b}Nydi1~4a@=LvbbkDULEIRhrM{lLeIsLj zl#~Ab`?r%rRR;#calG~3W%``wea}Ao7%XOErth6ogV?pXnfg?~AAG74$3MDBlON{3 zNk|6ld%Od|P#muvzkqd(Rd{lHt2)+GL&RQdu%)K~ufKZ*Tf3`JTj{_*P7Pzn#x-1D zdrJjMiH*(=&G6&qdN(msy$VJutNwcYB4PwQZC#K{3c@i>h&_KgDKnW zd%T;lBI2EoZg56l(M}i3BDJ-(KSxo6J)P-pZ}bxm1t|>~Z&UEnPj+MHrffQ6-&yt}T)H`V+Z5SS%!z4wl)|aAEhB0j<8bg`ggr^^G$IXc#-Z*g`iKNUY zhJ8*`I_vAM#e6u4x8C<)>{bYEjZR`w6Fd`P^if^CxX(!A|Ki3pzPoP&*YU>5VGNGU zqPw-67_%6kdnWO{{hNpZ1b*L@VL#Tlx>4bF;Mj*ZQBzSuU@+s=HwX9_wJ|e>auRbi zR69ujER_jWJUARSD}nMB1zydJWqkZ zo*yM}G}StYxn+2LQO;ECc{2Ul+*!r_xNSo-wr^gCM>npepfy$!4L1jdxo%>vyhqfjcqH&3@ zS@!N~M_rWzZ@xc_&j!3?Lm4{OR^iO08|dw*$A*qtd~#_D|NNK&sI&+@k5m(p%#vOa zk5COf?GIvW&l(QiV+7uKLc)?*)G!ns4NXi;{62%oIMt*}Gw{;U5Q@YXln~l+MsGBn zx0Yd1r`BK+BE)=*U1T{)sg+WGSrG!k7}nIN40V2RoR9D9l?Wc~sYX+M8J$zN^+qS= z5DWwnm=DlV6M@t~Wk4ctpUK1~!pXrEAm({$OKmzWE5r~ktf{Z&eHRIIKHnVIarE`G zoW&AJiDwQbQA*JaEV*+1<}?RirOQe{w_#+IfZXCnmCM3ei|J%GNV2LU77ZaDOE2z{ zarz$49BbpA^sL*QhEHdN5p z5c4l(UvIk_5H2cx_U&Ag(b-g2hH-Bo?>sctIqCZtWemFJRsfSzetzBHuoqj`*HP{4 zqCOWtclOF?Mn_|9J2fZ2he>aHE&segb2{hu@paE~^{;vHB2K=`GU1PZIh|qR+~eHp zIbR9lp$OdCQ-`$#ocBK-K#~>xl&U(3z4m>r2d6KNa>miNjaY4(twq@CNX!J6%oh++ z&NG#~eF9&}iRtth#Gq#;uT9Z-oIn-h^_$yirP@~@hKl8sKq+pMkh3TpCcrZ3Tvr1J zf#mqmH8eLkIYaX25eRa9%_E6?zpwo%`;ezA9MYA`qKD6-)_<3bPfaDwE;yxu^*D?KdRd$Sx zjbU{3OZ2QOM=g~HT3_edN>~kXSdA%sfB#lm@i#Bnvu&<(Q0SUl-IXjUkFz}A3?fo zUts%U`!=s{f@gf5U&s7#{kn&0>ltk6s-n!AS?BZA9}WA_yUx8}9yGh1tfWnbxPHDR zO3%y8A&9*c7Wj>gt)-!iGYC6B zJ{3R*l@aWGKL1Yp!(2yeqZ?MMnHE{&nQ^PNwYb2Jj9oeQ2~=^ zzcaBCsF$+u^rbP*x+lr+dv>(orRSf{=o~`C-^^C&CTU6ijsKt{4v^Zk;#v;*@!vryl| zAZ+{zo(Up%WV`0;rS4?`Y^Gqy=a)i#>Y~=dcQ4o??OvrQc6sv5nKKQU{7?w(_ej9Y zDu~f)c5Ete*Zp@Zg>*iM=lw5bx$!U6znrhV{>WYRG4ct7;`iIkoPA)(1sKxE{{%D< zk1cu4FaPk~lJ~NdqKhsMLRQ4UZ1rAO^t|VmNyAXu+L^ zNGw53_m(cJOBi;I={@0;3Sj+@k#%_}h?o6hD?wfpm<$HPh)D^$lY+fScaAQrT?ngD z!t8Yoz~<`e>fcRFjJ=W+Tg?jpcVfEevN}aTN-C1Z{55rTzhzh!4;(n)XlrZpc|0CD z8Jq7>6oViWuoeA3H_>Hv0arFE;aHI}6LdLCUO9B=5Zm@rgmf{?Uf5gu`}?=txN+mT zL?W?{YGR}AHeFVWh@v=Wu~@D(G&H=id-v`$bSifE@Zk|5XGO_{)_Oz9@3n?YaU u>GBn<)MRA;H%itL=@ww%Wf%QdfB^t}ZpX{M9AEDM0000)^})o%#0Qg_n5a)i-+gd<)kx@r@xf@^V&W2QVieaZO=BxU zqO!=a6oG-+@9uxjy|XaRTn37X(fc<)lXL%j&OP@#-}%me&MgB)^P%(TEIL!>j%{v6 znd|5(dJ0NF^b>%i(dbdP+x-N?Fi|Xv4tCqJC0*BlktFH0v9Ymp7T`$&bR7Zt$dMzb zeY={U_66I$UVoDt5N!vut(&IGnv_|SQ>(L?)cVqM7cN{FB4BfbxrYxQJ}Qdh^DX=O zL!xIFGT8xnyT-5_E4bwhhAoRh2-MbM%+NdwJ0f0y@VD|2d#d)*3cI*P!1mjXt>l&M5f2 zE?R!!%m@?)kgf1!UB`h)gNxJPx@Z_e!FrHn73LP>@XK$1g6Q^w;PU=!kW!EgaxP_N z6QT$ESGT45MWAh`_vS#Cg1kX?$N*{;*q+P4t~wS@9={e`0uPHT8EE$VV1IiPbRCSq zyPsadWK^IUuj?A2KRqyDS&p6@kbyGD?zXgRR-9x{)nfTm2U1@*%r%E)c-&~P8%R(Z zBUMyIfxB;w!tRy;483&@^JLX(uXdnokdDoPE@yIKGE`{SK;U@nsBd@%*9 z>p2>`t-lTSw)!D@^a3x~WFW4y~lw#lI6()1o;i_2NStsDq~8=0HMnUp<7o&r6sPgWUyQ@_TpVLP6=PGeRcOTa2M2Eif1OE= zWLkpvKf8p#>oj)i)G=_0d?EJ9m*a5rbsZQp2j-sJyW!)nXK)bGHDkk;0#em&8hh%I z0qWJtq;7e8ND*YH3BYnZvmus~HJD#YL3}+84Stb=JTsq!Gw+ST_ZJsYS{kAEPy`3h z1VTYodHur)_~@%?TJG*_1y1xhOR5X8aUM(JdjA{U{C8Fde4RNIoiMTKWE^Eo-pidYrtz}x;Z<)2FXMc66*;p z?E{`?ar(;@V}iiK?&bhxasrup`}Mmm%{FiVgRrM9Ok+PyT!xjEHQL7T+vh>VnJ43@ zX;z=JnFP)#z9uG%gVKa9O`{;xaW>u2nPf> z)DeQ)ZtA9K-o(@j9SmZ2Q>~5+n#JUeOgPWDW&8zUhU_bO-(}BC&;&+gaNIh_%STo(&#LF0MTv^g#Ten*E zv)}y=M^kNZZC4mN_cfbRgD-ma+euhY5ebrDWON1w`u4&zkDam>!#K*uVliuD%&%=s zNvf59muj*1&W^)<$GhP1hwq@*h>ZOB^WuisqYo8hKU|upv5DW8p{crRg2n8Tv6d-Yf-jiCiH&n7f>)8c!hjBn#Ln zi?q~NeWqP(E9S{vS{NN2Z7<}}b|Z6zgx<7)oTNc)F|qCVcFnHM9e!R(9u2w;<9PZh z*F3wZY|p;@S=G8k4*u^}6Qjv$9cc{}lK5JU04!l%Y&b{V20t`3#10P++h!J-oQ&?A z-f!0k#=MnNt0vIS$L}2`GEKV)#sp}AW!WjgNQM-~?{UD{IYUgdi0yBApv7=F{L=h< z>{W$3C>r!!&9N&r22{7mg*9GJW{F@EC2@S~4u+}| z3<;Kq>6sHJPK*(Z8B44?NG3KiGIIU&^z_5BEO#Q(yu-__8^>{LE|=@q_V)I71_lO3 z$u{8h>C;n8$;wE;uD2FP!E(-W)>$cSS3Dhx|9h0UYvCP)Xv$!7@@Qp;X+}MQ~ARx~Lmh?IK_ox~SsHTFJ%-4KZeuK-EAJ$VTvy zMWQZz$JeN%jx+XrzjJO!lNm>6f=P2f__^oa^SI}J|9`*ppUc(Ie~1?rAxtk!D@@}# zYDq;PaC>aubKDcQEo`1VWC95w`1Qlqbeu3^5q)ENwsDqA7I)|P|%`g&dK>+824Jb3UI^w@1OnSLrLDAYwngp&w+ zm8B2>Twb|Spc@_@x-Cxs)U!})H0R^u;#87DjQIF?a2rFO32vN@g36OA4g7DngJonupp4uELX{c&&YRCl;#i&iBmP@;vP z^U+|ooGit$uXEqyh=y!!Z*TKkBQ{H7#g6#Dy#-7(9Y=H^`u$~M4Bh#;jAE@uJ}>;P zRT)?8mi+eJ+uLJ;Gcqzr|v-kJ~EfB?(|PJttEl=DM-SqF0DTPWv%z5x26{%9YVyoRd`hbGLoH$y72ID?t}93^6~*0o-q~|7nx`P0f06b z1LFlP9sbA+CiM%XFUat2hq8=F5Dq!X&d#PAH*P3xMn^~K?%liWl(e)os;a8u>(F|9 zZ-6s8Iy#uRy1F__NJvoXJ3BjRW@d(pi;LNCK0iNCnVFe%S;ry8|40YAA`8q#tTxl}uCF#--o!GU4Tq=ZcC7 zc1BxU8xvx+T9vdCbs!l|K|RK+uCC^ONIwBYw@gI=klxeN!{w(>pK>|S=kUdw647&W zbABU^$okH@rIpP?(jm_!FlleS^aVUD0C_+kslSkj^z?KtKYH|t=Q%JiKt)AGl$@N* zQh>fgLql8!^78T&$w)~_VF!(jjBwra=g+CMw3MTCV`GD_K{{|xdH&|j8)aT_;Oy*d zK+h1+Vt88EZgnb=?0p`L)Y$EIMWYP{gYuAw#?8%5#R)jdMGg|Nu&}_93O$B&NZpr` zAs1A+D9XhR&h@_M(fObrW6ArT3DKbjUi+(8uPTHft(usapljEzQDI>rN3P9gQ*;{9 z2168YZEaCZObjnzSUhDL$c))+=C>gyCx=OY{rWZE3xNKE#N6E6L;D5*vV(R@OG~_% ze)L4k=mJraNQs7q2D*R$KI?Q>SC>NIlP6EO+}_^KbxBD{EE6D6qQAeNiE3YP|jq`GfkXBvKyz&6_u|)cS1Y1Yw>m;8f6P=u-wbMq+4E_9QCa z3(w#fS`aBxs|~Rch%%c^DlH*|-M)de)h>!gM6~hJrAy88b2F~JVB|r?Tk8`z6`Q5s z5zHE)8TgQ3s;{sAb$Mm2=zP?9t;u8zdT;;95-hgyjx7hRuC2PGtxGe*N$+VoAnfZ5ZZS6fMhzQz$G+rws$i^R~ z20Hkw6ra<=JSm`#)Sn)Grf$Mq9^3Vp1KSQ^^B@_G{uN*V%EX(FG09w#00000NkvXX Hu0mjfJI@|W diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout_down.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout_down.png deleted file mode 100644 index 1ab14b9dc931eeb1b624cca1bbf422a2445f1754..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1551 zcmV+q2JrcbP)4o$iGOaKRRrBWWrYV<@q2Zm^>vh`gb`7bL0j?*j)uxX` z!aYYvM{kYt{Yt0PNvTvyL#TvSUhc%Dn&b=v8ewD$pe7e3Hef0+7C>uke&WnM`uecVU1VjYbXVT!04KfB)mApl=xIvul!+E6~DBW=me9C*rZ3Qbhz3`6p%! zbgitcjL(D*4QR@y(YXY{RqdcpKI$Te&CJVReLt`C&9?agz-UujTT8K6j80EaiS1DT zHB|6CH#avt_z1YwYURN%#*Ddunae_{2Kiy%TmogY*{Hp}o!D-Q&d$#M(MODfD_D=f z$g6tBI`M8|JlqF(5BtEyJ$QL}ISmaB(bm=$9UL4e;}!$7R0^OUGFknS>X%M8zK{y> z((32IVho0XX%2^je?~o+hL=Yf{mo`GU0hu7_NX(NOuRqp1uIdH*@6Wceen6}>PlI> zF-9a3;XuQ%i9;KVfx0J^j$%^3T>7Gox}CZVKp`iMjg8dZ-L13<27|P`yv&1AS64^< z{r$>W1N{2>nidxqIXELDBUDjQq0}!eEz#xWCAGD+aYs2E4wKvM=H;E89cpQ5;qB|| z>v?cjS67R|p=gc%VsiM=ay}ZJ323kryH>C&upm;paS=-y&%RxpR+MsT5aFAwaXO&qb*e%jffF1}0$nW>l?(Qz_?d=t<`wGyZ zP$-*c&X-zmz`XjFMF1SdN-c>rCgz5Q|N9+O46U@?=W zLd+uQtNhFB`JR&Q~w$?l;(4{sk zKAoMN%1eW-$H&L~p4aQ;%G|94tl<&>s#qi#A9bAt_*OQ&STM9V|zt1B3np zMAWIyD7Zm(&<-pwCdGR;Knr#OBmtzbnVA``&Cuz|$w>u3ELyOIg#}($U0uxqgbPDI z05vf&ac?mcW1uax9(@rAaa4@pp$@WzAmKZTm5yhzKgLS|&~ye+k=BExohHK;TVp#IZLg`R`6e8?WRj}=I9swa zZH6TCua%XR3oK!m#D4$(Ev$vRluGe46JQBU$HvBf1I9X8tZ`7` zn4h2jm?iz6vaPH$l}c&<6IOt+boSP4HlMrQ?w^K-hkwSo+SJt4ypjXSV7ugFI{c0V z!7h_iKqS%{@M%&vD240^*>TW -#import - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -extern const NSString* kFB_SDK_VersionNumber; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef DEBUG -#define FBLOG -#define FBLOG2 -#else -#define FBLOG -#define FBLOG2 -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -typedef unsigned long long FBUID; -typedef unsigned long long FBID; - -#define FBAPI_ERROR_DOMAIN @"api.facebook.com" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Error codes - -#define FBAPI_EC_SUCCESS 0 -#define FBAPI_EC_UNKNOWN 1 -#define FBAPI_EC_SERVICE 2 -#define FBAPI_EC_METHOD 3 -#define FBAPI_EC_TOO_MANY_CALLS 4 -#define FBAPI_EC_BAD_IP 5 -#define FBAPI_EC_HOST_API 6 -#define FBAPI_EC_HOST_UP 7 -#define FBAPI_EC_SECURE 8 -#define FBAPI_EC_RATE 9 -#define FBAPI_EC_PERMISSION_DENIED 10 -#define FBAPI_EC_DEPRECATED 11 -#define FBAPI_EC_VERSION 12 - -#define FBAPI_EC_PARAM 100 -#define FBAPI_EC_PARAM_FBAPI_KEY 101 -#define FBAPI_EC_PARAM_SESSION_KEY 102 -#define FBAPI_EC_PARAM_CALL_ID 103 -#define FBAPI_EC_PARAM_SIGNATURE 104 -#define FBAPI_EC_PARAM_TOO_MANY 105 -#define FBAPI_EC_PARAM_USER_ID 110 -#define FBAPI_EC_PARAM_USER_FIELD 111 -#define FBAPI_EC_PARAM_SOCIAL_FIELD 112 -#define FBAPI_EC_PARAM_EMAIL 113 -#define FBAPI_EC_PARAM_ALBUM_ID 120 -#define FBAPI_EC_PARAM_PHOTO_ID 121 -#define FBAPI_EC_PARAM_FEED_PRIORITY 130 -#define FBAPI_EC_PARAM_CATEGORY 140 -#define FBAPI_EC_PARAM_SUBCATEGORY 141 -#define FBAPI_EC_PARAM_TITLE 142 -#define FBAPI_EC_PARAM_DESCRIPTION 143 -#define FBAPI_EC_PARAM_BAD_JSON 144 -#define FBAPI_EC_PARAM_BAD_EID 150 -#define FBAPI_EC_PARAM_UNKNOWN_CITY 151 -#define FBAPI_EC_PARAM_BAD_PAGE_TYPE 152 - -#define FBAPI_EC_PERMISSION 200 -#define FBAPI_EC_PERMISSION_USER 210 -#define FBAPI_EC_PERMISSION_ALBUM 220 -#define FBAPI_EC_PERMISSION_PHOTO 221 -#define FBAPI_EC_PERMISSION_MESSAGE 230 -#define FBAPI_EC_PERMISSION_MARKUP_OTHER_USER 240 -#define FBAPI_EC_PERMISSION_STATUS_UPDATE 250 -#define FBAPI_EC_PERMISSION_PHOTO_UPLOAD 260 -#define FBAPI_EC_PERMISSION_SMS 270 -#define FBAPI_EC_PERMISSION_CREATE_LISTING 280 -#define FBAPI_EC_PERMISSION_EVENT 290 -#define FBAPI_EC_PERMISSION_LARGE_FBML_TEMPLATE 291 -#define FBAPI_EC_PERMISSION_LIVEMESSAGE 292 -#define FBAPI_EC_PERMISSION_RSVP_EVENT 299 - -#define FBAPI_EC_EDIT 300 -#define FBAPI_EC_EDIT_USER_DATA 310 -#define FBAPI_EC_EDIT_PHOTO 320 -#define FBAPI_EC_EDIT_ALBUM_SIZE 321 -#define FBAPI_EC_EDIT_PHOTO_TAG_SUBJECT 322 -#define FBAPI_EC_EDIT_PHOTO_TAG_PHOTO 323 -#define FBAPI_EC_EDIT_PHOTO_FILE 324 -#define FBAPI_EC_EDIT_PHOTO_PENDING_LIMIT 325 -#define FBAPI_EC_EDIT_PHOTO_TAG_LIMIT 326 -#define FBAPI_EC_EDIT_ALBUM_REORDER_PHOTO_NOT_IN_ALBUM 327 -#define FBAPI_EC_EDIT_ALBUM_REORDER_TOO_FEW_PHOTOS 328 -#define FBAPI_EC_MALFORMED_MARKUP 329 -#define FBAPI_EC_EDIT_MARKUP 330 -#define FBAPI_EC_EDIT_FEED_TOO_MANY_USER_CALLS 340 -#define FBAPI_EC_EDIT_FEED_TOO_MANY_USER_ACTION_CALLS 341 -#define FBAPI_EC_EDIT_FEED_TITLE_LINK 342 -#define FBAPI_EC_EDIT_FEED_TITLE_LENGTH 343 -#define FBAPI_EC_EDIT_FEED_TITLE_NAME 344 -#define FBAPI_EC_EDIT_FEED_TITLE_BLANK 345 -#define FBAPI_EC_EDIT_FEED_BODY_LENGTH 346 -#define FBAPI_EC_EDIT_FEED_PHOTO_SRC 347 -#define FBAPI_EC_EDIT_FEED_PHOTO_LINK 348 -#define FBAPI_EC_EDIT_VIDEO_SIZE 350 -#define FBAPI_EC_EDIT_VIDEO_INVALID_FILE 351 -#define FBAPI_EC_EDIT_VIDEO_INVALID_TYPE 352 -#define FBAPI_EC_EDIT_FEED_TITLE_ARRAY 360 -#define FBAPI_EC_EDIT_FEED_TITLE_PARAMS 361 -#define FBAPI_EC_EDIT_FEED_BODY_ARRAY 362 -#define FBAPI_EC_EDIT_FEED_BODY_PARAMS 363 -#define FBAPI_EC_EDIT_FEED_PHOTO 364 -#define FBAPI_EC_EDIT_FEED_TEMPLATE 365 -#define FBAPI_EC_EDIT_FEED_TARGET 366 -#define FBAPI_EC_USERS_CREATE_INVALID_EMAIL 370 -#define FBAPI_EC_USERS_CREATE_EXISTING_EMAIL 371 -#define FBAPI_EC_USERS_CREATE_BIRTHDAY 372 -#define FBAPI_EC_USERS_CREATE_PASSWORD 373 -#define FBAPI_EC_USERS_REGISTER_INVALID_CREDENTIAL 374 -#define FBAPI_EC_USERS_REGISTER_CONF_FAILURE 375 -#define FBAPI_EC_USERS_REGISTER_EXISTING 376 -#define FBAPI_EC_USERS_REGISTER_DEFAULT_ERROR 377 -#define FBAPI_EC_USERS_REGISTER_PASSWORD_BLANK 378 -#define FBAPI_EC_USERS_REGISTER_PASSWORD_INVALID_CHARS 379 -#define FBAPI_EC_USERS_REGISTER_PASSWORD_SHORT 380 -#define FBAPI_EC_USERS_REGISTER_PASSWORD_WEAK 381 -#define FBAPI_EC_USERS_REGISTER_USERNAME_ERROR 382 -#define FBAPI_EC_USERS_REGISTER_MISSING_INPUT 383 -#define FBAPI_EC_USERS_REGISTER_INCOMPLETE_BDAY 384 -#define FBAPI_EC_USERS_REGISTER_INVALID_EMAIL 385 -#define FBAPI_EC_USERS_REGISTER_EMAIL_DISABLED 386 -#define FBAPI_EC_USERS_REGISTER_ADD_USER_FAILED 387 -#define FBAPI_EC_USERS_REGISTER_NO_GENDER 388 - -#define FBAPI_EC_AUTH_EMAIL 400 -#define FBAPI_EC_AUTH_LOGIN 401 -#define FBAPI_EC_AUTH_SIG 402 -#define FBAPI_EC_AUTH_TIME 403 - -#define FBAPI_EC_SESSION_METHOD 451 -#define FBAPI_EC_SESSION_REQUIRED 453 -#define FBAPI_EC_SESSION_REQUIRED_FOR_SECRET 454 -#define FBAPI_EC_SESSION_CANNOT_USE_SESSION_SECRET 455 - -#define FBAPI_EC_MESG_BANNED 500 -#define FBAPI_EC_MESG_NO_BODY 501 -#define FBAPI_EC_MESG_TOO_LONG 502 -#define FBAPI_EC_MESG_RATE 503 -#define FBAPI_EC_MESG_INVALID_THREAD 504 -#define FBAPI_EC_MESG_INVALID_RECIP 505 -#define FBAPI_EC_POKE_INVALID_RECIP 510 -#define FBAPI_EC_POKE_OUTSTANDING 511 -#define FBAPI_EC_POKE_RATE 512 - -#define FQL_EC_UNKNOWN_ERROR 600 -#define FQL_EC_PARSER_ERROR 601 -#define FQL_EC_UNKNOWN_FIELD 602 -#define FQL_EC_UNKNOWN_TABLE 603 -#define FQL_EC_NO_INDEX 604 -#define FQL_EC_UNKNOWN_FUNCTION 605 -#define FQL_EC_INVALID_PARAM 606 -#define FQL_EC_INVALID_FIELD 607 -#define FQL_EC_INVALID_SESSION 608 - -#define FBAPI_EC_REF_SET_FAILED 700 -#define FBAPI_EC_FB_APP_UNKNOWN_ERROR 750 -#define FBAPI_EC_FB_APP_FETCH_FAILED 751 -#define FBAPI_EC_FB_APP_NO_DATA 752 -#define FBAPI_EC_FB_APP_NO_PERMISSIONS 753 -#define FBAPI_EC_FB_APP_TAG_MISSING 754 - -#define FBAPI_EC_DATA_UNKNOWN_ERROR 800 -#define FBAPI_EC_DATA_INVALID_OPERATION 801 -#define FBAPI_EC_DATA_QUOTA_EXCEEDED 802 -#define FBAPI_EC_DATA_OBJECT_NOT_FOUND 803 -#define FBAPI_EC_DATA_OBJECT_ALREADY_EXISTS 804 -#define FBAPI_EC_DATA_DATABASE_ERROR 805 -#define FBAPI_EC_DATA_CREATE_TEMPLATE_ERROR 806 -#define FBAPI_EC_DATA_TEMPLATE_EXISTS_ERROR 807 -#define FBAPI_EC_DATA_TEMPLATE_HANDLE_TOO_LONG 808 -#define FBAPI_EC_DATA_TEMPLATE_HANDLE_ALREADY_IN_USE 809 -#define FBAPI_EC_DATA_TOO_MANY_TEMPLATE_BUNDLES 810 -#define FBAPI_EC_DATA_MALFORMED_ACTION_LINK 811 -#define FBAPI_EC_DATA_TEMPLATE_USES_RESERVED_TOKEN 812 - -#define FBAPI_EC_NO_SUCH_APP 900 -#define FBAPI_BATCH_TOO_MANY_ITEMS 950 -#define FBAPI_EC_BATCH_ALREADY_STARTED 951 -#define FBAPI_EC_BATCH_NOT_STARTED 952 -#define FBAPI_EC_BATCH_METHOD_NOT_ALLOWED_IN_BATCH_MODE 953 - -#define FBAPI_EC_EVENT_INVALID_TIME 1000 -#define FBAPI_EC_INFO_NO_INFORMATION 1050 -#define FBAPI_EC_INFO_SET_FAILED 1051 - -#define FBAPI_EC_LIVEMESSAGE_SEND_FAILED 1100 -#define FBAPI_EC_LIVEMESSAGE_EVENT_NAME_TOO_LONG 1101 -#define FBAPI_EC_LIVEMESSAGE_MESSAGE_TOO_LONG 1102 - -#define FBAPI_EC_PAGES_CREATE 1201 - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -NSMutableArray* FBCreateNonRetainingArray(); - -BOOL FBIsDeviceIPad(); diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m deleted file mode 100644 index 77ec5ca4..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBConnectGlobal.h" - -const NSString* kFB_SDK_VersionNumber = @"iphone/1.3.0"; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -const void* RetainNoOp(CFAllocatorRef allocator, const void *value) { return value; } -void ReleaseNoOp(CFAllocatorRef allocator, const void *value) { } - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// public - -NSMutableArray* FBCreateNonRetainingArray() { - CFArrayCallBacks callbacks = kCFTypeArrayCallBacks; - callbacks.retain = RetainNoOp; - callbacks.release = ReleaseNoOp; - return (NSMutableArray*)CFArrayCreateMutable(nil, 0, &callbacks); -} - - -BOOL FBIsDeviceIPad() { -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200 - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { - return YES; - } -#endif - return NO; -} diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/close.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.bundle/images/close.png similarity index 100% rename from Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/close.png rename to Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.bundle/images/close.png diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/fbicon.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.bundle/images/fbicon.png similarity index 100% rename from Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/fbicon.png rename to Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.bundle/images/fbicon.png diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h index 097547bc..70bae3ac 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h @@ -1,10 +1,10 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software @@ -14,14 +14,21 @@ * limitations under the License. */ -#import "FBConnectGlobal.h" +#import +#import @protocol FBDialogDelegate; -@class FBSession; + +/** + * Do not use this interface directly, instead, use dialog in Facebook.h + * + * Facebook dialog interface for start the facebook webView UIServer Dialog. + */ @interface FBDialog : UIView { id _delegate; - FBSession* _session; + NSMutableDictionary *_params; + NSString * _serverURL; NSURL* _loadingURL; UIWebView* _webView; UIActivityIndicatorView* _spinner; @@ -30,6 +37,9 @@ UIButton* _closeButton; UIDeviceOrientation _orientation; BOOL _showingKeyboard; + + // Ensures that UI elements behind the dialog are disabled. + UIView* _modalBackgroundView; } /** @@ -38,19 +48,20 @@ @property(nonatomic,assign) id delegate; /** - * The session for which the login is taking place. + * The parameters. */ -@property(nonatomic,assign) FBSession* session; +@property(nonatomic, retain) NSMutableDictionary* params; /** - * The title that is shown in the header atop the view; + * The title that is shown in the header atop the view. */ @property(nonatomic,copy) NSString* title; -/** - * Creates the view but does not display it. - */ -- (id)initWithSession:(FBSession*)session; +- (NSString *) getStringFromUrl: (NSString*) url needle:(NSString *) needle; + +- (id)initWithURL: (NSString *) loadingURL + params: (NSMutableDictionary *) params + delegate: (id ) delegate; /** * Displays the view with an animation. @@ -69,8 +80,8 @@ /** * Displays a URL in the dialog. */ -- (void)loadURL:(NSString*)url method:(NSString*)method get:(NSDictionary*)getParams - post:(NSDictionary*)postParams; +- (void)loadURL:(NSString*)url + get:(NSDictionary*)getParams; /** * Hides the view and notifies delegates of success or cancellation. @@ -97,15 +108,21 @@ * * Implementations must call dismissWithSuccess:YES at some point to hide the dialog. */ -- (void)dialogDidSucceed:(NSURL*)url; +- (void)dialogDidSucceed:(NSURL *)url; -- (void)bounce2AnimationStopped; -- (void)keyboardWillShow:(NSNotification*)notification; -- (void)keyboardWillHide:(NSNotification*)notification; +/** + * Subclasses should override to process data returned from the server in a 'fbconnect' url. + * + * Implementations must call dismissWithSuccess:YES at some point to hide the dialog. + */ +- (void)dialogDidCancel:(NSURL *)url; @end /////////////////////////////////////////////////////////////////////////////////////////////////// +/* + *Your application should implement this delegate + */ @protocol FBDialogDelegate @optional @@ -113,28 +130,38 @@ /** * Called when the dialog succeeds and is about to be dismissed. */ -- (void)dialogDidSucceed:(FBDialog*)dialog; +- (void)dialogDidComplete:(FBDialog *)dialog; + +/** + * Called when the dialog succeeds with a returning url. + */ +- (void)dialogCompleteWithUrl:(NSURL *)url; + +/** + * Called when the dialog get canceled by the user. + */ +- (void)dialogDidNotCompleteWithUrl:(NSURL *)url; /** * Called when the dialog is cancelled and is about to be dismissed. */ -- (void)dialogDidCancel:(FBDialog*)dialog; +- (void)dialogDidNotComplete:(FBDialog *)dialog; /** * Called when dialog failed to load due to an error. */ -- (void)dialog:(FBDialog*)dialog didFailWithError:(NSError*)error; +- (void)dialog:(FBDialog*)dialog didFailWithError:(NSError *)error; /** * Asks if a link touched by a user should be opened in an external browser. * - * If a user touches a link, the default behavior is to open the link in the Safari browser, + * If a user touches a link, the default behavior is to open the link in the Safari browser, * which will cause your app to quit. You may want to prevent this from happening, open the link * in your own internal browser, or perhaps warn the user that they are about to leave your app. * If so, implement this method on your delegate and return NO. If you warn the user, you * should hold onto the URL and once you have received their acknowledgement open the URL yourself * using [[UIApplication sharedApplication] openURL:]. */ -- (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL*)url; +- (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL *)url; @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m index 1aaed9f4..40455fa7 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m @@ -1,5 +1,5 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,14 @@ * limitations under the License. */ + #import "FBDialog.h" -#import "FBSession.h" +#import "Facebook.h" /////////////////////////////////////////////////////////////////////////////////////////////////// // global static NSString* kDefaultTitle = @"Connect to Facebook"; -static NSString* kStringBoundary = @"3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f"; static CGFloat kFacebookBlue[4] = {0.42578125, 0.515625, 0.703125, 1.0}; static CGFloat kBorderGray[4] = {0.3, 0.3, 0.3, 0.8}; @@ -37,9 +37,21 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL FBIsDeviceIPad() { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200 + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + return YES; + } +#endif + return NO; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + @implementation FBDialog -@synthesize session = _session, delegate = _delegate; +@synthesize delegate = _delegate, + params = _params; /////////////////////////////////////////////////////////////////////////////////////////////////// // private @@ -57,7 +69,7 @@ - (void)addRoundedRectToPath:(CGContextRef)context rect:(CGRect)rect radius:(flo CGContextScaleCTM(context, radius, radius); float fw = CGRectGetWidth(rect) / radius; float fh = CGRectGetHeight(rect) / radius; - + CGContextMoveToPoint(context, fw, fh/2); CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); @@ -84,7 +96,7 @@ - (void)drawRect:(CGRect)rect fill:(const CGFloat*)fillColors radius:(CGFloat)ra } CGContextRestoreGState(context); } - + CGColorSpaceRelease(space); } @@ -96,28 +108,28 @@ - (void)strokeLines:(CGRect)rect stroke:(const CGFloat*)strokeColor { CGContextSetStrokeColorSpace(context, space); CGContextSetStrokeColor(context, strokeColor); CGContextSetLineWidth(context, 1.0); - + { - CGPoint points[] = {rect.origin.x+0.5, rect.origin.y-0.5, - rect.origin.x+rect.size.width, rect.origin.y-0.5}; + CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y-0.5}, + {rect.origin.x+rect.size.width, rect.origin.y-0.5}}; CGContextStrokeLineSegments(context, points, 2); } { - CGPoint points[] = {rect.origin.x+0.5, rect.origin.y+rect.size.height-0.5, - rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height-0.5}; + CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y+rect.size.height-0.5}, + {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height-0.5}}; CGContextStrokeLineSegments(context, points, 2); } { - CGPoint points[] = {rect.origin.x+rect.size.width-0.5, rect.origin.y, - rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height}; + CGPoint points[] = {{rect.origin.x+rect.size.width-0.5, rect.origin.y}, + {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height}}; CGContextStrokeLineSegments(context, points, 2); } { - CGPoint points[] = {rect.origin.x+0.5, rect.origin.y, - rect.origin.x+0.5, rect.origin.y+rect.size.height}; + CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y}, + {rect.origin.x+0.5, rect.origin.y+rect.size.height}}; CGContextStrokeLineSegments(context, points, 2); } - + CGContextRestoreGState(context); CGColorSpaceRelease(space); @@ -211,11 +223,17 @@ - (NSURL*)generateURL:(NSString*)baseURL params:(NSDictionary*)params { NSMutableArray* pairs = [NSMutableArray array]; for (NSString* key in params.keyEnumerator) { NSString* value = [params objectForKey:key]; - NSString* val = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSString* pair = [NSString stringWithFormat:@"%@=%@", key, val]; - [pairs addObject:pair]; + NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes( + NULL, /* allocator */ + (CFStringRef)value, + NULL, /* charactersToLeaveUnescaped */ + (CFStringRef)@"!*'();:@&=+$,/?%#[]", + kCFStringEncodingUTF8); + + [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, escaped_value]]; + [escaped_value release]; } - + NSString* query = [pairs componentsJoinedByString:@"&"]; NSString* url = [NSString stringWithFormat:@"%@?%@", baseURL, query]; return [NSURL URLWithString:url]; @@ -224,28 +242,6 @@ - (NSURL*)generateURL:(NSString*)baseURL params:(NSDictionary*)params { } } -- (NSMutableData*)generatePostBody:(NSDictionary*)params { - if (!params) { - return nil; - } - - NSMutableData* body = [NSMutableData data]; - NSString* endLine = [NSString stringWithFormat:@"\r\n--%@\r\n", kStringBoundary]; - - [body appendData:[[NSString stringWithFormat:@"--%@\r\n", kStringBoundary] - dataUsingEncoding:NSUTF8StringEncoding]]; - - for (id key in [params keyEnumerator]) { - [body appendData:[[NSString - stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] - dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[[params valueForKey:key] dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[endLine dataUsingEncoding:NSUTF8StringEncoding]]; - } - - return body; -} - - (void)addObservers { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) @@ -268,6 +264,7 @@ - (void)removeObservers { - (void)postDismissCleanup { [self removeObservers]; [self removeFromSuperview]; + [_modalBackgroundView removeFromSuperview]; } - (void)dismiss:(BOOL)animated { @@ -275,7 +272,7 @@ - (void)dismiss:(BOOL)animated { [_loadingURL release]; _loadingURL = nil; - + if (animated) { [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:kTransitionDuration]; @@ -289,37 +286,30 @@ - (void)dismiss:(BOOL)animated { } - (void)cancel { - [self dismissWithSuccess:NO animated:YES]; + [self dialogDidCancel:nil]; } /////////////////////////////////////////////////////////////////////////////////////////////////// // NSObject - (id)init { - return [self initWithSession:[FBSession session]]; -} - -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - -- (id)initWithSession:(FBSession*)session { if (self = [super initWithFrame:CGRectZero]) { _delegate = nil; - _session = [session retain]; _loadingURL = nil; _orientation = UIDeviceOrientationUnknown; _showingKeyboard = NO; - + self.backgroundColor = [UIColor clearColor]; self.autoresizesSubviews = YES; self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.contentMode = UIViewContentModeRedraw; - - UIImage* iconImage = [UIImage imageNamed:@"FBConnect.bundle/images/fbicon.png"]; - UIImage* closeImage = [UIImage imageNamed:@"FBConnect.bundle/images/close.png"]; - + + UIImage* iconImage = [UIImage imageNamed:@"FBDialog.bundle/images/fbicon.png"]; + UIImage* closeImage = [UIImage imageNamed:@"FBDialog.bundle/images/close.png"]; + _iconView = [[UIImageView alloc] initWithImage:iconImage]; [self addSubview:_iconView]; - + UIColor* color = [UIColor colorWithRed:167.0/255 green:184.0/255 blue:216.0/255 alpha:1]; _closeButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; [_closeButton setImage:closeImage forState:UIControlStateNormal]; @@ -327,16 +317,19 @@ - (id)initWithSession:(FBSession*)session { [_closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; [_closeButton addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside]; - if ([_closeButton respondsToSelector:@selector(titleLabel)]) { - _closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12]; - } else { // This triggers a deprecation warning but at least it will work on OS 2.x - _closeButton.font = [UIFont boldSystemFontOfSize:12]; - } - _closeButton.showsTouchWhenHighlighted = YES; + + // To be compatible with OS 2.x + #if __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_2_2 + _closeButton.font = [UIFont boldSystemFontOfSize:12]; + #else + _closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12]; + #endif + + _closeButton.showsTouchWhenHighlighted = YES; _closeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin; [self addSubview:_closeButton]; - + CGFloat titleLabelFontSize = (FBIsDeviceIPad() ? 18 : 14); _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; _titleLabel.text = kDefaultTitle; @@ -346,8 +339,8 @@ - (id)initWithSession:(FBSession*)session { _titleLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; [self addSubview:_titleLabel]; - - _webView = [[UIWebView alloc] initWithFrame:CGRectZero]; + + _webView = [[UIWebView alloc] initWithFrame:CGRectMake(kPadding, kPadding, 480, 480)]; _webView.delegate = self; _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self addSubview:_webView]; @@ -358,6 +351,7 @@ - (id)initWithSession:(FBSession*)session { UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; [self addSubview:_spinner]; + _modalBackgroundView = [[UIView alloc] init]; } return self; } @@ -365,12 +359,14 @@ - (id)initWithSession:(FBSession*)session { - (void)dealloc { _webView.delegate = nil; [_webView release]; + [_params release]; + [_serverURL release]; [_spinner release]; [_titleLabel release]; [_iconView release]; [_closeButton release]; [_loadingURL release]; - [_session release]; + [_modalBackgroundView release]; [super dealloc]; } @@ -399,9 +395,20 @@ - (void)drawRect:(CGRect)rect { - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSURL* url = request.URL; + if ([url.scheme isEqualToString:@"fbconnect"]) { - if ([url.resourceSpecifier isEqualToString:@"cancel"]) { - [self dismissWithSuccess:NO animated:YES]; + if ([[url.resourceSpecifier substringToIndex:8] isEqualToString:@"//cancel"]) { + NSString * errorCode = [self getStringFromUrl:[url absoluteString] needle:@"error_code="]; + NSString * errorStr = [self getStringFromUrl:[url absoluteString] needle:@"error_msg="]; + if (errorCode) { + NSDictionary * errorData = [NSDictionary dictionaryWithObject:errorStr forKey:@"error_msg"]; + NSError * error = [NSError errorWithDomain:@"facebookErrDomain" + code:[errorCode intValue] + userInfo:errorData]; + [self dismissWithError:error animated:YES]; + } else { + [self dialogDidCancel:url]; + } } else { [self dialogDidSucceed:url]; } @@ -414,7 +421,7 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) return NO; } } - + [[UIApplication sharedApplication] openURL:request.URL]; return NO; } else { @@ -425,7 +432,7 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) - (void)webViewDidFinishLoad:(UIWebView *)webView { [_spinner stopAnimating]; _spinner.hidden = YES; - + self.title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"]; [self updateWebOrientation]; } @@ -457,8 +464,11 @@ - (void)deviceOrientationDidChange:(void*)object { // UIKeyboardNotifications - (void)keyboardWillShow:(NSNotification*)notification { + + _showingKeyboard = YES; + if (FBIsDeviceIPad()) { - // On the iPad the screen is large enough that we don't need to + // On the iPad the screen is large enough that we don't need to // resize the dialog to accomodate the keyboard popping up return; } @@ -469,11 +479,11 @@ - (void)keyboardWillShow:(NSNotification*)notification { -(kPadding + kBorderWidth), -(kPadding + kBorderWidth) - _titleLabel.frame.size.height); } - - _showingKeyboard = YES; } - (void)keyboardWillHide:(NSNotification*)notification { + _showingKeyboard = NO; + if (FBIsDeviceIPad()) { return; } @@ -483,13 +493,41 @@ - (void)keyboardWillHide:(NSNotification*)notification { kPadding + kBorderWidth, kPadding + kBorderWidth + _titleLabel.frame.size.height); } - - _showingKeyboard = NO; } - -/////////////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////////////// // public +/** + * Find a specific parameter from the url + */ +- (NSString *) getStringFromUrl: (NSString*) url needle:(NSString *) needle { + NSString * str = nil; + NSRange start = [url rangeOfString:needle]; + if (start.location != NSNotFound) { + NSRange end = [[url substringFromIndex:start.location+start.length] rangeOfString:@"&"]; + NSUInteger offset = start.location+start.length; + str = end.location == NSNotFound + ? [url substringFromIndex:offset] + : [url substringWithRange:NSMakeRange(offset, end.location)]; + str = [str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } + + return str; +} + +- (id)initWithURL: (NSString *) serverURL + params: (NSMutableDictionary *) params + delegate: (id ) delegate { + + self = [self init]; + _serverURL = [serverURL retain]; + _params = [params retain]; + _delegate = delegate; + + return self; +} + - (NSString*)title { return _titleLabel.text; } @@ -498,11 +536,24 @@ - (void)setTitle:(NSString*)title { _titleLabel.text = title; } +- (void)load { + [self loadURL:_serverURL get:_params]; +} + +- (void)loadURL:(NSString*)url get:(NSDictionary*)getParams { + + [_loadingURL release]; + _loadingURL = [[self generateURL:url params:getParams] retain]; + NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:_loadingURL]; + + [_webView loadRequest:request]; +} + - (void)show { [self load]; [self sizeToFitOrientation:NO]; - CGFloat innerWidth = self.frame.size.width - (kBorderWidth+1)*2; + CGFloat innerWidth = self.frame.size.width - (kBorderWidth+1)*2; [_iconView sizeToFit]; [_titleLabel sizeToFit]; [_closeButton sizeToFit]; @@ -512,7 +563,7 @@ - (void)show { kBorderWidth, innerWidth - (_titleLabel.frame.size.height + _iconView.frame.size.width + kTitleMarginX*2), _titleLabel.frame.size.height + kTitleMarginY*2); - + _iconView.frame = CGRectMake( kBorderWidth + kTitleMarginX, kBorderWidth + floor(_titleLabel.frame.size.height/2 - _iconView.frame.size.height/2), @@ -524,7 +575,7 @@ - (void)show { kBorderWidth, _titleLabel.frame.size.height, _titleLabel.frame.size.height); - + _webView.frame = CGRectMake( kBorderWidth+1, kBorderWidth + _titleLabel.frame.size.height, @@ -539,10 +590,15 @@ - (void)show { if (!window) { window = [[UIApplication sharedApplication].windows objectAtIndex:0]; } + + _modalBackgroundView.frame = window.frame; + [_modalBackgroundView addSubview:self]; + [window addSubview:_modalBackgroundView]; + [window addSubview:self]; [self dialogWillAppear]; - + self.transform = CGAffineTransformScale([self transformForOrientation], 0.001, 0.001); [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:kTransitionDuration/1.5]; @@ -556,12 +612,12 @@ - (void)show { - (void)dismissWithSuccess:(BOOL)success animated:(BOOL)animated { if (success) { - if ([_delegate respondsToSelector:@selector(dialogDidSucceed:)]) { - [_delegate dialogDidSucceed:self]; + if ([_delegate respondsToSelector:@selector(dialogDidComplete:)]) { + [_delegate dialogDidComplete:self]; } } else { - if ([_delegate respondsToSelector:@selector(dialogDidCancel:)]) { - [_delegate dialogDidCancel:self]; + if ([_delegate respondsToSelector:@selector(dialogDidNotComplete:)]) { + [_delegate dialogDidNotComplete:self]; } } @@ -576,53 +632,25 @@ - (void)dismissWithError:(NSError*)error animated:(BOOL)animated { [self dismiss:animated]; } -- (void)load { - // Intended for subclasses to override -} - -- (void)loadURL:(NSString*)url method:(NSString*)method get:(NSDictionary*)getParams - post:(NSDictionary*)postParams { - // This "test cookie" is required by login.php, or it complains that you need to enable JavaScript - NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - NSHTTPCookie* testCookie = [NSHTTPCookie cookieWithProperties: - [NSDictionary dictionaryWithObjectsAndKeys: - @"1", NSHTTPCookieValue, - @"test_cookie", NSHTTPCookieName, - @".facebook.com", NSHTTPCookieDomain, - @"/", NSHTTPCookiePath, - nil]]; - [cookies setCookie:testCookie]; - - [_loadingURL release]; - _loadingURL = [[self generateURL:url params:getParams] retain]; - NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:_loadingURL]; - - if (method) { - [request setHTTPMethod:method]; - - if ([[method uppercaseString] isEqualToString:@"POST"]) { - NSString* contentType = [NSString - stringWithFormat:@"multipart/form-data; boundary=%@", kStringBoundary]; - [request setValue:contentType forHTTPHeaderField:@"Content-Type"]; - - NSData* body = [self generatePostBody:postParams]; - if (body) { - [request setHTTPBody:body]; - } - } - } - - [_webView loadRequest:request]; -} - - (void)dialogWillAppear { } - (void)dialogWillDisappear { } -- (void)dialogDidSucceed:(NSURL*)url { +- (void)dialogDidSucceed:(NSURL *)url { + + if ([_delegate respondsToSelector:@selector(dialogCompleteWithUrl:)]) { + [_delegate dialogCompleteWithUrl:url]; + } [self dismissWithSuccess:YES animated:YES]; } +- (void)dialogDidCancel:(NSURL *)url { + if ([_delegate respondsToSelector:@selector(dialogDidNotCompleteWithUrl:)]) { + [_delegate dialogDidNotCompleteWithUrl:url]; + } + [self dismissWithSuccess:NO animated:YES]; +} + @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h deleted file mode 100644 index 50ba0f61..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBDialog.h" - -@interface FBFeedDialog : FBDialog { - long long _templateBundleId; - NSString* _templateData; - NSString* _bodyGeneral; -} - -/** - * The id for a previously registered template bundle. - */ -@property(nonatomic) long long templateBundleId; - -/** - * A JSON string containing template data. - * - * See http://wiki.developers.facebook.com/index.php/Template_Data - */ -@property(nonatomic,copy) NSString* templateData; - -/** - * Additional markup for a short story. - */ -@property(nonatomic,copy) NSString* bodyGeneral; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m deleted file mode 100644 index cc310fef..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBFeedDialog.h" -#import "FBSession.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kFeedURL = @"http://www.facebook.com/connect/prompt_feed.php"; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBFeedDialog - -@synthesize templateBundleId = _templateBundleId, templateData = _templateData, - bodyGeneral = _bodyGeneral; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -- (NSString*)generateFeedInfo { - NSMutableArray* pairs = [NSMutableArray array]; - - if (_templateBundleId) { - [pairs addObject:[NSString stringWithFormat:@"\"template_id\": %lld", _templateBundleId]]; - } - if (_templateData) { - [pairs addObject:[NSString stringWithFormat:@"\"template_data\": %@", _templateData]]; - } - if (_bodyGeneral) { - [pairs addObject:[NSString stringWithFormat:@"\"body_general\": \"%@\"", _bodyGeneral]]; - } - - return [NSString stringWithFormat:@"{%@}", [pairs componentsJoinedByString:@","]]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - if (self = [super initWithSession:session]) { - _templateBundleId = 0; - _templateData = nil; - _bodyGeneral = nil; - } - return self; -} - -- (void)dealloc { - [_templateData release]; - [_bodyGeneral release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBDialog - -- (void)load { - NSDictionary* getParams = [NSDictionary dictionaryWithObjectsAndKeys: - @"touch", @"display", nil]; - - NSString* feedInfo = [self generateFeedInfo]; - NSDictionary* postParams = [NSDictionary dictionaryWithObjectsAndKeys: - _session.apiKey, @"api_key", _session.sessionKey, @"session_key", - @"1", @"preview", @"fbconnect:success", @"callback", @"fbconnect:cancel", @"cancel", - feedInfo, @"feed_info", @"self_feed", @"feed_target_type", nil]; - - [self loadURL:kFeedURL method:@"POST" get:getParams post:postParams]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h deleted file mode 100644 index 4f98f4f5..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBSession.h" - -typedef enum { - FBLoginButtonStyleNormal, - FBLoginButtonStyleWide, -} FBLoginButtonStyle; - -/** - * Standard button which lets the user log in or out of the session. - * - * The button will automatically change to reflect the state of the session, showing - * "login" if the session is not connected, and "logout" if the session is connected. - */ -@interface FBLoginButton : UIControl { - FBLoginButtonStyle _style; - FBSession* _session; - UIImageView* _imageView; -} - -/** - * The visual style of the button. - */ -@property(nonatomic) FBLoginButtonStyle style; - -/** - * The session object that the button will log in and out of. - * - * The default value is the global session singleton, so there is usually no need to - * set this property yourself. - */ -@property(nonatomic,retain) FBSession* session; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m deleted file mode 100644 index 06b5818b..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBLoginButton.h" -#import "FBLoginDialog.h" - -#import - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -static UIAccessibilityTraits *traitImage = nil, *traitButton = nil; - -@implementation FBLoginButton - -@synthesize session = _session, style = _style; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -+ (void)initialize { - if (self == [FBLoginButton class]) { - // Try to load the accessibility trait values on OS 3.0 - traitImage = dlsym(RTLD_SELF, "UIAccessibilityTraitImage"); - traitButton = dlsym(RTLD_SELF, "UIAccessibilityTraitButton"); - } -} - -- (UIImage*)buttonImage { - if (_session.isConnected) { - return [UIImage imageNamed:@"FBConnect.bundle/images/logout.png"]; - } else { - if (_style == FBLoginButtonStyleNormal) { - return [UIImage imageNamed:@"FBConnect.bundle/images/login.png"]; - } else if (_style == FBLoginButtonStyleWide) { - return [UIImage imageNamed:@"FBConnect.bundle/images/login2.png"]; - } else { - return nil; - } - } -} - -- (UIImage*)buttonHighlightedImage { - if (_session.isConnected) { - return [UIImage imageNamed:@"FBConnect.bundle/images/logout_down.png"]; - } else { - if (_style == FBLoginButtonStyleNormal) { - return [UIImage imageNamed:@"FBConnect.bundle/images/login_down.png"]; - } else if (_style == FBLoginButtonStyleWide) { - return [UIImage imageNamed:@"FBConnect.bundle/images/login2_down.png"]; - } else { - return nil; - } - } -} - -- (void)updateImage { - if (self.highlighted) { - _imageView.image = [self buttonHighlightedImage]; - } else { - _imageView.image = [self buttonImage]; - } -} - -- (void)touchUpInside { - if (_session.isConnected) { - [_session logout]; - } else { - FBLoginDialog* dialog = [[[FBLoginDialog alloc] initWithSession:_session] autorelease]; - [dialog show]; - } -} - -- (void)initButton { - _style = FBLoginButtonStyleNormal; - - _imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; - _imageView.contentMode = UIViewContentModeCenter; - [self addSubview:_imageView]; - - self.backgroundColor = [UIColor clearColor]; - [self addTarget:self action:@selector(touchUpInside) - forControlEvents:UIControlEventTouchUpInside]; - - self.session = [FBSession session]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithFrame:(CGRect)frame { - if (self = [super initWithFrame:frame]) { - [self initButton]; - if (CGRectIsEmpty(frame)) { - [self sizeToFit]; - } - } - return self; -} - -- (void)awakeFromNib { - [self initButton]; -} - -- (void)dealloc { - [_session.delegates removeObject:self]; - [_session release]; - [_imageView release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// UIView - -- (CGSize)sizeThatFits:(CGSize)size { - return _imageView.image.size; -} - -- (void)layoutSubviews { - _imageView.frame = self.bounds; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// UIControl - -- (void)setHighlighted:(BOOL)highlighted { - [super setHighlighted:highlighted]; - [self updateImage]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBSessionDelegate - -- (void)session:(FBSession*)session didLogin:(FBUID)uid { - [self updateImage]; -} - -- (void)sessionDidLogout:(FBSession*)session { - [self updateImage]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// UIAccessibility informal protocol (on 3.0 only) - -- (BOOL)isAccessibilityElement { - return YES; -} - -- (UIAccessibilityTraits)accessibilityTraits { - if (traitImage && traitButton) - return [super accessibilityTraits]|*traitImage|*traitButton; - else - return [super accessibilityTraits]; -} - -- (NSString *)accessibilityLabel { - if (_session.isConnected) { - return NSLocalizedString(@"Disconnect from Facebook", @"Accessibility label"); - } else { - return NSLocalizedString(@"Connect to Facebook", @"Accessibility label"); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// public - -- (void)setSession:(FBSession*)session { - if (session != _session) { - [_session.delegates removeObject:self]; - [_session release]; - _session = [session retain]; - [_session.delegates addObject:self]; - - [self updateImage]; - } -} - -- (void)setStyle:(FBLoginButtonStyle)style { - _style = style; - - [self updateImage]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h index 8eb0b908..f5c6ebae 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h @@ -1,10 +1,10 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software @@ -12,13 +12,37 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ + #import "FBDialog.h" -#import "FBRequest.h" -@interface FBLoginDialog : FBDialog { - FBRequest* _getSessionRequest; +@protocol FBLoginDialogDelegate; + +/** + * Do not use this interface directly, instead, use authorize in Facebook.h + * + * Facebook Login Dialog interface for start the facebook webView login dialog. + * It start pop-ups prompting for credentials and permissions. + */ + +@interface FBLoginDialog : FBDialog { + id _loginDelegate; } +-(id) initWithURL:(NSString *) loginURL + loginParams:(NSMutableDictionary *) params + delegate:(id ) delegate; @end + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@protocol FBLoginDialogDelegate + +- (void)fbDialogLogin:(NSString*)token expirationDate:(NSDate*)expirationDate; + +- (void)fbDialogNotLogin:(BOOL)cancelled; + +@end + + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m index 9d49f603..70552bf8 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m @@ -1,131 +1,94 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 - + * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ +#import "FBDialog.h" #import "FBLoginDialog.h" -#import "FBSession.h" -#import "FBRequest.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kLoginURL = @"http://www.facebook.com/login.php"; /////////////////////////////////////////////////////////////////////////////////////////////////// @implementation FBLoginDialog /////////////////////////////////////////////////////////////////////////////////////////////////// -// private +// public -- (void)connectToGetSession:(NSString*)token { - _getSessionRequest = [[FBRequest requestWithSession:_session delegate:self] retain]; - NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObject:token forKey:@"auth_token"]; - if (!_session.apiSecret) { - [params setObject:@"1" forKey:@"generate_session_secret"]; - } +/* + * initialize the FBLoginDialog with url and parameters + */ +- (id)initWithURL:(NSString*) loginURL + loginParams:(NSMutableDictionary*) params + delegate:(id ) delegate{ - if (_session.getSessionProxy) { - [_getSessionRequest post:_session.getSessionProxy params:params]; - } else { - [_getSessionRequest call:@"facebook.auth.getSession" params:params]; - } -} - -- (void)loadLoginPage { - NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: - @"1", @"fbconnect", @"touch", @"connect_display", _session.apiKey, @"api_key", - @"fbconnect://success", @"next", nil]; - - [self loadURL:kLoginURL method:@"GET" get:params post:nil]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - if (self = [super initWithSession:session]) { - _getSessionRequest = nil; - } + self = [super init]; + _serverURL = [loginURL retain]; + _params = [params retain]; + _loginDelegate = delegate; return self; } -- (void)dealloc { - _getSessionRequest.delegate = nil; - [_getSessionRequest release]; - [super dealloc]; -} - /////////////////////////////////////////////////////////////////////////////////////////////////// // FBDialog -- (void)load { - [self loadLoginPage]; -} - -- (void)dialogWillDisappear { - [_webView stringByEvaluatingJavaScriptFromString:@"email.blur();"]; - - [_getSessionRequest cancel]; +/** + * Override FBDialog : to call when the webView Dialog did succeed + */ +- (void) dialogDidSucceed:(NSURL*)url { + NSString *q = [url absoluteString]; + NSString *token = [self getStringFromUrl:q needle:@"access_token="]; + NSString *expTime = [self getStringFromUrl:q needle:@"expires_in="]; + NSDate *expirationDate =nil; - if (![_session isConnected]) { - [_session cancelLogin]; + if (expTime != nil) { + int expVal = [expTime intValue]; + if (expVal == 0) { + expirationDate = [NSDate distantFuture]; + } else { + expirationDate = [NSDate dateWithTimeIntervalSinceNow:expVal]; + } + } + + if ((token == (NSString *) [NSNull null]) || (token.length == 0)) { + [self dialogDidCancel:url]; + [self dismissWithSuccess:NO animated:YES]; + } else { + if ([_loginDelegate respondsToSelector:@selector(fbDialogLogin:expirationDate:)]) { + [_loginDelegate fbDialogLogin:token expirationDate:expirationDate]; + } + [self dismissWithSuccess:YES animated:YES]; } + } -- (void)dialogDidSucceed:(NSURL*)url { - NSString* q = url.query; - NSRange start = [q rangeOfString:@"auth_token="]; - if (start.location != NSNotFound) { - NSRange end = [q rangeOfString:@"&"]; - NSUInteger offset = start.location+start.length; - NSString* token = end.location == NSNotFound - ? [q substringFromIndex:offset] - : [q substringWithRange:NSMakeRange(offset, end.location-offset)]; - - if (token) { - [self connectToGetSession:token]; - } +/** + * Override FBDialog : to call with the login dialog get canceled + */ +- (void)dialogDidCancel:(NSURL *)url { + [self dismissWithSuccess:NO animated:YES]; + if ([_loginDelegate respondsToSelector:@selector(fbDialogNotLogin:)]) { + [_loginDelegate fbDialogNotLogin:YES]; } } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBRequestDelegate - -- (void)request:(FBRequest*)request didLoad:(id)result { - NSDictionary* object = result; - FBUID uid = [[object objectForKey:@"uid"] longLongValue]; - NSString* sessionKey = [object objectForKey:@"session_key"]; - NSString* sessionSecret = [object objectForKey:@"secret"]; - NSTimeInterval expires = [[object objectForKey:@"expires"] floatValue]; - NSDate* expiration = expires ? [NSDate dateWithTimeIntervalSince1970:expires] : nil; - - [_getSessionRequest release]; - _getSessionRequest = nil; - - [_session begin:uid sessionKey:sessionKey sessionSecret:sessionSecret expires:expiration]; - [_session resume]; - - [self dismissWithSuccess:YES animated:YES]; +- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { + if (!(([error.domain isEqualToString:@"NSURLErrorDomain"] && error.code == -999) || + ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102))) { + [super webView:webView didFailLoadWithError:error]; + if ([_loginDelegate respondsToSelector:@selector(fbDialogNotLogin:)]) { + [_loginDelegate fbDialogNotLogin:NO]; + } + } } -- (void)request:(FBRequest*)request didFailWithError:(NSError*)error { - [_getSessionRequest release]; - _getSessionRequest = nil; - - [self dismissWithError:error animated:YES]; -} - @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h deleted file mode 100644 index d203ddbe..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBLoginDialog.h" - -@interface FBPermissionDialog : FBLoginDialog { - NSString* _permission; - NSTimer* _redirectTimer; -} - -/** - * The extended permission to request. - * - * See http://wiki.developers.facebook.com/index.php/Extended_permissions - */ -@property(nonatomic,copy) NSString* permission; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m deleted file mode 100644 index f604ef6e..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBPermissionDialog.h" -#import "FBSession.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kPermissionURL = @"http://www.facebook.com/connect/prompt_permission.php"; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBPermissionDialog - -@synthesize permission = _permission; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -- (void)redirectToLoginDelayed { - _redirectTimer = nil; - - // This loads the login page, which will just redirect back to the callback url - // since the login cookies are set - [super load]; -} - -- (void)redirectToLogin { - _redirectTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self - selector:@selector(redirectToLoginDelayed) userInfo:nil repeats:NO]; -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - if (self = [super initWithSession:session]) { - _permission = nil; - _redirectTimer = nil; - } - return self; -} - -- (void)dealloc { - [_redirectTimer invalidate]; - [_permission release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBDialog - -- (void)load { - NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: - @"touch", @"display", _session.apiKey, @"api_key", _session.sessionKey, @"session_key", - _permission, @"ext_perm", @"fbconnect:success", @"next", @"fbconnect:cancel", @"cancel", nil]; - - [self loadURL:kPermissionURL method:@"GET" get:params post:nil]; -} - -- (void)dialogDidSucceed:(NSURL*)url { - if ([_permission isEqualToString:@"offline_access"]) { - [super dialogDidSucceed:url]; - } else { - [self dismissWithSuccess:YES animated:YES]; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// UIWebViewDelegate - -- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request - navigationType:(UIWebViewNavigationType)navigationType { - if ([_permission isEqualToString:@"offline_access"]) { - NSURL* url = request.URL; - if ([url.scheme isEqualToString:@"fbconnect"]) { - if ([url.resourceSpecifier isEqualToString:@"success"]) { - [self redirectToLogin]; - return NO; - } - } - } - return [super webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h index 75ac9e74..f44b6f50 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h @@ -1,10 +1,10 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software @@ -12,126 +12,71 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ -#import "FBConnectGlobal.h" +#import +#import @protocol FBRequestDelegate; -@class FBSession; +/** + * Do not use this interface directly, instead, use method in Facebook.h + */ @interface FBRequest : NSObject { - FBSession* _session; id _delegate; NSString* _url; - NSString* _method; - id _userInfo; + NSString* _httpMethod; NSMutableDictionary* _params; - NSObject* _dataParam; - NSDate* _timestamp; NSURLConnection* _connection; NSMutableData* _responseText; } -/** - * Creates a new API request for the global session. - */ -+ (FBRequest*)request; - -/** - * Creates a new API request for the global session with a delegate. - */ -+ (FBRequest*)requestWithDelegate:(id)delegate; - -/** - * Creates a new API request for a particular session. - */ -+ (FBRequest*)requestWithSession:(FBSession*)session; - -/** - * Creates a new API request for the global session with a delegate. - */ -+ (FBRequest*)requestWithSession:(FBSession*)session delegate:(id)delegate; @property(nonatomic,assign) id delegate; /** * The URL which will be contacted to execute the request. */ -@property(nonatomic,readonly) NSString* url; +@property(nonatomic,copy) NSString* url; /** * The API method which will be called. */ -@property(nonatomic,readonly) NSString* method; - -/** - * An object used by the user of the request to help identify the meaning of the request. - */ -@property(nonatomic,retain) id userInfo; +@property(nonatomic,copy) NSString* httpMethod; /** * The dictionary of parameters to pass to the method. * - * These values in the dictionary will be converted to strings using the + * These values in the dictionary will be converted to strings using the * standard Objective-C object-to-string conversion facilities. */ -@property(nonatomic,readonly) NSDictionary* params; +@property(nonatomic,retain) NSMutableDictionary* params; +@property(nonatomic,assign) NSURLConnection* connection; +@property(nonatomic,assign) NSMutableData* responseText; -/** - * A data parameter. - * - * Used for methods such as photos.upload, video.upload, events.create, and - * events.edit. - */ -@property(nonatomic,readonly) NSObject* dataParam; -/** - * The timestamp of when the request was sent to the server. - */ -@property(nonatomic,readonly) NSDate* timestamp; ++ (NSString*)serializeURL:(NSString *)baseUrl + params:(NSDictionary *)params; -/** - * Indicates if the request has been sent and is awaiting a response. - */ -@property(nonatomic,readonly) BOOL loading; ++ (NSString*)serializeURL:(NSString *)baseUrl + params:(NSDictionary *)params + httpMethod:(NSString *)httpMethod; -/** - * Creates a new request paired to a session. - */ -- (id)initWithSession:(FBSession*)session; ++ (FBRequest*)getRequestWithParams:(NSMutableDictionary *) params + httpMethod:(NSString *) httpMethod + delegate:(id)delegate + requestURL:(NSString *) url; +- (BOOL) loading; -/** - * Calls a method on the server asynchronously. - * - * The delegate will be called for each stage of the loading process. - */ -- (void)call:(NSString*)method params:(NSDictionary*)params; - -/** - * Calls a method on the server asynchronously, with a file upload component. - * - * The delegate will be called for each stage of the loading process. - */ -- (void)call:(NSString*)method params:(NSDictionary*)params dataParam:(NSData*)dataParam; - -/** - * Calls a URL on the server asynchronously. - * - * The delegate will be called for each stage of the loading process. - */ -- (void)post:(NSString*)url params:(NSDictionary*)params; - -/** - * Stops an active request before the response has returned. - */ -- (void)cancel; - -- (void)connect; +- (void) connect; @end -/////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/* + *Your application should implement this delegate + */ @protocol FBRequestDelegate @optional @@ -139,29 +84,33 @@ /** * Called just before the request is sent to the server. */ -- (void)requestLoading:(FBRequest*)request; +- (void)requestLoading:(FBRequest *)request; /** * Called when the server responds and begins to send back data. */ -- (void)request:(FBRequest*)request didReceiveResponse:(NSURLResponse*)response; +- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response; /** * Called when an error prevents the request from completing successfully. */ -- (void)request:(FBRequest*)request didFailWithError:(NSError*)error; +- (void)request:(FBRequest *)request didFailWithError:(NSError *)error; /** - * Called when a request returns and its response has been parsed into an object. + * Called when a request returns and its response has been parsed into + * an object. * - * The resulting object may be a dictionary, an array, a string, or a number, depending - * on thee format of the API response. + * The resulting object may be a dictionary, an array, a string, or a number, + * depending on thee format of the API response. */ -- (void)request:(FBRequest*)request didLoad:(id)result; +- (void)request:(FBRequest *)request didLoad:(id)result; /** - * Called when the request was cancelled. + * Called when a request returns a response. + * + * The result object is the raw response from the server of type NSData */ -- (void)requestWasCancelled:(FBRequest*)request; +- (void)request:(FBRequest *)request didLoadRawResponse:(NSData *)data; @end + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m index 50dd54e5..7b2cc2ea 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m @@ -1,10 +1,10 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software @@ -12,20 +12,17 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ #import "FBRequest.h" -#import "FBSession.h" -#import "FBXMLHandler.h" -#import +#import "JSON.h" /////////////////////////////////////////////////////////////////////////////////////////////////// // global -static NSString* kAPIVersion = @"1.0"; -static NSString* kAPIFormat = @"XML"; static NSString* kUserAgent = @"FacebookConnect"; static NSString* kStringBoundary = @"3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f"; +static const int kGeneralErrorCode = 10000; static const NSTimeInterval kTimeoutInterval = 180.0; @@ -33,281 +30,328 @@ @implementation FBRequest -@synthesize delegate = _delegate, - url = _url, - method = _method, - params = _params, - dataParam = _dataParam, - userInfo = _userInfo, - timestamp = _timestamp; +@synthesize delegate = _delegate, + url = _url, + httpMethod = _httpMethod, + params = _params, + connection = _connection, + responseText = _responseText; -/////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////// // class public -+ (FBRequest*)request { - return [self requestWithSession:[FBSession session]]; -} ++ (FBRequest *)getRequestWithParams:(NSMutableDictionary *) params + httpMethod:(NSString *) httpMethod + delegate:(id) delegate + requestURL:(NSString *) url { -+ (FBRequest*)requestWithDelegate:(id)delegate { - return [self requestWithSession:[FBSession session] delegate:delegate]; -} - -+ (FBRequest*)requestWithSession:(FBSession*)session { - return [[[FBRequest alloc] initWithSession:session] autorelease]; -} - -+ (FBRequest*)requestWithSession:(FBSession*)session delegate:(id)delegate { - FBRequest* request = [[[FBRequest alloc] initWithSession:session] autorelease]; + FBRequest* request = [[[FBRequest alloc] init] autorelease]; request.delegate = delegate; + request.url = url; + request.httpMethod = httpMethod; + request.params = params; + request.connection = nil; + request.responseText = nil; + return request; } /////////////////////////////////////////////////////////////////////////////////////////////////// // private -- (NSString*)md5HexDigest:(NSString*)input { - const char* str = [input UTF8String]; - unsigned char result[CC_MD5_DIGEST_LENGTH]; - CC_MD5(str, strlen(str), result); - - NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2]; - for(int i = 0; i 0) { + for (id key in dataDictionary) { + NSObject *dataParam = [dataDictionary valueForKey:key]; + if ([dataParam isKindOfClass:[UIImage class]]) { + NSData* imageData = UIImagePNGRepresentation((UIImage*)dataParam); + [self utfAppendBody:body + data:[NSString stringWithFormat: + @"Content-Disposition: form-data; filename=\"%@\"\r\n", key]]; + [self utfAppendBody:body + data:[NSString stringWithString:@"Content-Type: image/png\r\n\r\n"]]; + [body appendData:imageData]; + } else { + NSAssert([dataParam isKindOfClass:[NSData class]], + @"dataParam must be a UIImage or NSData"); + [self utfAppendBody:body + data:[NSString stringWithFormat: + @"Content-Disposition: form-data; filename=\"%@\"\r\n", key]]; + [self utfAppendBody:body + data:[NSString stringWithString:@"Content-Type: content/unknown\r\n\r\n"]]; + [body appendData:(NSData*)dataParam]; + } + [self utfAppendBody:body data:endLine]; + } - [self utfAppendBody:body data:endLine]; } - - FBLOG2(@"Sending %s", [body bytes]); + return body; } -- (id)parseXMLResponse:(NSData*)data error:(NSError**)error { - FBXMLHandler* handler = [[[FBXMLHandler alloc] init] autorelease]; - NSXMLParser* parser = [[[NSXMLParser alloc] initWithData:data] autorelease]; - parser.delegate = handler; - [parser parse]; +/** + * Formulate the NSError + */ +- (id)formError:(NSInteger)code userInfo:(NSDictionary *) errorData { + return [NSError errorWithDomain:@"facebookErrDomain" code:code userInfo:errorData]; - if (handler.parseError) { - if (error) { - *error = [[handler.parseError retain] autorelease]; +} + +/** + * parse the response data + */ +- (id)parseJsonResponse:(NSData *)data error:(NSError **)error { + + NSString* responseString = [[[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding] + autorelease]; + SBJSON *jsonParser = [[SBJSON new] autorelease]; + if ([responseString isEqualToString:@"true"]) { + return [NSDictionary dictionaryWithObject:@"true" forKey:@"result"]; + } else if ([responseString isEqualToString:@"false"]) { + if (error != nil) { + *error = [self formError:kGeneralErrorCode + userInfo:[NSDictionary + dictionaryWithObject:@"This operation can not be completed" + forKey:@"error_msg"]]; } return nil; - } else if ([handler.rootName isEqualToString:@"error_response"]) { - NSDictionary* errorDict = handler.rootObject; - NSInteger code = [[errorDict objectForKey:@"error_code"] intValue]; - NSDictionary* info = [NSDictionary dictionaryWithObjectsAndKeys: - [errorDict objectForKey:@"error_msg"], NSLocalizedDescriptionKey, - [errorDict objectForKey:@"request_args"], @"request_args", - nil]; - if (error) { - *error = [NSError errorWithDomain:FBAPI_ERROR_DOMAIN code:code userInfo:info]; + } + + + id result = [jsonParser objectWithString:responseString]; + + if (![result isKindOfClass:[NSArray class]]) { + if ([result objectForKey:@"error"] != nil) { + if (error != nil) { + *error = [self formError:kGeneralErrorCode + userInfo:result]; + } + return nil; + } + + if ([result objectForKey:@"error_code"] != nil) { + if (error != nil) { + *error = [self formError:[[result objectForKey:@"error_code"] intValue] userInfo:result]; + } + return nil; + } + + if ([result objectForKey:@"error_msg"] != nil) { + if (error != nil) { + *error = [self formError:kGeneralErrorCode userInfo:result]; + } + } + + if ([result objectForKey:@"error_reason"] != nil) { + if (error != nil) { + *error = [self formError:kGeneralErrorCode userInfo:result]; + } } - return nil; - } else { - return [[handler.rootObject retain] autorelease]; } + + return result; + } -- (void)failWithError:(NSError*)error { +/* + * private helper function: call the delegate function when the request + * fails with error + */ +- (void)failWithError:(NSError *)error { if ([_delegate respondsToSelector:@selector(request:didFailWithError:)]) { [_delegate request:self didFailWithError:error]; } } -- (void)handleResponseData:(NSData*)data { - FBLOG2(@"DATA: %s", data.bytes); - NSError* error = nil; - id result = [self parseXMLResponse:data error:&error]; - if (error) { - [self failWithError:error]; - } else if ([_delegate respondsToSelector:@selector(request:didLoad:)]) { - [_delegate request:self didLoad:result]; +/* + * private helper function: handle the response data + */ +- (void)handleResponseData:(NSData *)data { + if ([_delegate respondsToSelector: + @selector(request:didLoadRawResponse:)]) { + [_delegate request:self didLoadRawResponse:data]; } + + if ([_delegate respondsToSelector:@selector(request:didLoad:)] || + [_delegate respondsToSelector: + @selector(request:didFailWithError:)]) { + NSError* error = nil; + id result = [self parseJsonResponse:data error:&error]; + + if (error) { + [self failWithError:error]; + } else if ([_delegate respondsToSelector: + @selector(request:didLoad:)]) { + [_delegate request:self didLoad:(result == nil ? data : result)]; + } + + } + } + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// public + +/** + * @return boolean - whether this request is processing + */ +- (BOOL)loading { + return !!_connection; +} + +/** + * make the Facebook request + */ - (void)connect { - FBLOG(@"Connecting to %@ %@", _url, _params); if ([_delegate respondsToSelector:@selector(requestLoading:)]) { [_delegate requestLoading:self]; } - NSString* url = _method ? _url : [self generateGetURL]; - NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData - timeoutInterval:kTimeoutInterval]; + NSString* url = [[self class] serializeURL:_url params:_params httpMethod:_httpMethod]; + NSMutableURLRequest* request = + [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:kTimeoutInterval]; [request setValue:kUserAgent forHTTPHeaderField:@"User-Agent"]; - - if (_method) { - [request setHTTPMethod:@"POST"]; - + + + [request setHTTPMethod:self.httpMethod]; + if ([self.httpMethod isEqualToString: @"POST"]) { NSString* contentType = [NSString - stringWithFormat:@"multipart/form-data; boundary=%@", kStringBoundary]; + stringWithFormat:@"multipart/form-data; boundary=%@", kStringBoundary]; [request setValue:contentType forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:[self generatePostBody]]; } - - _timestamp = [[NSDate date] retain]; + _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; -} -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - _session = session; - _delegate = nil; - _url = nil; - _method = nil; - _params = nil; - _userInfo = nil; - _timestamp = nil; - _connection = nil; - _responseText = nil; - return self; } +/** + * Free internal structure + */ - (void)dealloc { [_connection cancel]; [_connection release]; [_responseText release]; [_url release]; - [_method release]; + [_httpMethod release]; [_params release]; - [_userInfo release]; - [_timestamp release]; [super dealloc]; } -- (NSString*)description { - return [NSString stringWithFormat:@"", _method ? _method : _url]; -} - ////////////////////////////////////////////////////////////////////////////////////////////////// // NSURLConnectionDelegate - -- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { _responseText = [[NSMutableData alloc] init]; NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; - if ([_delegate respondsToSelector:@selector(request:didReceiveResponse:)]) { + if ([_delegate respondsToSelector: + @selector(request:didReceiveResponse:)]) { [_delegate request:self didReceiveResponse:httpResponse]; } } --(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [_responseText appendData:data]; } -- (NSCachedURLResponse*)connection:(NSURLConnection*)connection +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse { return nil; } --(void)connectionDidFinishLoading:(NSURLConnection*)connection { +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { [self handleResponseData:_responseText]; - + [_responseText release]; _responseText = nil; [_connection release]; _connection = nil; } -- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error { +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { [self failWithError:error]; [_responseText release]; @@ -316,63 +360,4 @@ - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error _connection = nil; } -////////////////////////////////////////////////////////////////////////////////////////////////// -// public - -- (BOOL)loading { - return !!_connection; -} - -- (void)call:(NSString*)method params:(NSDictionary*)params { - [self call:method params:params dataParam:nil]; -} - -- (void)call:(NSString*)method params:(NSDictionary*)params dataParam:(NSData*)dataParam { - _url = [[self urlForMethod:method] retain]; - _method = [method copy]; - _params = params - ? [[NSMutableDictionary alloc] initWithDictionary:params] - : [[NSMutableDictionary alloc] init]; - _dataParam = dataParam; - - [_params setObject:_method forKey:@"method"]; - [_params setObject:_session.apiKey forKey:@"api_key"]; - [_params setObject:kAPIVersion forKey:@"v"]; - [_params setObject:kAPIFormat forKey:@"format"]; - - if (![self isSpecialMethod]) { - [_params setObject:_session.sessionKey forKey:@"session_key"]; - [_params setObject:[self generateCallId] forKey:@"call_id"]; - - if (_session.sessionSecret) { - [_params setObject:@"1" forKey:@"ss"]; - } - } - - [_params setObject:[self generateSig] forKey:@"sig"]; - - [_session send:self]; -} - -- (void)post:(NSString*)url params:(NSDictionary*)params { - _url = [url retain]; - _params = params - ? [[NSMutableDictionary alloc] initWithDictionary:params] - : [[NSMutableDictionary alloc] init]; - - [_session send:self]; -} - -- (void)cancel { - if (_connection) { - [_connection cancel]; - [_connection release]; - _connection = nil; - - if ([_delegate respondsToSelector:@selector(requestWasCancelled:)]) { - [_delegate requestWasCancelled:self]; - } - } -} - @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h deleted file mode 100644 index 15c77f50..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBConnectGlobal.h" - -@protocol FBSessionDelegate; -@class FBRequest; - -/** - * An FBSession represents a single user's authenticated session for a Facebook application. - * - * To create a session, you must use the session key of your application (which can - * be found on the Facebook developer website). You may then use the login dialog to ask - * the user to enter their email address and password. If successful, you will get back a - * session key which can be used to make requests to the Facebook API. - * - * Session keys are cached and stored on the disk of the device so that you do not need to ask - * the user to login every time they launch the app. To restore the last active session, call the - * resume method after instantiating your session. - */ -@interface FBSession : NSObject { - NSMutableArray* _delegates; - NSString* _apiKey; - NSString* _apiSecret; - NSString* _getSessionProxy; - FBUID _uid; - NSString* _sessionKey; - NSString* _sessionSecret; - NSDate* _expirationDate; - NSMutableArray* _requestQueue; - NSDate* _lastRequestTime; - int _requestBurstCount; - NSTimer* _requestTimer; -} - -/** - * Delegates which implement FBSessionDelegate. - */ -@property(nonatomic,readonly) NSMutableArray* delegates; - -/** - * The URL used for API HTTP requests. - */ -@property(nonatomic,readonly) NSString* apiURL; - -/** - * The URL used for secure API HTTP requests. - */ -@property(nonatomic,readonly) NSString* apiSecureURL; - -/** - * Your application's API key, as passed to the constructor. - */ -@property(nonatomic,readonly) NSString* apiKey; - -/** - * Your application's API secret, as passed to the constructor. - */ -@property(nonatomic,readonly) NSString* apiSecret; - -/** - * The URL to call to create a session key after login. - * - * This is an alternative to calling auth.getSession directly using the secret key. - */ -@property(nonatomic,readonly) NSString* getSessionProxy; - -/** - * The current user's Facebook id. - */ -@property(nonatomic,readonly) FBUID uid; - -/** - * The current user's session key. - */ -@property(nonatomic,readonly) NSString* sessionKey; - -/** - * The current user's session secret. - */ -@property(nonatomic,readonly) NSString* sessionSecret; - -/** - * The expiration date of the session key. - */ -@property(nonatomic,readonly) NSDate* expirationDate; - -/** - * Determines if the session is active and connected to a user. - */ -@property(nonatomic,readonly) BOOL isConnected; - -/** - * The globally shared session instance. - */ -+ (FBSession*)session; - -/** - * Sets the globally shared session instance. - * - * This session is not retained, so you are still responsible for retaining it yourself. The - * first session that is created is automatically stored here. - */ -+ (void)setSession:(FBSession*)session; - -/** - * Constructs a session and stores it as the globally shared session instance. - * - * @param secret the application secret (optional) - */ -+ (FBSession*)sessionForApplication:(NSString*)key secret:(NSString*)secret - delegate:(id)delegate; - -/** - * Constructs a session and stores it as the global singleton. - * - * @param getSessionProxy a url to that proxies auth.getSession (optional) - */ -+ (FBSession*)sessionForApplication:(NSString*)key getSessionProxy:(NSString*)getSessionProxy - delegate:(id)delegate; - -/** - * Constructs a session for an application. - * - * @param secret the application secret (optional) - * @param getSessionProxy a url to that proxies auth.getSession (optional) - */ -- (FBSession*)initWithKey:(NSString*)key secret:(NSString*)secret - getSessionProxy:(NSString*)getSessionProxy; - -/** - * Begins a session for a user with a given key and secret. - */ -- (void)begin:(FBUID)uid sessionKey:(NSString*)sessionKey sessionSecret:(NSString*)sessionSecret - expires:(NSDate*)expires; - -/** - * Resumes a previous session whose uid, session key, and secret are cached on disk. - */ -- (BOOL)resume; - -/** - * Cancels a login (no-op if the login is already complete). - */ -- (void)cancelLogin; - -/** - * Ends the current session and deletes the uid, session key, and secret from disk. - */ -- (void)logout; - -/** - * Sends a fully configured request to the server for execution. - */ -- (void)send:(FBRequest*)request; - -/** - * Deletes all cookies belonging to facebook - */ -- (void)deleteFacebookCookies; - -- (void)requestTimerReady; - -@end - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@protocol FBSessionDelegate - -/** - * Called when a user has successfully logged in and begun a session. - */ -- (void)session:(FBSession*)session didLogin:(FBUID)uid; - -@optional - -/** - * Called when a user closes the login dialog without logging in. - */ -- (void)sessionDidNotLogin:(FBSession*)session; - -/** - * Called when a session is about to log out. - */ -- (void)session:(FBSession*)session willLogout:(FBUID)uid; - -/** - * Called when a session has logged out. - */ -- (void)sessionDidLogout:(FBSession*)session; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m deleted file mode 100644 index c21f11bb..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBSession.h" -#import "FBRequest.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kAPIRestURL = @"http://api.facebook.com/restserver.php"; -static NSString* kAPIRestSecureURL = @"https://api.facebook.com/restserver.php"; - -static const int kMaxBurstRequests = 3; -static const NSTimeInterval kBurstDuration = 2; - -static FBSession* sharedSession = nil; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBSession - -@synthesize delegates = _delegates, apiKey = _apiKey, apiSecret = _apiSecret, - getSessionProxy = _getSessionProxy, uid = _uid, sessionKey = _sessionKey, - sessionSecret = _sessionSecret, expirationDate = _expirationDate; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// class public - -+ (FBSession*)session { - return sharedSession; -} - -+ (void)setSession:(FBSession*)session { - sharedSession = session; -} - -+ (FBSession*)sessionForApplication:(NSString*)key secret:(NSString*)secret - delegate:(id)delegate { - FBSession* session = [[[FBSession alloc] initWithKey:key secret:secret - getSessionProxy:nil] autorelease]; - [session.delegates addObject:delegate]; - return session; -} - -+ (FBSession*)sessionForApplication:(NSString*)key getSessionProxy:(NSString*)getSessionProxy - delegate:(id)delegate { - FBSession* session = [[[FBSession alloc] initWithKey:key secret:nil - getSessionProxy:getSessionProxy] autorelease]; - [session.delegates addObject:delegate]; - return session; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -- (void)save { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - if (_uid) { - [defaults setObject:[NSNumber numberWithLongLong:_uid] forKey:@"FBUserId"]; - } else { - [defaults removeObjectForKey:@"FBUserId"]; - } - - if (_sessionKey) { - [defaults setObject:_sessionKey forKey:@"FBSessionKey"]; - } else { - [defaults removeObjectForKey:@"FBSessionKey"]; - } - - if (_sessionSecret) { - [defaults setObject:_sessionSecret forKey:@"FBSessionSecret"]; - } else { - [defaults removeObjectForKey:@"FBSessionSecret"]; - } - - if (_expirationDate) { - [defaults setObject:_expirationDate forKey:@"FBSessionExpires"]; - } else { - [defaults removeObjectForKey:@"FBSessionExpires"]; - } - - [defaults synchronize]; -} - -- (void)unsave { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - [defaults removeObjectForKey:@"FBUserId"]; - [defaults removeObjectForKey:@"FBSessionKey"]; - [defaults removeObjectForKey:@"FBSessionSecret"]; - [defaults removeObjectForKey:@"FBSessionExpires"]; - [defaults synchronize]; -} - -- (void)startFlushTimer { - if (!_requestTimer) { - NSTimeInterval t = kBurstDuration + [_lastRequestTime timeIntervalSinceNow]; - _requestTimer = [NSTimer scheduledTimerWithTimeInterval:t target:self - selector:@selector(requestTimerReady) userInfo:nil repeats:NO]; - } -} - -- (void)enqueueRequest:(FBRequest*)request { - [_requestQueue addObject:request]; - [self startFlushTimer]; -} - -- (BOOL)performRequest:(FBRequest*)request enqueue:(BOOL)enqueue { - // Stagger requests that happen in short bursts to prevent the server from rejecting - // them for making too many requests in a short time - NSTimeInterval t = [_lastRequestTime timeIntervalSinceNow]; - BOOL burst = t && t > -kBurstDuration; - if (burst && ++_requestBurstCount > kMaxBurstRequests) { - if (enqueue) { - [self enqueueRequest:request]; - } - return NO; - } else { - [request performSelector:@selector(connect)]; - - if (!burst) { - _requestBurstCount = 1; - [_lastRequestTime release]; - _lastRequestTime = [[request timestamp] retain]; - } - } - return YES; -} - -- (void)flushRequestQueue { - while (_requestQueue.count) { - FBRequest* request = [_requestQueue objectAtIndex:0]; - if ([self performRequest:request enqueue:NO]) { - [_requestQueue removeObjectAtIndex:0]; - } else { - [self startFlushTimer]; - break; - } - } -} - -- (void)requestTimerReady { - _requestTimer = nil; - [self flushRequestQueue]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (FBSession*)initWithKey:(NSString*)key secret:(NSString*)secret - getSessionProxy:(NSString*)getSessionProxy { - if (self = [super init]) { - if (!sharedSession) { - sharedSession = self; - } - - _delegates = FBCreateNonRetainingArray(); - _apiKey = [key copy]; - _apiSecret = [secret copy]; - _getSessionProxy = [getSessionProxy copy]; - _uid = 0; - _sessionKey = nil; - _sessionSecret = nil; - _expirationDate = nil; - _requestQueue = [[NSMutableArray alloc] init]; - _lastRequestTime = nil; - _requestBurstCount = 0; - _requestTimer = nil; - } - return self; -} - -- (void)dealloc { - if (sharedSession == self) { - sharedSession = nil; - } - - [_delegates release]; - [_requestQueue release]; - [_apiKey release]; - [_apiSecret release]; - [_getSessionProxy release]; - [_sessionKey release]; - [_sessionSecret release]; - [_expirationDate release]; - [_lastRequestTime release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// public - -- (NSString*)apiURL { - return kAPIRestURL; -} - -- (NSString*)apiSecureURL { - return kAPIRestSecureURL; -} - -- (BOOL)isConnected { - return !!_sessionKey; -} - -- (void)begin:(FBUID)uid sessionKey:(NSString*)sessionKey - sessionSecret:(NSString*)sessionSecret expires:(NSDate*)expires { - _uid = uid; - _sessionKey = [sessionKey copy]; - _sessionSecret = [sessionSecret copy]; - _expirationDate = [expires retain]; - - [self save]; -} - -- (BOOL)resume { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - FBUID uid = [[defaults objectForKey:@"FBUserId"] longLongValue]; - if (uid) { - NSDate* expirationDate = [defaults objectForKey:@"FBSessionExpires"]; - if (!expirationDate || [expirationDate timeIntervalSinceNow] > 0) { - _uid = uid; - _sessionKey = [[defaults stringForKey:@"FBSessionKey"] copy]; - _sessionSecret = [[defaults stringForKey:@"FBSessionSecret"] copy]; - _expirationDate = [expirationDate retain]; - - for (id delegate in _delegates) { - [delegate session:self didLogin:_uid]; - } - return YES; - } - } - return NO; -} - -- (void)cancelLogin { - if (![self isConnected]) { - for (id delegate in _delegates) { - if ([delegate respondsToSelector:@selector(sessionDidNotLogin:)]) { - [delegate sessionDidNotLogin:self]; - } - } - } -} - -- (void)logout { - if (_sessionKey) { - for (id delegate in _delegates) { - if ([delegate respondsToSelector:@selector(session:willLogout:)]) { - [delegate session:self willLogout:_uid]; - } - } - - [self deleteFacebookCookies]; - - - _uid = 0; - [_sessionKey release]; - _sessionKey = nil; - [_sessionSecret release]; - _sessionSecret = nil; - [_expirationDate release]; - _expirationDate = nil; - [self unsave]; - - for (id delegate in _delegates) { - if ([delegate respondsToSelector:@selector(sessionDidLogout:)]) { - [delegate sessionDidLogout:self]; - } - } - } else { - [self deleteFacebookCookies]; - [self unsave]; - } -} - -- (void)send:(FBRequest*)request { - [self performRequest:request enqueue:YES]; -} - -- (void)deleteFacebookCookies { - NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - NSArray* facebookCookies = [cookies cookiesForURL: - [NSURL URLWithString:@"http://login.facebook.com"]]; - for (NSHTTPCookie* cookie in facebookCookies) { - [cookies deleteCookie:cookie]; - } -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h deleted file mode 100755 index b926a01e..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "FBDialog.h" - -@interface FBStreamDialog : FBDialog { - NSString* _attachment; - NSString* _actionLinks; - NSString* _targetId; - NSString* _userMessagePrompt; -} - -/** - * A JSON-encoded object containing the text of the post, relevant links, a - * media type (image, video, mp3, flash), as well as any other key/value pairs - * you may want to add. - * - * Note: If you want to use this call to update a user's status, don't pass an - * attachment; the content of the userMessage parameter will become the user's - * new status and will appear at the top of the user's profile. - * - * For more info, see http://wiki.developers.facebook.com/index.php/Attachment_(Streams) - */ -@property(nonatomic,copy) NSString* attachment; - -/** - * A JSON-encoded array of action link objects, containing the link text and a - * hyperlink. - */ -@property(nonatomic,copy) NSString* actionLinks; - -/** - * The ID of the user or the Page where you are publishing the content. If this - * is specified, the post appears on the Wall of the target user, not on the - * Wall of the user who published the post. This mimics the action of posting - * on a friend's Wall on Facebook itself. - * - * Note: To post on the user's own wall, leave this blank. - */ -@property(nonatomic,copy) NSString* targetId; - -/** - * Text you provide the user as a prompt to specify a userMessage. This appears - * above the box where the user enters a custom message. - * For example, "What's on your mind?" - */ -@property(nonatomic,copy) NSString* userMessagePrompt; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m deleted file mode 100755 index 99fdf142..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "FBStreamDialog.h" -#import "FBSession.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kStreamURL = @"http://www.facebook.com/connect/prompt_feed.php"; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBStreamDialog - -@synthesize attachment = _attachment, - actionLinks = _actionLinks, - targetId = _targetId, - userMessagePrompt = _userMessagePrompt; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - if (self = [super initWithSession:session]) { - _attachment = @""; - _actionLinks = @""; - _targetId = @""; - _userMessagePrompt = @""; - } - return self; -} - -- (void)dealloc { - [_attachment release]; - [_actionLinks release]; - [_targetId release]; - [_userMessagePrompt release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBDialog - -- (void)load { - NSDictionary* getParams = [NSDictionary dictionaryWithObjectsAndKeys: - @"touch", @"display", nil]; - - NSDictionary* postParams = [NSDictionary dictionaryWithObjectsAndKeys: - _session.apiKey, @"api_key", - _session.sessionKey, @"session_key", - @"1", @"preview", - @"fbconnect:success", @"callback", - @"fbconnect:cancel", @"cancel", - _attachment, @"attachment", - _actionLinks, @"action_links", - _targetId, @"target_id", - _userMessagePrompt, @"user_message_prompt", - nil]; - - [self loadURL:kStreamURL method:@"POST" get:getParams post:postParams]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h deleted file mode 100644 index a60ef6ad..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBConnectGlobal.h" - -@interface FBXMLHandler : NSObject { - NSMutableArray* _stack; - NSMutableArray* _nameStack; - id _rootObject; - NSString* _rootName; - NSMutableString* _chars; - NSError* _parseError; -} - -@property(nonatomic,readonly) id rootObject; -@property(nonatomic,readonly) NSString* rootName; -@property(nonatomic,readonly) NSError* parseError; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m deleted file mode 100644 index 54de261f..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBXMLHandler.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBXMLHandler - -@synthesize rootObject = _rootObject, rootName = _rootName, parseError = _parseError; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -- (NSString*)topName { - return [_nameStack lastObject]; -} - -- (id)topObject:(BOOL)create { - id object = [_stack objectAtIndex:_stack.count-1]; - if (object == [NSNull null] && create) { - object = [NSMutableDictionary dictionary]; - [_stack replaceObjectAtIndex:_stack.count-1 withObject:object]; - } - return object; -} - -- (id)topContainer { - if (_stack.count < 2) { - return nil; - } else { - id object = [_stack objectAtIndex:_stack.count-2]; - if (object == [NSNull null]) { - object = [NSMutableDictionary dictionary]; - [_stack replaceObjectAtIndex:_stack.count-2 withObject:object]; - } - return object; - } -} - -- (void)flushCharacters { - NSCharacterSet* whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - for (NSInteger i = 0; i < _chars.length; ++i) { - unichar c = [_chars characterAtIndex:i]; - if (![whitespace characterIsMember:c]) { - id topContainer = self.topContainer; - if ([topContainer isKindOfClass:[NSMutableArray class]]) { - id object = [NSDictionary dictionaryWithObject:_chars forKey:self.topName]; - [_stack replaceObjectAtIndex:_stack.count-1 withObject:object]; - } else { - [_stack replaceObjectAtIndex:_stack.count-1 withObject:_chars]; - } - break; - } - } - - [_chars release]; - _chars = nil; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)init { - if (self = [super init]) { - _stack = [[NSMutableArray alloc] init]; - _nameStack = [[NSMutableArray alloc] init]; - _rootObject = nil; - _rootName = nil; - _chars = nil; - _parseError = nil; - } - return self; -} - -- (void)dealloc { - [_stack release]; - [_nameStack release]; - [_rootObject release]; - [_rootName release]; - [_chars release]; - [_parseError release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSXMLParserDelegate - -- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName - namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName - attributes:(NSDictionary *)attributeDict { - [self flushCharacters]; - - id object = nil; - if ([[attributeDict objectForKey:@"list"] isEqualToString:@"true"]) { - object = [NSMutableArray array]; - } else { - object = [NSNull null]; - } - - [_stack addObject:object]; - [_nameStack addObject:elementName]; -} - -- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { - if (!_chars) { - _chars = [string mutableCopy]; - } else { - [_chars appendString:string]; - } -} - -- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName - namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { - [self flushCharacters]; - - id object = [[[self topObject:NO] retain] autorelease]; - NSString* name = [[self.topName retain] autorelease]; - [_stack removeLastObject]; - [_nameStack removeLastObject]; - - if (!_stack.count) { - _rootObject = [object retain]; - _rootName = [name retain]; - } else { - id topObject = [self topObject:YES]; - if ([topObject isKindOfClass:[NSMutableArray class]]) { - [topObject addObject:object]; - } else if ([topObject isKindOfClass:[NSMutableDictionary class]]) { - [topObject setObject:object forKey:name]; - } - } -} - -- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)error { - _parseError = [error retain]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.h new file mode 100644 index 00000000..9c391798 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.h @@ -0,0 +1,113 @@ +/* + * Copyright 2010 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FBLoginDialog.h" +#import "FBRequest.h" + +@protocol FBSessionDelegate; + +/** + * Main Facebook interface for interacting with the Facebook developer API. + * Provides methods to log in and log out a user, make requests using the REST + * and Graph APIs, and start user interface interactions (such as + * pop-ups promoting for credentials, permissions, stream posts, etc.) + */ +@interface Facebook : NSObject{ + NSString* _accessToken; + NSDate* _expirationDate; + id _sessionDelegate; + FBRequest* _request; + FBDialog* _loginDialog; + FBDialog* _fbDialog; + NSString* _appId; + NSString* _localAppId; + NSArray* _permissions; +} + +@property(nonatomic, copy) NSString* accessToken; +@property(nonatomic, copy) NSDate* expirationDate; +@property(nonatomic, assign) id sessionDelegate; +@property(nonatomic, copy) NSString* localAppId; + +- (id)initWithAppId:(NSString *)app_id; + +- (void)authorize:(NSArray *)permissions + delegate:(id)delegate; + +- (void)authorize:(NSArray *)permissions + delegate:(id)delegate + localAppId:(NSString *)localAppId; + +- (BOOL)handleOpenURL:(NSURL *)url; + +- (void)logout:(id)delegate; + +- (FBRequest*)requestWithParams:(NSMutableDictionary *)params + andDelegate:(id )delegate; + +- (FBRequest*)requestWithMethodName:(NSString *)methodName + andParams:(NSMutableDictionary *)params + andHttpMethod:(NSString *)httpMethod + andDelegate:(id )delegate; + +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andDelegate:(id )delegate; + +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andParams:(NSMutableDictionary *)params + andDelegate:(id )delegate; + +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andParams:(NSMutableDictionary *)params + andHttpMethod:(NSString *)httpMethod + andDelegate:(id )delegate; + +- (void)dialog:(NSString *)action + andDelegate:(id)delegate; + +- (void)dialog:(NSString *)action + andParams:(NSMutableDictionary *)params + andDelegate:(id )delegate; + +- (BOOL)isSessionValid; + +@end + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Your application should implement this delegate to receive session callbacks. + */ +@protocol FBSessionDelegate + +@optional + +/** + * Called when the user successfully logged in. + */ +- (void)fbDidLogin; + +/** + * Called when the user dismissed the dialog without logging in. + */ +- (void)fbDidNotLogin:(BOOL)cancelled; + +/** + * Called when the user logged out. + */ +- (void)fbDidLogout; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.m new file mode 100644 index 00000000..23d8f5fc --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.m @@ -0,0 +1,660 @@ +/* + * Copyright 2010 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Facebook.h" +#import "FBLoginDialog.h" +#import "FBRequest.h" + +static NSString* kDialogBaseURL = @"https://m.facebook.com/dialog/"; +static NSString* kGraphBaseURL = @"https://graph.facebook.com/"; +static NSString* kRestserverBaseURL = @"https://api.facebook.com/method/"; + +static NSString* kFBAppAuthURLScheme = @"fbauth"; +static NSString* kFBAppAuthURLPath = @"authorize"; +static NSString* kRedirectURL = @"fbconnect://success"; + +static NSString* kLogin = @"oauth"; +static NSString* kSDK = @"ios"; +static NSString* kSDKVersion = @"2"; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface Facebook () + +// private properties +@property(nonatomic, retain) NSArray* permissions; + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation Facebook + +@synthesize accessToken = _accessToken, + expirationDate = _expirationDate, + sessionDelegate = _sessionDelegate, + permissions = _permissions, + localAppId = _localAppId; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + + +/** + * Initialize the Facebook object with application ID. + */ +- (id)initWithAppId:(NSString *)app_id { + self = [super init]; + if (self) { + [_appId release]; + _appId = [app_id copy]; + } + return self; +} + +/** + * Override NSObject : free the space + */ +- (void)dealloc { + [_accessToken release]; + [_expirationDate release]; + [_request release]; + [_loginDialog release]; + [_fbDialog release]; + [_appId release]; + [_permissions release]; + [_localAppId release]; + [super dealloc]; +} + +/** + * A private helper function for sending HTTP requests. + * + * @param url + * url to send http request + * @param params + * parameters to append to the url + * @param httpMethod + * http method @"GET" or @"POST" + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + */ +- (FBRequest*)openUrl:(NSString *)url + params:(NSMutableDictionary *)params + httpMethod:(NSString *)httpMethod + delegate:(id)delegate { + + [params setValue:@"json" forKey:@"format"]; + [params setValue:kSDK forKey:@"sdk"]; + [params setValue:kSDKVersion forKey:@"sdk_version"]; + if ([self isSessionValid]) { + [params setValue:self.accessToken forKey:@"access_token"]; + } + + [_request release]; + _request = [[FBRequest getRequestWithParams:params + httpMethod:httpMethod + delegate:delegate + requestURL:url] retain]; + [_request connect]; + return _request; +} + +/** + * A private function for getting the app's base url. + */ +- (NSString *)getOwnBaseUrl { + return [NSString stringWithFormat:@"fb%@%@://authorize", + _appId, + _localAppId ? _localAppId : @""]; +} + +/** + * A private function for opening the authorization dialog. + */ +- (void)authorizeWithFBAppAuth:(BOOL)tryFBAppAuth + safariAuth:(BOOL)trySafariAuth { + NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys: + _appId, @"client_id", + @"user_agent", @"type", + kRedirectURL, @"redirect_uri", + @"touch", @"display", + kSDKVersion, @"sdk", + nil]; + + NSString *loginDialogURL = [kDialogBaseURL stringByAppendingString:kLogin]; + + if (_permissions != nil) { + NSString* scope = [_permissions componentsJoinedByString:@","]; + [params setValue:scope forKey:@"scope"]; + } + + if (_localAppId) { + [params setValue:_localAppId forKey:@"local_client_id"]; + } + + // If the device is running a version of iOS that supports multitasking, + // try to obtain the access token from the Facebook app installed + // on the device. + // If the Facebook app isn't installed or it doesn't support + // the fbauth:// URL scheme, fall back on Safari for obtaining the access token. + // This minimizes the chance that the user will have to enter his or + // her credentials in order to authorize the application. + BOOL didOpenOtherApp = NO; + UIDevice *device = [UIDevice currentDevice]; + if ([device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported]) { + if (tryFBAppAuth) { + NSString *scheme = kFBAppAuthURLScheme; + if (_localAppId) { + scheme = [scheme stringByAppendingString:@"2"]; + } + NSString *urlPrefix = [NSString stringWithFormat:@"%@://%@", scheme, kFBAppAuthURLPath]; + NSString *fbAppUrl = [FBRequest serializeURL:urlPrefix params:params]; + didOpenOtherApp = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:fbAppUrl]]; + } + + if (trySafariAuth && !didOpenOtherApp) { + NSString *nextUrl = [self getOwnBaseUrl]; + [params setValue:nextUrl forKey:@"redirect_uri"]; + + NSString *fbAppUrl = [FBRequest serializeURL:loginDialogURL params:params]; + didOpenOtherApp = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:fbAppUrl]]; + } + } + + // If single sign-on failed, open an inline login dialog. This will require the user to + // enter his or her credentials. + if (!didOpenOtherApp) { + [_loginDialog release]; + _loginDialog = [[FBLoginDialog alloc] initWithURL:loginDialogURL + loginParams:params + delegate:self]; + [_loginDialog show]; + } +} + +/** + * A function for parsing URL parameters. + */ +- (NSDictionary*)parseURLParams:(NSString *)query { + NSArray *pairs = [query componentsSeparatedByString:@"&"]; + NSMutableDictionary *params = [[[NSMutableDictionary alloc] init] autorelease]; + for (NSString *pair in pairs) { + NSArray *kv = [pair componentsSeparatedByString:@"="]; + NSString *val = + [[kv objectAtIndex:1] + stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + + [params setObject:val forKey:[kv objectAtIndex:0]]; + } + return params; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +//public + +- (void)authorize:(NSArray *)permissions + delegate:(id)delegate { + [self authorize:permissions + delegate:delegate + localAppId:nil]; +} + +/** + * Starts a dialog which prompts the user to log in to Facebook and grant + * the requested permissions to the application. + * + * If the device supports multitasking, we use fast app switching to show + * the dialog in the Facebook app or, if the Facebook app isn't installed, + * in Safari (this enables single sign-on by allowing multiple apps on + * the device to share the same user session). + * When the user grants or denies the permissions, the app that + * showed the dialog (the Facebook app or Safari) redirects back to + * the calling application, passing in the URL the access token + * and/or any other parameters the Facebook backend includes in + * the result (such as an error code if an error occurs). + * + * See http://developers.facebook.com/docs/authentication/ for more details. + * + * Also note that requests may be made to the API without calling + * authorize() first, in which case only public information is returned. + * + * @param permissions + * A list of permission required for this application: e.g. + * "read_stream", "publish_stream", or "offline_access". see + * http://developers.facebook.com/docs/authentication/permissions + * This parameter should not be null -- if you do not require any + * permissions, then pass in an empty String array. + * @param delegate + * Callback interface for notifying the calling application when + * the user has logged in. + * @param localAppId + * localAppId is a string of lowercase letters that is + * appended to the base URL scheme used for SSO. For example, + * if your facebook ID is "350685531728" and you set localAppId to + * "abcd", the Facebook app will expect your application to bind to + * the following URL scheme: "fb350685531728abcd". + * This is useful if your have multiple iOS applications that + * share a single Facebook application id (for example, if you + * have a free and a paid version on the same app) and you want + * to use SSO with both apps. Giving both apps different + * localAppId values will allow the Facebook app to disambiguate + * their URL schemes and always redirect the user back to the + * correct app, even if both the free and the app is installed + * on the device. + * localAppId is supported on version 3.4.1 and above of the Facebook + * app. If the user has an older version of the Facebook app + * installed and your app uses localAppId parameter, the SDK will + * proceed as if the Facebook app isn't installed on the device + * and redirect the user to Safari. + */ +- (void)authorize:(NSArray *)permissions + delegate:(id)delegate + localAppId:(NSString *)localAppId { + self.localAppId = localAppId; + self.permissions = permissions; + + _sessionDelegate = delegate; + + [self authorizeWithFBAppAuth:YES safariAuth:YES]; +} + +/** + * This function processes the URL the Facebook application or Safari used to + * open your application during a single sign-on flow. + * + * You MUST call this function in your UIApplicationDelegate's handleOpenURL + * method (see + * http://developer.apple.com/library/ios/#documentation/uikit/reference/UIApplicationDelegate_Protocol/Reference/Reference.html + * for more info). + * + * This will ensure that the authorization process will proceed smoothly once the + * Facebook application or Safari redirects back to your application. + * + * @param URL the URL that was passed to the application delegate's handleOpenURL method. + * + * @return YES if the URL starts with 'fb[app_id]://authorize and hence was handled + * by SDK, NO otherwise. + */ +- (BOOL)handleOpenURL:(NSURL *)url { + // If the URL's structure doesn't match the structure used for Facebook authorization, abort. + if (![[url absoluteString] hasPrefix:[self getOwnBaseUrl]]) { + return NO; + } + + NSString *query = [url fragment]; + + // Version 3.2.3 of the Facebook app encodes the parameters in the query but + // version 3.3 and above encode the parameters in the fragment. To support + // both versions of the Facebook app, we try to parse the query if + // the fragment is missing. + if (!query) { + query = [url query]; + } + + NSDictionary *params = [self parseURLParams:query]; + NSString *accessToken = [params valueForKey:@"access_token"]; + + // If the URL doesn't contain the access token, an error has occurred. + if (!accessToken) { + NSString *errorReason = [params valueForKey:@"error"]; + + // If the error response indicates that we should try again using Safari, open + // the authorization dialog in Safari. + if (errorReason && [errorReason isEqualToString:@"service_disabled_use_browser"]) { + [self authorizeWithFBAppAuth:NO safariAuth:YES]; + return YES; + } + + // If the error response indicates that we should try the authorization flow + // in an inline dialog, do that. + if (errorReason && [errorReason isEqualToString:@"service_disabled"]) { + [self authorizeWithFBAppAuth:NO safariAuth:NO]; + return YES; + } + + // The facebook app may return an error_code parameter in case it + // encounters a UIWebViewDelegate error. This should not be treated + // as a cancel. + NSString *errorCode = [params valueForKey:@"error_code"]; + + BOOL userDidCancel = + !errorCode && (!errorReason || [errorReason isEqualToString:@"access_denied"]); + [self fbDialogNotLogin:userDidCancel]; + return YES; + } + + // We have an access token, so parse the expiration date. + NSString *expTime = [params valueForKey:@"expires_in"]; + NSDate *expirationDate = [NSDate distantFuture]; + if (expTime != nil) { + int expVal = [expTime intValue]; + if (expVal != 0) { + expirationDate = [NSDate dateWithTimeIntervalSinceNow:expVal]; + } + } + + [self fbDialogLogin:accessToken expirationDate:expirationDate]; + return YES; +} + +/** + * Invalidate the current user session by removing the access token in + * memory, clearing the browser cookie, and calling auth.expireSession + * through the API. + * + * Note that this method dosen't unauthorize the application -- + * it just invalidates the access token. To unauthorize the application, + * the user must remove the app in the app settings page under the privacy + * settings screen on facebook.com. + * + * @param delegate + * Callback interface for notifying the calling application when + * the application has logged out + */ +- (void)logout:(id)delegate { + + _sessionDelegate = delegate; + + NSMutableDictionary * params = [[NSMutableDictionary alloc] init]; + [self requestWithMethodName:@"auth.expireSession" + andParams:params andHttpMethod:@"GET" + andDelegate:nil]; + + [params release]; + [_accessToken release]; + _accessToken = nil; + [_expirationDate release]; + _expirationDate = nil; + + NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSArray* facebookCookies = [cookies cookiesForURL: + [NSURL URLWithString:@"http://login.facebook.com"]]; + + for (NSHTTPCookie* cookie in facebookCookies) { + [cookies deleteCookie:cookie]; + } + + if ([self.sessionDelegate respondsToSelector:@selector(fbDidLogout)]) { + [_sessionDelegate fbDidLogout]; + } +} + +/** + * Make a request to Facebook's REST API with the given + * parameters. One of the parameter keys must be "method" and its value + * should be a valid REST server API method. + * + * See http://developers.facebook.com/docs/reference/rest/ + * + * @param parameters + * Key-value pairs of parameters to the request. Refer to the + * documentation: one of the parameters must be "method". + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithParams:(NSMutableDictionary *)params + andDelegate:(id )delegate { + if ([params objectForKey:@"method"] == nil) { + NSLog(@"API Method must be specified"); + return nil; + } + + NSString * methodName = [params objectForKey:@"method"]; + [params removeObjectForKey:@"method"]; + + return [self requestWithMethodName:methodName + andParams:params + andHttpMethod:@"GET" + andDelegate:delegate]; +} + +/** + * Make a request to Facebook's REST API with the given method name and + * parameters. + * + * See http://developers.facebook.com/docs/reference/rest/ + * + * + * @param methodName + * a valid REST server API method. + * @param parameters + * Key-value pairs of parameters to the request. Refer to the + * documentation: one of the parameters must be "method". To upload + * a file, you should specify the httpMethod to be "POST" and the + * “params” you passed in should contain a value of the type + * (UIImage *) or (NSData *) which contains the content that you + * want to upload + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithMethodName:(NSString *)methodName + andParams:(NSMutableDictionary *)params + andHttpMethod:(NSString *)httpMethod + andDelegate:(id )delegate { + NSString * fullURL = [kRestserverBaseURL stringByAppendingString:methodName]; + return [self openUrl:fullURL + params:params + httpMethod:httpMethod + delegate:delegate]; +} + +/** + * Make a request to the Facebook Graph API without any parameters. + * + * See http://developers.facebook.com/docs/api + * + * @param graphPath + * Path to resource in the Facebook graph, e.g., to fetch data + * about the currently logged authenticated user, provide "me", + * which will fetch http://graph.facebook.com/me + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andDelegate:(id )delegate { + + return [self requestWithGraphPath:graphPath + andParams:[NSMutableDictionary dictionary] + andHttpMethod:@"GET" + andDelegate:delegate]; +} + +/** + * Make a request to the Facebook Graph API with the given string + * parameters using an HTTP GET (default method). + * + * See http://developers.facebook.com/docs/api + * + * + * @param graphPath + * Path to resource in the Facebook graph, e.g., to fetch data + * about the currently logged authenticated user, provide "me", + * which will fetch http://graph.facebook.com/me + * @param parameters + * key-value string parameters, e.g. the path "search" with + * parameters "q" : "facebook" would produce a query for the + * following graph resource: + * https://graph.facebook.com/search?q=facebook + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andParams:(NSMutableDictionary *)params + andDelegate:(id )delegate { + + return [self requestWithGraphPath:graphPath + andParams:params + andHttpMethod:@"GET" + andDelegate:delegate]; +} + +/** + * Make a request to the Facebook Graph API with the given + * HTTP method and string parameters. Note that binary data parameters + * (e.g. pictures) are not yet supported by this helper function. + * + * See http://developers.facebook.com/docs/api + * + * + * @param graphPath + * Path to resource in the Facebook graph, e.g., to fetch data + * about the currently logged authenticated user, provide "me", + * which will fetch http://graph.facebook.com/me + * @param parameters + * key-value string parameters, e.g. the path "search" with + * parameters {"q" : "facebook"} would produce a query for the + * following graph resource: + * https://graph.facebook.com/search?q=facebook + * To upload a file, you should specify the httpMethod to be + * "POST" and the “params” you passed in should contain a value + * of the type (UIImage *) or (NSData *) which contains the + * content that you want to upload + * @param httpMethod + * http verb, e.g. "GET", "POST", "DELETE" + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andParams:(NSMutableDictionary *)params + andHttpMethod:(NSString *)httpMethod + andDelegate:(id )delegate { + + NSString * fullURL = [kGraphBaseURL stringByAppendingString:graphPath]; + return [self openUrl:fullURL + params:params + httpMethod:httpMethod + delegate:delegate]; +} + +/** + * Generate a UI dialog for the request action. + * + * @param action + * String representation of the desired method: e.g. "login", + * "feed", ... + * @param delegate + * Callback interface to notify the calling application when the + * dialog has completed. + */ +- (void)dialog:(NSString *)action + andDelegate:(id)delegate { + NSMutableDictionary * params = [NSMutableDictionary dictionary]; + [self dialog:action andParams:params andDelegate:delegate]; +} + +/** + * Generate a UI dialog for the request action with the provided parameters. + * + * @param action + * String representation of the desired method: e.g. "login", + * "feed", ... + * @param parameters + * key-value string parameters + * @param delegate + * Callback interface to notify the calling application when the + * dialog has completed. + */ +- (void)dialog:(NSString *)action + andParams:(NSMutableDictionary *)params + andDelegate:(id )delegate { + + [_fbDialog release]; + + NSString *dialogURL = [kDialogBaseURL stringByAppendingString:action]; + [params setObject:@"touch" forKey:@"display"]; + [params setObject:kSDKVersion forKey:@"sdk"]; + [params setObject:kRedirectURL forKey:@"redirect_uri"]; + + if (action == kLogin) { + [params setObject:@"user_agent" forKey:@"type"]; + _fbDialog = [[FBLoginDialog alloc] initWithURL:dialogURL loginParams:params delegate:self]; + } else { + [params setObject:_appId forKey:@"app_id"]; + if ([self isSessionValid]) { + [params setValue:[self.accessToken stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] + forKey:@"access_token"]; + } + _fbDialog = [[FBDialog alloc] initWithURL:dialogURL params:params delegate:delegate]; + } + + [_fbDialog show]; +} + +/** + * @return boolean - whether this object has an non-expired session token + */ +- (BOOL)isSessionValid { + return (self.accessToken != nil && self.expirationDate != nil + && NSOrderedDescending == [self.expirationDate compare:[NSDate date]]); + +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +//FBLoginDialogDelegate + +/** + * Set the authToken and expirationDate after login succeed + */ +- (void)fbDialogLogin:(NSString *)token expirationDate:(NSDate *)expirationDate { + self.accessToken = token; + self.expirationDate = expirationDate; + if ([self.sessionDelegate respondsToSelector:@selector(fbDidLogin)]) { + [_sessionDelegate fbDidLogin]; + } + +} + +/** + * Did not login call the not login delegate + */ +- (void)fbDialogNotLogin:(BOOL)cancelled { + if ([self.sessionDelegate respondsToSelector:@selector(fbDidNotLogin:)]) { + [_sessionDelegate fbDidNotLogin:cancelled]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +//FBRequestDelegate + +/** + * Handle the auth.ExpireSession api call failure + */ +- (void)request:(FBRequest*)request didFailWithError:(NSError*)error{ + NSLog(@"Failed to expire the session"); +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/JSON.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/JSON.h new file mode 100644 index 00000000..1e58c9ad --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/JSON.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @mainpage A strict JSON parser and generator for Objective-C + + JSON (JavaScript Object Notation) is a lightweight data-interchange + format. This framework provides two apis for parsing and generating + JSON. One standard object-based and a higher level api consisting of + categories added to existing Objective-C classes. + + Learn more on the http://code.google.com/p/json-framework project site. + + This framework does its best to be as strict as possible, both in what it + accepts and what it generates. For example, it does not support trailing commas + in arrays or objects. Nor does it support embedded comments, or + anything else not in the JSON specification. This is considered a feature. + +*/ + +#import "SBJSON.h" +#import "NSObject+SBJSON.h" +#import "NSString+SBJSON.h" + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.h new file mode 100644 index 00000000..ecf0ee40 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + + +/** + @brief Adds JSON generation to Foundation classes + + This is a category on NSObject that adds methods for returning JSON representations + of standard objects to the objects themselves. This means you can call the + -JSONRepresentation method on an NSArray object and it'll do what you want. + */ +@interface NSObject (NSObject_SBJSON) + +/** + @brief Returns a string containing the receiver encoded as a JSON fragment. + + This method is added as a category on NSObject but is only actually + supported for the following objects: + @li NSDictionary + @li NSArray + @li NSString + @li NSNumber (also used for booleans) + @li NSNull + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (NSString *)JSONFragment; + +/** + @brief Returns a string containing the receiver encoded in JSON. + + This method is added as a category on NSObject but is only actually + supported for the following objects: + @li NSDictionary + @li NSArray + */ +- (NSString *)JSONRepresentation; + +@end + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.m new file mode 100644 index 00000000..20b084b6 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.m @@ -0,0 +1,53 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "NSObject+SBJSON.h" +#import "SBJsonWriter.h" + +@implementation NSObject (NSObject_SBJSON) + +- (NSString *)JSONFragment { + SBJsonWriter *jsonWriter = [SBJsonWriter new]; + NSString *json = [jsonWriter stringWithFragment:self]; + if (!json) + NSLog(@"-JSONFragment failed. Error trace is: %@", [jsonWriter errorTrace]); + [jsonWriter release]; + return json; +} + +- (NSString *)JSONRepresentation { + SBJsonWriter *jsonWriter = [SBJsonWriter new]; + NSString *json = [jsonWriter stringWithObject:self]; + if (!json) + NSLog(@"-JSONRepresentation failed. Error trace is: %@", [jsonWriter errorTrace]); + [jsonWriter release]; + return json; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.h new file mode 100644 index 00000000..fad7179c --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +/** + @brief Adds JSON parsing methods to NSString + +This is a category on NSString that adds methods for parsing the target string. +*/ +@interface NSString (NSString_SBJSON) + + +/** + @brief Returns the object represented in the receiver, or nil on error. + + Returns a a scalar object represented by the string's JSON fragment representation. + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (id)JSONFragmentValue; + +/** + @brief Returns the NSDictionary or NSArray represented by the current string's JSON representation. + + Returns the dictionary or array represented in the receiver, or nil on error. + + Returns the NSDictionary or NSArray represented by the current string's JSON representation. + */ +- (id)JSONValue; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.m new file mode 100644 index 00000000..41a5a85b --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.m @@ -0,0 +1,55 @@ +/* + Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "NSString+SBJSON.h" +#import "SBJsonParser.h" + +@implementation NSString (NSString_SBJSON) + +- (id)JSONFragmentValue +{ + SBJsonParser *jsonParser = [SBJsonParser new]; + id repr = [jsonParser fragmentWithString:self]; + if (!repr) + NSLog(@"-JSONFragmentValue failed. Error trace is: %@", [jsonParser errorTrace]); + [jsonParser release]; + return repr; +} + +- (id)JSONValue +{ + SBJsonParser *jsonParser = [SBJsonParser new]; + id repr = [jsonParser objectWithString:self]; + if (!repr) + NSLog(@"-JSONValue failed. Error trace is: %@", [jsonParser errorTrace]); + [jsonParser release]; + return repr; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.h new file mode 100644 index 00000000..43d63c30 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.h @@ -0,0 +1,75 @@ +/* + Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonParser.h" +#import "SBJsonWriter.h" + +/** + @brief Facade for SBJsonWriter/SBJsonParser. + + Requests are forwarded to instances of SBJsonWriter and SBJsonParser. + */ +@interface SBJSON : SBJsonBase { + +@private + SBJsonParser *jsonParser; + SBJsonWriter *jsonWriter; +} + + +/// Return the fragment represented by the given string +- (id)fragmentWithString:(NSString*)jsonrep + error:(NSError**)error; + +/// Return the object represented by the given string +- (id)objectWithString:(NSString*)jsonrep + error:(NSError**)error; + +/// Parse the string and return the represented object (or scalar) +- (id)objectWithString:(id)value + allowScalar:(BOOL)x + error:(NSError**)error; + + +/// Return JSON representation of an array or dictionary +- (NSString*)stringWithObject:(id)value + error:(NSError**)error; + +/// Return JSON representation of any legal JSON value +- (NSString*)stringWithFragment:(id)value + error:(NSError**)error; + +/// Return JSON representation (or fragment) for the given object +- (NSString*)stringWithObject:(id)value + allowScalar:(BOOL)x + error:(NSError**)error; + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.m new file mode 100644 index 00000000..2a30f1a7 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.m @@ -0,0 +1,212 @@ +/* + Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJSON.h" + +@implementation SBJSON + +- (id)init { + self = [super init]; + if (self) { + jsonWriter = [SBJsonWriter new]; + jsonParser = [SBJsonParser new]; + [self setMaxDepth:512]; + + } + return self; +} + +- (void)dealloc { + [jsonWriter release]; + [jsonParser release]; + [super dealloc]; +} + +#pragma mark Writer + + +- (NSString *)stringWithObject:(id)obj { + NSString *repr = [jsonWriter stringWithObject:obj]; + if (repr) + return repr; + + [errorTrace release]; + errorTrace = [[jsonWriter errorTrace] mutableCopy]; + return nil; +} + +/** + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + @param allowScalar wether to return json fragments for scalar objects + @param error used to return an error by reference (pass NULL if this is not desired) + +@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (NSString*)stringWithObject:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { + + NSString *json = allowScalar ? [jsonWriter stringWithFragment:value] : [jsonWriter stringWithObject:value]; + if (json) + return json; + + [errorTrace release]; + errorTrace = [[jsonWriter errorTrace] mutableCopy]; + + if (error) + *error = [errorTrace lastObject]; + return nil; +} + +/** + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + @param error used to return an error by reference (pass NULL if this is not desired) + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (NSString*)stringWithFragment:(id)value error:(NSError**)error { + return [self stringWithObject:value + allowScalar:YES + error:error]; +} + +/** + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. + + @param value a NSDictionary or NSArray instance + @param error used to return an error by reference (pass NULL if this is not desired) + */ +- (NSString*)stringWithObject:(id)value error:(NSError**)error { + return [self stringWithObject:value + allowScalar:NO + error:error]; +} + +#pragma mark Parsing + +- (id)objectWithString:(NSString *)repr { + id obj = [jsonParser objectWithString:repr]; + if (obj) + return obj; + + [errorTrace release]; + errorTrace = [[jsonParser errorTrace] mutableCopy]; + + return nil; +} + +/** + Returns the object represented by the passed-in string or nil on error. The returned object can be + a string, number, boolean, null, array or dictionary. + + @param value the json string to parse + @param allowScalar whether to return objects for JSON fragments + @param error used to return an error by reference (pass NULL if this is not desired) + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (id)objectWithString:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { + + id obj = allowScalar ? [jsonParser fragmentWithString:value] : [jsonParser objectWithString:value]; + if (obj) + return obj; + + [errorTrace release]; + errorTrace = [[jsonParser errorTrace] mutableCopy]; + + if (error) + *error = [errorTrace lastObject]; + return nil; +} + +/** + Returns the object represented by the passed-in string or nil on error. The returned object can be + a string, number, boolean, null, array or dictionary. + + @param repr the json string to parse + @param error used to return an error by reference (pass NULL if this is not desired) + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (id)fragmentWithString:(NSString*)repr error:(NSError**)error { + return [self objectWithString:repr + allowScalar:YES + error:error]; +} + +/** + Returns the object represented by the passed-in string or nil on error. The returned object + will be either a dictionary or an array. + + @param repr the json string to parse + @param error used to return an error by reference (pass NULL if this is not desired) + */ +- (id)objectWithString:(NSString*)repr error:(NSError**)error { + return [self objectWithString:repr + allowScalar:NO + error:error]; +} + + + +#pragma mark Properties - parsing + +- (NSUInteger)maxDepth { + return jsonParser.maxDepth; +} + +- (void)setMaxDepth:(NSUInteger)d { + jsonWriter.maxDepth = jsonParser.maxDepth = d; +} + + +#pragma mark Properties - writing + +- (BOOL)humanReadable { + return jsonWriter.humanReadable; +} + +- (void)setHumanReadable:(BOOL)x { + jsonWriter.humanReadable = x; +} + +- (BOOL)sortKeys { + return jsonWriter.sortKeys; +} + +- (void)setSortKeys:(BOOL)x { + jsonWriter.sortKeys = x; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.h new file mode 100644 index 00000000..7b108440 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +extern NSString * SBJSONErrorDomain; + + +enum { + EUNSUPPORTED = 1, + EPARSENUM, + EPARSE, + EFRAGMENT, + ECTRL, + EUNICODE, + EDEPTH, + EESCAPE, + ETRAILCOMMA, + ETRAILGARBAGE, + EEOF, + EINPUT +}; + +/** + @brief Common base class for parsing & writing. + + This class contains the common error-handling code and option between the parser/writer. + */ +@interface SBJsonBase : NSObject { + NSMutableArray *errorTrace; + +@protected + NSUInteger depth, maxDepth; +} + +/** + @brief The maximum recursing depth. + + Defaults to 512. If the input is nested deeper than this the input will be deemed to be + malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can + turn off this security feature by setting the maxDepth value to 0. + */ +@property NSUInteger maxDepth; + +/** + @brief Return an error trace, or nil if there was no errors. + + Note that this method returns the trace of the last method that failed. + You need to check the return value of the call you're making to figure out + if the call actually failed, before you know call this method. + */ + @property(copy,readonly) NSArray* errorTrace; + +/// @internal for use in subclasses to add errors to the stack trace +- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str; + +/// @internal for use in subclasess to clear the error before a new parsing attempt +- (void)clearErrorTrace; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.m new file mode 100644 index 00000000..6684325d --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.m @@ -0,0 +1,78 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonBase.h" +NSString * SBJSONErrorDomain = @"org.brautaset.JSON.ErrorDomain"; + + +@implementation SBJsonBase + +@synthesize errorTrace; +@synthesize maxDepth; + +- (id)init { + self = [super init]; + if (self) + self.maxDepth = 512; + return self; +} + +- (void)dealloc { + [errorTrace release]; + [super dealloc]; +} + +- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str { + NSDictionary *userInfo; + if (!errorTrace) { + errorTrace = [NSMutableArray new]; + userInfo = [NSDictionary dictionaryWithObject:str forKey:NSLocalizedDescriptionKey]; + + } else { + userInfo = [NSDictionary dictionaryWithObjectsAndKeys: + str, NSLocalizedDescriptionKey, + [errorTrace lastObject], NSUnderlyingErrorKey, + nil]; + } + + NSError *error = [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:userInfo]; + + [self willChangeValueForKey:@"errorTrace"]; + [errorTrace addObject:error]; + [self didChangeValueForKey:@"errorTrace"]; +} + +- (void)clearErrorTrace { + [self willChangeValueForKey:@"errorTrace"]; + [errorTrace release]; + errorTrace = nil; + [self didChangeValueForKey:@"errorTrace"]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.h new file mode 100644 index 00000000..e95304d9 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonBase.h" + +/** + @brief Options for the parser class. + + This exists so the SBJSON facade can implement the options in the parser without having to re-declare them. + */ +@protocol SBJsonParser + +/** + @brief Return the object represented by the given string. + + Returns the object represented by the passed-in string or nil on error. The returned object can be + a string, number, boolean, null, array or dictionary. + + @param repr the json string to parse + */ +- (id)objectWithString:(NSString *)repr; + +@end + + +/** + @brief The JSON parser class. + + JSON is mapped to Objective-C types in the following way: + + @li Null -> NSNull + @li String -> NSMutableString + @li Array -> NSMutableArray + @li Object -> NSMutableDictionary + @li Boolean -> NSNumber (initialised with -initWithBool:) + @li Number -> NSDecimalNumber + + Since Objective-C doesn't have a dedicated class for boolean values, these turns into NSNumber + instances. These are initialised with the -initWithBool: method, and + round-trip back to JSON properly. (They won't silently suddenly become 0 or 1; they'll be + represented as 'true' and 'false' again.) + + JSON numbers turn into NSDecimalNumber instances, + as we can thus avoid any loss of precision. (JSON allows ridiculously large numbers.) + + */ +@interface SBJsonParser : SBJsonBase { + +@private + const char *c; +} + +@end + +// don't use - exists for backwards compatibility with 2.1.x only. Will be removed in 2.3. +@interface SBJsonParser (Private) +- (id)fragmentWithString:(id)repr; +@end + + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.m new file mode 100644 index 00000000..eda051a8 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.m @@ -0,0 +1,475 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonParser.h" + +@interface SBJsonParser () + +- (BOOL)scanValue:(NSObject **)o; + +- (BOOL)scanRestOfArray:(NSMutableArray **)o; +- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o; +- (BOOL)scanRestOfNull:(NSNull **)o; +- (BOOL)scanRestOfFalse:(NSNumber **)o; +- (BOOL)scanRestOfTrue:(NSNumber **)o; +- (BOOL)scanRestOfString:(NSMutableString **)o; + +// Cannot manage without looking at the first digit +- (BOOL)scanNumber:(NSNumber **)o; + +- (BOOL)scanHexQuad:(unichar *)x; +- (BOOL)scanUnicodeChar:(unichar *)x; + +- (BOOL)scanIsAtEnd; + +@end + +#define skipWhitespace(c) while (isspace(*c)) c++ +#define skipDigits(c) while (isdigit(*c)) c++ + + +@implementation SBJsonParser + +static char ctrl[0x22]; + + ++ (void)initialize { + ctrl[0] = '\"'; + ctrl[1] = '\\'; + for (int i = 1; i < 0x20; i++) + ctrl[i+1] = i; + ctrl[0x21] = 0; +} + +/** + @deprecated This exists in order to provide fragment support in older APIs in one more version. + It should be removed in the next major version. + */ +- (id)fragmentWithString:(id)repr { + [self clearErrorTrace]; + + if (!repr) { + [self addErrorWithCode:EINPUT description:@"Input was 'nil'"]; + return nil; + } + + depth = 0; + c = [repr UTF8String]; + + id o; + if (![self scanValue:&o]) { + return nil; + } + + // We found some valid JSON. But did it also contain something else? + if (![self scanIsAtEnd]) { + [self addErrorWithCode:ETRAILGARBAGE description:@"Garbage after JSON"]; + return nil; + } + + NSAssert1(o, @"Should have a valid object from %@", repr); + return o; +} + +- (id)objectWithString:(NSString *)repr { + + id o = [self fragmentWithString:repr]; + if (!o) + return nil; + + // Check that the object we've found is a valid JSON container. + if (![o isKindOfClass:[NSDictionary class]] && ![o isKindOfClass:[NSArray class]]) { + [self addErrorWithCode:EFRAGMENT description:@"Valid fragment, but not JSON"]; + return nil; + } + + return o; +} + +/* + In contrast to the public methods, it is an error to omit the error parameter here. + */ +- (BOOL)scanValue:(NSObject **)o +{ + skipWhitespace(c); + + switch (*c++) { + case '{': + return [self scanRestOfDictionary:(NSMutableDictionary **)o]; + break; + case '[': + return [self scanRestOfArray:(NSMutableArray **)o]; + break; + case '"': + return [self scanRestOfString:(NSMutableString **)o]; + break; + case 'f': + return [self scanRestOfFalse:(NSNumber **)o]; + break; + case 't': + return [self scanRestOfTrue:(NSNumber **)o]; + break; + case 'n': + return [self scanRestOfNull:(NSNull **)o]; + break; + case '-': + case '0'...'9': + c--; // cannot verify number correctly without the first character + return [self scanNumber:(NSNumber **)o]; + break; + case '+': + [self addErrorWithCode:EPARSENUM description: @"Leading + disallowed in number"]; + return NO; + break; + case 0x0: + [self addErrorWithCode:EEOF description:@"Unexpected end of string"]; + return NO; + break; + default: + [self addErrorWithCode:EPARSE description: @"Unrecognised leading character"]; + return NO; + break; + } + + NSAssert(0, @"Should never get here"); + return NO; +} + +- (BOOL)scanRestOfTrue:(NSNumber **)o +{ + if (!strncmp(c, "rue", 3)) { + c += 3; + *o = [NSNumber numberWithBool:YES]; + return YES; + } + [self addErrorWithCode:EPARSE description:@"Expected 'true'"]; + return NO; +} + +- (BOOL)scanRestOfFalse:(NSNumber **)o +{ + if (!strncmp(c, "alse", 4)) { + c += 4; + *o = [NSNumber numberWithBool:NO]; + return YES; + } + [self addErrorWithCode:EPARSE description: @"Expected 'false'"]; + return NO; +} + +- (BOOL)scanRestOfNull:(NSNull **)o { + if (!strncmp(c, "ull", 3)) { + c += 3; + *o = [NSNull null]; + return YES; + } + [self addErrorWithCode:EPARSE description: @"Expected 'null'"]; + return NO; +} + +- (BOOL)scanRestOfArray:(NSMutableArray **)o { + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + + *o = [NSMutableArray arrayWithCapacity:8]; + + for (; *c ;) { + id v; + + skipWhitespace(c); + if (*c == ']' && c++) { + depth--; + return YES; + } + + if (![self scanValue:&v]) { + [self addErrorWithCode:EPARSE description:@"Expected value while parsing array"]; + return NO; + } + + [*o addObject:v]; + + skipWhitespace(c); + if (*c == ',' && c++) { + skipWhitespace(c); + if (*c == ']') { + [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in array"]; + return NO; + } + } + } + + [self addErrorWithCode:EEOF description: @"End of input while parsing array"]; + return NO; +} + +- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o +{ + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + + *o = [NSMutableDictionary dictionaryWithCapacity:7]; + + for (; *c ;) { + id k, v; + + skipWhitespace(c); + if (*c == '}' && c++) { + depth--; + return YES; + } + + if (!(*c == '\"' && c++ && [self scanRestOfString:&k])) { + [self addErrorWithCode:EPARSE description: @"Object key string expected"]; + return NO; + } + + skipWhitespace(c); + if (*c != ':') { + [self addErrorWithCode:EPARSE description: @"Expected ':' separating key and value"]; + return NO; + } + + c++; + if (![self scanValue:&v]) { + NSString *string = [NSString stringWithFormat:@"Object value expected for key: %@", k]; + [self addErrorWithCode:EPARSE description: string]; + return NO; + } + + [*o setObject:v forKey:k]; + + skipWhitespace(c); + if (*c == ',' && c++) { + skipWhitespace(c); + if (*c == '}') { + [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in object"]; + return NO; + } + } + } + + [self addErrorWithCode:EEOF description: @"End of input while parsing object"]; + return NO; +} + +- (BOOL)scanRestOfString:(NSMutableString **)o +{ + *o = [NSMutableString stringWithCapacity:16]; + do { + // First see if there's a portion we can grab in one go. + // Doing this caused a massive speedup on the long string. + size_t len = strcspn(c, ctrl); + if (len) { + // check for + id t = [[NSString alloc] initWithBytesNoCopy:(char*)c + length:len + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + if (t) { + [*o appendString:t]; + [t release]; + c += len; + } + } + + if (*c == '"') { + c++; + return YES; + + } else if (*c == '\\') { + unichar uc = *++c; + switch (uc) { + case '\\': + case '/': + case '"': + break; + + case 'b': uc = '\b'; break; + case 'n': uc = '\n'; break; + case 'r': uc = '\r'; break; + case 't': uc = '\t'; break; + case 'f': uc = '\f'; break; + + case 'u': + c++; + if (![self scanUnicodeChar:&uc]) { + [self addErrorWithCode:EUNICODE description: @"Broken unicode character"]; + return NO; + } + c--; // hack. + break; + default: + [self addErrorWithCode:EESCAPE description: [NSString stringWithFormat:@"Illegal escape sequence '0x%x'", uc]]; + return NO; + break; + } + CFStringAppendCharacters((CFMutableStringRef)*o, &uc, 1); + c++; + + } else if (*c < 0x20) { + [self addErrorWithCode:ECTRL description: [NSString stringWithFormat:@"Unescaped control character '0x%x'", *c]]; + return NO; + + } else { + NSLog(@"should not be able to get here"); + } + } while (*c); + + [self addErrorWithCode:EEOF description:@"Unexpected EOF while parsing string"]; + return NO; +} + +- (BOOL)scanUnicodeChar:(unichar *)x +{ + unichar hi, lo; + + if (![self scanHexQuad:&hi]) { + [self addErrorWithCode:EUNICODE description: @"Missing hex quad"]; + return NO; + } + + if (hi >= 0xd800) { // high surrogate char? + if (hi < 0xdc00) { // yes - expect a low char + + if (!(*c == '\\' && ++c && *c == 'u' && ++c && [self scanHexQuad:&lo])) { + [self addErrorWithCode:EUNICODE description: @"Missing low character in surrogate pair"]; + return NO; + } + + if (lo < 0xdc00 || lo >= 0xdfff) { + [self addErrorWithCode:EUNICODE description:@"Invalid low surrogate char"]; + return NO; + } + + hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000; + + } else if (hi < 0xe000) { + [self addErrorWithCode:EUNICODE description:@"Invalid high character in surrogate pair"]; + return NO; + } + } + + *x = hi; + return YES; +} + +- (BOOL)scanHexQuad:(unichar *)x +{ + *x = 0; + for (int i = 0; i < 4; i++) { + unichar uc = *c; + c++; + int d = (uc >= '0' && uc <= '9') + ? uc - '0' : (uc >= 'a' && uc <= 'f') + ? (uc - 'a' + 10) : (uc >= 'A' && uc <= 'F') + ? (uc - 'A' + 10) : -1; + if (d == -1) { + [self addErrorWithCode:EUNICODE description:@"Missing hex digit in quad"]; + return NO; + } + *x *= 16; + *x += d; + } + return YES; +} + +- (BOOL)scanNumber:(NSNumber **)o +{ + const char *ns = c; + + // The logic to test for validity of the number formatting is relicensed + // from JSON::XS with permission from its author Marc Lehmann. + // (Available at the CPAN: http://search.cpan.org/dist/JSON-XS/ .) + + if ('-' == *c) + c++; + + if ('0' == *c && c++) { + if (isdigit(*c)) { + [self addErrorWithCode:EPARSENUM description: @"Leading 0 disallowed in number"]; + return NO; + } + + } else if (!isdigit(*c) && c != ns) { + [self addErrorWithCode:EPARSENUM description: @"No digits after initial minus"]; + return NO; + + } else { + skipDigits(c); + } + + // Fractional part + if ('.' == *c && c++) { + + if (!isdigit(*c)) { + [self addErrorWithCode:EPARSENUM description: @"No digits after decimal point"]; + return NO; + } + skipDigits(c); + } + + // Exponential part + if ('e' == *c || 'E' == *c) { + c++; + + if ('-' == *c || '+' == *c) + c++; + + if (!isdigit(*c)) { + [self addErrorWithCode:EPARSENUM description: @"No digits after exponent"]; + return NO; + } + skipDigits(c); + } + + id str = [[NSString alloc] initWithBytesNoCopy:(char*)ns + length:c - ns + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + [str autorelease]; + if (str && (*o = [NSDecimalNumber decimalNumberWithString:str])) + return YES; + + [self addErrorWithCode:EPARSENUM description: @"Failed creating decimal instance"]; + return NO; +} + +- (BOOL)scanIsAtEnd +{ + skipWhitespace(c); + return !*c; +} + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.h new file mode 100644 index 00000000..f6f5e17b --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.h @@ -0,0 +1,129 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonBase.h" + +/** + @brief Options for the writer class. + + This exists so the SBJSON facade can implement the options in the writer without having to re-declare them. + */ +@protocol SBJsonWriter + +/** + @brief Whether we are generating human-readable (multiline) JSON. + + Set whether or not to generate human-readable JSON. The default is NO, which produces + JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable + JSON with linebreaks after each array value and dictionary key/value pair, indented two + spaces per nesting level. + */ +@property BOOL humanReadable; + +/** + @brief Whether or not to sort the dictionary keys in the output. + + If this is set to YES, the dictionary keys in the JSON output will be in sorted order. + (This is useful if you need to compare two structures, for example.) The default is NO. + */ +@property BOOL sortKeys; + +/** + @brief Return JSON representation (or fragment) for the given object. + + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + + */ +- (NSString*)stringWithObject:(id)value; + +@end + + +/** + @brief The JSON writer class. + + Objective-C types are mapped to JSON types in the following way: + + @li NSNull -> Null + @li NSString -> String + @li NSArray -> Array + @li NSDictionary -> Object + @li NSNumber (-initWithBool:) -> Boolean + @li NSNumber -> Number + + In JSON the keys of an object must be strings. NSDictionary keys need + not be, but attempting to convert an NSDictionary with non-string keys + into JSON will throw an exception. + + NSNumber instances created with the +initWithBool: method are + converted into the JSON boolean "true" and "false" values, and vice + versa. Any other NSNumber instances are converted to a JSON number the + way you would expect. + + */ +@interface SBJsonWriter : SBJsonBase { + +@private + BOOL sortKeys, humanReadable; +} + +@end + +// don't use - exists for backwards compatibility. Will be removed in 2.3. +@interface SBJsonWriter (Private) +- (NSString*)stringWithFragment:(id)value; +@end + +/** + @brief Allows generation of JSON for otherwise unsupported classes. + + If you have a custom class that you want to create a JSON representation for you can implement + this method in your class. It should return a representation of your object defined + in terms of objects that can be translated into JSON. For example, a Person + object might implement it like this: + + @code + - (id)jsonProxyObject { + return [NSDictionary dictionaryWithObjectsAndKeys: + name, @"name", + phone, @"phone", + email, @"email", + nil]; + } + @endcode + + */ +@interface NSObject (SBProxyForJson) +- (id)proxyForJson; +@end + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.m new file mode 100644 index 00000000..0f329041 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.m @@ -0,0 +1,237 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonWriter.h" + +@interface SBJsonWriter () + +- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json; +- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json; +- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json; +- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json; + +- (NSString*)indent; + +@end + +@implementation SBJsonWriter + +static NSMutableCharacterSet *kEscapeChars; + ++ (void)initialize { + kEscapeChars = [[NSMutableCharacterSet characterSetWithRange: NSMakeRange(0,32)] retain]; + [kEscapeChars addCharactersInString: @"\"\\"]; +} + + +@synthesize sortKeys; +@synthesize humanReadable; + +/** + @deprecated This exists in order to provide fragment support in older APIs in one more version. + It should be removed in the next major version. + */ +- (NSString*)stringWithFragment:(id)value { + [self clearErrorTrace]; + depth = 0; + NSMutableString *json = [NSMutableString stringWithCapacity:128]; + + if ([self appendValue:value into:json]) + return json; + + return nil; +} + + +- (NSString*)stringWithObject:(id)value { + + if ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]) { + return [self stringWithFragment:value]; + } + + if ([value respondsToSelector:@selector(proxyForJson)]) { + NSString *tmp = [self stringWithObject:[value proxyForJson]]; + if (tmp) + return tmp; + } + + + [self clearErrorTrace]; + [self addErrorWithCode:EFRAGMENT description:@"Not valid type for JSON"]; + return nil; +} + + +- (NSString*)indent { + return [@"\n" stringByPaddingToLength:1 + 2 * depth withString:@" " startingAtIndex:0]; +} + +- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json { + if ([fragment isKindOfClass:[NSDictionary class]]) { + if (![self appendDictionary:fragment into:json]) + return NO; + + } else if ([fragment isKindOfClass:[NSArray class]]) { + if (![self appendArray:fragment into:json]) + return NO; + + } else if ([fragment isKindOfClass:[NSString class]]) { + if (![self appendString:fragment into:json]) + return NO; + + } else if ([fragment isKindOfClass:[NSNumber class]]) { + if ('c' == *[fragment objCType]) + [json appendString:[fragment boolValue] ? @"true" : @"false"]; + else + [json appendString:[fragment stringValue]]; + + } else if ([fragment isKindOfClass:[NSNull class]]) { + [json appendString:@"null"]; + } else if ([fragment respondsToSelector:@selector(proxyForJson)]) { + [self appendValue:[fragment proxyForJson] into:json]; + + } else { + [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"JSON serialisation not supported for %@", [fragment class]]]; + return NO; + } + return YES; +} + +- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json { + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + [json appendString:@"["]; + + BOOL addComma = NO; + for (id value in fragment) { + if (addComma) + [json appendString:@","]; + else + addComma = YES; + + if ([self humanReadable]) + [json appendString:[self indent]]; + + if (![self appendValue:value into:json]) { + return NO; + } + } + + depth--; + if ([self humanReadable] && [fragment count]) + [json appendString:[self indent]]; + [json appendString:@"]"]; + return YES; +} + +- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json { + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + [json appendString:@"{"]; + + NSString *colon = [self humanReadable] ? @" : " : @":"; + BOOL addComma = NO; + NSArray *keys = [fragment allKeys]; + if (self.sortKeys) + keys = [keys sortedArrayUsingSelector:@selector(compare:)]; + + for (id value in keys) { + if (addComma) + [json appendString:@","]; + else + addComma = YES; + + if ([self humanReadable]) + [json appendString:[self indent]]; + + if (![value isKindOfClass:[NSString class]]) { + [self addErrorWithCode:EUNSUPPORTED description: @"JSON object key must be string"]; + return NO; + } + + if (![self appendString:value into:json]) + return NO; + + [json appendString:colon]; + if (![self appendValue:[fragment objectForKey:value] into:json]) { + [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"Unsupported value for key %@ in object", value]]; + return NO; + } + } + + depth--; + if ([self humanReadable] && [fragment count]) + [json appendString:[self indent]]; + [json appendString:@"}"]; + return YES; +} + +- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json { + + [json appendString:@"\""]; + + NSRange esc = [fragment rangeOfCharacterFromSet:kEscapeChars]; + if ( !esc.length ) { + // No special chars -- can just add the raw string: + [json appendString:fragment]; + + } else { + NSUInteger length = [fragment length]; + for (NSUInteger i = 0; i < length; i++) { + unichar uc = [fragment characterAtIndex:i]; + switch (uc) { + case '"': [json appendString:@"\\\""]; break; + case '\\': [json appendString:@"\\\\"]; break; + case '\t': [json appendString:@"\\t"]; break; + case '\n': [json appendString:@"\\n"]; break; + case '\r': [json appendString:@"\\r"]; break; + case '\b': [json appendString:@"\\b"]; break; + case '\f': [json appendString:@"\\f"]; break; + default: + if (uc < 0x20) { + [json appendFormat:@"\\u%04x", uc]; + } else { + CFStringAppendCharacters((CFMutableStringRef)json, &uc, 1); + } + break; + + } + } + } + + [json appendString:@"\""]; + return YES; +} + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h deleted file mode 100644 index a5190a03..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// SHKFBStreamDialog.h -// Adds a little bit extra control to FBStreamDialog -// -// Created by Nathan Weiner on 7/26/10. -// Copyright 2010 Idea Shower, LLC. All rights reserved. -// - -#import -#import "FBStreamDialog.h" - -@interface SHKFBStreamDialog : FBStreamDialog -{ - NSString *defaultStatus; -} - -@property (nonatomic, retain) NSString *defaultStatus; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m deleted file mode 100644 index 53ec2152..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m +++ /dev/null @@ -1,40 +0,0 @@ -// -// SHKFBStreamDialog.m -// RIL -// -// Created by Nathan Weiner on 7/26/10. -// Copyright 2010 Idea Shower, LLC. All rights reserved. -// - -#import "SHKFBStreamDialog.h" -#import "SHK.h" - -@implementation SHKFBStreamDialog - -@synthesize defaultStatus; - -- (void)dealloc -{ - [defaultStatus release]; - [super dealloc]; -} - -- (void)webViewDidFinishLoad:(UIWebView *)webView -{ - [super webViewDidFinishLoad:webView]; - - if (defaultStatus) - { - // Set the pre-filled status message - [_webView stringByEvaluatingJavaScriptFromString: - [NSString stringWithFormat:@"document.getElementsByName('feedform_user_message')[0].value = decodeURIComponent('%@')", - [SHKEncode(defaultStatus) stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"] - ] - ]; - - // Make the text field bigger - [_webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByName('feedform_user_message')[0].style.height='100px'"]; - } -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h index ab0ee137..770485fd 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h @@ -26,27 +26,9 @@ // #import +#import "Facebook.h" #import "SHKSharer.h" -#import "FBConnect.h" - -typedef enum -{ - SHKFacebookPendingNone, - SHKFacebookPendingLogin, - SHKFacebookPendingStatus, - SHKFacebookPendingImage -} SHKFacebookPendingAction; - @interface SHKFacebook : SHKSharer -{ - FBSession *session; - SHKFacebookPendingAction pendingFacebookAction; - FBLoginDialog *login; -} - -@property (retain) FBSession *session; -@property SHKFacebookPendingAction pendingFacebookAction; -@property (retain) FBLoginDialog *login; - ++ (BOOL)handleOpenURL:(NSURL*)url; @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 2e2be608..582ca2ac 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -26,22 +26,48 @@ // #import "SHKFacebook.h" -#import "SHKFBStreamDialog.h" -@implementation SHKFacebook +NSString *const kSHKStoredItemKey=@"kSHKStoredItem"; +NSString *const kSHKFacebookAccessTokenKey=@"kSHKFacebookAccessToken"; +NSString *const kSHKFacebookExpiryDateKey=@"kSHKFacebookExpiryDate"; -@synthesize session; -@synthesize pendingFacebookAction; -@synthesize login; +@interface SHKFacebook() ++ (Facebook*)facebook; ++ (void)flushAccessToken; +@end + +@implementation SHKFacebook - (void)dealloc { - [session.delegates removeObject:self]; - [session release]; - [login release]; [super dealloc]; } ++ (Facebook*)facebook +{ + static Facebook *facebook=nil; + @synchronized([SHKFacebook class]) { + if (! facebook) + facebook = [[Facebook alloc] initWithAppId:SHKFacebookAppID]; + } + return facebook; +} + ++ (void)flushAccessToken +{ + Facebook *facebook = [self facebook]; + facebook.accessToken = nil; + facebook.expirationDate = nil; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:kSHKFacebookAccessTokenKey]; + [defaults removeObjectForKey:kSHKFacebookExpiryDateKey]; + [defaults synchronize]; +} + ++ (BOOL)handleOpenURL:(NSURL*)url +{ + return [[SHKFacebook facebook] handleOpenURL:url]; +} #pragma mark - #pragma mark Configuration : Service Defination @@ -76,63 +102,41 @@ + (BOOL)canShareOffline - (BOOL)shouldAutoShare { - return YES; // FBConnect presents its own dialog + return YES; } #pragma mark - #pragma mark Authentication - (BOOL)isAuthorized -{ - if (session == nil) - { - - if(!SHKFacebookUseSessionProxy){ - self.session = [FBSession sessionForApplication:SHKFacebookKey - secret:SHKFacebookSecret - delegate:self]; - - }else { - self.session = [FBSession sessionForApplication:SHKFacebookKey - getSessionProxy:SHKFacebookSessionProxyURL - delegate:self]; - } - - - return [session resume]; - } - - return [session isConnected]; +{ + Facebook *facebook = [SHKFacebook facebook]; + if ([facebook isSessionValid]) return YES; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + facebook.accessToken = [defaults stringForKey:kSHKFacebookAccessTokenKey]; + facebook.expirationDate = [defaults objectForKey:kSHKFacebookExpiryDateKey]; + return [facebook isSessionValid]; } - (void)promptAuthorization { - self.pendingFacebookAction = SHKFacebookPendingLogin; - self.login = [[[FBLoginDialog alloc] initWithSession:[self session]] autorelease]; - [login show]; + [[NSUserDefaults standardUserDefaults] setObject:[self.item dictionaryRepresentation] + forKey:kSHKStoredItemKey]; + [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", + @"offline_access", nil] + delegate:self]; } -- (void)authFinished:(SHKRequest *)request +- (void)authFinished:(SHKRequest *)req { - } + (void)logout { - FBSession *fbSession; - - if(!SHKFacebookUseSessionProxy){ - fbSession = [FBSession sessionForApplication:SHKFacebookKey - secret:SHKFacebookSecret - delegate:self]; - - }else { - fbSession = [FBSession sessionForApplication:SHKFacebookKey - getSessionProxy:SHKFacebookSessionProxyURL - delegate:self]; - } - - [fbSession logout]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:kSHKStoredItemKey]; + [self flushAccessToken]; + [[self facebook] logout:nil]; } #pragma mark - @@ -140,81 +144,80 @@ + (void)logout - (BOOL)send { - if (item.shareType == SHKShareTypeURL) + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + NSString *actions = [NSString stringWithFormat:@"{\"name\":\"Get %@\",\"link\":\"%@\"}", + SHKMyAppName, SHKMyAppURL]; + [params setObject:actions forKey:@"actions"]; + + if (item.shareType == SHKShareTypeURL && item.URL) { - self.pendingFacebookAction = SHKFacebookPendingStatus; - - SHKFBStreamDialog* dialog = [[[SHKFBStreamDialog alloc] init] autorelease]; - dialog.delegate = self; - dialog.userMessagePrompt = SHKLocalizedString(@"Enter your message:"); - dialog.attachment = [NSString stringWithFormat: - @"{\ - \"name\":\"%@\",\ - \"href\":\"%@\"\ - }", - item.title == nil ? SHKEncodeURL(item.URL) : SHKEncode(item.title), - SHKEncodeURL(item.URL) - ]; - dialog.defaultStatus = item.text; - dialog.actionLinks = [NSString stringWithFormat:@"[{\"text\":\"Get %@\",\"href\":\"%@\"}]", - SHKEncode(SHKMyAppName), - SHKEncode(SHKMyAppURL)]; - [dialog show]; - + NSString *url = [item.URL absoluteString]; + [params setObject:url forKey:@"link"]; + [params setObject:item.title == nil ? url : item.title + forKey:@"name"]; + if (item.text) + [params setObject:item.text forKey:@"message"]; + NSString *pictureURI = [item customValueForKey:@"picture"]; + if (pictureURI) + [params setObject:pictureURI forKey:@"picture"]; } - - else if (item.shareType == SHKShareTypeText) + else if (item.shareType == SHKShareTypeText && item.text) { - self.pendingFacebookAction = SHKFacebookPendingStatus; - - SHKFBStreamDialog* dialog = [[[SHKFBStreamDialog alloc] init] autorelease]; - dialog.delegate = self; - dialog.userMessagePrompt = SHKLocalizedString(@"Enter your message:"); - dialog.defaultStatus = item.text; - dialog.actionLinks = [NSString stringWithFormat:@"[{\"text\":\"Get %@\",\"href\":\"%@\"}]", - SHKEncode(SHKMyAppName), - SHKEncode(SHKMyAppURL)]; - [dialog show]; - - } - - else if (item.shareType == SHKShareTypeImage) - { - self.pendingFacebookAction = SHKFacebookPendingImage; - - FBPermissionDialog* dialog = [[[FBPermissionDialog alloc] init] autorelease]; - dialog.delegate = self; - dialog.permission = @"photo_upload"; - [dialog show]; - } - + [params setObject:item.text forKey:@"message"]; + } + else if (item.shareType == SHKShareTypeImage && item.image) + { + if (item.title) + [params setObject:item.title forKey:@"name"]; + if (item.text) + [params setObject:item.text forKey:@"message"]; + [params setObject:item.image forKey:@"picture"]; + // There does not appear to be a way to add the photo + // via the dialog option: + [[SHKFacebook facebook] requestWithGraphPath:@"me/photos" + andParams:params + andHttpMethod:@"POST" + andDelegate:self]; + return YES; + } + else + // There is nothing to send + return NO; + + [[SHKFacebook facebook] dialog:@"feed" + andParams:params + andDelegate:self]; return YES; } -- (void)sendImage -{ - [self sendDidStart]; +#pragma mark - +#pragma mark FBDialogDelegate methods - [[FBRequest requestWithDelegate:self] call:@"facebook.photos.upload" - params:[NSDictionary dictionaryWithObjectsAndKeys:item.title, @"caption", nil] - dataParam:UIImageJPEGRepresentation(item.image,1.0)]; +- (void)dialogDidComplete:(FBDialog *)dialog +{ + [self sendDidFinish]; } -- (void)dialogDidSucceed:(FBDialog*)dialog +- (void)dialogCompleteWithUrl:(NSURL *)url { - if (pendingFacebookAction == SHKFacebookPendingImage) - [self sendImage]; - - // TODO - the dialog has a SKIP button. Skipping still calls this even though it doesn't appear to post. - // - need to intercept the skip and handle it as a cancel? - else if (pendingFacebookAction == SHKFacebookPendingStatus) - [self sendDidFinish]; + // error_code=190: user changed password or revoked access to the application, + // so spin the user back over to authentication : + NSRange errorRange = [[url absoluteString] rangeOfString:@"error_code=190"]; + if (errorRange.location != NSNotFound) + { + [SHKFacebook flushAccessToken]; + [self authorize]; + } } - (void)dialogDidCancel:(FBDialog*)dialog { - if (pendingFacebookAction == SHKFacebookPendingStatus) - [self sendDidCancel]; + [self sendDidCancel]; +} + +- (void)dialog:(FBDialog *)dialog didFailWithError:(NSError *)error +{ + [self sendDidFailWithError:error]; } - (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL*)url @@ -222,34 +225,36 @@ - (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL*)url return YES; } - #pragma mark FBSessionDelegate methods -- (void)session:(FBSession*)session didLogin:(FBUID)uid +- (void)fbDidLogin { - // Try to share again - if (pendingFacebookAction == SHKFacebookPendingLogin) - { - self.pendingFacebookAction = SHKFacebookPendingNone; - [self share]; - } + NSString *accessToken = [[SHKFacebook facebook] accessToken]; + NSDate *expiryDate = [[SHKFacebook facebook] expirationDate]; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setObject:accessToken forKey:kSHKFacebookAccessTokenKey]; + [defaults setObject:expiryDate forKey:kSHKFacebookExpiryDateKey]; + NSDictionary *storedItem = [defaults objectForKey:kSHKStoredItemKey]; + if (storedItem) + { + self.item = [SHKItem itemFromDictionary:storedItem]; + [defaults removeObjectForKey:kSHKStoredItemKey]; + } + [defaults synchronize]; + if (self.item) + [self share]; } -- (void)session:(FBSession*)session willLogout:(FBUID)uid +#pragma mark FBRequestDelegate methods + +- (void)requestLoading:(FBRequest *)request { - // Not handling this + [self sendDidStart]; } - -#pragma mark FBRequestDelegate methods - -- (void)request:(FBRequest*)aRequest didLoad:(id)result +- (void)request:(FBRequest *)request didLoad:(id)result { - if ([aRequest.method isEqualToString:@"facebook.photos.upload"]) - { - // PID is in [result objectForKey:@"pid"]; - [self sendDidFinish]; - } + [self sendDidFinish]; } - (void)request:(FBRequest*)aRequest didFailWithError:(NSError*)error @@ -257,6 +262,4 @@ - (void)request:(FBRequest*)aRequest didFailWithError:(NSError*)error [self sendDidFailWithError:error]; } - - @end diff --git a/ShareKit-Info.plist b/ShareKit-Info.plist index d5dc4bd3..9c348dc9 100644 --- a/ShareKit-Info.plist +++ b/ShareKit-Info.plist @@ -20,8 +20,21 @@ APPL CFBundleSignature ???? + CFBundleURLTypes + + + CFBundleURLName + + CFBundleURLSchemes + + fb${FACEBOOK_APP_ID} + + + CFBundleVersion 1.0 + FacebookURLTypeIndex + 0 LSRequiresIPhoneOS NSMainNibFile diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index adcbf90e..3512eb3d 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -7,6 +7,17 @@ objects = { /* Begin PBXBuildFile section */ + 1940B69D138D45F900217886 /* Facebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B686138D45F900217886 /* Facebook.m */; }; + 1940B69E138D45F900217886 /* FBDialog.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 1940B688138D45F900217886 /* FBDialog.bundle */; }; + 1940B69F138D45F900217886 /* FBDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B68A138D45F900217886 /* FBDialog.m */; }; + 1940B6A0138D45F900217886 /* FBLoginDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B68C138D45F900217886 /* FBLoginDialog.m */; }; + 1940B6A1138D45F900217886 /* FBRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B68E138D45F900217886 /* FBRequest.m */; }; + 1940B6A2138D45F900217886 /* NSObject+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B692138D45F900217886 /* NSObject+SBJSON.m */; }; + 1940B6A3138D45F900217886 /* NSString+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B694138D45F900217886 /* NSString+SBJSON.m */; }; + 1940B6A4138D45F900217886 /* SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B696138D45F900217886 /* SBJSON.m */; }; + 1940B6A5138D45F900217886 /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B698138D45F900217886 /* SBJsonBase.m */; }; + 1940B6A6138D45F900217886 /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B69A138D45F900217886 /* SBJsonParser.m */; }; + 1940B6A7138D45F900217886 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B69C138D45F900217886 /* SBJsonWriter.m */; }; 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; @@ -30,7 +41,6 @@ 4379F2BE1291AC9700D2A41E /* TMemoryBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2AA1291AC9700D2A41E /* TMemoryBuffer.m */; }; 4379F2BF1291AC9700D2A41E /* TTransportException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2AD1291AC9700D2A41E /* TTransportException.m */; }; 4379F2C01291AC9700D2A41E /* TSharedProcessorFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2AF1291AC9700D2A41E /* TSharedProcessorFactory.m */; }; - 4379F2C11291AC9700D2A41E /* SHKEvernote.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2B11291AC9700D2A41E /* SHKEvernote.m */; }; 4379F2C21291AC9700D2A41E /* SHKEvernote.md in Resources */ = {isa = PBXBuildFile; fileRef = 4379F2B21291AC9700D2A41E /* SHKEvernote.md */; }; 4379F2EA1291AE5700D2A41E /* NSData+md5.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2E91291AE5700D2A41E /* NSData+md5.m */; }; 4379F3B21291C45700D2A41E /* SHKTextMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F3B11291C45700D2A41E /* SHKTextMessage.m */; }; @@ -65,17 +75,6 @@ 43A5371D11DBE3B9004A1712 /* SHKMail.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536BC11DBE3B9004A1712 /* SHKMail.m */; }; 43A5371E11DBE3B9004A1712 /* SHKSafari.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536BF11DBE3B9004A1712 /* SHKSafari.m */; }; 43A5371F11DBE3B9004A1712 /* SHKDelicious.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536C311DBE3B9004A1712 /* SHKDelicious.m */; }; - 43A5372011DBE3B9004A1712 /* FBConnect.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 43A536C611DBE3B9004A1712 /* FBConnect.bundle */; }; - 43A5372111DBE3B9004A1712 /* FBConnectGlobal.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536C911DBE3B9004A1712 /* FBConnectGlobal.m */; }; - 43A5372211DBE3B9004A1712 /* FBDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536CB11DBE3B9004A1712 /* FBDialog.m */; }; - 43A5372311DBE3B9004A1712 /* FBFeedDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536CD11DBE3B9004A1712 /* FBFeedDialog.m */; }; - 43A5372411DBE3B9004A1712 /* FBLoginButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536CF11DBE3B9004A1712 /* FBLoginButton.m */; }; - 43A5372511DBE3B9004A1712 /* FBLoginDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D111DBE3B9004A1712 /* FBLoginDialog.m */; }; - 43A5372611DBE3B9004A1712 /* FBPermissionDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D311DBE3B9004A1712 /* FBPermissionDialog.m */; }; - 43A5372711DBE3B9004A1712 /* FBRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D511DBE3B9004A1712 /* FBRequest.m */; }; - 43A5372811DBE3B9004A1712 /* FBSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D711DBE3B9004A1712 /* FBSession.m */; }; - 43A5372911DBE3B9004A1712 /* FBStreamDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D911DBE3B9004A1712 /* FBStreamDialog.m */; }; - 43A5372A11DBE3B9004A1712 /* FBXMLHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536DB11DBE3B9004A1712 /* FBXMLHandler.m */; }; 43A5372B11DBE3B9004A1712 /* SHKFacebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; }; 43A5372C11DBE3B9004A1712 /* SHKGoogleReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */; }; 43A5372D11DBE3B9004A1712 /* SHKPinboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536E311DBE3B9004A1712 /* SHKPinboard.m */; }; @@ -100,7 +99,6 @@ 43A5383B11DBE493004A1712 /* ShareKitAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5383511DBE493004A1712 /* ShareKitAppDelegate.m */; }; 43A53C0911DC07A9004A1712 /* SHKCustomShareMenuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */; }; 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */; }; - 43B934B511FE682600C9D3F3 /* SHKFBStreamDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43B934B411FE682600C9D3F3 /* SHKFBStreamDialog.m */; }; 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43C91D1C11EB963600F31FAE /* MainWindow-iPad.xib */; }; 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */ = {isa = PBXBuildFile; fileRef = 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */; }; 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */; }; @@ -109,6 +107,29 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 1940B685138D45F900217886 /* Facebook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Facebook.h; sourceTree = ""; }; + 1940B686138D45F900217886 /* Facebook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Facebook.m; sourceTree = ""; }; + 1940B687138D45F900217886 /* FBConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnect.h; sourceTree = ""; }; + 1940B688138D45F900217886 /* FBDialog.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = FBDialog.bundle; sourceTree = ""; }; + 1940B689138D45F900217886 /* FBDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBDialog.h; sourceTree = ""; }; + 1940B68A138D45F900217886 /* FBDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBDialog.m; sourceTree = ""; }; + 1940B68B138D45F900217886 /* FBLoginDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginDialog.h; sourceTree = ""; }; + 1940B68C138D45F900217886 /* FBLoginDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginDialog.m; sourceTree = ""; }; + 1940B68D138D45F900217886 /* FBRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBRequest.h; sourceTree = ""; }; + 1940B68E138D45F900217886 /* FBRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRequest.m; sourceTree = ""; }; + 1940B690138D45F900217886 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; + 1940B691138D45F900217886 /* NSObject+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJSON.h"; sourceTree = ""; }; + 1940B692138D45F900217886 /* NSObject+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJSON.m"; sourceTree = ""; }; + 1940B693138D45F900217886 /* NSString+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SBJSON.h"; sourceTree = ""; }; + 1940B694138D45F900217886 /* NSString+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SBJSON.m"; sourceTree = ""; }; + 1940B695138D45F900217886 /* SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJSON.h; sourceTree = ""; }; + 1940B696138D45F900217886 /* SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJSON.m; sourceTree = ""; }; + 1940B697138D45F900217886 /* SBJsonBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonBase.h; sourceTree = ""; }; + 1940B698138D45F900217886 /* SBJsonBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonBase.m; sourceTree = ""; }; + 1940B699138D45F900217886 /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = ""; }; + 1940B69A138D45F900217886 /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = ""; }; + 1940B69B138D45F900217886 /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = ""; }; + 1940B69C138D45F900217886 /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = ""; }; 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 1D6058910D05DD3D006BFB54 /* ShareKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShareKit.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; @@ -232,28 +253,6 @@ 43A536BF11DBE3B9004A1712 /* SHKSafari.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKSafari.m; sourceTree = ""; }; 43A536C211DBE3B9004A1712 /* SHKDelicious.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKDelicious.h; sourceTree = ""; }; 43A536C311DBE3B9004A1712 /* SHKDelicious.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKDelicious.m; sourceTree = ""; }; - 43A536C611DBE3B9004A1712 /* FBConnect.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = FBConnect.bundle; sourceTree = ""; }; - 43A536C711DBE3B9004A1712 /* FBConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnect.h; sourceTree = ""; }; - 43A536C811DBE3B9004A1712 /* FBConnectGlobal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnectGlobal.h; sourceTree = ""; }; - 43A536C911DBE3B9004A1712 /* FBConnectGlobal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBConnectGlobal.m; sourceTree = ""; }; - 43A536CA11DBE3B9004A1712 /* FBDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBDialog.h; sourceTree = ""; }; - 43A536CB11DBE3B9004A1712 /* FBDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBDialog.m; sourceTree = ""; }; - 43A536CC11DBE3B9004A1712 /* FBFeedDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBFeedDialog.h; sourceTree = ""; }; - 43A536CD11DBE3B9004A1712 /* FBFeedDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBFeedDialog.m; sourceTree = ""; }; - 43A536CE11DBE3B9004A1712 /* FBLoginButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginButton.h; sourceTree = ""; }; - 43A536CF11DBE3B9004A1712 /* FBLoginButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginButton.m; sourceTree = ""; }; - 43A536D011DBE3B9004A1712 /* FBLoginDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginDialog.h; sourceTree = ""; }; - 43A536D111DBE3B9004A1712 /* FBLoginDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginDialog.m; sourceTree = ""; }; - 43A536D211DBE3B9004A1712 /* FBPermissionDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBPermissionDialog.h; sourceTree = ""; }; - 43A536D311DBE3B9004A1712 /* FBPermissionDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBPermissionDialog.m; sourceTree = ""; }; - 43A536D411DBE3B9004A1712 /* FBRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBRequest.h; sourceTree = ""; }; - 43A536D511DBE3B9004A1712 /* FBRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRequest.m; sourceTree = ""; }; - 43A536D611DBE3B9004A1712 /* FBSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSession.h; sourceTree = ""; }; - 43A536D711DBE3B9004A1712 /* FBSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSession.m; sourceTree = ""; }; - 43A536D811DBE3B9004A1712 /* FBStreamDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBStreamDialog.h; sourceTree = ""; }; - 43A536D911DBE3B9004A1712 /* FBStreamDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBStreamDialog.m; sourceTree = ""; }; - 43A536DA11DBE3B9004A1712 /* FBXMLHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBXMLHandler.h; sourceTree = ""; }; - 43A536DB11DBE3B9004A1712 /* FBXMLHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBXMLHandler.m; sourceTree = ""; }; 43A536DC11DBE3B9004A1712 /* SHKFacebook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFacebook.h; sourceTree = ""; }; 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFacebook.m; sourceTree = ""; }; 43A536DF11DBE3B9004A1712 /* SHKGoogleReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKGoogleReader.h; sourceTree = ""; }; @@ -301,8 +300,6 @@ 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenuCell.m; sourceTree = ""; }; 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKCustomShareMenu.h; sourceTree = ""; }; 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenu.m; sourceTree = ""; }; - 43B934B311FE682600C9D3F3 /* SHKFBStreamDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFBStreamDialog.h; sourceTree = ""; }; - 43B934B411FE682600C9D3F3 /* SHKFBStreamDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFBStreamDialog.m; sourceTree = ""; }; 43C91D1C11EB963600F31FAE /* MainWindow-iPad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "MainWindow-iPad.xib"; path = "Resources-iPad/MainWindow-iPad.xib"; sourceTree = ""; }; 43C91DF311EBAE4800F31FAE /* SHKTumblr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKTumblr.h; sourceTree = ""; }; 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTumblr.m; sourceTree = ""; }; @@ -339,6 +336,44 @@ path = Classes; sourceTree = ""; }; + 1940B684138D45F800217886 /* FBConnect */ = { + isa = PBXGroup; + children = ( + 1940B688138D45F900217886 /* FBDialog.bundle */, + 1940B685138D45F900217886 /* Facebook.h */, + 1940B686138D45F900217886 /* Facebook.m */, + 1940B687138D45F900217886 /* FBConnect.h */, + 1940B689138D45F900217886 /* FBDialog.h */, + 1940B68A138D45F900217886 /* FBDialog.m */, + 1940B68B138D45F900217886 /* FBLoginDialog.h */, + 1940B68C138D45F900217886 /* FBLoginDialog.m */, + 1940B68D138D45F900217886 /* FBRequest.h */, + 1940B68E138D45F900217886 /* FBRequest.m */, + 1940B68F138D45F900217886 /* JSON */, + ); + path = FBConnect; + sourceTree = ""; + }; + 1940B68F138D45F900217886 /* JSON */ = { + isa = PBXGroup; + children = ( + 1940B690138D45F900217886 /* JSON.h */, + 1940B691138D45F900217886 /* NSObject+SBJSON.h */, + 1940B692138D45F900217886 /* NSObject+SBJSON.m */, + 1940B693138D45F900217886 /* NSString+SBJSON.h */, + 1940B694138D45F900217886 /* NSString+SBJSON.m */, + 1940B695138D45F900217886 /* SBJSON.h */, + 1940B696138D45F900217886 /* SBJSON.m */, + 1940B697138D45F900217886 /* SBJsonBase.h */, + 1940B698138D45F900217886 /* SBJsonBase.m */, + 1940B699138D45F900217886 /* SBJsonParser.h */, + 1940B69A138D45F900217886 /* SBJsonParser.m */, + 1940B69B138D45F900217886 /* SBJsonWriter.h */, + 1940B69C138D45F900217886 /* SBJsonWriter.m */, + ); + path = JSON; + sourceTree = ""; + }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( @@ -745,44 +780,13 @@ 43A536C411DBE3B9004A1712 /* Facebook */ = { isa = PBXGroup; children = ( - 43A536C511DBE3B9004A1712 /* FBConnect */, + 1940B684138D45F800217886 /* FBConnect */, 43A536DC11DBE3B9004A1712 /* SHKFacebook.h */, 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */, - 43B934B311FE682600C9D3F3 /* SHKFBStreamDialog.h */, - 43B934B411FE682600C9D3F3 /* SHKFBStreamDialog.m */, ); path = Facebook; sourceTree = ""; }; - 43A536C511DBE3B9004A1712 /* FBConnect */ = { - isa = PBXGroup; - children = ( - 43A536C611DBE3B9004A1712 /* FBConnect.bundle */, - 43A536C711DBE3B9004A1712 /* FBConnect.h */, - 43A536C811DBE3B9004A1712 /* FBConnectGlobal.h */, - 43A536C911DBE3B9004A1712 /* FBConnectGlobal.m */, - 43A536CA11DBE3B9004A1712 /* FBDialog.h */, - 43A536CB11DBE3B9004A1712 /* FBDialog.m */, - 43A536CC11DBE3B9004A1712 /* FBFeedDialog.h */, - 43A536CD11DBE3B9004A1712 /* FBFeedDialog.m */, - 43A536CE11DBE3B9004A1712 /* FBLoginButton.h */, - 43A536CF11DBE3B9004A1712 /* FBLoginButton.m */, - 43A536D011DBE3B9004A1712 /* FBLoginDialog.h */, - 43A536D111DBE3B9004A1712 /* FBLoginDialog.m */, - 43A536D211DBE3B9004A1712 /* FBPermissionDialog.h */, - 43A536D311DBE3B9004A1712 /* FBPermissionDialog.m */, - 43A536D411DBE3B9004A1712 /* FBRequest.h */, - 43A536D511DBE3B9004A1712 /* FBRequest.m */, - 43A536D611DBE3B9004A1712 /* FBSession.h */, - 43A536D711DBE3B9004A1712 /* FBSession.m */, - 43A536D811DBE3B9004A1712 /* FBStreamDialog.h */, - 43A536D911DBE3B9004A1712 /* FBStreamDialog.m */, - 43A536DA11DBE3B9004A1712 /* FBXMLHandler.h */, - 43A536DB11DBE3B9004A1712 /* FBXMLHandler.m */, - ); - path = FBConnect; - sourceTree = ""; - }; 43A536DE11DBE3B9004A1712 /* Google Reader */ = { isa = PBXGroup; children = ( @@ -952,12 +956,12 @@ 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */, 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */, 43A5371811DBE3B9004A1712 /* SHKSharers.plist in Resources */, - 43A5372011DBE3B9004A1712 /* FBConnect.bundle in Resources */, 43A5382811DBE480004A1712 /* example.pdf in Resources */, 43A5382911DBE480004A1712 /* sanFran.jpg in Resources */, 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */, 43FF9C7412270E9F00ADE53C /* Localizable.strings in Resources */, 4379F2C21291AC9700D2A41E /* SHKEvernote.md in Resources */, + 1940B69E138D45F900217886 /* FBDialog.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -999,16 +1003,6 @@ 43A5371D11DBE3B9004A1712 /* SHKMail.m in Sources */, 43A5371E11DBE3B9004A1712 /* SHKSafari.m in Sources */, 43A5371F11DBE3B9004A1712 /* SHKDelicious.m in Sources */, - 43A5372111DBE3B9004A1712 /* FBConnectGlobal.m in Sources */, - 43A5372211DBE3B9004A1712 /* FBDialog.m in Sources */, - 43A5372311DBE3B9004A1712 /* FBFeedDialog.m in Sources */, - 43A5372411DBE3B9004A1712 /* FBLoginButton.m in Sources */, - 43A5372511DBE3B9004A1712 /* FBLoginDialog.m in Sources */, - 43A5372611DBE3B9004A1712 /* FBPermissionDialog.m in Sources */, - 43A5372711DBE3B9004A1712 /* FBRequest.m in Sources */, - 43A5372811DBE3B9004A1712 /* FBSession.m in Sources */, - 43A5372911DBE3B9004A1712 /* FBStreamDialog.m in Sources */, - 43A5372A11DBE3B9004A1712 /* FBXMLHandler.m in Sources */, 43A5372B11DBE3B9004A1712 /* SHKFacebook.m in Sources */, 43A5372C11DBE3B9004A1712 /* SHKGoogleReader.m in Sources */, 43A5372D11DBE3B9004A1712 /* SHKPinboard.m in Sources */, @@ -1033,7 +1027,6 @@ 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */, 43150A8D11E78697008C6B68 /* SHKInstapaper.m in Sources */, 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */, - 43B934B511FE682600C9D3F3 /* SHKFBStreamDialog.m in Sources */, 432B147C11FF4B0700291B37 /* SHKPhotoAlbum.m in Sources */, 4379F2B31291AC9700D2A41E /* EDAMLimits.m in Sources */, 4379F2B41291AC9700D2A41E /* Errors.m in Sources */, @@ -1049,9 +1042,18 @@ 4379F2BE1291AC9700D2A41E /* TMemoryBuffer.m in Sources */, 4379F2BF1291AC9700D2A41E /* TTransportException.m in Sources */, 4379F2C01291AC9700D2A41E /* TSharedProcessorFactory.m in Sources */, - 4379F2C11291AC9700D2A41E /* SHKEvernote.m in Sources */, 4379F2EA1291AE5700D2A41E /* NSData+md5.m in Sources */, 4379F3B21291C45700D2A41E /* SHKTextMessage.m in Sources */, + 1940B69D138D45F900217886 /* Facebook.m in Sources */, + 1940B69F138D45F900217886 /* FBDialog.m in Sources */, + 1940B6A0138D45F900217886 /* FBLoginDialog.m in Sources */, + 1940B6A1138D45F900217886 /* FBRequest.m in Sources */, + 1940B6A2138D45F900217886 /* NSObject+SBJSON.m in Sources */, + 1940B6A3138D45F900217886 /* NSString+SBJSON.m in Sources */, + 1940B6A4138D45F900217886 /* SBJSON.m in Sources */, + 1940B6A5138D45F900217886 /* SBJsonBase.m in Sources */, + 1940B6A6138D45F900217886 /* SBJsonParser.m in Sources */, + 1940B6A7138D45F900217886 /* SBJsonWriter.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 6d04ca6c365997aab57e6e87414a4c3986843efb Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Wed, 25 May 2011 13:41:24 -0400 Subject: [PATCH 02/13] + Reinstating SHKEvernote.m (generates compile errors) --- ShareKit.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index 3512eb3d..b61a5cae 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 1940B6A5138D45F900217886 /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B698138D45F900217886 /* SBJsonBase.m */; }; 1940B6A6138D45F900217886 /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B69A138D45F900217886 /* SBJsonParser.m */; }; 1940B6A7138D45F900217886 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B69C138D45F900217886 /* SBJsonWriter.m */; }; + 19DDAEB0138D7686004A7C34 /* SHKEvernote.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2B11291AC9700D2A41E /* SHKEvernote.m */; }; 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; @@ -1054,6 +1055,7 @@ 1940B6A5138D45F900217886 /* SBJsonBase.m in Sources */, 1940B6A6138D45F900217886 /* SBJsonParser.m in Sources */, 1940B6A7138D45F900217886 /* SBJsonWriter.m in Sources */, + 19DDAEB0138D7686004A7C34 /* SHKEvernote.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 3094ef4038e0c59fcf5d50b8fd9c33f46abf5471 Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Wed, 25 May 2011 13:06:08 -0400 Subject: [PATCH 03/13] + Most recent version of FBConnect + New fields used by the app delegate for SHKFacebook + ShareKitAppDelegate now propagating appropriate incoming URLs + Replaced SHKFacebookKey and SHKFacebookSecret with SHKFacebookAppID + New version of SHKFacebook based on most recently released FBConnect library + Updated project file + [Update] Reinstating SHKEvernote.m (generates compile errors) --- Classes/Example/ShareKitAppDelegate.m | 30 + Classes/ShareKit/SHKConfig.h | 3 +- .../FBConnect.bundle/images/login.png | Bin 2102 -> 0 bytes .../FBConnect.bundle/images/login2.png | Bin 3843 -> 0 bytes .../FBConnect.bundle/images/login2_down.png | Bin 3728 -> 0 bytes .../FBConnect.bundle/images/login_down.png | Bin 1980 -> 0 bytes .../FBConnect.bundle/images/logout.png | Bin 1661 -> 0 bytes .../FBConnect.bundle/images/logout_down.png | Bin 1551 -> 0 bytes .../Services/Facebook/FBConnect/FBConnect.h | 18 +- .../Facebook/FBConnect/FBConnectGlobal.h | 218 ------ .../Facebook/FBConnect/FBConnectGlobal.m | 45 -- .../images/close.png | Bin .../images/fbicon.png | Bin .../Services/Facebook/FBConnect/FBDialog.h | 73 +- .../Services/Facebook/FBConnect/FBDialog.m | 280 ++++---- .../Facebook/FBConnect/FBFeedDialog.h | 42 -- .../Facebook/FBConnect/FBFeedDialog.m | 85 --- .../Facebook/FBConnect/FBLoginButton.h | 49 -- .../Facebook/FBConnect/FBLoginButton.m | 196 ------ .../Facebook/FBConnect/FBLoginDialog.h | 36 +- .../Facebook/FBConnect/FBLoginDialog.m | 149 ++-- .../Facebook/FBConnect/FBPermissionDialog.h | 31 - .../Facebook/FBConnect/FBPermissionDialog.m | 101 --- .../Services/Facebook/FBConnect/FBRequest.h | 137 ++-- .../Services/Facebook/FBConnect/FBRequest.m | 465 ++++++------ .../Services/Facebook/FBConnect/FBSession.h | 205 ------ .../Services/Facebook/FBConnect/FBSession.m | 301 -------- .../Facebook/FBConnect/FBStreamDialog.h | 62 -- .../Facebook/FBConnect/FBStreamDialog.m | 77 -- .../Facebook/FBConnect/FBXMLHandler.h | 32 - .../Facebook/FBConnect/FBXMLHandler.m | 152 ---- .../Services/Facebook/FBConnect/Facebook.h | 113 +++ .../Services/Facebook/FBConnect/Facebook.m | 660 ++++++++++++++++++ .../Services/Facebook/FBConnect/JSON/JSON.h | 50 ++ .../Facebook/FBConnect/JSON/NSObject+SBJSON.h | 68 ++ .../Facebook/FBConnect/JSON/NSObject+SBJSON.m | 53 ++ .../Facebook/FBConnect/JSON/NSString+SBJSON.h | 58 ++ .../Facebook/FBConnect/JSON/NSString+SBJSON.m | 55 ++ .../Services/Facebook/FBConnect/JSON/SBJSON.h | 75 ++ .../Services/Facebook/FBConnect/JSON/SBJSON.m | 212 ++++++ .../Facebook/FBConnect/JSON/SBJsonBase.h | 86 +++ .../Facebook/FBConnect/JSON/SBJsonBase.m | 78 +++ .../Facebook/FBConnect/JSON/SBJsonParser.h | 87 +++ .../Facebook/FBConnect/JSON/SBJsonParser.m | 475 +++++++++++++ .../Facebook/FBConnect/JSON/SBJsonWriter.h | 129 ++++ .../Facebook/FBConnect/JSON/SBJsonWriter.m | 237 +++++++ .../Services/Facebook/SHKFBStreamDialog.h | 19 - .../Services/Facebook/SHKFBStreamDialog.m | 40 -- .../Sharers/Services/Facebook/SHKFacebook.h | 22 +- .../Sharers/Services/Facebook/SHKFacebook.m | 263 +++---- ShareKit-Info.plist | 13 + ShareKit.xcodeproj/project.pbxproj | 168 ++--- 52 files changed, 3268 insertions(+), 2480 deletions(-) delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2_down.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login_down.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout_down.png delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m rename Classes/ShareKit/Sharers/Services/Facebook/FBConnect/{FBConnect.bundle => FBDialog.bundle}/images/close.png (100%) rename Classes/ShareKit/Sharers/Services/Facebook/FBConnect/{FBConnect.bundle => FBDialog.bundle}/images/fbicon.png (100%) delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m delete mode 100755 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h delete mode 100755 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/JSON.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.m delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h delete mode 100644 Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m diff --git a/Classes/Example/ShareKitAppDelegate.m b/Classes/Example/ShareKitAppDelegate.m index e905ec41..259a5503 100644 --- a/Classes/Example/ShareKitAppDelegate.m +++ b/Classes/Example/ShareKitAppDelegate.m @@ -9,6 +9,7 @@ #import "ShareKitAppDelegate.h" #import "RootViewController.h" +#import "SHKFacebook.h" #import "SHKReadItLater.h" #import "SHKFacebook.h" @@ -45,6 +46,35 @@ - (void)applicationWillTerminate:(UIApplication *)application // Save data if appropriate } +- (BOOL)handleOpenURL:(NSURL*)url +{ + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + NSNumber *index = [info objectForKey:@"FacebookURLTypeIndex"]; + if (! index) return YES; + + NSArray *urlTypes = [info objectForKey:@"CFBundleURLTypes"]; + if ((! urlTypes) || ([urlTypes count] <= [index integerValue])) return YES; + + NSDictionary *facebookURL = [urlTypes objectAtIndex:[index integerValue]]; + NSString *scheme = [[facebookURL objectForKey:@"CFBundleURLSchemes"] lastObject]; + if ([[url scheme] isEqualToString:scheme]) + return [SHKFacebook handleOpenURL:url]; + return YES; +} + +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation +{ + return [self handleOpenURL:url]; +} + +- (BOOL)application:(UIApplication *)application + handleOpenURL:(NSURL *)url +{ + return [self handleOpenURL:url]; +} #pragma mark - #pragma mark Memory management diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index c2aa3565..9c6a1efb 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -46,8 +46,7 @@ // If SHKFacebookUseSessionProxy is enabled then SHKFacebookSecret is ignored and should be left blank #define SHKFacebookUseSessionProxy NO -#define SHKFacebookKey @"" -#define SHKFacebookSecret @"" +#define SHKFacebookAppID @"" #define SHKFacebookSessionProxyURL @"" // Read It Later - http://readitlaterlist.com/api/?shk diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login.png deleted file mode 100644 index 77bc30c27400597b79ccc126fabd5bcc0fb3a41c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2102 zcmV-62+8+}P)*hL`sNJ)3hS3TI$f|ffT8Va8oI?La8WKP?HeL zfgrVN3wB7sCK%HYY-)q;wY{wO{haB!cOPDx-Sq=ks;W8Y*uMAdJ#*(f-<)&qumVQK zM5-ngNriE$$iyO#Q;9T0>OumDW(II|b@f_{#qzu;iYsWWRj``|+OlkwB&oycbRKJN zZf=PJ?qon48OYnWZ?DUpTl`X9VWnYK-eSEVsuU(qLxO&H*k!*H7`%1KGt~FRFHfC1 z)yTl+KyTTyrOIqJ|E}zj@6FNZO)3Sh835ep3V;5WqkRsC0V zvPF$i6%NY^N;4n~%fgDSIo)mV@2BBzHBZ!nuvDM9KpzZC3PLj|`pkuT!nPFAE`w3n zEJH1XLkiF{D{3LyXvi_35mZvff3+DI1v(9zg8?5xK|j|i#Z#l>s?q8dphtmD&1h!3 z(AqJrD^#t0fGUHm038E5l&%m8yk^2+woJ*p$LZi}Q~8!92?4(wK97U{76cXa1~YUS zmjAb>Kvu{8N(VFpWFjdp%)x6fZbojFk&oByZjAdCk`P)7hv0G9VA2M$qq-D}7tV&; zLs{&mhIf;BgK|x(S1Y_LnoYG@6(m(i|%%bd(74n6yJhR*>X- z{CQn=%*j@xp?*7z8CrC9-^EvE=c1}|2{x>+zz<$M4O!GfrPfkVg0x0rZ74*QhJK4Y zP_i5zv$vR?5hIn2t&Igb91ifmRVppn)MH4HXk#xb{C+=v`u)dIwsanLJb#?}WPjA3 zFlnIqZo=spElAtiy_~-jTSi@#GZ()qkL}kd&yRl)Yj70gGB|IIQa6@$j>qHdF!wXKYIN% z25tRhv*7UIJun)yaoa0L&*Iq~Ysr?y=YGC_6B>Sd5!Y_o(&9Geq!H^pM8QuzxkApH?Cg+tsyI^ZNs`!uvaPT<4&SYP2mxwi z4?edU9)Fn6Gc_6X*t6?l9D4gRbP%vi*k0HkC&DZdw>YC+4%@UCJ#^PSCUwNdiGE{w zaXhOdXQu${!*{6P)>BIHLoIuWg_#&|Ik9^AD*l=G&RpSsPJU#=(={b{uwp*VMcU2F z9k*c}uwtNpfJSSe*NX6ZJxOgDIu*~cjL8GU)cw245P4H9qw0Z$ShaE)^0STj^SSHj zx^FEfkF8?Ga)=s~wXO<9MJYd3we0$-T$pOimmp`W0~R`txnQ*j-bO zhbjy4<~z+0L^Wh8LYvkt!;kmY;Q0HOX-*YAFnM|I6vSx2C~yL$4(?wH6LZ46fW`M4 zz20~m4|sIlm48`r_CiYktLBl zO+kw7iGezPkEv|zXZ!Vj?!SC#KHA#aap}@OQL}y#RxHVm+ctf@7$%hy7M&k&{$v-P z`sP}wwFbnB&4XpLp@EkI8JaY1>d{{L{@T0LJvglulCOW`*m-=b#*HU8lwkduVm`-i zl+E`KMi|ui$BU?Y>Z@q^;Be$gpx~T3b1k85Bi75*x`~?D3}Tt?9-AE5&x>!I!K(*0 zqUqQRe43?^KQwiYvAy?pecbl$>8sp!_8&K~WPTQYLEX|1>2vMZ2h!p;=FG=h#oF51 z9=mzV+;lm5a9}X)$uO2W65Bg=GR&Kumo!Hwiis-x;suf7$XJ!iJ}~6sH$GERv20Gt zYo@bJMP@la>N|1b#DaJqosP8kLFh@Xb-Dv+>+GMleY%p)=L}y@PAG;_TE-2<-d&`S zRa;+6UUg}$%M(!EOve~4rO7qygjBX-F-#d#`;T!KwL~srqa-PB@6=T2#GN~LrY(4O zrsPO~A01Gy(}tl_zSl7WqJlp>E7WdVUS7_+1dTxXgEfr0`uh53y83+2xrG9Q zPsq{J0aM8%(-08>Nhgo^jq+_z(Omtnj~qGj4o&-oXtFM1U^g~4u4!#;{f@`uDW*BK z0^8I@qtV!nM&lQim6d<0tE;<6Q$9fux`c$v$iTKli=!s0s;G)erA%A#B#eH0lxZNU g4hAy&(0>FN0K8&LR2ps7(*OVf07*qoM6N<$f~YXATM diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2.png deleted file mode 100644 index 03e8eba939acaebddd108b1efb168708b9fcdeb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3843 zcmV+e5B%_nP){~+iKvoh= zNPvKmT|rt_S=F`}p|xslr9E1u;k2a|+fxv8fq$P!l0&* zLjNlY4r&2verk3^fHQ#scfo=MQxg*tA5^JSW9eF__)eiAgW_PYEf5GCvDs|TZ{NOs zZy3ln24FJ-@2$7qx+-l%(c1LmKsW_^3O)?iU9?ow#T0@-aB5B=kr*1o>JJF2UzKVmg+&|XMKP#&NueQ245Rtum!_UN_{M6wT&dxOupks0hUFT3VnFebLPMSm!}1J- z*;0g09azdu2tp%>eg(h^eI7_7gbyBq5`f`TN(Y5LhldmW0FIM=eO@>GJ`Zn~G*7g8 z-n2S{;%bFHYXHa2z>HV3@5p71Fm39!RCz1eU7^ny!2Wm}IDzl=U`j~5B0`$hj|I4iH_qpNoxa8GIt2Yhwh1ZFI-v>dZhE8vUO0A8a zP&`gr6r=b#nOKr)Tc=}aU;byai@h&~#}Mf!G%4 z@yj19L|U?$U(Z-sCCe3p(H!H4)7}M(&WGg-N>P}X35U~z`i5q_`{4Izzi)QzGe?dg(IUE=(Ddg7lOGytbV1^`&2!=AcUIQ@PCgXXH(?eln$pQ%S_VLCpnJ$=<=v-q2J{)@6V zZkZZcCd34A@WLfPBzOlnfHsFhAb6fU7X@#4iUu1iZ-v>YL&K?VT$7oGY2~9ZcjkC} z{}9}oCIbPm=7{^*pz#njhWOBXxUyKF?9V!-2iW-O0owYbZ zfbcqcc$Q|Q)fstXzKmx(^Va}d)XWw&#un$`EAz+T)6+H_J>5q(`uS=(z-QEl$z{ZR z5XobWpS<5uM;KIpWsKl9`5j>f-G3f#<1)RoI2YJza}B%XaZVJnvPZwH(J`7%~Te?u&&`P!^b5IYqkIB|jX~1k(2OY>8 zkpQR5hci|mUuh&Dd0bTHxm#%ku@IR1V6vn_XSBdWs}u8QcDf#B6D6a@ZZ4BGRyH|p z9Y{0=kdZ?1BEN}b50fjX5@dTkE+;)BA~PcazJM03-4}(s{u1I!0UV2>0od>JVZxYf z4&INCw2^~*WnR_RdID=AI=WrtY!4RRScH2ku9x{WwWqMDY8PL2H?FDR!70c|k@*{c zw*&j?T8OtKDsS(>W{k`phIJ2r9T}+>e!s2Ljvqa~4eed$h?j^*AHA0cLgHf4FsSbXeh%nfHEN7vwS)h&$!?Pdp>v=QBLT5^j%9~38Vy3LSZvmWck@Ft- z`9CR`dLB40)s*Y*UkIm1kBkg>$49`eK zS!pgDl)=hIXVJ#Tfa&FhXr~Ezwp%4n9b1 zZA1F~)bIc5=kCX@E$i^^3v2Mzo2PQyX=vVe?NhtC4UEc4a|j&TsP=v5j@ii09)Z<& z&B8~At=zsRUZ_P`@dzxNJD$c44cO7`k>kL?I`{fgc-&6hyK*MKUi<6aTyG}-VH$_| zbLs4{JZ7v9>&s%vVw#_oO#7qI#4zXtY+AF3e4`~lf5b6xv3Qg-u)VMAvNCW-w_`vF zAzeqxm6pE2Svd4g#fzTKvplQK)Yo*Mydc`<|zEK*ate1!DCXD9G z-0QnO#mS~KTt>y3tvn++Xg07+!KjxqwNy{a6L)_jW=+gSab6#f_mYvgCO<7)_lg*EO=e8{md!5a*Lj&{JoJrnS>}|o9Mm7PMvcSd zvMg+^K7gqdkNTrl9Bydh&+XWK94i->Vch6k;^pysTi>pgWlS172b0ES;n2~L+?(f& z<-cFsc?4&ho49W!TVs)VFn|NW%iF}=a^Ge-^G04r$`zt41$z#*VC9lB%1-%s>bdQF z=?GHoH-E-xJapd@Y<}Z_Yy_*@SbZiR-_V2*qzzO+q!}s78wjp%c)YW{Wz zXU)l|Huc#Ylv(WX)3^mxQdlf1e9~?2pL_%$W>@6qYWIO={(Jt+Qe@HudE}W7Fl|B( z?zm-2cs%O>AG6QWHOp{5njBK5V|oWDX^3IH*<*|&NY6*e`O91N19VR|iFkVbZ8Sk0 zcxl@q{Pmp%{PB^SLwc&TQSBR+sF!`Tv*r}7irpb$+d}04vm;g<)Hv7xoX4dEJuY09fu<@9_x6B=b_iGN*L~N(pdf0%C>jg^)ra-)Q+2?&RDG&*M&eZ|^Arc?c9Y&n`t@XA_pr8WpO83H*{y46K87 zjKyO=>pnfl<(Cy_;NZbJ)YkqROJVA0GL*oYLo<_orvA_VZ9ng`_S-kn z2A=`lc~N-O^q=)!*)dw|Gvpwm9t0CT@%$cqZ3&xsC73z6NZtUj`{&w28Lx^ATXowc z?0xf5+1OWid=hayre^0#ynYJbfmHFF#|wt^`N0!A@QXF`Q2qS(_-$5Byj0yVfcMJp zD`nn`+YWQy&fSd|m6MD|DwpAh^jzJi)&YLoLx7!rZ7%ALhVIuBf8O-M5P0S11X-8k zr@Od}850YUXfabZt&{a;Hb?-M?2zKnZ)@mtqz+78V{}RoFea}L!OFT>>!kg-fii+l*gheCb z)xho6_PB52q!J?X7>&J&OV3P?S_4Otg*GaMxhY|%or}r0cG$VYuNJYa5o^qNyw3wg zt^}82yX5OweMb?GZ7ietB_59fJTuKg!0&?H>Ahn6l5B6cZrQRWS3U=hmt?OX0bf*K zo5PEP4d*VKf4LM-=4Ub9f0Hhxe=Pome9cyk%i*1)C!eF+9wA%| z7cdZ4RaH&iw{PEFPN%bo?r9XaDKu0_tJU_H&E{j}<>fE0TD59F-Es?pa8iia(J>Gw zhBtNEa8rkyO4;El^gr0C1^P)1RCwC#Tv==z*A+d(;U(xd@ur-_X; zR+2VOyxX#r*rM!cH6>CK_ibi+-y04|$rL4Tjah-emk9YsBcXZkug;%8 ze}sWpWK7%L-M!6hHvhV+X{*~@R7%XNgIAZ;C4xaTm@FkGYe~5!H2Y-A2s znpdH+;l=X$UY8)6MOjvKZ|SmnflL@JukR`Mja_7xVbT?d9*y8=;AbO7t}P>3j`Hy#uXz|h%OmxoYR24E?bge;{XNvS)F6VV6*HPL9& zU9HOl2C!5Bz%t;uF?m-{XlZUB1v?mS+T69s&X5?{f#cziY@&3H?Q_1 z6Bvd(PnKl@co-H@!sf1OxLpp!6Df>O&Eo3yX_&3WFjhZa!gGJ;R~c_QVscuArVJUn>!N>SpXa1 z8JkCfd@C3X_b2F*DU>^msIIVM_)GtN)6M4JBFZbWw~%B3TrkZq58zzzE^q(~3@Ohf z#3CpyG2ofK8(=XRG3AS((r!abLj^io>+rXCF9U*!Pl_x{EM)nMZ#LQN3v+I% z%{oNM6MYh;A`p0c3A`fS{$K?D`55nea%(*rYwYNHq!B|NFJjRk400SUXAy$o1j0#y z*w4lnlvQPB_-E%3k0*)2ZHUAqL=&pf)$ZcFeMU+ zRE9}ZP+nGoa5RZeE{?-Y0n6@jyUMvfyR8^bdjMJzlnD%?5++6#F-OcK8_ZO`m1Kf1 zcVhqa_TX*)jYk5guPTPS%)yUmX2Tern&%mfvG!v7nC&8!1}U;#Kmx8(3)v#kvnB3p z?RhC;ejzyzJ7o|CWV6LatZCu*B`IK>b|cI*=BeojA1~7@QxLJtWi=^uAI%r}O*U9m zdxSLMk$zSVSxqt=b}Nydi1~4a@=LvbbkDULEIRhrM{lLeIsLj zl#~Ab`?r%rRR;#calG~3W%``wea}Ao7%XOErth6ogV?pXnfg?~AAG74$3MDBlON{3 zNk|6ld%Od|P#muvzkqd(Rd{lHt2)+GL&RQdu%)K~ufKZ*Tf3`JTj{_*P7Pzn#x-1D zdrJjMiH*(=&G6&qdN(msy$VJutNwcYB4PwQZC#K{3c@i>h&_KgDKnW zd%T;lBI2EoZg56l(M}i3BDJ-(KSxo6J)P-pZ}bxm1t|>~Z&UEnPj+MHrffQ6-&yt}T)H`V+Z5SS%!z4wl)|aAEhB0j<8bg`ggr^^G$IXc#-Z*g`iKNUY zhJ8*`I_vAM#e6u4x8C<)>{bYEjZR`w6Fd`P^if^CxX(!A|Ki3pzPoP&*YU>5VGNGU zqPw-67_%6kdnWO{{hNpZ1b*L@VL#Tlx>4bF;Mj*ZQBzSuU@+s=HwX9_wJ|e>auRbi zR69ujER_jWJUARSD}nMB1zydJWqkZ zo*yM}G}StYxn+2LQO;ECc{2Ul+*!r_xNSo-wr^gCM>npepfy$!4L1jdxo%>vyhqfjcqH&3@ zS@!N~M_rWzZ@xc_&j!3?Lm4{OR^iO08|dw*$A*qtd~#_D|NNK&sI&+@k5m(p%#vOa zk5COf?GIvW&l(QiV+7uKLc)?*)G!ns4NXi;{62%oIMt*}Gw{;U5Q@YXln~l+MsGBn zx0Yd1r`BK+BE)=*U1T{)sg+WGSrG!k7}nIN40V2RoR9D9l?Wc~sYX+M8J$zN^+qS= z5DWwnm=DlV6M@t~Wk4ctpUK1~!pXrEAm({$OKmzWE5r~ktf{Z&eHRIIKHnVIarE`G zoW&AJiDwQbQA*JaEV*+1<}?RirOQe{w_#+IfZXCnmCM3ei|J%GNV2LU77ZaDOE2z{ zarz$49BbpA^sL*QhEHdN5p z5c4l(UvIk_5H2cx_U&Ag(b-g2hH-Bo?>sctIqCZtWemFJRsfSzetzBHuoqj`*HP{4 zqCOWtclOF?Mn_|9J2fZ2he>aHE&segb2{hu@paE~^{;vHB2K=`GU1PZIh|qR+~eHp zIbR9lp$OdCQ-`$#ocBK-K#~>xl&U(3z4m>r2d6KNa>miNjaY4(twq@CNX!J6%oh++ z&NG#~eF9&}iRtth#Gq#;uT9Z-oIn-h^_$yirP@~@hKl8sKq+pMkh3TpCcrZ3Tvr1J zf#mqmH8eLkIYaX25eRa9%_E6?zpwo%`;ezA9MYA`qKD6-)_<3bPfaDwE;yxu^*D?KdRd$Sx zjbU{3OZ2QOM=g~HT3_edN>~kXSdA%sfB#lm@i#Bnvu&<(Q0SUl-IXjUkFz}A3?fo zUts%U`!=s{f@gf5U&s7#{kn&0>ltk6s-n!AS?BZA9}WA_yUx8}9yGh1tfWnbxPHDR zO3%y8A&9*c7Wj>gt)-!iGYC6B zJ{3R*l@aWGKL1Yp!(2yeqZ?MMnHE{&nQ^PNwYb2Jj9oeQ2~=^ zzcaBCsF$+u^rbP*x+lr+dv>(orRSf{=o~`C-^^C&CTU6ijsKt{4v^Zk;#v;*@!vryl| zAZ+{zo(Up%WV`0;rS4?`Y^Gqy=a)i#>Y~=dcQ4o??OvrQc6sv5nKKQU{7?w(_ej9Y zDu~f)c5Ete*Zp@Zg>*iM=lw5bx$!U6znrhV{>WYRG4ct7;`iIkoPA)(1sKxE{{%D< zk1cu4FaPk~lJ~NdqKhsMLRQ4UZ1rAO^t|VmNyAXu+L^ zNGw53_m(cJOBi;I={@0;3Sj+@k#%_}h?o6hD?wfpm<$HPh)D^$lY+fScaAQrT?ngD z!t8Yoz~<`e>fcRFjJ=W+Tg?jpcVfEevN}aTN-C1Z{55rTzhzh!4;(n)XlrZpc|0CD z8Jq7>6oViWuoeA3H_>Hv0arFE;aHI}6LdLCUO9B=5Zm@rgmf{?Uf5gu`}?=txN+mT zL?W?{YGR}AHeFVWh@v=Wu~@D(G&H=id-v`$bSifE@Zk|5XGO_{)_Oz9@3n?YaU u>GBn<)MRA;H%itL=@ww%Wf%QdfB^t}ZpX{M9AEDM0000)^})o%#0Qg_n5a)i-+gd<)kx@r@xf@^V&W2QVieaZO=BxU zqO!=a6oG-+@9uxjy|XaRTn37X(fc<)lXL%j&OP@#-}%me&MgB)^P%(TEIL!>j%{v6 znd|5(dJ0NF^b>%i(dbdP+x-N?Fi|Xv4tCqJC0*BlktFH0v9Ymp7T`$&bR7Zt$dMzb zeY={U_66I$UVoDt5N!vut(&IGnv_|SQ>(L?)cVqM7cN{FB4BfbxrYxQJ}Qdh^DX=O zL!xIFGT8xnyT-5_E4bwhhAoRh2-MbM%+NdwJ0f0y@VD|2d#d)*3cI*P!1mjXt>l&M5f2 zE?R!!%m@?)kgf1!UB`h)gNxJPx@Z_e!FrHn73LP>@XK$1g6Q^w;PU=!kW!EgaxP_N z6QT$ESGT45MWAh`_vS#Cg1kX?$N*{;*q+P4t~wS@9={e`0uPHT8EE$VV1IiPbRCSq zyPsadWK^IUuj?A2KRqyDS&p6@kbyGD?zXgRR-9x{)nfTm2U1@*%r%E)c-&~P8%R(Z zBUMyIfxB;w!tRy;483&@^JLX(uXdnokdDoPE@yIKGE`{SK;U@nsBd@%*9 z>p2>`t-lTSw)!D@^a3x~WFW4y~lw#lI6()1o;i_2NStsDq~8=0HMnUp<7o&r6sPgWUyQ@_TpVLP6=PGeRcOTa2M2Eif1OE= zWLkpvKf8p#>oj)i)G=_0d?EJ9m*a5rbsZQp2j-sJyW!)nXK)bGHDkk;0#em&8hh%I z0qWJtq;7e8ND*YH3BYnZvmus~HJD#YL3}+84Stb=JTsq!Gw+ST_ZJsYS{kAEPy`3h z1VTYodHur)_~@%?TJG*_1y1xhOR5X8aUM(JdjA{U{C8Fde4RNIoiMTKWE^Eo-pidYrtz}x;Z<)2FXMc66*;p z?E{`?ar(;@V}iiK?&bhxasrup`}Mmm%{FiVgRrM9Ok+PyT!xjEHQL7T+vh>VnJ43@ zX;z=JnFP)#z9uG%gVKa9O`{;xaW>u2nPf> z)DeQ)ZtA9K-o(@j9SmZ2Q>~5+n#JUeOgPWDW&8zUhU_bO-(}BC&;&+gaNIh_%STo(&#LF0MTv^g#Ten*E zv)}y=M^kNZZC4mN_cfbRgD-ma+euhY5ebrDWON1w`u4&zkDam>!#K*uVliuD%&%=s zNvf59muj*1&W^)<$GhP1hwq@*h>ZOB^WuisqYo8hKU|upv5DW8p{crRg2n8Tv6d-Yf-jiCiH&n7f>)8c!hjBn#Ln zi?q~NeWqP(E9S{vS{NN2Z7<}}b|Z6zgx<7)oTNc)F|qCVcFnHM9e!R(9u2w;<9PZh z*F3wZY|p;@S=G8k4*u^}6Qjv$9cc{}lK5JU04!l%Y&b{V20t`3#10P++h!J-oQ&?A z-f!0k#=MnNt0vIS$L}2`GEKV)#sp}AW!WjgNQM-~?{UD{IYUgdi0yBApv7=F{L=h< z>{W$3C>r!!&9N&r22{7mg*9GJW{F@EC2@S~4u+}| z3<;Kq>6sHJPK*(Z8B44?NG3KiGIIU&^z_5BEO#Q(yu-__8^>{LE|=@q_V)I71_lO3 z$u{8h>C;n8$;wE;uD2FP!E(-W)>$cSS3Dhx|9h0UYvCP)Xv$!7@@Qp;X+}MQ~ARx~Lmh?IK_ox~SsHTFJ%-4KZeuK-EAJ$VTvy zMWQZz$JeN%jx+XrzjJO!lNm>6f=P2f__^oa^SI}J|9`*ppUc(Ie~1?rAxtk!D@@}# zYDq;PaC>aubKDcQEo`1VWC95w`1Qlqbeu3^5q)ENwsDqA7I)|P|%`g&dK>+824Jb3UI^w@1OnSLrLDAYwngp&w+ zm8B2>Twb|Spc@_@x-Cxs)U!})H0R^u;#87DjQIF?a2rFO32vN@g36OA4g7DngJonupp4uELX{c&&YRCl;#i&iBmP@;vP z^U+|ooGit$uXEqyh=y!!Z*TKkBQ{H7#g6#Dy#-7(9Y=H^`u$~M4Bh#;jAE@uJ}>;P zRT)?8mi+eJ+uLJ;Gcqzr|v-kJ~EfB?(|PJttEl=DM-SqF0DTPWv%z5x26{%9YVyoRd`hbGLoH$y72ID?t}93^6~*0o-q~|7nx`P0f06b z1LFlP9sbA+CiM%XFUat2hq8=F5Dq!X&d#PAH*P3xMn^~K?%liWl(e)os;a8u>(F|9 zZ-6s8Iy#uRy1F__NJvoXJ3BjRW@d(pi;LNCK0iNCnVFe%S;ry8|40YAA`8q#tTxl}uCF#--o!GU4Tq=ZcC7 zc1BxU8xvx+T9vdCbs!l|K|RK+uCC^ONIwBYw@gI=klxeN!{w(>pK>|S=kUdw647&W zbABU^$okH@rIpP?(jm_!FlleS^aVUD0C_+kslSkj^z?KtKYH|t=Q%JiKt)AGl$@N* zQh>fgLql8!^78T&$w)~_VF!(jjBwra=g+CMw3MTCV`GD_K{{|xdH&|j8)aT_;Oy*d zK+h1+Vt88EZgnb=?0p`L)Y$EIMWYP{gYuAw#?8%5#R)jdMGg|Nu&}_93O$B&NZpr` zAs1A+D9XhR&h@_M(fObrW6ArT3DKbjUi+(8uPTHft(usapljEzQDI>rN3P9gQ*;{9 z2168YZEaCZObjnzSUhDL$c))+=C>gyCx=OY{rWZE3xNKE#N6E6L;D5*vV(R@OG~_% ze)L4k=mJraNQs7q2D*R$KI?Q>SC>NIlP6EO+}_^KbxBD{EE6D6qQAeNiE3YP|jq`GfkXBvKyz&6_u|)cS1Y1Yw>m;8f6P=u-wbMq+4E_9QCa z3(w#fS`aBxs|~Rch%%c^DlH*|-M)de)h>!gM6~hJrAy88b2F~JVB|r?Tk8`z6`Q5s z5zHE)8TgQ3s;{sAb$Mm2=zP?9t;u8zdT;;95-hgyjx7hRuC2PGtxGe*N$+VoAnfZ5ZZS6fMhzQz$G+rws$i^R~ z20Hkw6ra<=JSm`#)Sn)Grf$Mq9^3Vp1KSQ^^B@_G{uN*V%EX(FG09w#00000NkvXX Hu0mjfJI@|W diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout_down.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout_down.png deleted file mode 100644 index 1ab14b9dc931eeb1b624cca1bbf422a2445f1754..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1551 zcmV+q2JrcbP)4o$iGOaKRRrBWWrYV<@q2Zm^>vh`gb`7bL0j?*j)uxX` z!aYYvM{kYt{Yt0PNvTvyL#TvSUhc%Dn&b=v8ewD$pe7e3Hef0+7C>uke&WnM`uecVU1VjYbXVT!04KfB)mApl=xIvul!+E6~DBW=me9C*rZ3Qbhz3`6p%! zbgitcjL(D*4QR@y(YXY{RqdcpKI$Te&CJVReLt`C&9?agz-UujTT8K6j80EaiS1DT zHB|6CH#avt_z1YwYURN%#*Ddunae_{2Kiy%TmogY*{Hp}o!D-Q&d$#M(MODfD_D=f z$g6tBI`M8|JlqF(5BtEyJ$QL}ISmaB(bm=$9UL4e;}!$7R0^OUGFknS>X%M8zK{y> z((32IVho0XX%2^je?~o+hL=Yf{mo`GU0hu7_NX(NOuRqp1uIdH*@6Wceen6}>PlI> zF-9a3;XuQ%i9;KVfx0J^j$%^3T>7Gox}CZVKp`iMjg8dZ-L13<27|P`yv&1AS64^< z{r$>W1N{2>nidxqIXELDBUDjQq0}!eEz#xWCAGD+aYs2E4wKvM=H;E89cpQ5;qB|| z>v?cjS67R|p=gc%VsiM=ay}ZJ323kryH>C&upm;paS=-y&%RxpR+MsT5aFAwaXO&qb*e%jffF1}0$nW>l?(Qz_?d=t<`wGyZ zP$-*c&X-zmz`XjFMF1SdN-c>rCgz5Q|N9+O46U@?=W zLd+uQtNhFB`JR&Q~w$?l;(4{sk zKAoMN%1eW-$H&L~p4aQ;%G|94tl<&>s#qi#A9bAt_*OQ&STM9V|zt1B3np zMAWIyD7Zm(&<-pwCdGR;Knr#OBmtzbnVA``&Cuz|$w>u3ELyOIg#}($U0uxqgbPDI z05vf&ac?mcW1uax9(@rAaa4@pp$@WzAmKZTm5yhzKgLS|&~ye+k=BExohHK;TVp#IZLg`R`6e8?WRj}=I9swa zZH6TCua%XR3oK!m#D4$(Ev$vRluGe46JQBU$HvBf1I9X8tZ`7` zn4h2jm?iz6vaPH$l}c&<6IOt+boSP4HlMrQ?w^K-hkwSo+SJt4ypjXSV7ugFI{c0V z!7h_iKqS%{@M%&vD240^*>TW -#import - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -extern const NSString* kFB_SDK_VersionNumber; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef DEBUG -#define FBLOG -#define FBLOG2 -#else -#define FBLOG -#define FBLOG2 -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -typedef unsigned long long FBUID; -typedef unsigned long long FBID; - -#define FBAPI_ERROR_DOMAIN @"api.facebook.com" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Error codes - -#define FBAPI_EC_SUCCESS 0 -#define FBAPI_EC_UNKNOWN 1 -#define FBAPI_EC_SERVICE 2 -#define FBAPI_EC_METHOD 3 -#define FBAPI_EC_TOO_MANY_CALLS 4 -#define FBAPI_EC_BAD_IP 5 -#define FBAPI_EC_HOST_API 6 -#define FBAPI_EC_HOST_UP 7 -#define FBAPI_EC_SECURE 8 -#define FBAPI_EC_RATE 9 -#define FBAPI_EC_PERMISSION_DENIED 10 -#define FBAPI_EC_DEPRECATED 11 -#define FBAPI_EC_VERSION 12 - -#define FBAPI_EC_PARAM 100 -#define FBAPI_EC_PARAM_FBAPI_KEY 101 -#define FBAPI_EC_PARAM_SESSION_KEY 102 -#define FBAPI_EC_PARAM_CALL_ID 103 -#define FBAPI_EC_PARAM_SIGNATURE 104 -#define FBAPI_EC_PARAM_TOO_MANY 105 -#define FBAPI_EC_PARAM_USER_ID 110 -#define FBAPI_EC_PARAM_USER_FIELD 111 -#define FBAPI_EC_PARAM_SOCIAL_FIELD 112 -#define FBAPI_EC_PARAM_EMAIL 113 -#define FBAPI_EC_PARAM_ALBUM_ID 120 -#define FBAPI_EC_PARAM_PHOTO_ID 121 -#define FBAPI_EC_PARAM_FEED_PRIORITY 130 -#define FBAPI_EC_PARAM_CATEGORY 140 -#define FBAPI_EC_PARAM_SUBCATEGORY 141 -#define FBAPI_EC_PARAM_TITLE 142 -#define FBAPI_EC_PARAM_DESCRIPTION 143 -#define FBAPI_EC_PARAM_BAD_JSON 144 -#define FBAPI_EC_PARAM_BAD_EID 150 -#define FBAPI_EC_PARAM_UNKNOWN_CITY 151 -#define FBAPI_EC_PARAM_BAD_PAGE_TYPE 152 - -#define FBAPI_EC_PERMISSION 200 -#define FBAPI_EC_PERMISSION_USER 210 -#define FBAPI_EC_PERMISSION_ALBUM 220 -#define FBAPI_EC_PERMISSION_PHOTO 221 -#define FBAPI_EC_PERMISSION_MESSAGE 230 -#define FBAPI_EC_PERMISSION_MARKUP_OTHER_USER 240 -#define FBAPI_EC_PERMISSION_STATUS_UPDATE 250 -#define FBAPI_EC_PERMISSION_PHOTO_UPLOAD 260 -#define FBAPI_EC_PERMISSION_SMS 270 -#define FBAPI_EC_PERMISSION_CREATE_LISTING 280 -#define FBAPI_EC_PERMISSION_EVENT 290 -#define FBAPI_EC_PERMISSION_LARGE_FBML_TEMPLATE 291 -#define FBAPI_EC_PERMISSION_LIVEMESSAGE 292 -#define FBAPI_EC_PERMISSION_RSVP_EVENT 299 - -#define FBAPI_EC_EDIT 300 -#define FBAPI_EC_EDIT_USER_DATA 310 -#define FBAPI_EC_EDIT_PHOTO 320 -#define FBAPI_EC_EDIT_ALBUM_SIZE 321 -#define FBAPI_EC_EDIT_PHOTO_TAG_SUBJECT 322 -#define FBAPI_EC_EDIT_PHOTO_TAG_PHOTO 323 -#define FBAPI_EC_EDIT_PHOTO_FILE 324 -#define FBAPI_EC_EDIT_PHOTO_PENDING_LIMIT 325 -#define FBAPI_EC_EDIT_PHOTO_TAG_LIMIT 326 -#define FBAPI_EC_EDIT_ALBUM_REORDER_PHOTO_NOT_IN_ALBUM 327 -#define FBAPI_EC_EDIT_ALBUM_REORDER_TOO_FEW_PHOTOS 328 -#define FBAPI_EC_MALFORMED_MARKUP 329 -#define FBAPI_EC_EDIT_MARKUP 330 -#define FBAPI_EC_EDIT_FEED_TOO_MANY_USER_CALLS 340 -#define FBAPI_EC_EDIT_FEED_TOO_MANY_USER_ACTION_CALLS 341 -#define FBAPI_EC_EDIT_FEED_TITLE_LINK 342 -#define FBAPI_EC_EDIT_FEED_TITLE_LENGTH 343 -#define FBAPI_EC_EDIT_FEED_TITLE_NAME 344 -#define FBAPI_EC_EDIT_FEED_TITLE_BLANK 345 -#define FBAPI_EC_EDIT_FEED_BODY_LENGTH 346 -#define FBAPI_EC_EDIT_FEED_PHOTO_SRC 347 -#define FBAPI_EC_EDIT_FEED_PHOTO_LINK 348 -#define FBAPI_EC_EDIT_VIDEO_SIZE 350 -#define FBAPI_EC_EDIT_VIDEO_INVALID_FILE 351 -#define FBAPI_EC_EDIT_VIDEO_INVALID_TYPE 352 -#define FBAPI_EC_EDIT_FEED_TITLE_ARRAY 360 -#define FBAPI_EC_EDIT_FEED_TITLE_PARAMS 361 -#define FBAPI_EC_EDIT_FEED_BODY_ARRAY 362 -#define FBAPI_EC_EDIT_FEED_BODY_PARAMS 363 -#define FBAPI_EC_EDIT_FEED_PHOTO 364 -#define FBAPI_EC_EDIT_FEED_TEMPLATE 365 -#define FBAPI_EC_EDIT_FEED_TARGET 366 -#define FBAPI_EC_USERS_CREATE_INVALID_EMAIL 370 -#define FBAPI_EC_USERS_CREATE_EXISTING_EMAIL 371 -#define FBAPI_EC_USERS_CREATE_BIRTHDAY 372 -#define FBAPI_EC_USERS_CREATE_PASSWORD 373 -#define FBAPI_EC_USERS_REGISTER_INVALID_CREDENTIAL 374 -#define FBAPI_EC_USERS_REGISTER_CONF_FAILURE 375 -#define FBAPI_EC_USERS_REGISTER_EXISTING 376 -#define FBAPI_EC_USERS_REGISTER_DEFAULT_ERROR 377 -#define FBAPI_EC_USERS_REGISTER_PASSWORD_BLANK 378 -#define FBAPI_EC_USERS_REGISTER_PASSWORD_INVALID_CHARS 379 -#define FBAPI_EC_USERS_REGISTER_PASSWORD_SHORT 380 -#define FBAPI_EC_USERS_REGISTER_PASSWORD_WEAK 381 -#define FBAPI_EC_USERS_REGISTER_USERNAME_ERROR 382 -#define FBAPI_EC_USERS_REGISTER_MISSING_INPUT 383 -#define FBAPI_EC_USERS_REGISTER_INCOMPLETE_BDAY 384 -#define FBAPI_EC_USERS_REGISTER_INVALID_EMAIL 385 -#define FBAPI_EC_USERS_REGISTER_EMAIL_DISABLED 386 -#define FBAPI_EC_USERS_REGISTER_ADD_USER_FAILED 387 -#define FBAPI_EC_USERS_REGISTER_NO_GENDER 388 - -#define FBAPI_EC_AUTH_EMAIL 400 -#define FBAPI_EC_AUTH_LOGIN 401 -#define FBAPI_EC_AUTH_SIG 402 -#define FBAPI_EC_AUTH_TIME 403 - -#define FBAPI_EC_SESSION_METHOD 451 -#define FBAPI_EC_SESSION_REQUIRED 453 -#define FBAPI_EC_SESSION_REQUIRED_FOR_SECRET 454 -#define FBAPI_EC_SESSION_CANNOT_USE_SESSION_SECRET 455 - -#define FBAPI_EC_MESG_BANNED 500 -#define FBAPI_EC_MESG_NO_BODY 501 -#define FBAPI_EC_MESG_TOO_LONG 502 -#define FBAPI_EC_MESG_RATE 503 -#define FBAPI_EC_MESG_INVALID_THREAD 504 -#define FBAPI_EC_MESG_INVALID_RECIP 505 -#define FBAPI_EC_POKE_INVALID_RECIP 510 -#define FBAPI_EC_POKE_OUTSTANDING 511 -#define FBAPI_EC_POKE_RATE 512 - -#define FQL_EC_UNKNOWN_ERROR 600 -#define FQL_EC_PARSER_ERROR 601 -#define FQL_EC_UNKNOWN_FIELD 602 -#define FQL_EC_UNKNOWN_TABLE 603 -#define FQL_EC_NO_INDEX 604 -#define FQL_EC_UNKNOWN_FUNCTION 605 -#define FQL_EC_INVALID_PARAM 606 -#define FQL_EC_INVALID_FIELD 607 -#define FQL_EC_INVALID_SESSION 608 - -#define FBAPI_EC_REF_SET_FAILED 700 -#define FBAPI_EC_FB_APP_UNKNOWN_ERROR 750 -#define FBAPI_EC_FB_APP_FETCH_FAILED 751 -#define FBAPI_EC_FB_APP_NO_DATA 752 -#define FBAPI_EC_FB_APP_NO_PERMISSIONS 753 -#define FBAPI_EC_FB_APP_TAG_MISSING 754 - -#define FBAPI_EC_DATA_UNKNOWN_ERROR 800 -#define FBAPI_EC_DATA_INVALID_OPERATION 801 -#define FBAPI_EC_DATA_QUOTA_EXCEEDED 802 -#define FBAPI_EC_DATA_OBJECT_NOT_FOUND 803 -#define FBAPI_EC_DATA_OBJECT_ALREADY_EXISTS 804 -#define FBAPI_EC_DATA_DATABASE_ERROR 805 -#define FBAPI_EC_DATA_CREATE_TEMPLATE_ERROR 806 -#define FBAPI_EC_DATA_TEMPLATE_EXISTS_ERROR 807 -#define FBAPI_EC_DATA_TEMPLATE_HANDLE_TOO_LONG 808 -#define FBAPI_EC_DATA_TEMPLATE_HANDLE_ALREADY_IN_USE 809 -#define FBAPI_EC_DATA_TOO_MANY_TEMPLATE_BUNDLES 810 -#define FBAPI_EC_DATA_MALFORMED_ACTION_LINK 811 -#define FBAPI_EC_DATA_TEMPLATE_USES_RESERVED_TOKEN 812 - -#define FBAPI_EC_NO_SUCH_APP 900 -#define FBAPI_BATCH_TOO_MANY_ITEMS 950 -#define FBAPI_EC_BATCH_ALREADY_STARTED 951 -#define FBAPI_EC_BATCH_NOT_STARTED 952 -#define FBAPI_EC_BATCH_METHOD_NOT_ALLOWED_IN_BATCH_MODE 953 - -#define FBAPI_EC_EVENT_INVALID_TIME 1000 -#define FBAPI_EC_INFO_NO_INFORMATION 1050 -#define FBAPI_EC_INFO_SET_FAILED 1051 - -#define FBAPI_EC_LIVEMESSAGE_SEND_FAILED 1100 -#define FBAPI_EC_LIVEMESSAGE_EVENT_NAME_TOO_LONG 1101 -#define FBAPI_EC_LIVEMESSAGE_MESSAGE_TOO_LONG 1102 - -#define FBAPI_EC_PAGES_CREATE 1201 - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -NSMutableArray* FBCreateNonRetainingArray(); - -BOOL FBIsDeviceIPad(); diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m deleted file mode 100644 index 77ec5ca4..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBConnectGlobal.h" - -const NSString* kFB_SDK_VersionNumber = @"iphone/1.3.0"; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -const void* RetainNoOp(CFAllocatorRef allocator, const void *value) { return value; } -void ReleaseNoOp(CFAllocatorRef allocator, const void *value) { } - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// public - -NSMutableArray* FBCreateNonRetainingArray() { - CFArrayCallBacks callbacks = kCFTypeArrayCallBacks; - callbacks.retain = RetainNoOp; - callbacks.release = ReleaseNoOp; - return (NSMutableArray*)CFArrayCreateMutable(nil, 0, &callbacks); -} - - -BOOL FBIsDeviceIPad() { -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200 - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { - return YES; - } -#endif - return NO; -} diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/close.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.bundle/images/close.png similarity index 100% rename from Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/close.png rename to Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.bundle/images/close.png diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/fbicon.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.bundle/images/fbicon.png similarity index 100% rename from Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/fbicon.png rename to Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.bundle/images/fbicon.png diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h index 097547bc..70bae3ac 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h @@ -1,10 +1,10 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software @@ -14,14 +14,21 @@ * limitations under the License. */ -#import "FBConnectGlobal.h" +#import +#import @protocol FBDialogDelegate; -@class FBSession; + +/** + * Do not use this interface directly, instead, use dialog in Facebook.h + * + * Facebook dialog interface for start the facebook webView UIServer Dialog. + */ @interface FBDialog : UIView { id _delegate; - FBSession* _session; + NSMutableDictionary *_params; + NSString * _serverURL; NSURL* _loadingURL; UIWebView* _webView; UIActivityIndicatorView* _spinner; @@ -30,6 +37,9 @@ UIButton* _closeButton; UIDeviceOrientation _orientation; BOOL _showingKeyboard; + + // Ensures that UI elements behind the dialog are disabled. + UIView* _modalBackgroundView; } /** @@ -38,19 +48,20 @@ @property(nonatomic,assign) id delegate; /** - * The session for which the login is taking place. + * The parameters. */ -@property(nonatomic,assign) FBSession* session; +@property(nonatomic, retain) NSMutableDictionary* params; /** - * The title that is shown in the header atop the view; + * The title that is shown in the header atop the view. */ @property(nonatomic,copy) NSString* title; -/** - * Creates the view but does not display it. - */ -- (id)initWithSession:(FBSession*)session; +- (NSString *) getStringFromUrl: (NSString*) url needle:(NSString *) needle; + +- (id)initWithURL: (NSString *) loadingURL + params: (NSMutableDictionary *) params + delegate: (id ) delegate; /** * Displays the view with an animation. @@ -69,8 +80,8 @@ /** * Displays a URL in the dialog. */ -- (void)loadURL:(NSString*)url method:(NSString*)method get:(NSDictionary*)getParams - post:(NSDictionary*)postParams; +- (void)loadURL:(NSString*)url + get:(NSDictionary*)getParams; /** * Hides the view and notifies delegates of success or cancellation. @@ -97,15 +108,21 @@ * * Implementations must call dismissWithSuccess:YES at some point to hide the dialog. */ -- (void)dialogDidSucceed:(NSURL*)url; +- (void)dialogDidSucceed:(NSURL *)url; -- (void)bounce2AnimationStopped; -- (void)keyboardWillShow:(NSNotification*)notification; -- (void)keyboardWillHide:(NSNotification*)notification; +/** + * Subclasses should override to process data returned from the server in a 'fbconnect' url. + * + * Implementations must call dismissWithSuccess:YES at some point to hide the dialog. + */ +- (void)dialogDidCancel:(NSURL *)url; @end /////////////////////////////////////////////////////////////////////////////////////////////////// +/* + *Your application should implement this delegate + */ @protocol FBDialogDelegate @optional @@ -113,28 +130,38 @@ /** * Called when the dialog succeeds and is about to be dismissed. */ -- (void)dialogDidSucceed:(FBDialog*)dialog; +- (void)dialogDidComplete:(FBDialog *)dialog; + +/** + * Called when the dialog succeeds with a returning url. + */ +- (void)dialogCompleteWithUrl:(NSURL *)url; + +/** + * Called when the dialog get canceled by the user. + */ +- (void)dialogDidNotCompleteWithUrl:(NSURL *)url; /** * Called when the dialog is cancelled and is about to be dismissed. */ -- (void)dialogDidCancel:(FBDialog*)dialog; +- (void)dialogDidNotComplete:(FBDialog *)dialog; /** * Called when dialog failed to load due to an error. */ -- (void)dialog:(FBDialog*)dialog didFailWithError:(NSError*)error; +- (void)dialog:(FBDialog*)dialog didFailWithError:(NSError *)error; /** * Asks if a link touched by a user should be opened in an external browser. * - * If a user touches a link, the default behavior is to open the link in the Safari browser, + * If a user touches a link, the default behavior is to open the link in the Safari browser, * which will cause your app to quit. You may want to prevent this from happening, open the link * in your own internal browser, or perhaps warn the user that they are about to leave your app. * If so, implement this method on your delegate and return NO. If you warn the user, you * should hold onto the URL and once you have received their acknowledgement open the URL yourself * using [[UIApplication sharedApplication] openURL:]. */ -- (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL*)url; +- (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL *)url; @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m index 1aaed9f4..40455fa7 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m @@ -1,5 +1,5 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,14 @@ * limitations under the License. */ + #import "FBDialog.h" -#import "FBSession.h" +#import "Facebook.h" /////////////////////////////////////////////////////////////////////////////////////////////////// // global static NSString* kDefaultTitle = @"Connect to Facebook"; -static NSString* kStringBoundary = @"3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f"; static CGFloat kFacebookBlue[4] = {0.42578125, 0.515625, 0.703125, 1.0}; static CGFloat kBorderGray[4] = {0.3, 0.3, 0.3, 0.8}; @@ -37,9 +37,21 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL FBIsDeviceIPad() { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200 + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + return YES; + } +#endif + return NO; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + @implementation FBDialog -@synthesize session = _session, delegate = _delegate; +@synthesize delegate = _delegate, + params = _params; /////////////////////////////////////////////////////////////////////////////////////////////////// // private @@ -57,7 +69,7 @@ - (void)addRoundedRectToPath:(CGContextRef)context rect:(CGRect)rect radius:(flo CGContextScaleCTM(context, radius, radius); float fw = CGRectGetWidth(rect) / radius; float fh = CGRectGetHeight(rect) / radius; - + CGContextMoveToPoint(context, fw, fh/2); CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); @@ -84,7 +96,7 @@ - (void)drawRect:(CGRect)rect fill:(const CGFloat*)fillColors radius:(CGFloat)ra } CGContextRestoreGState(context); } - + CGColorSpaceRelease(space); } @@ -96,28 +108,28 @@ - (void)strokeLines:(CGRect)rect stroke:(const CGFloat*)strokeColor { CGContextSetStrokeColorSpace(context, space); CGContextSetStrokeColor(context, strokeColor); CGContextSetLineWidth(context, 1.0); - + { - CGPoint points[] = {rect.origin.x+0.5, rect.origin.y-0.5, - rect.origin.x+rect.size.width, rect.origin.y-0.5}; + CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y-0.5}, + {rect.origin.x+rect.size.width, rect.origin.y-0.5}}; CGContextStrokeLineSegments(context, points, 2); } { - CGPoint points[] = {rect.origin.x+0.5, rect.origin.y+rect.size.height-0.5, - rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height-0.5}; + CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y+rect.size.height-0.5}, + {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height-0.5}}; CGContextStrokeLineSegments(context, points, 2); } { - CGPoint points[] = {rect.origin.x+rect.size.width-0.5, rect.origin.y, - rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height}; + CGPoint points[] = {{rect.origin.x+rect.size.width-0.5, rect.origin.y}, + {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height}}; CGContextStrokeLineSegments(context, points, 2); } { - CGPoint points[] = {rect.origin.x+0.5, rect.origin.y, - rect.origin.x+0.5, rect.origin.y+rect.size.height}; + CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y}, + {rect.origin.x+0.5, rect.origin.y+rect.size.height}}; CGContextStrokeLineSegments(context, points, 2); } - + CGContextRestoreGState(context); CGColorSpaceRelease(space); @@ -211,11 +223,17 @@ - (NSURL*)generateURL:(NSString*)baseURL params:(NSDictionary*)params { NSMutableArray* pairs = [NSMutableArray array]; for (NSString* key in params.keyEnumerator) { NSString* value = [params objectForKey:key]; - NSString* val = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSString* pair = [NSString stringWithFormat:@"%@=%@", key, val]; - [pairs addObject:pair]; + NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes( + NULL, /* allocator */ + (CFStringRef)value, + NULL, /* charactersToLeaveUnescaped */ + (CFStringRef)@"!*'();:@&=+$,/?%#[]", + kCFStringEncodingUTF8); + + [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, escaped_value]]; + [escaped_value release]; } - + NSString* query = [pairs componentsJoinedByString:@"&"]; NSString* url = [NSString stringWithFormat:@"%@?%@", baseURL, query]; return [NSURL URLWithString:url]; @@ -224,28 +242,6 @@ - (NSURL*)generateURL:(NSString*)baseURL params:(NSDictionary*)params { } } -- (NSMutableData*)generatePostBody:(NSDictionary*)params { - if (!params) { - return nil; - } - - NSMutableData* body = [NSMutableData data]; - NSString* endLine = [NSString stringWithFormat:@"\r\n--%@\r\n", kStringBoundary]; - - [body appendData:[[NSString stringWithFormat:@"--%@\r\n", kStringBoundary] - dataUsingEncoding:NSUTF8StringEncoding]]; - - for (id key in [params keyEnumerator]) { - [body appendData:[[NSString - stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] - dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[[params valueForKey:key] dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[endLine dataUsingEncoding:NSUTF8StringEncoding]]; - } - - return body; -} - - (void)addObservers { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) @@ -268,6 +264,7 @@ - (void)removeObservers { - (void)postDismissCleanup { [self removeObservers]; [self removeFromSuperview]; + [_modalBackgroundView removeFromSuperview]; } - (void)dismiss:(BOOL)animated { @@ -275,7 +272,7 @@ - (void)dismiss:(BOOL)animated { [_loadingURL release]; _loadingURL = nil; - + if (animated) { [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:kTransitionDuration]; @@ -289,37 +286,30 @@ - (void)dismiss:(BOOL)animated { } - (void)cancel { - [self dismissWithSuccess:NO animated:YES]; + [self dialogDidCancel:nil]; } /////////////////////////////////////////////////////////////////////////////////////////////////// // NSObject - (id)init { - return [self initWithSession:[FBSession session]]; -} - -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - -- (id)initWithSession:(FBSession*)session { if (self = [super initWithFrame:CGRectZero]) { _delegate = nil; - _session = [session retain]; _loadingURL = nil; _orientation = UIDeviceOrientationUnknown; _showingKeyboard = NO; - + self.backgroundColor = [UIColor clearColor]; self.autoresizesSubviews = YES; self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.contentMode = UIViewContentModeRedraw; - - UIImage* iconImage = [UIImage imageNamed:@"FBConnect.bundle/images/fbicon.png"]; - UIImage* closeImage = [UIImage imageNamed:@"FBConnect.bundle/images/close.png"]; - + + UIImage* iconImage = [UIImage imageNamed:@"FBDialog.bundle/images/fbicon.png"]; + UIImage* closeImage = [UIImage imageNamed:@"FBDialog.bundle/images/close.png"]; + _iconView = [[UIImageView alloc] initWithImage:iconImage]; [self addSubview:_iconView]; - + UIColor* color = [UIColor colorWithRed:167.0/255 green:184.0/255 blue:216.0/255 alpha:1]; _closeButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; [_closeButton setImage:closeImage forState:UIControlStateNormal]; @@ -327,16 +317,19 @@ - (id)initWithSession:(FBSession*)session { [_closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; [_closeButton addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside]; - if ([_closeButton respondsToSelector:@selector(titleLabel)]) { - _closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12]; - } else { // This triggers a deprecation warning but at least it will work on OS 2.x - _closeButton.font = [UIFont boldSystemFontOfSize:12]; - } - _closeButton.showsTouchWhenHighlighted = YES; + + // To be compatible with OS 2.x + #if __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_2_2 + _closeButton.font = [UIFont boldSystemFontOfSize:12]; + #else + _closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12]; + #endif + + _closeButton.showsTouchWhenHighlighted = YES; _closeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin; [self addSubview:_closeButton]; - + CGFloat titleLabelFontSize = (FBIsDeviceIPad() ? 18 : 14); _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; _titleLabel.text = kDefaultTitle; @@ -346,8 +339,8 @@ - (id)initWithSession:(FBSession*)session { _titleLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; [self addSubview:_titleLabel]; - - _webView = [[UIWebView alloc] initWithFrame:CGRectZero]; + + _webView = [[UIWebView alloc] initWithFrame:CGRectMake(kPadding, kPadding, 480, 480)]; _webView.delegate = self; _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self addSubview:_webView]; @@ -358,6 +351,7 @@ - (id)initWithSession:(FBSession*)session { UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; [self addSubview:_spinner]; + _modalBackgroundView = [[UIView alloc] init]; } return self; } @@ -365,12 +359,14 @@ - (id)initWithSession:(FBSession*)session { - (void)dealloc { _webView.delegate = nil; [_webView release]; + [_params release]; + [_serverURL release]; [_spinner release]; [_titleLabel release]; [_iconView release]; [_closeButton release]; [_loadingURL release]; - [_session release]; + [_modalBackgroundView release]; [super dealloc]; } @@ -399,9 +395,20 @@ - (void)drawRect:(CGRect)rect { - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSURL* url = request.URL; + if ([url.scheme isEqualToString:@"fbconnect"]) { - if ([url.resourceSpecifier isEqualToString:@"cancel"]) { - [self dismissWithSuccess:NO animated:YES]; + if ([[url.resourceSpecifier substringToIndex:8] isEqualToString:@"//cancel"]) { + NSString * errorCode = [self getStringFromUrl:[url absoluteString] needle:@"error_code="]; + NSString * errorStr = [self getStringFromUrl:[url absoluteString] needle:@"error_msg="]; + if (errorCode) { + NSDictionary * errorData = [NSDictionary dictionaryWithObject:errorStr forKey:@"error_msg"]; + NSError * error = [NSError errorWithDomain:@"facebookErrDomain" + code:[errorCode intValue] + userInfo:errorData]; + [self dismissWithError:error animated:YES]; + } else { + [self dialogDidCancel:url]; + } } else { [self dialogDidSucceed:url]; } @@ -414,7 +421,7 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) return NO; } } - + [[UIApplication sharedApplication] openURL:request.URL]; return NO; } else { @@ -425,7 +432,7 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) - (void)webViewDidFinishLoad:(UIWebView *)webView { [_spinner stopAnimating]; _spinner.hidden = YES; - + self.title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"]; [self updateWebOrientation]; } @@ -457,8 +464,11 @@ - (void)deviceOrientationDidChange:(void*)object { // UIKeyboardNotifications - (void)keyboardWillShow:(NSNotification*)notification { + + _showingKeyboard = YES; + if (FBIsDeviceIPad()) { - // On the iPad the screen is large enough that we don't need to + // On the iPad the screen is large enough that we don't need to // resize the dialog to accomodate the keyboard popping up return; } @@ -469,11 +479,11 @@ - (void)keyboardWillShow:(NSNotification*)notification { -(kPadding + kBorderWidth), -(kPadding + kBorderWidth) - _titleLabel.frame.size.height); } - - _showingKeyboard = YES; } - (void)keyboardWillHide:(NSNotification*)notification { + _showingKeyboard = NO; + if (FBIsDeviceIPad()) { return; } @@ -483,13 +493,41 @@ - (void)keyboardWillHide:(NSNotification*)notification { kPadding + kBorderWidth, kPadding + kBorderWidth + _titleLabel.frame.size.height); } - - _showingKeyboard = NO; } - -/////////////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////////////// // public +/** + * Find a specific parameter from the url + */ +- (NSString *) getStringFromUrl: (NSString*) url needle:(NSString *) needle { + NSString * str = nil; + NSRange start = [url rangeOfString:needle]; + if (start.location != NSNotFound) { + NSRange end = [[url substringFromIndex:start.location+start.length] rangeOfString:@"&"]; + NSUInteger offset = start.location+start.length; + str = end.location == NSNotFound + ? [url substringFromIndex:offset] + : [url substringWithRange:NSMakeRange(offset, end.location)]; + str = [str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } + + return str; +} + +- (id)initWithURL: (NSString *) serverURL + params: (NSMutableDictionary *) params + delegate: (id ) delegate { + + self = [self init]; + _serverURL = [serverURL retain]; + _params = [params retain]; + _delegate = delegate; + + return self; +} + - (NSString*)title { return _titleLabel.text; } @@ -498,11 +536,24 @@ - (void)setTitle:(NSString*)title { _titleLabel.text = title; } +- (void)load { + [self loadURL:_serverURL get:_params]; +} + +- (void)loadURL:(NSString*)url get:(NSDictionary*)getParams { + + [_loadingURL release]; + _loadingURL = [[self generateURL:url params:getParams] retain]; + NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:_loadingURL]; + + [_webView loadRequest:request]; +} + - (void)show { [self load]; [self sizeToFitOrientation:NO]; - CGFloat innerWidth = self.frame.size.width - (kBorderWidth+1)*2; + CGFloat innerWidth = self.frame.size.width - (kBorderWidth+1)*2; [_iconView sizeToFit]; [_titleLabel sizeToFit]; [_closeButton sizeToFit]; @@ -512,7 +563,7 @@ - (void)show { kBorderWidth, innerWidth - (_titleLabel.frame.size.height + _iconView.frame.size.width + kTitleMarginX*2), _titleLabel.frame.size.height + kTitleMarginY*2); - + _iconView.frame = CGRectMake( kBorderWidth + kTitleMarginX, kBorderWidth + floor(_titleLabel.frame.size.height/2 - _iconView.frame.size.height/2), @@ -524,7 +575,7 @@ - (void)show { kBorderWidth, _titleLabel.frame.size.height, _titleLabel.frame.size.height); - + _webView.frame = CGRectMake( kBorderWidth+1, kBorderWidth + _titleLabel.frame.size.height, @@ -539,10 +590,15 @@ - (void)show { if (!window) { window = [[UIApplication sharedApplication].windows objectAtIndex:0]; } + + _modalBackgroundView.frame = window.frame; + [_modalBackgroundView addSubview:self]; + [window addSubview:_modalBackgroundView]; + [window addSubview:self]; [self dialogWillAppear]; - + self.transform = CGAffineTransformScale([self transformForOrientation], 0.001, 0.001); [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:kTransitionDuration/1.5]; @@ -556,12 +612,12 @@ - (void)show { - (void)dismissWithSuccess:(BOOL)success animated:(BOOL)animated { if (success) { - if ([_delegate respondsToSelector:@selector(dialogDidSucceed:)]) { - [_delegate dialogDidSucceed:self]; + if ([_delegate respondsToSelector:@selector(dialogDidComplete:)]) { + [_delegate dialogDidComplete:self]; } } else { - if ([_delegate respondsToSelector:@selector(dialogDidCancel:)]) { - [_delegate dialogDidCancel:self]; + if ([_delegate respondsToSelector:@selector(dialogDidNotComplete:)]) { + [_delegate dialogDidNotComplete:self]; } } @@ -576,53 +632,25 @@ - (void)dismissWithError:(NSError*)error animated:(BOOL)animated { [self dismiss:animated]; } -- (void)load { - // Intended for subclasses to override -} - -- (void)loadURL:(NSString*)url method:(NSString*)method get:(NSDictionary*)getParams - post:(NSDictionary*)postParams { - // This "test cookie" is required by login.php, or it complains that you need to enable JavaScript - NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - NSHTTPCookie* testCookie = [NSHTTPCookie cookieWithProperties: - [NSDictionary dictionaryWithObjectsAndKeys: - @"1", NSHTTPCookieValue, - @"test_cookie", NSHTTPCookieName, - @".facebook.com", NSHTTPCookieDomain, - @"/", NSHTTPCookiePath, - nil]]; - [cookies setCookie:testCookie]; - - [_loadingURL release]; - _loadingURL = [[self generateURL:url params:getParams] retain]; - NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:_loadingURL]; - - if (method) { - [request setHTTPMethod:method]; - - if ([[method uppercaseString] isEqualToString:@"POST"]) { - NSString* contentType = [NSString - stringWithFormat:@"multipart/form-data; boundary=%@", kStringBoundary]; - [request setValue:contentType forHTTPHeaderField:@"Content-Type"]; - - NSData* body = [self generatePostBody:postParams]; - if (body) { - [request setHTTPBody:body]; - } - } - } - - [_webView loadRequest:request]; -} - - (void)dialogWillAppear { } - (void)dialogWillDisappear { } -- (void)dialogDidSucceed:(NSURL*)url { +- (void)dialogDidSucceed:(NSURL *)url { + + if ([_delegate respondsToSelector:@selector(dialogCompleteWithUrl:)]) { + [_delegate dialogCompleteWithUrl:url]; + } [self dismissWithSuccess:YES animated:YES]; } +- (void)dialogDidCancel:(NSURL *)url { + if ([_delegate respondsToSelector:@selector(dialogDidNotCompleteWithUrl:)]) { + [_delegate dialogDidNotCompleteWithUrl:url]; + } + [self dismissWithSuccess:NO animated:YES]; +} + @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h deleted file mode 100644 index 50ba0f61..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBDialog.h" - -@interface FBFeedDialog : FBDialog { - long long _templateBundleId; - NSString* _templateData; - NSString* _bodyGeneral; -} - -/** - * The id for a previously registered template bundle. - */ -@property(nonatomic) long long templateBundleId; - -/** - * A JSON string containing template data. - * - * See http://wiki.developers.facebook.com/index.php/Template_Data - */ -@property(nonatomic,copy) NSString* templateData; - -/** - * Additional markup for a short story. - */ -@property(nonatomic,copy) NSString* bodyGeneral; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m deleted file mode 100644 index cc310fef..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBFeedDialog.h" -#import "FBSession.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kFeedURL = @"http://www.facebook.com/connect/prompt_feed.php"; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBFeedDialog - -@synthesize templateBundleId = _templateBundleId, templateData = _templateData, - bodyGeneral = _bodyGeneral; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -- (NSString*)generateFeedInfo { - NSMutableArray* pairs = [NSMutableArray array]; - - if (_templateBundleId) { - [pairs addObject:[NSString stringWithFormat:@"\"template_id\": %lld", _templateBundleId]]; - } - if (_templateData) { - [pairs addObject:[NSString stringWithFormat:@"\"template_data\": %@", _templateData]]; - } - if (_bodyGeneral) { - [pairs addObject:[NSString stringWithFormat:@"\"body_general\": \"%@\"", _bodyGeneral]]; - } - - return [NSString stringWithFormat:@"{%@}", [pairs componentsJoinedByString:@","]]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - if (self = [super initWithSession:session]) { - _templateBundleId = 0; - _templateData = nil; - _bodyGeneral = nil; - } - return self; -} - -- (void)dealloc { - [_templateData release]; - [_bodyGeneral release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBDialog - -- (void)load { - NSDictionary* getParams = [NSDictionary dictionaryWithObjectsAndKeys: - @"touch", @"display", nil]; - - NSString* feedInfo = [self generateFeedInfo]; - NSDictionary* postParams = [NSDictionary dictionaryWithObjectsAndKeys: - _session.apiKey, @"api_key", _session.sessionKey, @"session_key", - @"1", @"preview", @"fbconnect:success", @"callback", @"fbconnect:cancel", @"cancel", - feedInfo, @"feed_info", @"self_feed", @"feed_target_type", nil]; - - [self loadURL:kFeedURL method:@"POST" get:getParams post:postParams]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h deleted file mode 100644 index 4f98f4f5..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBSession.h" - -typedef enum { - FBLoginButtonStyleNormal, - FBLoginButtonStyleWide, -} FBLoginButtonStyle; - -/** - * Standard button which lets the user log in or out of the session. - * - * The button will automatically change to reflect the state of the session, showing - * "login" if the session is not connected, and "logout" if the session is connected. - */ -@interface FBLoginButton : UIControl { - FBLoginButtonStyle _style; - FBSession* _session; - UIImageView* _imageView; -} - -/** - * The visual style of the button. - */ -@property(nonatomic) FBLoginButtonStyle style; - -/** - * The session object that the button will log in and out of. - * - * The default value is the global session singleton, so there is usually no need to - * set this property yourself. - */ -@property(nonatomic,retain) FBSession* session; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m deleted file mode 100644 index 06b5818b..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBLoginButton.h" -#import "FBLoginDialog.h" - -#import - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -static UIAccessibilityTraits *traitImage = nil, *traitButton = nil; - -@implementation FBLoginButton - -@synthesize session = _session, style = _style; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -+ (void)initialize { - if (self == [FBLoginButton class]) { - // Try to load the accessibility trait values on OS 3.0 - traitImage = dlsym(RTLD_SELF, "UIAccessibilityTraitImage"); - traitButton = dlsym(RTLD_SELF, "UIAccessibilityTraitButton"); - } -} - -- (UIImage*)buttonImage { - if (_session.isConnected) { - return [UIImage imageNamed:@"FBConnect.bundle/images/logout.png"]; - } else { - if (_style == FBLoginButtonStyleNormal) { - return [UIImage imageNamed:@"FBConnect.bundle/images/login.png"]; - } else if (_style == FBLoginButtonStyleWide) { - return [UIImage imageNamed:@"FBConnect.bundle/images/login2.png"]; - } else { - return nil; - } - } -} - -- (UIImage*)buttonHighlightedImage { - if (_session.isConnected) { - return [UIImage imageNamed:@"FBConnect.bundle/images/logout_down.png"]; - } else { - if (_style == FBLoginButtonStyleNormal) { - return [UIImage imageNamed:@"FBConnect.bundle/images/login_down.png"]; - } else if (_style == FBLoginButtonStyleWide) { - return [UIImage imageNamed:@"FBConnect.bundle/images/login2_down.png"]; - } else { - return nil; - } - } -} - -- (void)updateImage { - if (self.highlighted) { - _imageView.image = [self buttonHighlightedImage]; - } else { - _imageView.image = [self buttonImage]; - } -} - -- (void)touchUpInside { - if (_session.isConnected) { - [_session logout]; - } else { - FBLoginDialog* dialog = [[[FBLoginDialog alloc] initWithSession:_session] autorelease]; - [dialog show]; - } -} - -- (void)initButton { - _style = FBLoginButtonStyleNormal; - - _imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; - _imageView.contentMode = UIViewContentModeCenter; - [self addSubview:_imageView]; - - self.backgroundColor = [UIColor clearColor]; - [self addTarget:self action:@selector(touchUpInside) - forControlEvents:UIControlEventTouchUpInside]; - - self.session = [FBSession session]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithFrame:(CGRect)frame { - if (self = [super initWithFrame:frame]) { - [self initButton]; - if (CGRectIsEmpty(frame)) { - [self sizeToFit]; - } - } - return self; -} - -- (void)awakeFromNib { - [self initButton]; -} - -- (void)dealloc { - [_session.delegates removeObject:self]; - [_session release]; - [_imageView release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// UIView - -- (CGSize)sizeThatFits:(CGSize)size { - return _imageView.image.size; -} - -- (void)layoutSubviews { - _imageView.frame = self.bounds; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// UIControl - -- (void)setHighlighted:(BOOL)highlighted { - [super setHighlighted:highlighted]; - [self updateImage]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBSessionDelegate - -- (void)session:(FBSession*)session didLogin:(FBUID)uid { - [self updateImage]; -} - -- (void)sessionDidLogout:(FBSession*)session { - [self updateImage]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// UIAccessibility informal protocol (on 3.0 only) - -- (BOOL)isAccessibilityElement { - return YES; -} - -- (UIAccessibilityTraits)accessibilityTraits { - if (traitImage && traitButton) - return [super accessibilityTraits]|*traitImage|*traitButton; - else - return [super accessibilityTraits]; -} - -- (NSString *)accessibilityLabel { - if (_session.isConnected) { - return NSLocalizedString(@"Disconnect from Facebook", @"Accessibility label"); - } else { - return NSLocalizedString(@"Connect to Facebook", @"Accessibility label"); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// public - -- (void)setSession:(FBSession*)session { - if (session != _session) { - [_session.delegates removeObject:self]; - [_session release]; - _session = [session retain]; - [_session.delegates addObject:self]; - - [self updateImage]; - } -} - -- (void)setStyle:(FBLoginButtonStyle)style { - _style = style; - - [self updateImage]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h index 8eb0b908..f5c6ebae 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h @@ -1,10 +1,10 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software @@ -12,13 +12,37 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ + #import "FBDialog.h" -#import "FBRequest.h" -@interface FBLoginDialog : FBDialog { - FBRequest* _getSessionRequest; +@protocol FBLoginDialogDelegate; + +/** + * Do not use this interface directly, instead, use authorize in Facebook.h + * + * Facebook Login Dialog interface for start the facebook webView login dialog. + * It start pop-ups prompting for credentials and permissions. + */ + +@interface FBLoginDialog : FBDialog { + id _loginDelegate; } +-(id) initWithURL:(NSString *) loginURL + loginParams:(NSMutableDictionary *) params + delegate:(id ) delegate; @end + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@protocol FBLoginDialogDelegate + +- (void)fbDialogLogin:(NSString*)token expirationDate:(NSDate*)expirationDate; + +- (void)fbDialogNotLogin:(BOOL)cancelled; + +@end + + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m index 9d49f603..70552bf8 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m @@ -1,131 +1,94 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 - + * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ +#import "FBDialog.h" #import "FBLoginDialog.h" -#import "FBSession.h" -#import "FBRequest.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kLoginURL = @"http://www.facebook.com/login.php"; /////////////////////////////////////////////////////////////////////////////////////////////////// @implementation FBLoginDialog /////////////////////////////////////////////////////////////////////////////////////////////////// -// private +// public -- (void)connectToGetSession:(NSString*)token { - _getSessionRequest = [[FBRequest requestWithSession:_session delegate:self] retain]; - NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObject:token forKey:@"auth_token"]; - if (!_session.apiSecret) { - [params setObject:@"1" forKey:@"generate_session_secret"]; - } +/* + * initialize the FBLoginDialog with url and parameters + */ +- (id)initWithURL:(NSString*) loginURL + loginParams:(NSMutableDictionary*) params + delegate:(id ) delegate{ - if (_session.getSessionProxy) { - [_getSessionRequest post:_session.getSessionProxy params:params]; - } else { - [_getSessionRequest call:@"facebook.auth.getSession" params:params]; - } -} - -- (void)loadLoginPage { - NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: - @"1", @"fbconnect", @"touch", @"connect_display", _session.apiKey, @"api_key", - @"fbconnect://success", @"next", nil]; - - [self loadURL:kLoginURL method:@"GET" get:params post:nil]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - if (self = [super initWithSession:session]) { - _getSessionRequest = nil; - } + self = [super init]; + _serverURL = [loginURL retain]; + _params = [params retain]; + _loginDelegate = delegate; return self; } -- (void)dealloc { - _getSessionRequest.delegate = nil; - [_getSessionRequest release]; - [super dealloc]; -} - /////////////////////////////////////////////////////////////////////////////////////////////////// // FBDialog -- (void)load { - [self loadLoginPage]; -} - -- (void)dialogWillDisappear { - [_webView stringByEvaluatingJavaScriptFromString:@"email.blur();"]; - - [_getSessionRequest cancel]; +/** + * Override FBDialog : to call when the webView Dialog did succeed + */ +- (void) dialogDidSucceed:(NSURL*)url { + NSString *q = [url absoluteString]; + NSString *token = [self getStringFromUrl:q needle:@"access_token="]; + NSString *expTime = [self getStringFromUrl:q needle:@"expires_in="]; + NSDate *expirationDate =nil; - if (![_session isConnected]) { - [_session cancelLogin]; + if (expTime != nil) { + int expVal = [expTime intValue]; + if (expVal == 0) { + expirationDate = [NSDate distantFuture]; + } else { + expirationDate = [NSDate dateWithTimeIntervalSinceNow:expVal]; + } + } + + if ((token == (NSString *) [NSNull null]) || (token.length == 0)) { + [self dialogDidCancel:url]; + [self dismissWithSuccess:NO animated:YES]; + } else { + if ([_loginDelegate respondsToSelector:@selector(fbDialogLogin:expirationDate:)]) { + [_loginDelegate fbDialogLogin:token expirationDate:expirationDate]; + } + [self dismissWithSuccess:YES animated:YES]; } + } -- (void)dialogDidSucceed:(NSURL*)url { - NSString* q = url.query; - NSRange start = [q rangeOfString:@"auth_token="]; - if (start.location != NSNotFound) { - NSRange end = [q rangeOfString:@"&"]; - NSUInteger offset = start.location+start.length; - NSString* token = end.location == NSNotFound - ? [q substringFromIndex:offset] - : [q substringWithRange:NSMakeRange(offset, end.location-offset)]; - - if (token) { - [self connectToGetSession:token]; - } +/** + * Override FBDialog : to call with the login dialog get canceled + */ +- (void)dialogDidCancel:(NSURL *)url { + [self dismissWithSuccess:NO animated:YES]; + if ([_loginDelegate respondsToSelector:@selector(fbDialogNotLogin:)]) { + [_loginDelegate fbDialogNotLogin:YES]; } } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBRequestDelegate - -- (void)request:(FBRequest*)request didLoad:(id)result { - NSDictionary* object = result; - FBUID uid = [[object objectForKey:@"uid"] longLongValue]; - NSString* sessionKey = [object objectForKey:@"session_key"]; - NSString* sessionSecret = [object objectForKey:@"secret"]; - NSTimeInterval expires = [[object objectForKey:@"expires"] floatValue]; - NSDate* expiration = expires ? [NSDate dateWithTimeIntervalSince1970:expires] : nil; - - [_getSessionRequest release]; - _getSessionRequest = nil; - - [_session begin:uid sessionKey:sessionKey sessionSecret:sessionSecret expires:expiration]; - [_session resume]; - - [self dismissWithSuccess:YES animated:YES]; +- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { + if (!(([error.domain isEqualToString:@"NSURLErrorDomain"] && error.code == -999) || + ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102))) { + [super webView:webView didFailLoadWithError:error]; + if ([_loginDelegate respondsToSelector:@selector(fbDialogNotLogin:)]) { + [_loginDelegate fbDialogNotLogin:NO]; + } + } } -- (void)request:(FBRequest*)request didFailWithError:(NSError*)error { - [_getSessionRequest release]; - _getSessionRequest = nil; - - [self dismissWithError:error animated:YES]; -} - @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h deleted file mode 100644 index d203ddbe..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBLoginDialog.h" - -@interface FBPermissionDialog : FBLoginDialog { - NSString* _permission; - NSTimer* _redirectTimer; -} - -/** - * The extended permission to request. - * - * See http://wiki.developers.facebook.com/index.php/Extended_permissions - */ -@property(nonatomic,copy) NSString* permission; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m deleted file mode 100644 index f604ef6e..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBPermissionDialog.h" -#import "FBSession.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kPermissionURL = @"http://www.facebook.com/connect/prompt_permission.php"; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBPermissionDialog - -@synthesize permission = _permission; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -- (void)redirectToLoginDelayed { - _redirectTimer = nil; - - // This loads the login page, which will just redirect back to the callback url - // since the login cookies are set - [super load]; -} - -- (void)redirectToLogin { - _redirectTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self - selector:@selector(redirectToLoginDelayed) userInfo:nil repeats:NO]; -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - if (self = [super initWithSession:session]) { - _permission = nil; - _redirectTimer = nil; - } - return self; -} - -- (void)dealloc { - [_redirectTimer invalidate]; - [_permission release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBDialog - -- (void)load { - NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: - @"touch", @"display", _session.apiKey, @"api_key", _session.sessionKey, @"session_key", - _permission, @"ext_perm", @"fbconnect:success", @"next", @"fbconnect:cancel", @"cancel", nil]; - - [self loadURL:kPermissionURL method:@"GET" get:params post:nil]; -} - -- (void)dialogDidSucceed:(NSURL*)url { - if ([_permission isEqualToString:@"offline_access"]) { - [super dialogDidSucceed:url]; - } else { - [self dismissWithSuccess:YES animated:YES]; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// UIWebViewDelegate - -- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request - navigationType:(UIWebViewNavigationType)navigationType { - if ([_permission isEqualToString:@"offline_access"]) { - NSURL* url = request.URL; - if ([url.scheme isEqualToString:@"fbconnect"]) { - if ([url.resourceSpecifier isEqualToString:@"success"]) { - [self redirectToLogin]; - return NO; - } - } - } - return [super webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h index 75ac9e74..f44b6f50 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h @@ -1,10 +1,10 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software @@ -12,126 +12,71 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ -#import "FBConnectGlobal.h" +#import +#import @protocol FBRequestDelegate; -@class FBSession; +/** + * Do not use this interface directly, instead, use method in Facebook.h + */ @interface FBRequest : NSObject { - FBSession* _session; id _delegate; NSString* _url; - NSString* _method; - id _userInfo; + NSString* _httpMethod; NSMutableDictionary* _params; - NSObject* _dataParam; - NSDate* _timestamp; NSURLConnection* _connection; NSMutableData* _responseText; } -/** - * Creates a new API request for the global session. - */ -+ (FBRequest*)request; - -/** - * Creates a new API request for the global session with a delegate. - */ -+ (FBRequest*)requestWithDelegate:(id)delegate; - -/** - * Creates a new API request for a particular session. - */ -+ (FBRequest*)requestWithSession:(FBSession*)session; - -/** - * Creates a new API request for the global session with a delegate. - */ -+ (FBRequest*)requestWithSession:(FBSession*)session delegate:(id)delegate; @property(nonatomic,assign) id delegate; /** * The URL which will be contacted to execute the request. */ -@property(nonatomic,readonly) NSString* url; +@property(nonatomic,copy) NSString* url; /** * The API method which will be called. */ -@property(nonatomic,readonly) NSString* method; - -/** - * An object used by the user of the request to help identify the meaning of the request. - */ -@property(nonatomic,retain) id userInfo; +@property(nonatomic,copy) NSString* httpMethod; /** * The dictionary of parameters to pass to the method. * - * These values in the dictionary will be converted to strings using the + * These values in the dictionary will be converted to strings using the * standard Objective-C object-to-string conversion facilities. */ -@property(nonatomic,readonly) NSDictionary* params; +@property(nonatomic,retain) NSMutableDictionary* params; +@property(nonatomic,assign) NSURLConnection* connection; +@property(nonatomic,assign) NSMutableData* responseText; -/** - * A data parameter. - * - * Used for methods such as photos.upload, video.upload, events.create, and - * events.edit. - */ -@property(nonatomic,readonly) NSObject* dataParam; -/** - * The timestamp of when the request was sent to the server. - */ -@property(nonatomic,readonly) NSDate* timestamp; ++ (NSString*)serializeURL:(NSString *)baseUrl + params:(NSDictionary *)params; -/** - * Indicates if the request has been sent and is awaiting a response. - */ -@property(nonatomic,readonly) BOOL loading; ++ (NSString*)serializeURL:(NSString *)baseUrl + params:(NSDictionary *)params + httpMethod:(NSString *)httpMethod; -/** - * Creates a new request paired to a session. - */ -- (id)initWithSession:(FBSession*)session; ++ (FBRequest*)getRequestWithParams:(NSMutableDictionary *) params + httpMethod:(NSString *) httpMethod + delegate:(id)delegate + requestURL:(NSString *) url; +- (BOOL) loading; -/** - * Calls a method on the server asynchronously. - * - * The delegate will be called for each stage of the loading process. - */ -- (void)call:(NSString*)method params:(NSDictionary*)params; - -/** - * Calls a method on the server asynchronously, with a file upload component. - * - * The delegate will be called for each stage of the loading process. - */ -- (void)call:(NSString*)method params:(NSDictionary*)params dataParam:(NSData*)dataParam; - -/** - * Calls a URL on the server asynchronously. - * - * The delegate will be called for each stage of the loading process. - */ -- (void)post:(NSString*)url params:(NSDictionary*)params; - -/** - * Stops an active request before the response has returned. - */ -- (void)cancel; - -- (void)connect; +- (void) connect; @end -/////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/* + *Your application should implement this delegate + */ @protocol FBRequestDelegate @optional @@ -139,29 +84,33 @@ /** * Called just before the request is sent to the server. */ -- (void)requestLoading:(FBRequest*)request; +- (void)requestLoading:(FBRequest *)request; /** * Called when the server responds and begins to send back data. */ -- (void)request:(FBRequest*)request didReceiveResponse:(NSURLResponse*)response; +- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response; /** * Called when an error prevents the request from completing successfully. */ -- (void)request:(FBRequest*)request didFailWithError:(NSError*)error; +- (void)request:(FBRequest *)request didFailWithError:(NSError *)error; /** - * Called when a request returns and its response has been parsed into an object. + * Called when a request returns and its response has been parsed into + * an object. * - * The resulting object may be a dictionary, an array, a string, or a number, depending - * on thee format of the API response. + * The resulting object may be a dictionary, an array, a string, or a number, + * depending on thee format of the API response. */ -- (void)request:(FBRequest*)request didLoad:(id)result; +- (void)request:(FBRequest *)request didLoad:(id)result; /** - * Called when the request was cancelled. + * Called when a request returns a response. + * + * The result object is the raw response from the server of type NSData */ -- (void)requestWasCancelled:(FBRequest*)request; +- (void)request:(FBRequest *)request didLoadRawResponse:(NSData *)data; @end + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m index 50dd54e5..7b2cc2ea 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m @@ -1,10 +1,10 @@ /* - * Copyright 2009 Facebook + * Copyright 2010 Facebook * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software @@ -12,20 +12,17 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ #import "FBRequest.h" -#import "FBSession.h" -#import "FBXMLHandler.h" -#import +#import "JSON.h" /////////////////////////////////////////////////////////////////////////////////////////////////// // global -static NSString* kAPIVersion = @"1.0"; -static NSString* kAPIFormat = @"XML"; static NSString* kUserAgent = @"FacebookConnect"; static NSString* kStringBoundary = @"3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f"; +static const int kGeneralErrorCode = 10000; static const NSTimeInterval kTimeoutInterval = 180.0; @@ -33,281 +30,328 @@ @implementation FBRequest -@synthesize delegate = _delegate, - url = _url, - method = _method, - params = _params, - dataParam = _dataParam, - userInfo = _userInfo, - timestamp = _timestamp; +@synthesize delegate = _delegate, + url = _url, + httpMethod = _httpMethod, + params = _params, + connection = _connection, + responseText = _responseText; -/////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////// // class public -+ (FBRequest*)request { - return [self requestWithSession:[FBSession session]]; -} ++ (FBRequest *)getRequestWithParams:(NSMutableDictionary *) params + httpMethod:(NSString *) httpMethod + delegate:(id) delegate + requestURL:(NSString *) url { -+ (FBRequest*)requestWithDelegate:(id)delegate { - return [self requestWithSession:[FBSession session] delegate:delegate]; -} - -+ (FBRequest*)requestWithSession:(FBSession*)session { - return [[[FBRequest alloc] initWithSession:session] autorelease]; -} - -+ (FBRequest*)requestWithSession:(FBSession*)session delegate:(id)delegate { - FBRequest* request = [[[FBRequest alloc] initWithSession:session] autorelease]; + FBRequest* request = [[[FBRequest alloc] init] autorelease]; request.delegate = delegate; + request.url = url; + request.httpMethod = httpMethod; + request.params = params; + request.connection = nil; + request.responseText = nil; + return request; } /////////////////////////////////////////////////////////////////////////////////////////////////// // private -- (NSString*)md5HexDigest:(NSString*)input { - const char* str = [input UTF8String]; - unsigned char result[CC_MD5_DIGEST_LENGTH]; - CC_MD5(str, strlen(str), result); - - NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2]; - for(int i = 0; i 0) { + for (id key in dataDictionary) { + NSObject *dataParam = [dataDictionary valueForKey:key]; + if ([dataParam isKindOfClass:[UIImage class]]) { + NSData* imageData = UIImagePNGRepresentation((UIImage*)dataParam); + [self utfAppendBody:body + data:[NSString stringWithFormat: + @"Content-Disposition: form-data; filename=\"%@\"\r\n", key]]; + [self utfAppendBody:body + data:[NSString stringWithString:@"Content-Type: image/png\r\n\r\n"]]; + [body appendData:imageData]; + } else { + NSAssert([dataParam isKindOfClass:[NSData class]], + @"dataParam must be a UIImage or NSData"); + [self utfAppendBody:body + data:[NSString stringWithFormat: + @"Content-Disposition: form-data; filename=\"%@\"\r\n", key]]; + [self utfAppendBody:body + data:[NSString stringWithString:@"Content-Type: content/unknown\r\n\r\n"]]; + [body appendData:(NSData*)dataParam]; + } + [self utfAppendBody:body data:endLine]; + } - [self utfAppendBody:body data:endLine]; } - - FBLOG2(@"Sending %s", [body bytes]); + return body; } -- (id)parseXMLResponse:(NSData*)data error:(NSError**)error { - FBXMLHandler* handler = [[[FBXMLHandler alloc] init] autorelease]; - NSXMLParser* parser = [[[NSXMLParser alloc] initWithData:data] autorelease]; - parser.delegate = handler; - [parser parse]; +/** + * Formulate the NSError + */ +- (id)formError:(NSInteger)code userInfo:(NSDictionary *) errorData { + return [NSError errorWithDomain:@"facebookErrDomain" code:code userInfo:errorData]; - if (handler.parseError) { - if (error) { - *error = [[handler.parseError retain] autorelease]; +} + +/** + * parse the response data + */ +- (id)parseJsonResponse:(NSData *)data error:(NSError **)error { + + NSString* responseString = [[[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding] + autorelease]; + SBJSON *jsonParser = [[SBJSON new] autorelease]; + if ([responseString isEqualToString:@"true"]) { + return [NSDictionary dictionaryWithObject:@"true" forKey:@"result"]; + } else if ([responseString isEqualToString:@"false"]) { + if (error != nil) { + *error = [self formError:kGeneralErrorCode + userInfo:[NSDictionary + dictionaryWithObject:@"This operation can not be completed" + forKey:@"error_msg"]]; } return nil; - } else if ([handler.rootName isEqualToString:@"error_response"]) { - NSDictionary* errorDict = handler.rootObject; - NSInteger code = [[errorDict objectForKey:@"error_code"] intValue]; - NSDictionary* info = [NSDictionary dictionaryWithObjectsAndKeys: - [errorDict objectForKey:@"error_msg"], NSLocalizedDescriptionKey, - [errorDict objectForKey:@"request_args"], @"request_args", - nil]; - if (error) { - *error = [NSError errorWithDomain:FBAPI_ERROR_DOMAIN code:code userInfo:info]; + } + + + id result = [jsonParser objectWithString:responseString]; + + if (![result isKindOfClass:[NSArray class]]) { + if ([result objectForKey:@"error"] != nil) { + if (error != nil) { + *error = [self formError:kGeneralErrorCode + userInfo:result]; + } + return nil; + } + + if ([result objectForKey:@"error_code"] != nil) { + if (error != nil) { + *error = [self formError:[[result objectForKey:@"error_code"] intValue] userInfo:result]; + } + return nil; + } + + if ([result objectForKey:@"error_msg"] != nil) { + if (error != nil) { + *error = [self formError:kGeneralErrorCode userInfo:result]; + } + } + + if ([result objectForKey:@"error_reason"] != nil) { + if (error != nil) { + *error = [self formError:kGeneralErrorCode userInfo:result]; + } } - return nil; - } else { - return [[handler.rootObject retain] autorelease]; } + + return result; + } -- (void)failWithError:(NSError*)error { +/* + * private helper function: call the delegate function when the request + * fails with error + */ +- (void)failWithError:(NSError *)error { if ([_delegate respondsToSelector:@selector(request:didFailWithError:)]) { [_delegate request:self didFailWithError:error]; } } -- (void)handleResponseData:(NSData*)data { - FBLOG2(@"DATA: %s", data.bytes); - NSError* error = nil; - id result = [self parseXMLResponse:data error:&error]; - if (error) { - [self failWithError:error]; - } else if ([_delegate respondsToSelector:@selector(request:didLoad:)]) { - [_delegate request:self didLoad:result]; +/* + * private helper function: handle the response data + */ +- (void)handleResponseData:(NSData *)data { + if ([_delegate respondsToSelector: + @selector(request:didLoadRawResponse:)]) { + [_delegate request:self didLoadRawResponse:data]; } + + if ([_delegate respondsToSelector:@selector(request:didLoad:)] || + [_delegate respondsToSelector: + @selector(request:didFailWithError:)]) { + NSError* error = nil; + id result = [self parseJsonResponse:data error:&error]; + + if (error) { + [self failWithError:error]; + } else if ([_delegate respondsToSelector: + @selector(request:didLoad:)]) { + [_delegate request:self didLoad:(result == nil ? data : result)]; + } + + } + } + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// public + +/** + * @return boolean - whether this request is processing + */ +- (BOOL)loading { + return !!_connection; +} + +/** + * make the Facebook request + */ - (void)connect { - FBLOG(@"Connecting to %@ %@", _url, _params); if ([_delegate respondsToSelector:@selector(requestLoading:)]) { [_delegate requestLoading:self]; } - NSString* url = _method ? _url : [self generateGetURL]; - NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData - timeoutInterval:kTimeoutInterval]; + NSString* url = [[self class] serializeURL:_url params:_params httpMethod:_httpMethod]; + NSMutableURLRequest* request = + [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:kTimeoutInterval]; [request setValue:kUserAgent forHTTPHeaderField:@"User-Agent"]; - - if (_method) { - [request setHTTPMethod:@"POST"]; - + + + [request setHTTPMethod:self.httpMethod]; + if ([self.httpMethod isEqualToString: @"POST"]) { NSString* contentType = [NSString - stringWithFormat:@"multipart/form-data; boundary=%@", kStringBoundary]; + stringWithFormat:@"multipart/form-data; boundary=%@", kStringBoundary]; [request setValue:contentType forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:[self generatePostBody]]; } - - _timestamp = [[NSDate date] retain]; + _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; -} -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - _session = session; - _delegate = nil; - _url = nil; - _method = nil; - _params = nil; - _userInfo = nil; - _timestamp = nil; - _connection = nil; - _responseText = nil; - return self; } +/** + * Free internal structure + */ - (void)dealloc { [_connection cancel]; [_connection release]; [_responseText release]; [_url release]; - [_method release]; + [_httpMethod release]; [_params release]; - [_userInfo release]; - [_timestamp release]; [super dealloc]; } -- (NSString*)description { - return [NSString stringWithFormat:@"", _method ? _method : _url]; -} - ////////////////////////////////////////////////////////////////////////////////////////////////// // NSURLConnectionDelegate - -- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { _responseText = [[NSMutableData alloc] init]; NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; - if ([_delegate respondsToSelector:@selector(request:didReceiveResponse:)]) { + if ([_delegate respondsToSelector: + @selector(request:didReceiveResponse:)]) { [_delegate request:self didReceiveResponse:httpResponse]; } } --(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [_responseText appendData:data]; } -- (NSCachedURLResponse*)connection:(NSURLConnection*)connection +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse { return nil; } --(void)connectionDidFinishLoading:(NSURLConnection*)connection { +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { [self handleResponseData:_responseText]; - + [_responseText release]; _responseText = nil; [_connection release]; _connection = nil; } -- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error { +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { [self failWithError:error]; [_responseText release]; @@ -316,63 +360,4 @@ - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error _connection = nil; } -////////////////////////////////////////////////////////////////////////////////////////////////// -// public - -- (BOOL)loading { - return !!_connection; -} - -- (void)call:(NSString*)method params:(NSDictionary*)params { - [self call:method params:params dataParam:nil]; -} - -- (void)call:(NSString*)method params:(NSDictionary*)params dataParam:(NSData*)dataParam { - _url = [[self urlForMethod:method] retain]; - _method = [method copy]; - _params = params - ? [[NSMutableDictionary alloc] initWithDictionary:params] - : [[NSMutableDictionary alloc] init]; - _dataParam = dataParam; - - [_params setObject:_method forKey:@"method"]; - [_params setObject:_session.apiKey forKey:@"api_key"]; - [_params setObject:kAPIVersion forKey:@"v"]; - [_params setObject:kAPIFormat forKey:@"format"]; - - if (![self isSpecialMethod]) { - [_params setObject:_session.sessionKey forKey:@"session_key"]; - [_params setObject:[self generateCallId] forKey:@"call_id"]; - - if (_session.sessionSecret) { - [_params setObject:@"1" forKey:@"ss"]; - } - } - - [_params setObject:[self generateSig] forKey:@"sig"]; - - [_session send:self]; -} - -- (void)post:(NSString*)url params:(NSDictionary*)params { - _url = [url retain]; - _params = params - ? [[NSMutableDictionary alloc] initWithDictionary:params] - : [[NSMutableDictionary alloc] init]; - - [_session send:self]; -} - -- (void)cancel { - if (_connection) { - [_connection cancel]; - [_connection release]; - _connection = nil; - - if ([_delegate respondsToSelector:@selector(requestWasCancelled:)]) { - [_delegate requestWasCancelled:self]; - } - } -} - @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h deleted file mode 100644 index 15c77f50..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBConnectGlobal.h" - -@protocol FBSessionDelegate; -@class FBRequest; - -/** - * An FBSession represents a single user's authenticated session for a Facebook application. - * - * To create a session, you must use the session key of your application (which can - * be found on the Facebook developer website). You may then use the login dialog to ask - * the user to enter their email address and password. If successful, you will get back a - * session key which can be used to make requests to the Facebook API. - * - * Session keys are cached and stored on the disk of the device so that you do not need to ask - * the user to login every time they launch the app. To restore the last active session, call the - * resume method after instantiating your session. - */ -@interface FBSession : NSObject { - NSMutableArray* _delegates; - NSString* _apiKey; - NSString* _apiSecret; - NSString* _getSessionProxy; - FBUID _uid; - NSString* _sessionKey; - NSString* _sessionSecret; - NSDate* _expirationDate; - NSMutableArray* _requestQueue; - NSDate* _lastRequestTime; - int _requestBurstCount; - NSTimer* _requestTimer; -} - -/** - * Delegates which implement FBSessionDelegate. - */ -@property(nonatomic,readonly) NSMutableArray* delegates; - -/** - * The URL used for API HTTP requests. - */ -@property(nonatomic,readonly) NSString* apiURL; - -/** - * The URL used for secure API HTTP requests. - */ -@property(nonatomic,readonly) NSString* apiSecureURL; - -/** - * Your application's API key, as passed to the constructor. - */ -@property(nonatomic,readonly) NSString* apiKey; - -/** - * Your application's API secret, as passed to the constructor. - */ -@property(nonatomic,readonly) NSString* apiSecret; - -/** - * The URL to call to create a session key after login. - * - * This is an alternative to calling auth.getSession directly using the secret key. - */ -@property(nonatomic,readonly) NSString* getSessionProxy; - -/** - * The current user's Facebook id. - */ -@property(nonatomic,readonly) FBUID uid; - -/** - * The current user's session key. - */ -@property(nonatomic,readonly) NSString* sessionKey; - -/** - * The current user's session secret. - */ -@property(nonatomic,readonly) NSString* sessionSecret; - -/** - * The expiration date of the session key. - */ -@property(nonatomic,readonly) NSDate* expirationDate; - -/** - * Determines if the session is active and connected to a user. - */ -@property(nonatomic,readonly) BOOL isConnected; - -/** - * The globally shared session instance. - */ -+ (FBSession*)session; - -/** - * Sets the globally shared session instance. - * - * This session is not retained, so you are still responsible for retaining it yourself. The - * first session that is created is automatically stored here. - */ -+ (void)setSession:(FBSession*)session; - -/** - * Constructs a session and stores it as the globally shared session instance. - * - * @param secret the application secret (optional) - */ -+ (FBSession*)sessionForApplication:(NSString*)key secret:(NSString*)secret - delegate:(id)delegate; - -/** - * Constructs a session and stores it as the global singleton. - * - * @param getSessionProxy a url to that proxies auth.getSession (optional) - */ -+ (FBSession*)sessionForApplication:(NSString*)key getSessionProxy:(NSString*)getSessionProxy - delegate:(id)delegate; - -/** - * Constructs a session for an application. - * - * @param secret the application secret (optional) - * @param getSessionProxy a url to that proxies auth.getSession (optional) - */ -- (FBSession*)initWithKey:(NSString*)key secret:(NSString*)secret - getSessionProxy:(NSString*)getSessionProxy; - -/** - * Begins a session for a user with a given key and secret. - */ -- (void)begin:(FBUID)uid sessionKey:(NSString*)sessionKey sessionSecret:(NSString*)sessionSecret - expires:(NSDate*)expires; - -/** - * Resumes a previous session whose uid, session key, and secret are cached on disk. - */ -- (BOOL)resume; - -/** - * Cancels a login (no-op if the login is already complete). - */ -- (void)cancelLogin; - -/** - * Ends the current session and deletes the uid, session key, and secret from disk. - */ -- (void)logout; - -/** - * Sends a fully configured request to the server for execution. - */ -- (void)send:(FBRequest*)request; - -/** - * Deletes all cookies belonging to facebook - */ -- (void)deleteFacebookCookies; - -- (void)requestTimerReady; - -@end - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@protocol FBSessionDelegate - -/** - * Called when a user has successfully logged in and begun a session. - */ -- (void)session:(FBSession*)session didLogin:(FBUID)uid; - -@optional - -/** - * Called when a user closes the login dialog without logging in. - */ -- (void)sessionDidNotLogin:(FBSession*)session; - -/** - * Called when a session is about to log out. - */ -- (void)session:(FBSession*)session willLogout:(FBUID)uid; - -/** - * Called when a session has logged out. - */ -- (void)sessionDidLogout:(FBSession*)session; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m deleted file mode 100644 index c21f11bb..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBSession.h" -#import "FBRequest.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kAPIRestURL = @"http://api.facebook.com/restserver.php"; -static NSString* kAPIRestSecureURL = @"https://api.facebook.com/restserver.php"; - -static const int kMaxBurstRequests = 3; -static const NSTimeInterval kBurstDuration = 2; - -static FBSession* sharedSession = nil; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBSession - -@synthesize delegates = _delegates, apiKey = _apiKey, apiSecret = _apiSecret, - getSessionProxy = _getSessionProxy, uid = _uid, sessionKey = _sessionKey, - sessionSecret = _sessionSecret, expirationDate = _expirationDate; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// class public - -+ (FBSession*)session { - return sharedSession; -} - -+ (void)setSession:(FBSession*)session { - sharedSession = session; -} - -+ (FBSession*)sessionForApplication:(NSString*)key secret:(NSString*)secret - delegate:(id)delegate { - FBSession* session = [[[FBSession alloc] initWithKey:key secret:secret - getSessionProxy:nil] autorelease]; - [session.delegates addObject:delegate]; - return session; -} - -+ (FBSession*)sessionForApplication:(NSString*)key getSessionProxy:(NSString*)getSessionProxy - delegate:(id)delegate { - FBSession* session = [[[FBSession alloc] initWithKey:key secret:nil - getSessionProxy:getSessionProxy] autorelease]; - [session.delegates addObject:delegate]; - return session; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -- (void)save { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - if (_uid) { - [defaults setObject:[NSNumber numberWithLongLong:_uid] forKey:@"FBUserId"]; - } else { - [defaults removeObjectForKey:@"FBUserId"]; - } - - if (_sessionKey) { - [defaults setObject:_sessionKey forKey:@"FBSessionKey"]; - } else { - [defaults removeObjectForKey:@"FBSessionKey"]; - } - - if (_sessionSecret) { - [defaults setObject:_sessionSecret forKey:@"FBSessionSecret"]; - } else { - [defaults removeObjectForKey:@"FBSessionSecret"]; - } - - if (_expirationDate) { - [defaults setObject:_expirationDate forKey:@"FBSessionExpires"]; - } else { - [defaults removeObjectForKey:@"FBSessionExpires"]; - } - - [defaults synchronize]; -} - -- (void)unsave { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - [defaults removeObjectForKey:@"FBUserId"]; - [defaults removeObjectForKey:@"FBSessionKey"]; - [defaults removeObjectForKey:@"FBSessionSecret"]; - [defaults removeObjectForKey:@"FBSessionExpires"]; - [defaults synchronize]; -} - -- (void)startFlushTimer { - if (!_requestTimer) { - NSTimeInterval t = kBurstDuration + [_lastRequestTime timeIntervalSinceNow]; - _requestTimer = [NSTimer scheduledTimerWithTimeInterval:t target:self - selector:@selector(requestTimerReady) userInfo:nil repeats:NO]; - } -} - -- (void)enqueueRequest:(FBRequest*)request { - [_requestQueue addObject:request]; - [self startFlushTimer]; -} - -- (BOOL)performRequest:(FBRequest*)request enqueue:(BOOL)enqueue { - // Stagger requests that happen in short bursts to prevent the server from rejecting - // them for making too many requests in a short time - NSTimeInterval t = [_lastRequestTime timeIntervalSinceNow]; - BOOL burst = t && t > -kBurstDuration; - if (burst && ++_requestBurstCount > kMaxBurstRequests) { - if (enqueue) { - [self enqueueRequest:request]; - } - return NO; - } else { - [request performSelector:@selector(connect)]; - - if (!burst) { - _requestBurstCount = 1; - [_lastRequestTime release]; - _lastRequestTime = [[request timestamp] retain]; - } - } - return YES; -} - -- (void)flushRequestQueue { - while (_requestQueue.count) { - FBRequest* request = [_requestQueue objectAtIndex:0]; - if ([self performRequest:request enqueue:NO]) { - [_requestQueue removeObjectAtIndex:0]; - } else { - [self startFlushTimer]; - break; - } - } -} - -- (void)requestTimerReady { - _requestTimer = nil; - [self flushRequestQueue]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (FBSession*)initWithKey:(NSString*)key secret:(NSString*)secret - getSessionProxy:(NSString*)getSessionProxy { - if (self = [super init]) { - if (!sharedSession) { - sharedSession = self; - } - - _delegates = FBCreateNonRetainingArray(); - _apiKey = [key copy]; - _apiSecret = [secret copy]; - _getSessionProxy = [getSessionProxy copy]; - _uid = 0; - _sessionKey = nil; - _sessionSecret = nil; - _expirationDate = nil; - _requestQueue = [[NSMutableArray alloc] init]; - _lastRequestTime = nil; - _requestBurstCount = 0; - _requestTimer = nil; - } - return self; -} - -- (void)dealloc { - if (sharedSession == self) { - sharedSession = nil; - } - - [_delegates release]; - [_requestQueue release]; - [_apiKey release]; - [_apiSecret release]; - [_getSessionProxy release]; - [_sessionKey release]; - [_sessionSecret release]; - [_expirationDate release]; - [_lastRequestTime release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// public - -- (NSString*)apiURL { - return kAPIRestURL; -} - -- (NSString*)apiSecureURL { - return kAPIRestSecureURL; -} - -- (BOOL)isConnected { - return !!_sessionKey; -} - -- (void)begin:(FBUID)uid sessionKey:(NSString*)sessionKey - sessionSecret:(NSString*)sessionSecret expires:(NSDate*)expires { - _uid = uid; - _sessionKey = [sessionKey copy]; - _sessionSecret = [sessionSecret copy]; - _expirationDate = [expires retain]; - - [self save]; -} - -- (BOOL)resume { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - FBUID uid = [[defaults objectForKey:@"FBUserId"] longLongValue]; - if (uid) { - NSDate* expirationDate = [defaults objectForKey:@"FBSessionExpires"]; - if (!expirationDate || [expirationDate timeIntervalSinceNow] > 0) { - _uid = uid; - _sessionKey = [[defaults stringForKey:@"FBSessionKey"] copy]; - _sessionSecret = [[defaults stringForKey:@"FBSessionSecret"] copy]; - _expirationDate = [expirationDate retain]; - - for (id delegate in _delegates) { - [delegate session:self didLogin:_uid]; - } - return YES; - } - } - return NO; -} - -- (void)cancelLogin { - if (![self isConnected]) { - for (id delegate in _delegates) { - if ([delegate respondsToSelector:@selector(sessionDidNotLogin:)]) { - [delegate sessionDidNotLogin:self]; - } - } - } -} - -- (void)logout { - if (_sessionKey) { - for (id delegate in _delegates) { - if ([delegate respondsToSelector:@selector(session:willLogout:)]) { - [delegate session:self willLogout:_uid]; - } - } - - [self deleteFacebookCookies]; - - - _uid = 0; - [_sessionKey release]; - _sessionKey = nil; - [_sessionSecret release]; - _sessionSecret = nil; - [_expirationDate release]; - _expirationDate = nil; - [self unsave]; - - for (id delegate in _delegates) { - if ([delegate respondsToSelector:@selector(sessionDidLogout:)]) { - [delegate sessionDidLogout:self]; - } - } - } else { - [self deleteFacebookCookies]; - [self unsave]; - } -} - -- (void)send:(FBRequest*)request { - [self performRequest:request enqueue:YES]; -} - -- (void)deleteFacebookCookies { - NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - NSArray* facebookCookies = [cookies cookiesForURL: - [NSURL URLWithString:@"http://login.facebook.com"]]; - for (NSHTTPCookie* cookie in facebookCookies) { - [cookies deleteCookie:cookie]; - } -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h deleted file mode 100755 index b926a01e..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "FBDialog.h" - -@interface FBStreamDialog : FBDialog { - NSString* _attachment; - NSString* _actionLinks; - NSString* _targetId; - NSString* _userMessagePrompt; -} - -/** - * A JSON-encoded object containing the text of the post, relevant links, a - * media type (image, video, mp3, flash), as well as any other key/value pairs - * you may want to add. - * - * Note: If you want to use this call to update a user's status, don't pass an - * attachment; the content of the userMessage parameter will become the user's - * new status and will appear at the top of the user's profile. - * - * For more info, see http://wiki.developers.facebook.com/index.php/Attachment_(Streams) - */ -@property(nonatomic,copy) NSString* attachment; - -/** - * A JSON-encoded array of action link objects, containing the link text and a - * hyperlink. - */ -@property(nonatomic,copy) NSString* actionLinks; - -/** - * The ID of the user or the Page where you are publishing the content. If this - * is specified, the post appears on the Wall of the target user, not on the - * Wall of the user who published the post. This mimics the action of posting - * on a friend's Wall on Facebook itself. - * - * Note: To post on the user's own wall, leave this blank. - */ -@property(nonatomic,copy) NSString* targetId; - -/** - * Text you provide the user as a prompt to specify a userMessage. This appears - * above the box where the user enters a custom message. - * For example, "What's on your mind?" - */ -@property(nonatomic,copy) NSString* userMessagePrompt; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m deleted file mode 100755 index 99fdf142..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "FBStreamDialog.h" -#import "FBSession.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// global - -static NSString* kStreamURL = @"http://www.facebook.com/connect/prompt_feed.php"; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBStreamDialog - -@synthesize attachment = _attachment, - actionLinks = _actionLinks, - targetId = _targetId, - userMessagePrompt = _userMessagePrompt; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)initWithSession:(FBSession*)session { - if (self = [super initWithSession:session]) { - _attachment = @""; - _actionLinks = @""; - _targetId = @""; - _userMessagePrompt = @""; - } - return self; -} - -- (void)dealloc { - [_attachment release]; - [_actionLinks release]; - [_targetId release]; - [_userMessagePrompt release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FBDialog - -- (void)load { - NSDictionary* getParams = [NSDictionary dictionaryWithObjectsAndKeys: - @"touch", @"display", nil]; - - NSDictionary* postParams = [NSDictionary dictionaryWithObjectsAndKeys: - _session.apiKey, @"api_key", - _session.sessionKey, @"session_key", - @"1", @"preview", - @"fbconnect:success", @"callback", - @"fbconnect:cancel", @"cancel", - _attachment, @"attachment", - _actionLinks, @"action_links", - _targetId, @"target_id", - _userMessagePrompt, @"user_message_prompt", - nil]; - - [self loadURL:kStreamURL method:@"POST" get:getParams post:postParams]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h deleted file mode 100644 index a60ef6ad..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBConnectGlobal.h" - -@interface FBXMLHandler : NSObject { - NSMutableArray* _stack; - NSMutableArray* _nameStack; - id _rootObject; - NSString* _rootName; - NSMutableString* _chars; - NSError* _parseError; -} - -@property(nonatomic,readonly) id rootObject; -@property(nonatomic,readonly) NSString* rootName; -@property(nonatomic,readonly) NSError* parseError; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m deleted file mode 100644 index 54de261f..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#import "FBXMLHandler.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation FBXMLHandler - -@synthesize rootObject = _rootObject, rootName = _rootName, parseError = _parseError; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// private - -- (NSString*)topName { - return [_nameStack lastObject]; -} - -- (id)topObject:(BOOL)create { - id object = [_stack objectAtIndex:_stack.count-1]; - if (object == [NSNull null] && create) { - object = [NSMutableDictionary dictionary]; - [_stack replaceObjectAtIndex:_stack.count-1 withObject:object]; - } - return object; -} - -- (id)topContainer { - if (_stack.count < 2) { - return nil; - } else { - id object = [_stack objectAtIndex:_stack.count-2]; - if (object == [NSNull null]) { - object = [NSMutableDictionary dictionary]; - [_stack replaceObjectAtIndex:_stack.count-2 withObject:object]; - } - return object; - } -} - -- (void)flushCharacters { - NSCharacterSet* whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - for (NSInteger i = 0; i < _chars.length; ++i) { - unichar c = [_chars characterAtIndex:i]; - if (![whitespace characterIsMember:c]) { - id topContainer = self.topContainer; - if ([topContainer isKindOfClass:[NSMutableArray class]]) { - id object = [NSDictionary dictionaryWithObject:_chars forKey:self.topName]; - [_stack replaceObjectAtIndex:_stack.count-1 withObject:object]; - } else { - [_stack replaceObjectAtIndex:_stack.count-1 withObject:_chars]; - } - break; - } - } - - [_chars release]; - _chars = nil; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSObject - -- (id)init { - if (self = [super init]) { - _stack = [[NSMutableArray alloc] init]; - _nameStack = [[NSMutableArray alloc] init]; - _rootObject = nil; - _rootName = nil; - _chars = nil; - _parseError = nil; - } - return self; -} - -- (void)dealloc { - [_stack release]; - [_nameStack release]; - [_rootObject release]; - [_rootName release]; - [_chars release]; - [_parseError release]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// NSXMLParserDelegate - -- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName - namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName - attributes:(NSDictionary *)attributeDict { - [self flushCharacters]; - - id object = nil; - if ([[attributeDict objectForKey:@"list"] isEqualToString:@"true"]) { - object = [NSMutableArray array]; - } else { - object = [NSNull null]; - } - - [_stack addObject:object]; - [_nameStack addObject:elementName]; -} - -- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { - if (!_chars) { - _chars = [string mutableCopy]; - } else { - [_chars appendString:string]; - } -} - -- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName - namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { - [self flushCharacters]; - - id object = [[[self topObject:NO] retain] autorelease]; - NSString* name = [[self.topName retain] autorelease]; - [_stack removeLastObject]; - [_nameStack removeLastObject]; - - if (!_stack.count) { - _rootObject = [object retain]; - _rootName = [name retain]; - } else { - id topObject = [self topObject:YES]; - if ([topObject isKindOfClass:[NSMutableArray class]]) { - [topObject addObject:object]; - } else if ([topObject isKindOfClass:[NSMutableDictionary class]]) { - [topObject setObject:object forKey:name]; - } - } -} - -- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)error { - _parseError = [error retain]; -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.h new file mode 100644 index 00000000..9c391798 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.h @@ -0,0 +1,113 @@ +/* + * Copyright 2010 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FBLoginDialog.h" +#import "FBRequest.h" + +@protocol FBSessionDelegate; + +/** + * Main Facebook interface for interacting with the Facebook developer API. + * Provides methods to log in and log out a user, make requests using the REST + * and Graph APIs, and start user interface interactions (such as + * pop-ups promoting for credentials, permissions, stream posts, etc.) + */ +@interface Facebook : NSObject{ + NSString* _accessToken; + NSDate* _expirationDate; + id _sessionDelegate; + FBRequest* _request; + FBDialog* _loginDialog; + FBDialog* _fbDialog; + NSString* _appId; + NSString* _localAppId; + NSArray* _permissions; +} + +@property(nonatomic, copy) NSString* accessToken; +@property(nonatomic, copy) NSDate* expirationDate; +@property(nonatomic, assign) id sessionDelegate; +@property(nonatomic, copy) NSString* localAppId; + +- (id)initWithAppId:(NSString *)app_id; + +- (void)authorize:(NSArray *)permissions + delegate:(id)delegate; + +- (void)authorize:(NSArray *)permissions + delegate:(id)delegate + localAppId:(NSString *)localAppId; + +- (BOOL)handleOpenURL:(NSURL *)url; + +- (void)logout:(id)delegate; + +- (FBRequest*)requestWithParams:(NSMutableDictionary *)params + andDelegate:(id )delegate; + +- (FBRequest*)requestWithMethodName:(NSString *)methodName + andParams:(NSMutableDictionary *)params + andHttpMethod:(NSString *)httpMethod + andDelegate:(id )delegate; + +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andDelegate:(id )delegate; + +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andParams:(NSMutableDictionary *)params + andDelegate:(id )delegate; + +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andParams:(NSMutableDictionary *)params + andHttpMethod:(NSString *)httpMethod + andDelegate:(id )delegate; + +- (void)dialog:(NSString *)action + andDelegate:(id)delegate; + +- (void)dialog:(NSString *)action + andParams:(NSMutableDictionary *)params + andDelegate:(id )delegate; + +- (BOOL)isSessionValid; + +@end + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Your application should implement this delegate to receive session callbacks. + */ +@protocol FBSessionDelegate + +@optional + +/** + * Called when the user successfully logged in. + */ +- (void)fbDidLogin; + +/** + * Called when the user dismissed the dialog without logging in. + */ +- (void)fbDidNotLogin:(BOOL)cancelled; + +/** + * Called when the user logged out. + */ +- (void)fbDidLogout; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.m new file mode 100644 index 00000000..23d8f5fc --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/Facebook.m @@ -0,0 +1,660 @@ +/* + * Copyright 2010 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Facebook.h" +#import "FBLoginDialog.h" +#import "FBRequest.h" + +static NSString* kDialogBaseURL = @"https://m.facebook.com/dialog/"; +static NSString* kGraphBaseURL = @"https://graph.facebook.com/"; +static NSString* kRestserverBaseURL = @"https://api.facebook.com/method/"; + +static NSString* kFBAppAuthURLScheme = @"fbauth"; +static NSString* kFBAppAuthURLPath = @"authorize"; +static NSString* kRedirectURL = @"fbconnect://success"; + +static NSString* kLogin = @"oauth"; +static NSString* kSDK = @"ios"; +static NSString* kSDKVersion = @"2"; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface Facebook () + +// private properties +@property(nonatomic, retain) NSArray* permissions; + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation Facebook + +@synthesize accessToken = _accessToken, + expirationDate = _expirationDate, + sessionDelegate = _sessionDelegate, + permissions = _permissions, + localAppId = _localAppId; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + + +/** + * Initialize the Facebook object with application ID. + */ +- (id)initWithAppId:(NSString *)app_id { + self = [super init]; + if (self) { + [_appId release]; + _appId = [app_id copy]; + } + return self; +} + +/** + * Override NSObject : free the space + */ +- (void)dealloc { + [_accessToken release]; + [_expirationDate release]; + [_request release]; + [_loginDialog release]; + [_fbDialog release]; + [_appId release]; + [_permissions release]; + [_localAppId release]; + [super dealloc]; +} + +/** + * A private helper function for sending HTTP requests. + * + * @param url + * url to send http request + * @param params + * parameters to append to the url + * @param httpMethod + * http method @"GET" or @"POST" + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + */ +- (FBRequest*)openUrl:(NSString *)url + params:(NSMutableDictionary *)params + httpMethod:(NSString *)httpMethod + delegate:(id)delegate { + + [params setValue:@"json" forKey:@"format"]; + [params setValue:kSDK forKey:@"sdk"]; + [params setValue:kSDKVersion forKey:@"sdk_version"]; + if ([self isSessionValid]) { + [params setValue:self.accessToken forKey:@"access_token"]; + } + + [_request release]; + _request = [[FBRequest getRequestWithParams:params + httpMethod:httpMethod + delegate:delegate + requestURL:url] retain]; + [_request connect]; + return _request; +} + +/** + * A private function for getting the app's base url. + */ +- (NSString *)getOwnBaseUrl { + return [NSString stringWithFormat:@"fb%@%@://authorize", + _appId, + _localAppId ? _localAppId : @""]; +} + +/** + * A private function for opening the authorization dialog. + */ +- (void)authorizeWithFBAppAuth:(BOOL)tryFBAppAuth + safariAuth:(BOOL)trySafariAuth { + NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys: + _appId, @"client_id", + @"user_agent", @"type", + kRedirectURL, @"redirect_uri", + @"touch", @"display", + kSDKVersion, @"sdk", + nil]; + + NSString *loginDialogURL = [kDialogBaseURL stringByAppendingString:kLogin]; + + if (_permissions != nil) { + NSString* scope = [_permissions componentsJoinedByString:@","]; + [params setValue:scope forKey:@"scope"]; + } + + if (_localAppId) { + [params setValue:_localAppId forKey:@"local_client_id"]; + } + + // If the device is running a version of iOS that supports multitasking, + // try to obtain the access token from the Facebook app installed + // on the device. + // If the Facebook app isn't installed or it doesn't support + // the fbauth:// URL scheme, fall back on Safari for obtaining the access token. + // This minimizes the chance that the user will have to enter his or + // her credentials in order to authorize the application. + BOOL didOpenOtherApp = NO; + UIDevice *device = [UIDevice currentDevice]; + if ([device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported]) { + if (tryFBAppAuth) { + NSString *scheme = kFBAppAuthURLScheme; + if (_localAppId) { + scheme = [scheme stringByAppendingString:@"2"]; + } + NSString *urlPrefix = [NSString stringWithFormat:@"%@://%@", scheme, kFBAppAuthURLPath]; + NSString *fbAppUrl = [FBRequest serializeURL:urlPrefix params:params]; + didOpenOtherApp = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:fbAppUrl]]; + } + + if (trySafariAuth && !didOpenOtherApp) { + NSString *nextUrl = [self getOwnBaseUrl]; + [params setValue:nextUrl forKey:@"redirect_uri"]; + + NSString *fbAppUrl = [FBRequest serializeURL:loginDialogURL params:params]; + didOpenOtherApp = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:fbAppUrl]]; + } + } + + // If single sign-on failed, open an inline login dialog. This will require the user to + // enter his or her credentials. + if (!didOpenOtherApp) { + [_loginDialog release]; + _loginDialog = [[FBLoginDialog alloc] initWithURL:loginDialogURL + loginParams:params + delegate:self]; + [_loginDialog show]; + } +} + +/** + * A function for parsing URL parameters. + */ +- (NSDictionary*)parseURLParams:(NSString *)query { + NSArray *pairs = [query componentsSeparatedByString:@"&"]; + NSMutableDictionary *params = [[[NSMutableDictionary alloc] init] autorelease]; + for (NSString *pair in pairs) { + NSArray *kv = [pair componentsSeparatedByString:@"="]; + NSString *val = + [[kv objectAtIndex:1] + stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + + [params setObject:val forKey:[kv objectAtIndex:0]]; + } + return params; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +//public + +- (void)authorize:(NSArray *)permissions + delegate:(id)delegate { + [self authorize:permissions + delegate:delegate + localAppId:nil]; +} + +/** + * Starts a dialog which prompts the user to log in to Facebook and grant + * the requested permissions to the application. + * + * If the device supports multitasking, we use fast app switching to show + * the dialog in the Facebook app or, if the Facebook app isn't installed, + * in Safari (this enables single sign-on by allowing multiple apps on + * the device to share the same user session). + * When the user grants or denies the permissions, the app that + * showed the dialog (the Facebook app or Safari) redirects back to + * the calling application, passing in the URL the access token + * and/or any other parameters the Facebook backend includes in + * the result (such as an error code if an error occurs). + * + * See http://developers.facebook.com/docs/authentication/ for more details. + * + * Also note that requests may be made to the API without calling + * authorize() first, in which case only public information is returned. + * + * @param permissions + * A list of permission required for this application: e.g. + * "read_stream", "publish_stream", or "offline_access". see + * http://developers.facebook.com/docs/authentication/permissions + * This parameter should not be null -- if you do not require any + * permissions, then pass in an empty String array. + * @param delegate + * Callback interface for notifying the calling application when + * the user has logged in. + * @param localAppId + * localAppId is a string of lowercase letters that is + * appended to the base URL scheme used for SSO. For example, + * if your facebook ID is "350685531728" and you set localAppId to + * "abcd", the Facebook app will expect your application to bind to + * the following URL scheme: "fb350685531728abcd". + * This is useful if your have multiple iOS applications that + * share a single Facebook application id (for example, if you + * have a free and a paid version on the same app) and you want + * to use SSO with both apps. Giving both apps different + * localAppId values will allow the Facebook app to disambiguate + * their URL schemes and always redirect the user back to the + * correct app, even if both the free and the app is installed + * on the device. + * localAppId is supported on version 3.4.1 and above of the Facebook + * app. If the user has an older version of the Facebook app + * installed and your app uses localAppId parameter, the SDK will + * proceed as if the Facebook app isn't installed on the device + * and redirect the user to Safari. + */ +- (void)authorize:(NSArray *)permissions + delegate:(id)delegate + localAppId:(NSString *)localAppId { + self.localAppId = localAppId; + self.permissions = permissions; + + _sessionDelegate = delegate; + + [self authorizeWithFBAppAuth:YES safariAuth:YES]; +} + +/** + * This function processes the URL the Facebook application or Safari used to + * open your application during a single sign-on flow. + * + * You MUST call this function in your UIApplicationDelegate's handleOpenURL + * method (see + * http://developer.apple.com/library/ios/#documentation/uikit/reference/UIApplicationDelegate_Protocol/Reference/Reference.html + * for more info). + * + * This will ensure that the authorization process will proceed smoothly once the + * Facebook application or Safari redirects back to your application. + * + * @param URL the URL that was passed to the application delegate's handleOpenURL method. + * + * @return YES if the URL starts with 'fb[app_id]://authorize and hence was handled + * by SDK, NO otherwise. + */ +- (BOOL)handleOpenURL:(NSURL *)url { + // If the URL's structure doesn't match the structure used for Facebook authorization, abort. + if (![[url absoluteString] hasPrefix:[self getOwnBaseUrl]]) { + return NO; + } + + NSString *query = [url fragment]; + + // Version 3.2.3 of the Facebook app encodes the parameters in the query but + // version 3.3 and above encode the parameters in the fragment. To support + // both versions of the Facebook app, we try to parse the query if + // the fragment is missing. + if (!query) { + query = [url query]; + } + + NSDictionary *params = [self parseURLParams:query]; + NSString *accessToken = [params valueForKey:@"access_token"]; + + // If the URL doesn't contain the access token, an error has occurred. + if (!accessToken) { + NSString *errorReason = [params valueForKey:@"error"]; + + // If the error response indicates that we should try again using Safari, open + // the authorization dialog in Safari. + if (errorReason && [errorReason isEqualToString:@"service_disabled_use_browser"]) { + [self authorizeWithFBAppAuth:NO safariAuth:YES]; + return YES; + } + + // If the error response indicates that we should try the authorization flow + // in an inline dialog, do that. + if (errorReason && [errorReason isEqualToString:@"service_disabled"]) { + [self authorizeWithFBAppAuth:NO safariAuth:NO]; + return YES; + } + + // The facebook app may return an error_code parameter in case it + // encounters a UIWebViewDelegate error. This should not be treated + // as a cancel. + NSString *errorCode = [params valueForKey:@"error_code"]; + + BOOL userDidCancel = + !errorCode && (!errorReason || [errorReason isEqualToString:@"access_denied"]); + [self fbDialogNotLogin:userDidCancel]; + return YES; + } + + // We have an access token, so parse the expiration date. + NSString *expTime = [params valueForKey:@"expires_in"]; + NSDate *expirationDate = [NSDate distantFuture]; + if (expTime != nil) { + int expVal = [expTime intValue]; + if (expVal != 0) { + expirationDate = [NSDate dateWithTimeIntervalSinceNow:expVal]; + } + } + + [self fbDialogLogin:accessToken expirationDate:expirationDate]; + return YES; +} + +/** + * Invalidate the current user session by removing the access token in + * memory, clearing the browser cookie, and calling auth.expireSession + * through the API. + * + * Note that this method dosen't unauthorize the application -- + * it just invalidates the access token. To unauthorize the application, + * the user must remove the app in the app settings page under the privacy + * settings screen on facebook.com. + * + * @param delegate + * Callback interface for notifying the calling application when + * the application has logged out + */ +- (void)logout:(id)delegate { + + _sessionDelegate = delegate; + + NSMutableDictionary * params = [[NSMutableDictionary alloc] init]; + [self requestWithMethodName:@"auth.expireSession" + andParams:params andHttpMethod:@"GET" + andDelegate:nil]; + + [params release]; + [_accessToken release]; + _accessToken = nil; + [_expirationDate release]; + _expirationDate = nil; + + NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSArray* facebookCookies = [cookies cookiesForURL: + [NSURL URLWithString:@"http://login.facebook.com"]]; + + for (NSHTTPCookie* cookie in facebookCookies) { + [cookies deleteCookie:cookie]; + } + + if ([self.sessionDelegate respondsToSelector:@selector(fbDidLogout)]) { + [_sessionDelegate fbDidLogout]; + } +} + +/** + * Make a request to Facebook's REST API with the given + * parameters. One of the parameter keys must be "method" and its value + * should be a valid REST server API method. + * + * See http://developers.facebook.com/docs/reference/rest/ + * + * @param parameters + * Key-value pairs of parameters to the request. Refer to the + * documentation: one of the parameters must be "method". + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithParams:(NSMutableDictionary *)params + andDelegate:(id )delegate { + if ([params objectForKey:@"method"] == nil) { + NSLog(@"API Method must be specified"); + return nil; + } + + NSString * methodName = [params objectForKey:@"method"]; + [params removeObjectForKey:@"method"]; + + return [self requestWithMethodName:methodName + andParams:params + andHttpMethod:@"GET" + andDelegate:delegate]; +} + +/** + * Make a request to Facebook's REST API with the given method name and + * parameters. + * + * See http://developers.facebook.com/docs/reference/rest/ + * + * + * @param methodName + * a valid REST server API method. + * @param parameters + * Key-value pairs of parameters to the request. Refer to the + * documentation: one of the parameters must be "method". To upload + * a file, you should specify the httpMethod to be "POST" and the + * “params” you passed in should contain a value of the type + * (UIImage *) or (NSData *) which contains the content that you + * want to upload + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithMethodName:(NSString *)methodName + andParams:(NSMutableDictionary *)params + andHttpMethod:(NSString *)httpMethod + andDelegate:(id )delegate { + NSString * fullURL = [kRestserverBaseURL stringByAppendingString:methodName]; + return [self openUrl:fullURL + params:params + httpMethod:httpMethod + delegate:delegate]; +} + +/** + * Make a request to the Facebook Graph API without any parameters. + * + * See http://developers.facebook.com/docs/api + * + * @param graphPath + * Path to resource in the Facebook graph, e.g., to fetch data + * about the currently logged authenticated user, provide "me", + * which will fetch http://graph.facebook.com/me + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andDelegate:(id )delegate { + + return [self requestWithGraphPath:graphPath + andParams:[NSMutableDictionary dictionary] + andHttpMethod:@"GET" + andDelegate:delegate]; +} + +/** + * Make a request to the Facebook Graph API with the given string + * parameters using an HTTP GET (default method). + * + * See http://developers.facebook.com/docs/api + * + * + * @param graphPath + * Path to resource in the Facebook graph, e.g., to fetch data + * about the currently logged authenticated user, provide "me", + * which will fetch http://graph.facebook.com/me + * @param parameters + * key-value string parameters, e.g. the path "search" with + * parameters "q" : "facebook" would produce a query for the + * following graph resource: + * https://graph.facebook.com/search?q=facebook + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andParams:(NSMutableDictionary *)params + andDelegate:(id )delegate { + + return [self requestWithGraphPath:graphPath + andParams:params + andHttpMethod:@"GET" + andDelegate:delegate]; +} + +/** + * Make a request to the Facebook Graph API with the given + * HTTP method and string parameters. Note that binary data parameters + * (e.g. pictures) are not yet supported by this helper function. + * + * See http://developers.facebook.com/docs/api + * + * + * @param graphPath + * Path to resource in the Facebook graph, e.g., to fetch data + * about the currently logged authenticated user, provide "me", + * which will fetch http://graph.facebook.com/me + * @param parameters + * key-value string parameters, e.g. the path "search" with + * parameters {"q" : "facebook"} would produce a query for the + * following graph resource: + * https://graph.facebook.com/search?q=facebook + * To upload a file, you should specify the httpMethod to be + * "POST" and the “params” you passed in should contain a value + * of the type (UIImage *) or (NSData *) which contains the + * content that you want to upload + * @param httpMethod + * http verb, e.g. "GET", "POST", "DELETE" + * @param delegate + * Callback interface for notifying the calling application when + * the request has received response + * @return FBRequest* + * Returns a pointer to the FBRequest object. + */ +- (FBRequest*)requestWithGraphPath:(NSString *)graphPath + andParams:(NSMutableDictionary *)params + andHttpMethod:(NSString *)httpMethod + andDelegate:(id )delegate { + + NSString * fullURL = [kGraphBaseURL stringByAppendingString:graphPath]; + return [self openUrl:fullURL + params:params + httpMethod:httpMethod + delegate:delegate]; +} + +/** + * Generate a UI dialog for the request action. + * + * @param action + * String representation of the desired method: e.g. "login", + * "feed", ... + * @param delegate + * Callback interface to notify the calling application when the + * dialog has completed. + */ +- (void)dialog:(NSString *)action + andDelegate:(id)delegate { + NSMutableDictionary * params = [NSMutableDictionary dictionary]; + [self dialog:action andParams:params andDelegate:delegate]; +} + +/** + * Generate a UI dialog for the request action with the provided parameters. + * + * @param action + * String representation of the desired method: e.g. "login", + * "feed", ... + * @param parameters + * key-value string parameters + * @param delegate + * Callback interface to notify the calling application when the + * dialog has completed. + */ +- (void)dialog:(NSString *)action + andParams:(NSMutableDictionary *)params + andDelegate:(id )delegate { + + [_fbDialog release]; + + NSString *dialogURL = [kDialogBaseURL stringByAppendingString:action]; + [params setObject:@"touch" forKey:@"display"]; + [params setObject:kSDKVersion forKey:@"sdk"]; + [params setObject:kRedirectURL forKey:@"redirect_uri"]; + + if (action == kLogin) { + [params setObject:@"user_agent" forKey:@"type"]; + _fbDialog = [[FBLoginDialog alloc] initWithURL:dialogURL loginParams:params delegate:self]; + } else { + [params setObject:_appId forKey:@"app_id"]; + if ([self isSessionValid]) { + [params setValue:[self.accessToken stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] + forKey:@"access_token"]; + } + _fbDialog = [[FBDialog alloc] initWithURL:dialogURL params:params delegate:delegate]; + } + + [_fbDialog show]; +} + +/** + * @return boolean - whether this object has an non-expired session token + */ +- (BOOL)isSessionValid { + return (self.accessToken != nil && self.expirationDate != nil + && NSOrderedDescending == [self.expirationDate compare:[NSDate date]]); + +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +//FBLoginDialogDelegate + +/** + * Set the authToken and expirationDate after login succeed + */ +- (void)fbDialogLogin:(NSString *)token expirationDate:(NSDate *)expirationDate { + self.accessToken = token; + self.expirationDate = expirationDate; + if ([self.sessionDelegate respondsToSelector:@selector(fbDidLogin)]) { + [_sessionDelegate fbDidLogin]; + } + +} + +/** + * Did not login call the not login delegate + */ +- (void)fbDialogNotLogin:(BOOL)cancelled { + if ([self.sessionDelegate respondsToSelector:@selector(fbDidNotLogin:)]) { + [_sessionDelegate fbDidNotLogin:cancelled]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +//FBRequestDelegate + +/** + * Handle the auth.ExpireSession api call failure + */ +- (void)request:(FBRequest*)request didFailWithError:(NSError*)error{ + NSLog(@"Failed to expire the session"); +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/JSON.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/JSON.h new file mode 100644 index 00000000..1e58c9ad --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/JSON.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @mainpage A strict JSON parser and generator for Objective-C + + JSON (JavaScript Object Notation) is a lightweight data-interchange + format. This framework provides two apis for parsing and generating + JSON. One standard object-based and a higher level api consisting of + categories added to existing Objective-C classes. + + Learn more on the http://code.google.com/p/json-framework project site. + + This framework does its best to be as strict as possible, both in what it + accepts and what it generates. For example, it does not support trailing commas + in arrays or objects. Nor does it support embedded comments, or + anything else not in the JSON specification. This is considered a feature. + +*/ + +#import "SBJSON.h" +#import "NSObject+SBJSON.h" +#import "NSString+SBJSON.h" + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.h new file mode 100644 index 00000000..ecf0ee40 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + + +/** + @brief Adds JSON generation to Foundation classes + + This is a category on NSObject that adds methods for returning JSON representations + of standard objects to the objects themselves. This means you can call the + -JSONRepresentation method on an NSArray object and it'll do what you want. + */ +@interface NSObject (NSObject_SBJSON) + +/** + @brief Returns a string containing the receiver encoded as a JSON fragment. + + This method is added as a category on NSObject but is only actually + supported for the following objects: + @li NSDictionary + @li NSArray + @li NSString + @li NSNumber (also used for booleans) + @li NSNull + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (NSString *)JSONFragment; + +/** + @brief Returns a string containing the receiver encoded in JSON. + + This method is added as a category on NSObject but is only actually + supported for the following objects: + @li NSDictionary + @li NSArray + */ +- (NSString *)JSONRepresentation; + +@end + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.m new file mode 100644 index 00000000..20b084b6 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSObject+SBJSON.m @@ -0,0 +1,53 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "NSObject+SBJSON.h" +#import "SBJsonWriter.h" + +@implementation NSObject (NSObject_SBJSON) + +- (NSString *)JSONFragment { + SBJsonWriter *jsonWriter = [SBJsonWriter new]; + NSString *json = [jsonWriter stringWithFragment:self]; + if (!json) + NSLog(@"-JSONFragment failed. Error trace is: %@", [jsonWriter errorTrace]); + [jsonWriter release]; + return json; +} + +- (NSString *)JSONRepresentation { + SBJsonWriter *jsonWriter = [SBJsonWriter new]; + NSString *json = [jsonWriter stringWithObject:self]; + if (!json) + NSLog(@"-JSONRepresentation failed. Error trace is: %@", [jsonWriter errorTrace]); + [jsonWriter release]; + return json; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.h new file mode 100644 index 00000000..fad7179c --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +/** + @brief Adds JSON parsing methods to NSString + +This is a category on NSString that adds methods for parsing the target string. +*/ +@interface NSString (NSString_SBJSON) + + +/** + @brief Returns the object represented in the receiver, or nil on error. + + Returns a a scalar object represented by the string's JSON fragment representation. + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (id)JSONFragmentValue; + +/** + @brief Returns the NSDictionary or NSArray represented by the current string's JSON representation. + + Returns the dictionary or array represented in the receiver, or nil on error. + + Returns the NSDictionary or NSArray represented by the current string's JSON representation. + */ +- (id)JSONValue; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.m new file mode 100644 index 00000000..41a5a85b --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/NSString+SBJSON.m @@ -0,0 +1,55 @@ +/* + Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "NSString+SBJSON.h" +#import "SBJsonParser.h" + +@implementation NSString (NSString_SBJSON) + +- (id)JSONFragmentValue +{ + SBJsonParser *jsonParser = [SBJsonParser new]; + id repr = [jsonParser fragmentWithString:self]; + if (!repr) + NSLog(@"-JSONFragmentValue failed. Error trace is: %@", [jsonParser errorTrace]); + [jsonParser release]; + return repr; +} + +- (id)JSONValue +{ + SBJsonParser *jsonParser = [SBJsonParser new]; + id repr = [jsonParser objectWithString:self]; + if (!repr) + NSLog(@"-JSONValue failed. Error trace is: %@", [jsonParser errorTrace]); + [jsonParser release]; + return repr; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.h new file mode 100644 index 00000000..43d63c30 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.h @@ -0,0 +1,75 @@ +/* + Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonParser.h" +#import "SBJsonWriter.h" + +/** + @brief Facade for SBJsonWriter/SBJsonParser. + + Requests are forwarded to instances of SBJsonWriter and SBJsonParser. + */ +@interface SBJSON : SBJsonBase { + +@private + SBJsonParser *jsonParser; + SBJsonWriter *jsonWriter; +} + + +/// Return the fragment represented by the given string +- (id)fragmentWithString:(NSString*)jsonrep + error:(NSError**)error; + +/// Return the object represented by the given string +- (id)objectWithString:(NSString*)jsonrep + error:(NSError**)error; + +/// Parse the string and return the represented object (or scalar) +- (id)objectWithString:(id)value + allowScalar:(BOOL)x + error:(NSError**)error; + + +/// Return JSON representation of an array or dictionary +- (NSString*)stringWithObject:(id)value + error:(NSError**)error; + +/// Return JSON representation of any legal JSON value +- (NSString*)stringWithFragment:(id)value + error:(NSError**)error; + +/// Return JSON representation (or fragment) for the given object +- (NSString*)stringWithObject:(id)value + allowScalar:(BOOL)x + error:(NSError**)error; + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.m new file mode 100644 index 00000000..2a30f1a7 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJSON.m @@ -0,0 +1,212 @@ +/* + Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJSON.h" + +@implementation SBJSON + +- (id)init { + self = [super init]; + if (self) { + jsonWriter = [SBJsonWriter new]; + jsonParser = [SBJsonParser new]; + [self setMaxDepth:512]; + + } + return self; +} + +- (void)dealloc { + [jsonWriter release]; + [jsonParser release]; + [super dealloc]; +} + +#pragma mark Writer + + +- (NSString *)stringWithObject:(id)obj { + NSString *repr = [jsonWriter stringWithObject:obj]; + if (repr) + return repr; + + [errorTrace release]; + errorTrace = [[jsonWriter errorTrace] mutableCopy]; + return nil; +} + +/** + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + @param allowScalar wether to return json fragments for scalar objects + @param error used to return an error by reference (pass NULL if this is not desired) + +@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (NSString*)stringWithObject:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { + + NSString *json = allowScalar ? [jsonWriter stringWithFragment:value] : [jsonWriter stringWithObject:value]; + if (json) + return json; + + [errorTrace release]; + errorTrace = [[jsonWriter errorTrace] mutableCopy]; + + if (error) + *error = [errorTrace lastObject]; + return nil; +} + +/** + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + @param error used to return an error by reference (pass NULL if this is not desired) + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (NSString*)stringWithFragment:(id)value error:(NSError**)error { + return [self stringWithObject:value + allowScalar:YES + error:error]; +} + +/** + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. + + @param value a NSDictionary or NSArray instance + @param error used to return an error by reference (pass NULL if this is not desired) + */ +- (NSString*)stringWithObject:(id)value error:(NSError**)error { + return [self stringWithObject:value + allowScalar:NO + error:error]; +} + +#pragma mark Parsing + +- (id)objectWithString:(NSString *)repr { + id obj = [jsonParser objectWithString:repr]; + if (obj) + return obj; + + [errorTrace release]; + errorTrace = [[jsonParser errorTrace] mutableCopy]; + + return nil; +} + +/** + Returns the object represented by the passed-in string or nil on error. The returned object can be + a string, number, boolean, null, array or dictionary. + + @param value the json string to parse + @param allowScalar whether to return objects for JSON fragments + @param error used to return an error by reference (pass NULL if this is not desired) + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (id)objectWithString:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { + + id obj = allowScalar ? [jsonParser fragmentWithString:value] : [jsonParser objectWithString:value]; + if (obj) + return obj; + + [errorTrace release]; + errorTrace = [[jsonParser errorTrace] mutableCopy]; + + if (error) + *error = [errorTrace lastObject]; + return nil; +} + +/** + Returns the object represented by the passed-in string or nil on error. The returned object can be + a string, number, boolean, null, array or dictionary. + + @param repr the json string to parse + @param error used to return an error by reference (pass NULL if this is not desired) + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (id)fragmentWithString:(NSString*)repr error:(NSError**)error { + return [self objectWithString:repr + allowScalar:YES + error:error]; +} + +/** + Returns the object represented by the passed-in string or nil on error. The returned object + will be either a dictionary or an array. + + @param repr the json string to parse + @param error used to return an error by reference (pass NULL if this is not desired) + */ +- (id)objectWithString:(NSString*)repr error:(NSError**)error { + return [self objectWithString:repr + allowScalar:NO + error:error]; +} + + + +#pragma mark Properties - parsing + +- (NSUInteger)maxDepth { + return jsonParser.maxDepth; +} + +- (void)setMaxDepth:(NSUInteger)d { + jsonWriter.maxDepth = jsonParser.maxDepth = d; +} + + +#pragma mark Properties - writing + +- (BOOL)humanReadable { + return jsonWriter.humanReadable; +} + +- (void)setHumanReadable:(BOOL)x { + jsonWriter.humanReadable = x; +} + +- (BOOL)sortKeys { + return jsonWriter.sortKeys; +} + +- (void)setSortKeys:(BOOL)x { + jsonWriter.sortKeys = x; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.h new file mode 100644 index 00000000..7b108440 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +extern NSString * SBJSONErrorDomain; + + +enum { + EUNSUPPORTED = 1, + EPARSENUM, + EPARSE, + EFRAGMENT, + ECTRL, + EUNICODE, + EDEPTH, + EESCAPE, + ETRAILCOMMA, + ETRAILGARBAGE, + EEOF, + EINPUT +}; + +/** + @brief Common base class for parsing & writing. + + This class contains the common error-handling code and option between the parser/writer. + */ +@interface SBJsonBase : NSObject { + NSMutableArray *errorTrace; + +@protected + NSUInteger depth, maxDepth; +} + +/** + @brief The maximum recursing depth. + + Defaults to 512. If the input is nested deeper than this the input will be deemed to be + malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can + turn off this security feature by setting the maxDepth value to 0. + */ +@property NSUInteger maxDepth; + +/** + @brief Return an error trace, or nil if there was no errors. + + Note that this method returns the trace of the last method that failed. + You need to check the return value of the call you're making to figure out + if the call actually failed, before you know call this method. + */ + @property(copy,readonly) NSArray* errorTrace; + +/// @internal for use in subclasses to add errors to the stack trace +- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str; + +/// @internal for use in subclasess to clear the error before a new parsing attempt +- (void)clearErrorTrace; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.m new file mode 100644 index 00000000..6684325d --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonBase.m @@ -0,0 +1,78 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonBase.h" +NSString * SBJSONErrorDomain = @"org.brautaset.JSON.ErrorDomain"; + + +@implementation SBJsonBase + +@synthesize errorTrace; +@synthesize maxDepth; + +- (id)init { + self = [super init]; + if (self) + self.maxDepth = 512; + return self; +} + +- (void)dealloc { + [errorTrace release]; + [super dealloc]; +} + +- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str { + NSDictionary *userInfo; + if (!errorTrace) { + errorTrace = [NSMutableArray new]; + userInfo = [NSDictionary dictionaryWithObject:str forKey:NSLocalizedDescriptionKey]; + + } else { + userInfo = [NSDictionary dictionaryWithObjectsAndKeys: + str, NSLocalizedDescriptionKey, + [errorTrace lastObject], NSUnderlyingErrorKey, + nil]; + } + + NSError *error = [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:userInfo]; + + [self willChangeValueForKey:@"errorTrace"]; + [errorTrace addObject:error]; + [self didChangeValueForKey:@"errorTrace"]; +} + +- (void)clearErrorTrace { + [self willChangeValueForKey:@"errorTrace"]; + [errorTrace release]; + errorTrace = nil; + [self didChangeValueForKey:@"errorTrace"]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.h new file mode 100644 index 00000000..e95304d9 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonBase.h" + +/** + @brief Options for the parser class. + + This exists so the SBJSON facade can implement the options in the parser without having to re-declare them. + */ +@protocol SBJsonParser + +/** + @brief Return the object represented by the given string. + + Returns the object represented by the passed-in string or nil on error. The returned object can be + a string, number, boolean, null, array or dictionary. + + @param repr the json string to parse + */ +- (id)objectWithString:(NSString *)repr; + +@end + + +/** + @brief The JSON parser class. + + JSON is mapped to Objective-C types in the following way: + + @li Null -> NSNull + @li String -> NSMutableString + @li Array -> NSMutableArray + @li Object -> NSMutableDictionary + @li Boolean -> NSNumber (initialised with -initWithBool:) + @li Number -> NSDecimalNumber + + Since Objective-C doesn't have a dedicated class for boolean values, these turns into NSNumber + instances. These are initialised with the -initWithBool: method, and + round-trip back to JSON properly. (They won't silently suddenly become 0 or 1; they'll be + represented as 'true' and 'false' again.) + + JSON numbers turn into NSDecimalNumber instances, + as we can thus avoid any loss of precision. (JSON allows ridiculously large numbers.) + + */ +@interface SBJsonParser : SBJsonBase { + +@private + const char *c; +} + +@end + +// don't use - exists for backwards compatibility with 2.1.x only. Will be removed in 2.3. +@interface SBJsonParser (Private) +- (id)fragmentWithString:(id)repr; +@end + + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.m new file mode 100644 index 00000000..eda051a8 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonParser.m @@ -0,0 +1,475 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonParser.h" + +@interface SBJsonParser () + +- (BOOL)scanValue:(NSObject **)o; + +- (BOOL)scanRestOfArray:(NSMutableArray **)o; +- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o; +- (BOOL)scanRestOfNull:(NSNull **)o; +- (BOOL)scanRestOfFalse:(NSNumber **)o; +- (BOOL)scanRestOfTrue:(NSNumber **)o; +- (BOOL)scanRestOfString:(NSMutableString **)o; + +// Cannot manage without looking at the first digit +- (BOOL)scanNumber:(NSNumber **)o; + +- (BOOL)scanHexQuad:(unichar *)x; +- (BOOL)scanUnicodeChar:(unichar *)x; + +- (BOOL)scanIsAtEnd; + +@end + +#define skipWhitespace(c) while (isspace(*c)) c++ +#define skipDigits(c) while (isdigit(*c)) c++ + + +@implementation SBJsonParser + +static char ctrl[0x22]; + + ++ (void)initialize { + ctrl[0] = '\"'; + ctrl[1] = '\\'; + for (int i = 1; i < 0x20; i++) + ctrl[i+1] = i; + ctrl[0x21] = 0; +} + +/** + @deprecated This exists in order to provide fragment support in older APIs in one more version. + It should be removed in the next major version. + */ +- (id)fragmentWithString:(id)repr { + [self clearErrorTrace]; + + if (!repr) { + [self addErrorWithCode:EINPUT description:@"Input was 'nil'"]; + return nil; + } + + depth = 0; + c = [repr UTF8String]; + + id o; + if (![self scanValue:&o]) { + return nil; + } + + // We found some valid JSON. But did it also contain something else? + if (![self scanIsAtEnd]) { + [self addErrorWithCode:ETRAILGARBAGE description:@"Garbage after JSON"]; + return nil; + } + + NSAssert1(o, @"Should have a valid object from %@", repr); + return o; +} + +- (id)objectWithString:(NSString *)repr { + + id o = [self fragmentWithString:repr]; + if (!o) + return nil; + + // Check that the object we've found is a valid JSON container. + if (![o isKindOfClass:[NSDictionary class]] && ![o isKindOfClass:[NSArray class]]) { + [self addErrorWithCode:EFRAGMENT description:@"Valid fragment, but not JSON"]; + return nil; + } + + return o; +} + +/* + In contrast to the public methods, it is an error to omit the error parameter here. + */ +- (BOOL)scanValue:(NSObject **)o +{ + skipWhitespace(c); + + switch (*c++) { + case '{': + return [self scanRestOfDictionary:(NSMutableDictionary **)o]; + break; + case '[': + return [self scanRestOfArray:(NSMutableArray **)o]; + break; + case '"': + return [self scanRestOfString:(NSMutableString **)o]; + break; + case 'f': + return [self scanRestOfFalse:(NSNumber **)o]; + break; + case 't': + return [self scanRestOfTrue:(NSNumber **)o]; + break; + case 'n': + return [self scanRestOfNull:(NSNull **)o]; + break; + case '-': + case '0'...'9': + c--; // cannot verify number correctly without the first character + return [self scanNumber:(NSNumber **)o]; + break; + case '+': + [self addErrorWithCode:EPARSENUM description: @"Leading + disallowed in number"]; + return NO; + break; + case 0x0: + [self addErrorWithCode:EEOF description:@"Unexpected end of string"]; + return NO; + break; + default: + [self addErrorWithCode:EPARSE description: @"Unrecognised leading character"]; + return NO; + break; + } + + NSAssert(0, @"Should never get here"); + return NO; +} + +- (BOOL)scanRestOfTrue:(NSNumber **)o +{ + if (!strncmp(c, "rue", 3)) { + c += 3; + *o = [NSNumber numberWithBool:YES]; + return YES; + } + [self addErrorWithCode:EPARSE description:@"Expected 'true'"]; + return NO; +} + +- (BOOL)scanRestOfFalse:(NSNumber **)o +{ + if (!strncmp(c, "alse", 4)) { + c += 4; + *o = [NSNumber numberWithBool:NO]; + return YES; + } + [self addErrorWithCode:EPARSE description: @"Expected 'false'"]; + return NO; +} + +- (BOOL)scanRestOfNull:(NSNull **)o { + if (!strncmp(c, "ull", 3)) { + c += 3; + *o = [NSNull null]; + return YES; + } + [self addErrorWithCode:EPARSE description: @"Expected 'null'"]; + return NO; +} + +- (BOOL)scanRestOfArray:(NSMutableArray **)o { + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + + *o = [NSMutableArray arrayWithCapacity:8]; + + for (; *c ;) { + id v; + + skipWhitespace(c); + if (*c == ']' && c++) { + depth--; + return YES; + } + + if (![self scanValue:&v]) { + [self addErrorWithCode:EPARSE description:@"Expected value while parsing array"]; + return NO; + } + + [*o addObject:v]; + + skipWhitespace(c); + if (*c == ',' && c++) { + skipWhitespace(c); + if (*c == ']') { + [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in array"]; + return NO; + } + } + } + + [self addErrorWithCode:EEOF description: @"End of input while parsing array"]; + return NO; +} + +- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o +{ + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + + *o = [NSMutableDictionary dictionaryWithCapacity:7]; + + for (; *c ;) { + id k, v; + + skipWhitespace(c); + if (*c == '}' && c++) { + depth--; + return YES; + } + + if (!(*c == '\"' && c++ && [self scanRestOfString:&k])) { + [self addErrorWithCode:EPARSE description: @"Object key string expected"]; + return NO; + } + + skipWhitespace(c); + if (*c != ':') { + [self addErrorWithCode:EPARSE description: @"Expected ':' separating key and value"]; + return NO; + } + + c++; + if (![self scanValue:&v]) { + NSString *string = [NSString stringWithFormat:@"Object value expected for key: %@", k]; + [self addErrorWithCode:EPARSE description: string]; + return NO; + } + + [*o setObject:v forKey:k]; + + skipWhitespace(c); + if (*c == ',' && c++) { + skipWhitespace(c); + if (*c == '}') { + [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in object"]; + return NO; + } + } + } + + [self addErrorWithCode:EEOF description: @"End of input while parsing object"]; + return NO; +} + +- (BOOL)scanRestOfString:(NSMutableString **)o +{ + *o = [NSMutableString stringWithCapacity:16]; + do { + // First see if there's a portion we can grab in one go. + // Doing this caused a massive speedup on the long string. + size_t len = strcspn(c, ctrl); + if (len) { + // check for + id t = [[NSString alloc] initWithBytesNoCopy:(char*)c + length:len + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + if (t) { + [*o appendString:t]; + [t release]; + c += len; + } + } + + if (*c == '"') { + c++; + return YES; + + } else if (*c == '\\') { + unichar uc = *++c; + switch (uc) { + case '\\': + case '/': + case '"': + break; + + case 'b': uc = '\b'; break; + case 'n': uc = '\n'; break; + case 'r': uc = '\r'; break; + case 't': uc = '\t'; break; + case 'f': uc = '\f'; break; + + case 'u': + c++; + if (![self scanUnicodeChar:&uc]) { + [self addErrorWithCode:EUNICODE description: @"Broken unicode character"]; + return NO; + } + c--; // hack. + break; + default: + [self addErrorWithCode:EESCAPE description: [NSString stringWithFormat:@"Illegal escape sequence '0x%x'", uc]]; + return NO; + break; + } + CFStringAppendCharacters((CFMutableStringRef)*o, &uc, 1); + c++; + + } else if (*c < 0x20) { + [self addErrorWithCode:ECTRL description: [NSString stringWithFormat:@"Unescaped control character '0x%x'", *c]]; + return NO; + + } else { + NSLog(@"should not be able to get here"); + } + } while (*c); + + [self addErrorWithCode:EEOF description:@"Unexpected EOF while parsing string"]; + return NO; +} + +- (BOOL)scanUnicodeChar:(unichar *)x +{ + unichar hi, lo; + + if (![self scanHexQuad:&hi]) { + [self addErrorWithCode:EUNICODE description: @"Missing hex quad"]; + return NO; + } + + if (hi >= 0xd800) { // high surrogate char? + if (hi < 0xdc00) { // yes - expect a low char + + if (!(*c == '\\' && ++c && *c == 'u' && ++c && [self scanHexQuad:&lo])) { + [self addErrorWithCode:EUNICODE description: @"Missing low character in surrogate pair"]; + return NO; + } + + if (lo < 0xdc00 || lo >= 0xdfff) { + [self addErrorWithCode:EUNICODE description:@"Invalid low surrogate char"]; + return NO; + } + + hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000; + + } else if (hi < 0xe000) { + [self addErrorWithCode:EUNICODE description:@"Invalid high character in surrogate pair"]; + return NO; + } + } + + *x = hi; + return YES; +} + +- (BOOL)scanHexQuad:(unichar *)x +{ + *x = 0; + for (int i = 0; i < 4; i++) { + unichar uc = *c; + c++; + int d = (uc >= '0' && uc <= '9') + ? uc - '0' : (uc >= 'a' && uc <= 'f') + ? (uc - 'a' + 10) : (uc >= 'A' && uc <= 'F') + ? (uc - 'A' + 10) : -1; + if (d == -1) { + [self addErrorWithCode:EUNICODE description:@"Missing hex digit in quad"]; + return NO; + } + *x *= 16; + *x += d; + } + return YES; +} + +- (BOOL)scanNumber:(NSNumber **)o +{ + const char *ns = c; + + // The logic to test for validity of the number formatting is relicensed + // from JSON::XS with permission from its author Marc Lehmann. + // (Available at the CPAN: http://search.cpan.org/dist/JSON-XS/ .) + + if ('-' == *c) + c++; + + if ('0' == *c && c++) { + if (isdigit(*c)) { + [self addErrorWithCode:EPARSENUM description: @"Leading 0 disallowed in number"]; + return NO; + } + + } else if (!isdigit(*c) && c != ns) { + [self addErrorWithCode:EPARSENUM description: @"No digits after initial minus"]; + return NO; + + } else { + skipDigits(c); + } + + // Fractional part + if ('.' == *c && c++) { + + if (!isdigit(*c)) { + [self addErrorWithCode:EPARSENUM description: @"No digits after decimal point"]; + return NO; + } + skipDigits(c); + } + + // Exponential part + if ('e' == *c || 'E' == *c) { + c++; + + if ('-' == *c || '+' == *c) + c++; + + if (!isdigit(*c)) { + [self addErrorWithCode:EPARSENUM description: @"No digits after exponent"]; + return NO; + } + skipDigits(c); + } + + id str = [[NSString alloc] initWithBytesNoCopy:(char*)ns + length:c - ns + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + [str autorelease]; + if (str && (*o = [NSDecimalNumber decimalNumberWithString:str])) + return YES; + + [self addErrorWithCode:EPARSENUM description: @"Failed creating decimal instance"]; + return NO; +} + +- (BOOL)scanIsAtEnd +{ + skipWhitespace(c); + return !*c; +} + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.h new file mode 100644 index 00000000..f6f5e17b --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.h @@ -0,0 +1,129 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonBase.h" + +/** + @brief Options for the writer class. + + This exists so the SBJSON facade can implement the options in the writer without having to re-declare them. + */ +@protocol SBJsonWriter + +/** + @brief Whether we are generating human-readable (multiline) JSON. + + Set whether or not to generate human-readable JSON. The default is NO, which produces + JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable + JSON with linebreaks after each array value and dictionary key/value pair, indented two + spaces per nesting level. + */ +@property BOOL humanReadable; + +/** + @brief Whether or not to sort the dictionary keys in the output. + + If this is set to YES, the dictionary keys in the JSON output will be in sorted order. + (This is useful if you need to compare two structures, for example.) The default is NO. + */ +@property BOOL sortKeys; + +/** + @brief Return JSON representation (or fragment) for the given object. + + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + + */ +- (NSString*)stringWithObject:(id)value; + +@end + + +/** + @brief The JSON writer class. + + Objective-C types are mapped to JSON types in the following way: + + @li NSNull -> Null + @li NSString -> String + @li NSArray -> Array + @li NSDictionary -> Object + @li NSNumber (-initWithBool:) -> Boolean + @li NSNumber -> Number + + In JSON the keys of an object must be strings. NSDictionary keys need + not be, but attempting to convert an NSDictionary with non-string keys + into JSON will throw an exception. + + NSNumber instances created with the +initWithBool: method are + converted into the JSON boolean "true" and "false" values, and vice + versa. Any other NSNumber instances are converted to a JSON number the + way you would expect. + + */ +@interface SBJsonWriter : SBJsonBase { + +@private + BOOL sortKeys, humanReadable; +} + +@end + +// don't use - exists for backwards compatibility. Will be removed in 2.3. +@interface SBJsonWriter (Private) +- (NSString*)stringWithFragment:(id)value; +@end + +/** + @brief Allows generation of JSON for otherwise unsupported classes. + + If you have a custom class that you want to create a JSON representation for you can implement + this method in your class. It should return a representation of your object defined + in terms of objects that can be translated into JSON. For example, a Person + object might implement it like this: + + @code + - (id)jsonProxyObject { + return [NSDictionary dictionaryWithObjectsAndKeys: + name, @"name", + phone, @"phone", + email, @"email", + nil]; + } + @endcode + + */ +@interface NSObject (SBProxyForJson) +- (id)proxyForJson; +@end + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.m new file mode 100644 index 00000000..0f329041 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/JSON/SBJsonWriter.m @@ -0,0 +1,237 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonWriter.h" + +@interface SBJsonWriter () + +- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json; +- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json; +- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json; +- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json; + +- (NSString*)indent; + +@end + +@implementation SBJsonWriter + +static NSMutableCharacterSet *kEscapeChars; + ++ (void)initialize { + kEscapeChars = [[NSMutableCharacterSet characterSetWithRange: NSMakeRange(0,32)] retain]; + [kEscapeChars addCharactersInString: @"\"\\"]; +} + + +@synthesize sortKeys; +@synthesize humanReadable; + +/** + @deprecated This exists in order to provide fragment support in older APIs in one more version. + It should be removed in the next major version. + */ +- (NSString*)stringWithFragment:(id)value { + [self clearErrorTrace]; + depth = 0; + NSMutableString *json = [NSMutableString stringWithCapacity:128]; + + if ([self appendValue:value into:json]) + return json; + + return nil; +} + + +- (NSString*)stringWithObject:(id)value { + + if ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]) { + return [self stringWithFragment:value]; + } + + if ([value respondsToSelector:@selector(proxyForJson)]) { + NSString *tmp = [self stringWithObject:[value proxyForJson]]; + if (tmp) + return tmp; + } + + + [self clearErrorTrace]; + [self addErrorWithCode:EFRAGMENT description:@"Not valid type for JSON"]; + return nil; +} + + +- (NSString*)indent { + return [@"\n" stringByPaddingToLength:1 + 2 * depth withString:@" " startingAtIndex:0]; +} + +- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json { + if ([fragment isKindOfClass:[NSDictionary class]]) { + if (![self appendDictionary:fragment into:json]) + return NO; + + } else if ([fragment isKindOfClass:[NSArray class]]) { + if (![self appendArray:fragment into:json]) + return NO; + + } else if ([fragment isKindOfClass:[NSString class]]) { + if (![self appendString:fragment into:json]) + return NO; + + } else if ([fragment isKindOfClass:[NSNumber class]]) { + if ('c' == *[fragment objCType]) + [json appendString:[fragment boolValue] ? @"true" : @"false"]; + else + [json appendString:[fragment stringValue]]; + + } else if ([fragment isKindOfClass:[NSNull class]]) { + [json appendString:@"null"]; + } else if ([fragment respondsToSelector:@selector(proxyForJson)]) { + [self appendValue:[fragment proxyForJson] into:json]; + + } else { + [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"JSON serialisation not supported for %@", [fragment class]]]; + return NO; + } + return YES; +} + +- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json { + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + [json appendString:@"["]; + + BOOL addComma = NO; + for (id value in fragment) { + if (addComma) + [json appendString:@","]; + else + addComma = YES; + + if ([self humanReadable]) + [json appendString:[self indent]]; + + if (![self appendValue:value into:json]) { + return NO; + } + } + + depth--; + if ([self humanReadable] && [fragment count]) + [json appendString:[self indent]]; + [json appendString:@"]"]; + return YES; +} + +- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json { + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + [json appendString:@"{"]; + + NSString *colon = [self humanReadable] ? @" : " : @":"; + BOOL addComma = NO; + NSArray *keys = [fragment allKeys]; + if (self.sortKeys) + keys = [keys sortedArrayUsingSelector:@selector(compare:)]; + + for (id value in keys) { + if (addComma) + [json appendString:@","]; + else + addComma = YES; + + if ([self humanReadable]) + [json appendString:[self indent]]; + + if (![value isKindOfClass:[NSString class]]) { + [self addErrorWithCode:EUNSUPPORTED description: @"JSON object key must be string"]; + return NO; + } + + if (![self appendString:value into:json]) + return NO; + + [json appendString:colon]; + if (![self appendValue:[fragment objectForKey:value] into:json]) { + [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"Unsupported value for key %@ in object", value]]; + return NO; + } + } + + depth--; + if ([self humanReadable] && [fragment count]) + [json appendString:[self indent]]; + [json appendString:@"}"]; + return YES; +} + +- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json { + + [json appendString:@"\""]; + + NSRange esc = [fragment rangeOfCharacterFromSet:kEscapeChars]; + if ( !esc.length ) { + // No special chars -- can just add the raw string: + [json appendString:fragment]; + + } else { + NSUInteger length = [fragment length]; + for (NSUInteger i = 0; i < length; i++) { + unichar uc = [fragment characterAtIndex:i]; + switch (uc) { + case '"': [json appendString:@"\\\""]; break; + case '\\': [json appendString:@"\\\\"]; break; + case '\t': [json appendString:@"\\t"]; break; + case '\n': [json appendString:@"\\n"]; break; + case '\r': [json appendString:@"\\r"]; break; + case '\b': [json appendString:@"\\b"]; break; + case '\f': [json appendString:@"\\f"]; break; + default: + if (uc < 0x20) { + [json appendFormat:@"\\u%04x", uc]; + } else { + CFStringAppendCharacters((CFMutableStringRef)json, &uc, 1); + } + break; + + } + } + } + + [json appendString:@"\""]; + return YES; +} + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h deleted file mode 100644 index a5190a03..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// SHKFBStreamDialog.h -// Adds a little bit extra control to FBStreamDialog -// -// Created by Nathan Weiner on 7/26/10. -// Copyright 2010 Idea Shower, LLC. All rights reserved. -// - -#import -#import "FBStreamDialog.h" - -@interface SHKFBStreamDialog : FBStreamDialog -{ - NSString *defaultStatus; -} - -@property (nonatomic, retain) NSString *defaultStatus; - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m deleted file mode 100644 index 53ec2152..00000000 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m +++ /dev/null @@ -1,40 +0,0 @@ -// -// SHKFBStreamDialog.m -// RIL -// -// Created by Nathan Weiner on 7/26/10. -// Copyright 2010 Idea Shower, LLC. All rights reserved. -// - -#import "SHKFBStreamDialog.h" -#import "SHK.h" - -@implementation SHKFBStreamDialog - -@synthesize defaultStatus; - -- (void)dealloc -{ - [defaultStatus release]; - [super dealloc]; -} - -- (void)webViewDidFinishLoad:(UIWebView *)webView -{ - [super webViewDidFinishLoad:webView]; - - if (defaultStatus) - { - // Set the pre-filled status message - [_webView stringByEvaluatingJavaScriptFromString: - [NSString stringWithFormat:@"document.getElementsByName('feedform_user_message')[0].value = decodeURIComponent('%@')", - [SHKEncode(defaultStatus) stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"] - ] - ]; - - // Make the text field bigger - [_webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByName('feedform_user_message')[0].style.height='100px'"]; - } -} - -@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h index ab0ee137..770485fd 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h @@ -26,27 +26,9 @@ // #import +#import "Facebook.h" #import "SHKSharer.h" -#import "FBConnect.h" - -typedef enum -{ - SHKFacebookPendingNone, - SHKFacebookPendingLogin, - SHKFacebookPendingStatus, - SHKFacebookPendingImage -} SHKFacebookPendingAction; - @interface SHKFacebook : SHKSharer -{ - FBSession *session; - SHKFacebookPendingAction pendingFacebookAction; - FBLoginDialog *login; -} - -@property (retain) FBSession *session; -@property SHKFacebookPendingAction pendingFacebookAction; -@property (retain) FBLoginDialog *login; - ++ (BOOL)handleOpenURL:(NSURL*)url; @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 2e2be608..582ca2ac 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -26,22 +26,48 @@ // #import "SHKFacebook.h" -#import "SHKFBStreamDialog.h" -@implementation SHKFacebook +NSString *const kSHKStoredItemKey=@"kSHKStoredItem"; +NSString *const kSHKFacebookAccessTokenKey=@"kSHKFacebookAccessToken"; +NSString *const kSHKFacebookExpiryDateKey=@"kSHKFacebookExpiryDate"; -@synthesize session; -@synthesize pendingFacebookAction; -@synthesize login; +@interface SHKFacebook() ++ (Facebook*)facebook; ++ (void)flushAccessToken; +@end + +@implementation SHKFacebook - (void)dealloc { - [session.delegates removeObject:self]; - [session release]; - [login release]; [super dealloc]; } ++ (Facebook*)facebook +{ + static Facebook *facebook=nil; + @synchronized([SHKFacebook class]) { + if (! facebook) + facebook = [[Facebook alloc] initWithAppId:SHKFacebookAppID]; + } + return facebook; +} + ++ (void)flushAccessToken +{ + Facebook *facebook = [self facebook]; + facebook.accessToken = nil; + facebook.expirationDate = nil; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:kSHKFacebookAccessTokenKey]; + [defaults removeObjectForKey:kSHKFacebookExpiryDateKey]; + [defaults synchronize]; +} + ++ (BOOL)handleOpenURL:(NSURL*)url +{ + return [[SHKFacebook facebook] handleOpenURL:url]; +} #pragma mark - #pragma mark Configuration : Service Defination @@ -76,63 +102,41 @@ + (BOOL)canShareOffline - (BOOL)shouldAutoShare { - return YES; // FBConnect presents its own dialog + return YES; } #pragma mark - #pragma mark Authentication - (BOOL)isAuthorized -{ - if (session == nil) - { - - if(!SHKFacebookUseSessionProxy){ - self.session = [FBSession sessionForApplication:SHKFacebookKey - secret:SHKFacebookSecret - delegate:self]; - - }else { - self.session = [FBSession sessionForApplication:SHKFacebookKey - getSessionProxy:SHKFacebookSessionProxyURL - delegate:self]; - } - - - return [session resume]; - } - - return [session isConnected]; +{ + Facebook *facebook = [SHKFacebook facebook]; + if ([facebook isSessionValid]) return YES; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + facebook.accessToken = [defaults stringForKey:kSHKFacebookAccessTokenKey]; + facebook.expirationDate = [defaults objectForKey:kSHKFacebookExpiryDateKey]; + return [facebook isSessionValid]; } - (void)promptAuthorization { - self.pendingFacebookAction = SHKFacebookPendingLogin; - self.login = [[[FBLoginDialog alloc] initWithSession:[self session]] autorelease]; - [login show]; + [[NSUserDefaults standardUserDefaults] setObject:[self.item dictionaryRepresentation] + forKey:kSHKStoredItemKey]; + [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", + @"offline_access", nil] + delegate:self]; } -- (void)authFinished:(SHKRequest *)request +- (void)authFinished:(SHKRequest *)req { - } + (void)logout { - FBSession *fbSession; - - if(!SHKFacebookUseSessionProxy){ - fbSession = [FBSession sessionForApplication:SHKFacebookKey - secret:SHKFacebookSecret - delegate:self]; - - }else { - fbSession = [FBSession sessionForApplication:SHKFacebookKey - getSessionProxy:SHKFacebookSessionProxyURL - delegate:self]; - } - - [fbSession logout]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:kSHKStoredItemKey]; + [self flushAccessToken]; + [[self facebook] logout:nil]; } #pragma mark - @@ -140,81 +144,80 @@ + (void)logout - (BOOL)send { - if (item.shareType == SHKShareTypeURL) + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + NSString *actions = [NSString stringWithFormat:@"{\"name\":\"Get %@\",\"link\":\"%@\"}", + SHKMyAppName, SHKMyAppURL]; + [params setObject:actions forKey:@"actions"]; + + if (item.shareType == SHKShareTypeURL && item.URL) { - self.pendingFacebookAction = SHKFacebookPendingStatus; - - SHKFBStreamDialog* dialog = [[[SHKFBStreamDialog alloc] init] autorelease]; - dialog.delegate = self; - dialog.userMessagePrompt = SHKLocalizedString(@"Enter your message:"); - dialog.attachment = [NSString stringWithFormat: - @"{\ - \"name\":\"%@\",\ - \"href\":\"%@\"\ - }", - item.title == nil ? SHKEncodeURL(item.URL) : SHKEncode(item.title), - SHKEncodeURL(item.URL) - ]; - dialog.defaultStatus = item.text; - dialog.actionLinks = [NSString stringWithFormat:@"[{\"text\":\"Get %@\",\"href\":\"%@\"}]", - SHKEncode(SHKMyAppName), - SHKEncode(SHKMyAppURL)]; - [dialog show]; - + NSString *url = [item.URL absoluteString]; + [params setObject:url forKey:@"link"]; + [params setObject:item.title == nil ? url : item.title + forKey:@"name"]; + if (item.text) + [params setObject:item.text forKey:@"message"]; + NSString *pictureURI = [item customValueForKey:@"picture"]; + if (pictureURI) + [params setObject:pictureURI forKey:@"picture"]; } - - else if (item.shareType == SHKShareTypeText) + else if (item.shareType == SHKShareTypeText && item.text) { - self.pendingFacebookAction = SHKFacebookPendingStatus; - - SHKFBStreamDialog* dialog = [[[SHKFBStreamDialog alloc] init] autorelease]; - dialog.delegate = self; - dialog.userMessagePrompt = SHKLocalizedString(@"Enter your message:"); - dialog.defaultStatus = item.text; - dialog.actionLinks = [NSString stringWithFormat:@"[{\"text\":\"Get %@\",\"href\":\"%@\"}]", - SHKEncode(SHKMyAppName), - SHKEncode(SHKMyAppURL)]; - [dialog show]; - - } - - else if (item.shareType == SHKShareTypeImage) - { - self.pendingFacebookAction = SHKFacebookPendingImage; - - FBPermissionDialog* dialog = [[[FBPermissionDialog alloc] init] autorelease]; - dialog.delegate = self; - dialog.permission = @"photo_upload"; - [dialog show]; - } - + [params setObject:item.text forKey:@"message"]; + } + else if (item.shareType == SHKShareTypeImage && item.image) + { + if (item.title) + [params setObject:item.title forKey:@"name"]; + if (item.text) + [params setObject:item.text forKey:@"message"]; + [params setObject:item.image forKey:@"picture"]; + // There does not appear to be a way to add the photo + // via the dialog option: + [[SHKFacebook facebook] requestWithGraphPath:@"me/photos" + andParams:params + andHttpMethod:@"POST" + andDelegate:self]; + return YES; + } + else + // There is nothing to send + return NO; + + [[SHKFacebook facebook] dialog:@"feed" + andParams:params + andDelegate:self]; return YES; } -- (void)sendImage -{ - [self sendDidStart]; +#pragma mark - +#pragma mark FBDialogDelegate methods - [[FBRequest requestWithDelegate:self] call:@"facebook.photos.upload" - params:[NSDictionary dictionaryWithObjectsAndKeys:item.title, @"caption", nil] - dataParam:UIImageJPEGRepresentation(item.image,1.0)]; +- (void)dialogDidComplete:(FBDialog *)dialog +{ + [self sendDidFinish]; } -- (void)dialogDidSucceed:(FBDialog*)dialog +- (void)dialogCompleteWithUrl:(NSURL *)url { - if (pendingFacebookAction == SHKFacebookPendingImage) - [self sendImage]; - - // TODO - the dialog has a SKIP button. Skipping still calls this even though it doesn't appear to post. - // - need to intercept the skip and handle it as a cancel? - else if (pendingFacebookAction == SHKFacebookPendingStatus) - [self sendDidFinish]; + // error_code=190: user changed password or revoked access to the application, + // so spin the user back over to authentication : + NSRange errorRange = [[url absoluteString] rangeOfString:@"error_code=190"]; + if (errorRange.location != NSNotFound) + { + [SHKFacebook flushAccessToken]; + [self authorize]; + } } - (void)dialogDidCancel:(FBDialog*)dialog { - if (pendingFacebookAction == SHKFacebookPendingStatus) - [self sendDidCancel]; + [self sendDidCancel]; +} + +- (void)dialog:(FBDialog *)dialog didFailWithError:(NSError *)error +{ + [self sendDidFailWithError:error]; } - (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL*)url @@ -222,34 +225,36 @@ - (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL*)url return YES; } - #pragma mark FBSessionDelegate methods -- (void)session:(FBSession*)session didLogin:(FBUID)uid +- (void)fbDidLogin { - // Try to share again - if (pendingFacebookAction == SHKFacebookPendingLogin) - { - self.pendingFacebookAction = SHKFacebookPendingNone; - [self share]; - } + NSString *accessToken = [[SHKFacebook facebook] accessToken]; + NSDate *expiryDate = [[SHKFacebook facebook] expirationDate]; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setObject:accessToken forKey:kSHKFacebookAccessTokenKey]; + [defaults setObject:expiryDate forKey:kSHKFacebookExpiryDateKey]; + NSDictionary *storedItem = [defaults objectForKey:kSHKStoredItemKey]; + if (storedItem) + { + self.item = [SHKItem itemFromDictionary:storedItem]; + [defaults removeObjectForKey:kSHKStoredItemKey]; + } + [defaults synchronize]; + if (self.item) + [self share]; } -- (void)session:(FBSession*)session willLogout:(FBUID)uid +#pragma mark FBRequestDelegate methods + +- (void)requestLoading:(FBRequest *)request { - // Not handling this + [self sendDidStart]; } - -#pragma mark FBRequestDelegate methods - -- (void)request:(FBRequest*)aRequest didLoad:(id)result +- (void)request:(FBRequest *)request didLoad:(id)result { - if ([aRequest.method isEqualToString:@"facebook.photos.upload"]) - { - // PID is in [result objectForKey:@"pid"]; - [self sendDidFinish]; - } + [self sendDidFinish]; } - (void)request:(FBRequest*)aRequest didFailWithError:(NSError*)error @@ -257,6 +262,4 @@ - (void)request:(FBRequest*)aRequest didFailWithError:(NSError*)error [self sendDidFailWithError:error]; } - - @end diff --git a/ShareKit-Info.plist b/ShareKit-Info.plist index d5dc4bd3..9c348dc9 100644 --- a/ShareKit-Info.plist +++ b/ShareKit-Info.plist @@ -20,8 +20,21 @@ APPL CFBundleSignature ???? + CFBundleURLTypes + + + CFBundleURLName + + CFBundleURLSchemes + + fb${FACEBOOK_APP_ID} + + + CFBundleVersion 1.0 + FacebookURLTypeIndex + 0 LSRequiresIPhoneOS NSMainNibFile diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index adcbf90e..b61a5cae 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -7,6 +7,18 @@ objects = { /* Begin PBXBuildFile section */ + 1940B69D138D45F900217886 /* Facebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B686138D45F900217886 /* Facebook.m */; }; + 1940B69E138D45F900217886 /* FBDialog.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 1940B688138D45F900217886 /* FBDialog.bundle */; }; + 1940B69F138D45F900217886 /* FBDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B68A138D45F900217886 /* FBDialog.m */; }; + 1940B6A0138D45F900217886 /* FBLoginDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B68C138D45F900217886 /* FBLoginDialog.m */; }; + 1940B6A1138D45F900217886 /* FBRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B68E138D45F900217886 /* FBRequest.m */; }; + 1940B6A2138D45F900217886 /* NSObject+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B692138D45F900217886 /* NSObject+SBJSON.m */; }; + 1940B6A3138D45F900217886 /* NSString+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B694138D45F900217886 /* NSString+SBJSON.m */; }; + 1940B6A4138D45F900217886 /* SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B696138D45F900217886 /* SBJSON.m */; }; + 1940B6A5138D45F900217886 /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B698138D45F900217886 /* SBJsonBase.m */; }; + 1940B6A6138D45F900217886 /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B69A138D45F900217886 /* SBJsonParser.m */; }; + 1940B6A7138D45F900217886 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B69C138D45F900217886 /* SBJsonWriter.m */; }; + 19DDAEB0138D7686004A7C34 /* SHKEvernote.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2B11291AC9700D2A41E /* SHKEvernote.m */; }; 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; @@ -30,7 +42,6 @@ 4379F2BE1291AC9700D2A41E /* TMemoryBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2AA1291AC9700D2A41E /* TMemoryBuffer.m */; }; 4379F2BF1291AC9700D2A41E /* TTransportException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2AD1291AC9700D2A41E /* TTransportException.m */; }; 4379F2C01291AC9700D2A41E /* TSharedProcessorFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2AF1291AC9700D2A41E /* TSharedProcessorFactory.m */; }; - 4379F2C11291AC9700D2A41E /* SHKEvernote.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2B11291AC9700D2A41E /* SHKEvernote.m */; }; 4379F2C21291AC9700D2A41E /* SHKEvernote.md in Resources */ = {isa = PBXBuildFile; fileRef = 4379F2B21291AC9700D2A41E /* SHKEvernote.md */; }; 4379F2EA1291AE5700D2A41E /* NSData+md5.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2E91291AE5700D2A41E /* NSData+md5.m */; }; 4379F3B21291C45700D2A41E /* SHKTextMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F3B11291C45700D2A41E /* SHKTextMessage.m */; }; @@ -65,17 +76,6 @@ 43A5371D11DBE3B9004A1712 /* SHKMail.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536BC11DBE3B9004A1712 /* SHKMail.m */; }; 43A5371E11DBE3B9004A1712 /* SHKSafari.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536BF11DBE3B9004A1712 /* SHKSafari.m */; }; 43A5371F11DBE3B9004A1712 /* SHKDelicious.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536C311DBE3B9004A1712 /* SHKDelicious.m */; }; - 43A5372011DBE3B9004A1712 /* FBConnect.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 43A536C611DBE3B9004A1712 /* FBConnect.bundle */; }; - 43A5372111DBE3B9004A1712 /* FBConnectGlobal.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536C911DBE3B9004A1712 /* FBConnectGlobal.m */; }; - 43A5372211DBE3B9004A1712 /* FBDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536CB11DBE3B9004A1712 /* FBDialog.m */; }; - 43A5372311DBE3B9004A1712 /* FBFeedDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536CD11DBE3B9004A1712 /* FBFeedDialog.m */; }; - 43A5372411DBE3B9004A1712 /* FBLoginButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536CF11DBE3B9004A1712 /* FBLoginButton.m */; }; - 43A5372511DBE3B9004A1712 /* FBLoginDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D111DBE3B9004A1712 /* FBLoginDialog.m */; }; - 43A5372611DBE3B9004A1712 /* FBPermissionDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D311DBE3B9004A1712 /* FBPermissionDialog.m */; }; - 43A5372711DBE3B9004A1712 /* FBRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D511DBE3B9004A1712 /* FBRequest.m */; }; - 43A5372811DBE3B9004A1712 /* FBSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D711DBE3B9004A1712 /* FBSession.m */; }; - 43A5372911DBE3B9004A1712 /* FBStreamDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D911DBE3B9004A1712 /* FBStreamDialog.m */; }; - 43A5372A11DBE3B9004A1712 /* FBXMLHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536DB11DBE3B9004A1712 /* FBXMLHandler.m */; }; 43A5372B11DBE3B9004A1712 /* SHKFacebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; }; 43A5372C11DBE3B9004A1712 /* SHKGoogleReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */; }; 43A5372D11DBE3B9004A1712 /* SHKPinboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536E311DBE3B9004A1712 /* SHKPinboard.m */; }; @@ -100,7 +100,6 @@ 43A5383B11DBE493004A1712 /* ShareKitAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5383511DBE493004A1712 /* ShareKitAppDelegate.m */; }; 43A53C0911DC07A9004A1712 /* SHKCustomShareMenuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */; }; 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */; }; - 43B934B511FE682600C9D3F3 /* SHKFBStreamDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43B934B411FE682600C9D3F3 /* SHKFBStreamDialog.m */; }; 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43C91D1C11EB963600F31FAE /* MainWindow-iPad.xib */; }; 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */ = {isa = PBXBuildFile; fileRef = 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */; }; 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */; }; @@ -109,6 +108,29 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 1940B685138D45F900217886 /* Facebook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Facebook.h; sourceTree = ""; }; + 1940B686138D45F900217886 /* Facebook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Facebook.m; sourceTree = ""; }; + 1940B687138D45F900217886 /* FBConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnect.h; sourceTree = ""; }; + 1940B688138D45F900217886 /* FBDialog.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = FBDialog.bundle; sourceTree = ""; }; + 1940B689138D45F900217886 /* FBDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBDialog.h; sourceTree = ""; }; + 1940B68A138D45F900217886 /* FBDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBDialog.m; sourceTree = ""; }; + 1940B68B138D45F900217886 /* FBLoginDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginDialog.h; sourceTree = ""; }; + 1940B68C138D45F900217886 /* FBLoginDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginDialog.m; sourceTree = ""; }; + 1940B68D138D45F900217886 /* FBRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBRequest.h; sourceTree = ""; }; + 1940B68E138D45F900217886 /* FBRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRequest.m; sourceTree = ""; }; + 1940B690138D45F900217886 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; + 1940B691138D45F900217886 /* NSObject+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJSON.h"; sourceTree = ""; }; + 1940B692138D45F900217886 /* NSObject+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJSON.m"; sourceTree = ""; }; + 1940B693138D45F900217886 /* NSString+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SBJSON.h"; sourceTree = ""; }; + 1940B694138D45F900217886 /* NSString+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SBJSON.m"; sourceTree = ""; }; + 1940B695138D45F900217886 /* SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJSON.h; sourceTree = ""; }; + 1940B696138D45F900217886 /* SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJSON.m; sourceTree = ""; }; + 1940B697138D45F900217886 /* SBJsonBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonBase.h; sourceTree = ""; }; + 1940B698138D45F900217886 /* SBJsonBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonBase.m; sourceTree = ""; }; + 1940B699138D45F900217886 /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = ""; }; + 1940B69A138D45F900217886 /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = ""; }; + 1940B69B138D45F900217886 /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = ""; }; + 1940B69C138D45F900217886 /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = ""; }; 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 1D6058910D05DD3D006BFB54 /* ShareKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShareKit.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; @@ -232,28 +254,6 @@ 43A536BF11DBE3B9004A1712 /* SHKSafari.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKSafari.m; sourceTree = ""; }; 43A536C211DBE3B9004A1712 /* SHKDelicious.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKDelicious.h; sourceTree = ""; }; 43A536C311DBE3B9004A1712 /* SHKDelicious.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKDelicious.m; sourceTree = ""; }; - 43A536C611DBE3B9004A1712 /* FBConnect.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = FBConnect.bundle; sourceTree = ""; }; - 43A536C711DBE3B9004A1712 /* FBConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnect.h; sourceTree = ""; }; - 43A536C811DBE3B9004A1712 /* FBConnectGlobal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnectGlobal.h; sourceTree = ""; }; - 43A536C911DBE3B9004A1712 /* FBConnectGlobal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBConnectGlobal.m; sourceTree = ""; }; - 43A536CA11DBE3B9004A1712 /* FBDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBDialog.h; sourceTree = ""; }; - 43A536CB11DBE3B9004A1712 /* FBDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBDialog.m; sourceTree = ""; }; - 43A536CC11DBE3B9004A1712 /* FBFeedDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBFeedDialog.h; sourceTree = ""; }; - 43A536CD11DBE3B9004A1712 /* FBFeedDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBFeedDialog.m; sourceTree = ""; }; - 43A536CE11DBE3B9004A1712 /* FBLoginButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginButton.h; sourceTree = ""; }; - 43A536CF11DBE3B9004A1712 /* FBLoginButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginButton.m; sourceTree = ""; }; - 43A536D011DBE3B9004A1712 /* FBLoginDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginDialog.h; sourceTree = ""; }; - 43A536D111DBE3B9004A1712 /* FBLoginDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginDialog.m; sourceTree = ""; }; - 43A536D211DBE3B9004A1712 /* FBPermissionDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBPermissionDialog.h; sourceTree = ""; }; - 43A536D311DBE3B9004A1712 /* FBPermissionDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBPermissionDialog.m; sourceTree = ""; }; - 43A536D411DBE3B9004A1712 /* FBRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBRequest.h; sourceTree = ""; }; - 43A536D511DBE3B9004A1712 /* FBRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRequest.m; sourceTree = ""; }; - 43A536D611DBE3B9004A1712 /* FBSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSession.h; sourceTree = ""; }; - 43A536D711DBE3B9004A1712 /* FBSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSession.m; sourceTree = ""; }; - 43A536D811DBE3B9004A1712 /* FBStreamDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBStreamDialog.h; sourceTree = ""; }; - 43A536D911DBE3B9004A1712 /* FBStreamDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBStreamDialog.m; sourceTree = ""; }; - 43A536DA11DBE3B9004A1712 /* FBXMLHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBXMLHandler.h; sourceTree = ""; }; - 43A536DB11DBE3B9004A1712 /* FBXMLHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBXMLHandler.m; sourceTree = ""; }; 43A536DC11DBE3B9004A1712 /* SHKFacebook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFacebook.h; sourceTree = ""; }; 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFacebook.m; sourceTree = ""; }; 43A536DF11DBE3B9004A1712 /* SHKGoogleReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKGoogleReader.h; sourceTree = ""; }; @@ -301,8 +301,6 @@ 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenuCell.m; sourceTree = ""; }; 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKCustomShareMenu.h; sourceTree = ""; }; 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenu.m; sourceTree = ""; }; - 43B934B311FE682600C9D3F3 /* SHKFBStreamDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFBStreamDialog.h; sourceTree = ""; }; - 43B934B411FE682600C9D3F3 /* SHKFBStreamDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFBStreamDialog.m; sourceTree = ""; }; 43C91D1C11EB963600F31FAE /* MainWindow-iPad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "MainWindow-iPad.xib"; path = "Resources-iPad/MainWindow-iPad.xib"; sourceTree = ""; }; 43C91DF311EBAE4800F31FAE /* SHKTumblr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKTumblr.h; sourceTree = ""; }; 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTumblr.m; sourceTree = ""; }; @@ -339,6 +337,44 @@ path = Classes; sourceTree = ""; }; + 1940B684138D45F800217886 /* FBConnect */ = { + isa = PBXGroup; + children = ( + 1940B688138D45F900217886 /* FBDialog.bundle */, + 1940B685138D45F900217886 /* Facebook.h */, + 1940B686138D45F900217886 /* Facebook.m */, + 1940B687138D45F900217886 /* FBConnect.h */, + 1940B689138D45F900217886 /* FBDialog.h */, + 1940B68A138D45F900217886 /* FBDialog.m */, + 1940B68B138D45F900217886 /* FBLoginDialog.h */, + 1940B68C138D45F900217886 /* FBLoginDialog.m */, + 1940B68D138D45F900217886 /* FBRequest.h */, + 1940B68E138D45F900217886 /* FBRequest.m */, + 1940B68F138D45F900217886 /* JSON */, + ); + path = FBConnect; + sourceTree = ""; + }; + 1940B68F138D45F900217886 /* JSON */ = { + isa = PBXGroup; + children = ( + 1940B690138D45F900217886 /* JSON.h */, + 1940B691138D45F900217886 /* NSObject+SBJSON.h */, + 1940B692138D45F900217886 /* NSObject+SBJSON.m */, + 1940B693138D45F900217886 /* NSString+SBJSON.h */, + 1940B694138D45F900217886 /* NSString+SBJSON.m */, + 1940B695138D45F900217886 /* SBJSON.h */, + 1940B696138D45F900217886 /* SBJSON.m */, + 1940B697138D45F900217886 /* SBJsonBase.h */, + 1940B698138D45F900217886 /* SBJsonBase.m */, + 1940B699138D45F900217886 /* SBJsonParser.h */, + 1940B69A138D45F900217886 /* SBJsonParser.m */, + 1940B69B138D45F900217886 /* SBJsonWriter.h */, + 1940B69C138D45F900217886 /* SBJsonWriter.m */, + ); + path = JSON; + sourceTree = ""; + }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( @@ -745,44 +781,13 @@ 43A536C411DBE3B9004A1712 /* Facebook */ = { isa = PBXGroup; children = ( - 43A536C511DBE3B9004A1712 /* FBConnect */, + 1940B684138D45F800217886 /* FBConnect */, 43A536DC11DBE3B9004A1712 /* SHKFacebook.h */, 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */, - 43B934B311FE682600C9D3F3 /* SHKFBStreamDialog.h */, - 43B934B411FE682600C9D3F3 /* SHKFBStreamDialog.m */, ); path = Facebook; sourceTree = ""; }; - 43A536C511DBE3B9004A1712 /* FBConnect */ = { - isa = PBXGroup; - children = ( - 43A536C611DBE3B9004A1712 /* FBConnect.bundle */, - 43A536C711DBE3B9004A1712 /* FBConnect.h */, - 43A536C811DBE3B9004A1712 /* FBConnectGlobal.h */, - 43A536C911DBE3B9004A1712 /* FBConnectGlobal.m */, - 43A536CA11DBE3B9004A1712 /* FBDialog.h */, - 43A536CB11DBE3B9004A1712 /* FBDialog.m */, - 43A536CC11DBE3B9004A1712 /* FBFeedDialog.h */, - 43A536CD11DBE3B9004A1712 /* FBFeedDialog.m */, - 43A536CE11DBE3B9004A1712 /* FBLoginButton.h */, - 43A536CF11DBE3B9004A1712 /* FBLoginButton.m */, - 43A536D011DBE3B9004A1712 /* FBLoginDialog.h */, - 43A536D111DBE3B9004A1712 /* FBLoginDialog.m */, - 43A536D211DBE3B9004A1712 /* FBPermissionDialog.h */, - 43A536D311DBE3B9004A1712 /* FBPermissionDialog.m */, - 43A536D411DBE3B9004A1712 /* FBRequest.h */, - 43A536D511DBE3B9004A1712 /* FBRequest.m */, - 43A536D611DBE3B9004A1712 /* FBSession.h */, - 43A536D711DBE3B9004A1712 /* FBSession.m */, - 43A536D811DBE3B9004A1712 /* FBStreamDialog.h */, - 43A536D911DBE3B9004A1712 /* FBStreamDialog.m */, - 43A536DA11DBE3B9004A1712 /* FBXMLHandler.h */, - 43A536DB11DBE3B9004A1712 /* FBXMLHandler.m */, - ); - path = FBConnect; - sourceTree = ""; - }; 43A536DE11DBE3B9004A1712 /* Google Reader */ = { isa = PBXGroup; children = ( @@ -952,12 +957,12 @@ 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */, 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */, 43A5371811DBE3B9004A1712 /* SHKSharers.plist in Resources */, - 43A5372011DBE3B9004A1712 /* FBConnect.bundle in Resources */, 43A5382811DBE480004A1712 /* example.pdf in Resources */, 43A5382911DBE480004A1712 /* sanFran.jpg in Resources */, 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */, 43FF9C7412270E9F00ADE53C /* Localizable.strings in Resources */, 4379F2C21291AC9700D2A41E /* SHKEvernote.md in Resources */, + 1940B69E138D45F900217886 /* FBDialog.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -999,16 +1004,6 @@ 43A5371D11DBE3B9004A1712 /* SHKMail.m in Sources */, 43A5371E11DBE3B9004A1712 /* SHKSafari.m in Sources */, 43A5371F11DBE3B9004A1712 /* SHKDelicious.m in Sources */, - 43A5372111DBE3B9004A1712 /* FBConnectGlobal.m in Sources */, - 43A5372211DBE3B9004A1712 /* FBDialog.m in Sources */, - 43A5372311DBE3B9004A1712 /* FBFeedDialog.m in Sources */, - 43A5372411DBE3B9004A1712 /* FBLoginButton.m in Sources */, - 43A5372511DBE3B9004A1712 /* FBLoginDialog.m in Sources */, - 43A5372611DBE3B9004A1712 /* FBPermissionDialog.m in Sources */, - 43A5372711DBE3B9004A1712 /* FBRequest.m in Sources */, - 43A5372811DBE3B9004A1712 /* FBSession.m in Sources */, - 43A5372911DBE3B9004A1712 /* FBStreamDialog.m in Sources */, - 43A5372A11DBE3B9004A1712 /* FBXMLHandler.m in Sources */, 43A5372B11DBE3B9004A1712 /* SHKFacebook.m in Sources */, 43A5372C11DBE3B9004A1712 /* SHKGoogleReader.m in Sources */, 43A5372D11DBE3B9004A1712 /* SHKPinboard.m in Sources */, @@ -1033,7 +1028,6 @@ 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */, 43150A8D11E78697008C6B68 /* SHKInstapaper.m in Sources */, 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */, - 43B934B511FE682600C9D3F3 /* SHKFBStreamDialog.m in Sources */, 432B147C11FF4B0700291B37 /* SHKPhotoAlbum.m in Sources */, 4379F2B31291AC9700D2A41E /* EDAMLimits.m in Sources */, 4379F2B41291AC9700D2A41E /* Errors.m in Sources */, @@ -1049,9 +1043,19 @@ 4379F2BE1291AC9700D2A41E /* TMemoryBuffer.m in Sources */, 4379F2BF1291AC9700D2A41E /* TTransportException.m in Sources */, 4379F2C01291AC9700D2A41E /* TSharedProcessorFactory.m in Sources */, - 4379F2C11291AC9700D2A41E /* SHKEvernote.m in Sources */, 4379F2EA1291AE5700D2A41E /* NSData+md5.m in Sources */, 4379F3B21291C45700D2A41E /* SHKTextMessage.m in Sources */, + 1940B69D138D45F900217886 /* Facebook.m in Sources */, + 1940B69F138D45F900217886 /* FBDialog.m in Sources */, + 1940B6A0138D45F900217886 /* FBLoginDialog.m in Sources */, + 1940B6A1138D45F900217886 /* FBRequest.m in Sources */, + 1940B6A2138D45F900217886 /* NSObject+SBJSON.m in Sources */, + 1940B6A3138D45F900217886 /* NSString+SBJSON.m in Sources */, + 1940B6A4138D45F900217886 /* SBJSON.m in Sources */, + 1940B6A5138D45F900217886 /* SBJsonBase.m in Sources */, + 1940B6A6138D45F900217886 /* SBJsonParser.m in Sources */, + 1940B6A7138D45F900217886 /* SBJsonWriter.m in Sources */, + 19DDAEB0138D7686004A7C34 /* SHKEvernote.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From cc9f2ac4ede48cf88402c501c745643c477f6bb5 Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Wed, 25 May 2011 16:02:33 -0400 Subject: [PATCH 04/13] Instructions specific to the new FBConnect code --- README | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/README b/README index 87f0bac7..eb535d4c 100644 --- a/README +++ b/README @@ -1,5 +1,49 @@ The code hosted here on github is for ongoing development and contributions and may contain untested code. Please use a stable release from http://getsharekit.com for use in your own app. +## Further installation instructions: + +0. At the top of your AppDelegate.m file, be sure to include SHKFacebook.h: + +#import "SHKFacebook.h" + +1. In your AppDelegate, include these two methods (or merge if you already use them, remembering to properly delegate): + +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation +{ + return [SHKFacebook handleOpenURL:url]; +} + +- (BOOL)application:(UIApplication *)application + handleOpenURL:(NSURL *)url +{ + return [SHKFacebook handleOpenURL:url]; +} + +2. In your App-Info.plist, include this property: + + CFBundleURLTypes + + + CFBundleURLName + + CFBundleURLSchemes + + fb${FACEBOOK_APP_ID} + + + + +Where fb${FACEBOOK_APP_ID} looks like fb1234 + +3. Finally, in SHKConfig.h, set the facebook API ID: + +#define SHKFacebookAppID @"1234" + +4. Follow the standard ShareKit instructions below + *** To download a stable release visit: From ebf8f37cf6e3133a536d86708522b4d6a35b0319 Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Thu, 26 May 2011 10:08:28 -0400 Subject: [PATCH 05/13] Including the image's image (as NSData) in the dictionaryRepresentation --- Classes/ShareKit/Core/SHKItem.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Classes/ShareKit/Core/SHKItem.m b/Classes/ShareKit/Core/SHKItem.m index 76a44613..f0df7353 100644 --- a/Classes/ShareKit/Core/SHKItem.m +++ b/Classes/ShareKit/Core/SHKItem.m @@ -150,6 +150,11 @@ + (SHKItem *)itemFromDictionary:(NSDictionary *)dictionary item.text = [dictionary objectForKey:@"text"]; item.tags = [dictionary objectForKey:@"tags"]; + NSData *imageData = [dictionary objectForKey:@"image"]; + if (imageData) { + item.image = [UIImage imageWithData:imageData]; + } + if ([dictionary objectForKey:@"custom"] != nil) item.custom = [[[dictionary objectForKey:@"custom"] mutableCopy] autorelease]; @@ -177,6 +182,11 @@ - (NSDictionary *)dictionaryRepresentation if (tags != nil) [dictionary setObject:tags forKey:@"tags"]; + if (image != nil) + { + NSData *imageData = UIImagePNGRepresentation(image); + [dictionary setObject:imageData forKey:@"image"]; + } // If you add anymore, make sure to add a method for retrieving them to the itemWithDictionary function too return dictionary; From 1f0d6a91adcf969a01641272044f7bca472dfa89 Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Thu, 26 May 2011 10:55:52 -0400 Subject: [PATCH 06/13] Storing and retrieving the actual image so that image posts work correctly after authorization --- .../Sharers/Services/Facebook/SHKFacebook.m | 51 +++++++++++++++++-- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 582ca2ac..a3a0c7b7 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -27,13 +27,15 @@ #import "SHKFacebook.h" -NSString *const kSHKStoredItemKey=@"kSHKStoredItem"; -NSString *const kSHKFacebookAccessTokenKey=@"kSHKFacebookAccessToken"; -NSString *const kSHKFacebookExpiryDateKey=@"kSHKFacebookExpiryDate"; +static NSString *const kSHKStoredItemKey=@"kSHKStoredItem"; +static NSString *const kSHKFacebookAccessTokenKey=@"kSHKFacebookAccessToken"; +static NSString *const kSHKFacebookExpiryDateKey=@"kSHKFacebookExpiryDate"; @interface SHKFacebook() + (Facebook*)facebook; + (void)flushAccessToken; ++ (NSString *)storedImagePath:(UIImage*)image; ++ (UIImage*)storedImage:(NSString*)imagePath; @end @implementation SHKFacebook @@ -64,6 +66,37 @@ + (void)flushAccessToken [defaults synchronize]; } ++ (NSString *)storedImagePath:(UIImage*)image +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSArray *paths = NSSearchPathForDirectoriesInDomains( NSCachesDirectory, NSUserDomainMask, YES); + NSString *cache = [paths objectAtIndex:0]; + NSString *imagePath = [cache stringByAppendingPathComponent:@"SHKImage"]; + + // Check if the path exists, otherwise create it + if (![fileManager fileExistsAtPath:imagePath]) + [fileManager createDirectoryAtPath:imagePath withIntermediateDirectories:YES attributes:nil error:nil]; + + NSString *uid = [NSString stringWithFormat:@"img-%i-%i", [[NSDate date] timeIntervalSince1970], arc4random()]; + // store image in cache + NSData *imageData = UIImagePNGRepresentation(image); + imagePath = [imagePath stringByAppendingPathComponent:uid]; + [imageData writeToFile:imagePath atomically:YES]; + + return imagePath; +} + ++ (UIImage*)storedImage:(NSString*)imagePath { + NSData *imageData = [NSData dataWithContentsOfFile:imagePath]; + UIImage *image = nil; + if (imageData) { + image = [UIImage imageWithData:imageData]; + } + // Unlink the stored file: + [[NSFileManager defaultManager] removeItemAtPath:imagePath error:nil]; + return image; +} + + (BOOL)handleOpenURL:(NSURL*)url { return [[SHKFacebook facebook] handleOpenURL:url]; @@ -121,8 +154,12 @@ - (BOOL)isAuthorized - (void)promptAuthorization { - [[NSUserDefaults standardUserDefaults] setObject:[self.item dictionaryRepresentation] - forKey:kSHKStoredItemKey]; + NSMutableDictionary *itemRep = [NSMutableDictionary dictionaryWithDictionary:[self.item dictionaryRepresentation]]; + if (item.image) + { + [itemRep setObject:[SHKFacebook storedImagePath:item.image] forKey:@"imagePath"]; + } + [[NSUserDefaults standardUserDefaults] setObject:itemRep forKey:kSHKStoredItemKey]; [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", @"offline_access", nil] delegate:self]; @@ -238,6 +275,10 @@ - (void)fbDidLogin if (storedItem) { self.item = [SHKItem itemFromDictionary:storedItem]; + NSString *imagePath = [storedItem objectForKey:@"imagePath"]; + if (imagePath) { + self.item.image = [SHKFacebook storedImage:imagePath]; + } [defaults removeObjectForKey:kSHKStoredItemKey]; } [defaults synchronize]; From fce93809e4e13a1e6aabf2612d893b92c5f31ef3 Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Thu, 26 May 2011 17:56:30 -0400 Subject: [PATCH 07/13] + A bit more of a description of what is happening with the Facebook IDs + Added SHKFacebookLocalAppID --- Classes/ShareKit/SHKConfig.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 9c6a1efb..6d594592 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -43,10 +43,17 @@ #define SHKDeliciousSecretKey @"" // Facebook - http://www.facebook.com/developers -// If SHKFacebookUseSessionProxy is enabled then SHKFacebookSecret is ignored and should be left blank - +// SHKFacebookAppID is the Application ID provided by Facebook +// SHKFacebookLocalAppID is used if you need to differentiate between several iOS apps running against a single Facebook app. Leave it blank unless you are sure of what you are doing. +// The CFBundleURLSchemes in your App-Info.plist should be "fb" + the concatenation of these two IDs. +// Example: +// SHKFacebookAppID = 555 +// SHKFacebookLocalAppID = funk +// +// Your CFBundleURLSchemes entry: fb555funk #define SHKFacebookUseSessionProxy NO #define SHKFacebookAppID @"" +#define SHKFacebookLocalAppID @"" #define SHKFacebookSessionProxyURL @"" // Read It Later - http://readitlaterlist.com/api/?shk From 88ef9cb8e3915333b01611bda25f33f3355c7f17 Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Thu, 26 May 2011 17:56:52 -0400 Subject: [PATCH 08/13] Support for SHKFacebookLocalAppID --- .../Sharers/Services/Facebook/SHKFacebook.m | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index a3a0c7b7..e56ca70f 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -160,9 +160,16 @@ - (void)promptAuthorization [itemRep setObject:[SHKFacebook storedImagePath:item.image] forKey:@"imagePath"]; } [[NSUserDefaults standardUserDefaults] setObject:itemRep forKey:kSHKStoredItemKey]; - [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", - @"offline_access", nil] - delegate:self]; + if ((! SHKFacebookLocalAppID) || [SHKFacebookLocalAppID isEqualToString:@""]) { + [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", + @"offline_access", nil] + delegate:self]; + } else { + [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", + @"offline_access", nil] + delegate:self + localAppId:SHKFacebookLocalAppID]; + } } - (void)authFinished:(SHKRequest *)req From ab6ecdc9c8e0c6305ba1cde28d0cef8e2235cad9 Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Mon, 30 May 2011 09:48:52 -0400 Subject: [PATCH 09/13] Added Evernote related definitions --- Classes/ShareKit/SHKConfig.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 6d594592..39950957 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -85,6 +85,13 @@ #define SHKBitLyLogin @"" #define SHKBitLyKey @"" + +// Evernote +#define SHKEvernoteUserStoreURL @"" +#define SHKEvernoteConsumerKey @"" +#define SHKEvernoteSecretKey @"" +#define SHKEvernoteNetStoreURLBase @"" + // ShareMenu Ordering #define SHKShareMenuAlphabeticalOrder 1 // Setting this to 1 will show list in Alphabetical Order, setting to 0 will follow the order in SHKShares.plist From aedfae065d2d01022b94bb5ac2311a85ee95513f Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Mon, 30 May 2011 09:49:15 -0400 Subject: [PATCH 10/13] Correctly setting item caption --- Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index e56ca70f..acbf6109 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -212,7 +212,7 @@ - (BOOL)send else if (item.shareType == SHKShareTypeImage && item.image) { if (item.title) - [params setObject:item.title forKey:@"name"]; + [params setObject:item.title forKey:@"caption"]; if (item.text) [params setObject:item.text forKey:@"message"]; [params setObject:item.image forKey:@"picture"]; From 3ae4020368974a38b6147def59db400d255794a5 Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Mon, 30 May 2011 09:49:51 -0400 Subject: [PATCH 11/13] Reenabled SHKEvernote with new #defines in SHKConfig.h --- ShareKit.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index b61a5cae..eaa9289b 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1913BF76138FF6A800AAD620 /* SHKEvernote.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2B11291AC9700D2A41E /* SHKEvernote.m */; }; 1940B69D138D45F900217886 /* Facebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B686138D45F900217886 /* Facebook.m */; }; 1940B69E138D45F900217886 /* FBDialog.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 1940B688138D45F900217886 /* FBDialog.bundle */; }; 1940B69F138D45F900217886 /* FBDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B68A138D45F900217886 /* FBDialog.m */; }; @@ -18,7 +19,6 @@ 1940B6A5138D45F900217886 /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B698138D45F900217886 /* SBJsonBase.m */; }; 1940B6A6138D45F900217886 /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B69A138D45F900217886 /* SBJsonParser.m */; }; 1940B6A7138D45F900217886 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1940B69C138D45F900217886 /* SBJsonWriter.m */; }; - 19DDAEB0138D7686004A7C34 /* SHKEvernote.m in Sources */ = {isa = PBXBuildFile; fileRef = 4379F2B11291AC9700D2A41E /* SHKEvernote.m */; }; 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; @@ -1055,7 +1055,7 @@ 1940B6A5138D45F900217886 /* SBJsonBase.m in Sources */, 1940B6A6138D45F900217886 /* SBJsonParser.m in Sources */, 1940B6A7138D45F900217886 /* SBJsonWriter.m in Sources */, - 19DDAEB0138D7686004A7C34 /* SHKEvernote.m in Sources */, + 1913BF76138FF6A800AAD620 /* SHKEvernote.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 490a3e4c0f40d04f7fce77a1ee0c396af7d14a2d Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Tue, 31 May 2011 11:03:15 -0400 Subject: [PATCH 12/13] Handle the case where the Facebook object does not have a sessionDelegate (typically indicative of a non-multitasking process that required authorization) --- Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index acbf6109..409fe8ba 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -99,7 +99,12 @@ + (UIImage*)storedImage:(NSString*)imagePath { + (BOOL)handleOpenURL:(NSURL*)url { - return [[SHKFacebook facebook] handleOpenURL:url]; + Facebook *fb = [SHKFacebook facebook]; + if (! fb.sessionDelegate) { + SHKFacebook *sharer = [[[SHKFacebook alloc] init] autorelease]; + fb.sessionDelegate = sharer; + } + return [fb handleOpenURL:url]; } #pragma mark - From c06a4ce951e0fb883b725355140491c15d6ee237 Mon Sep 17 00:00:00 2001 From: Andrew Hannon Date: Tue, 31 May 2011 15:32:03 -0400 Subject: [PATCH 13/13] Handling SHKFacebookLocalAppID conditional in the preprocessor, as the previous implementation was causing some compiler errors. It should only be defined if you have use for it... --- Classes/ShareKit/SHKConfig.h | 2 +- .../Sharers/Services/Facebook/SHKFacebook.m | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 39950957..48ad2f39 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -53,7 +53,7 @@ // Your CFBundleURLSchemes entry: fb555funk #define SHKFacebookUseSessionProxy NO #define SHKFacebookAppID @"" -#define SHKFacebookLocalAppID @"" +//#define SHKFacebookLocalAppID @"" #define SHKFacebookSessionProxyURL @"" // Read It Later - http://readitlaterlist.com/api/?shk diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 409fe8ba..6c9d9009 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -165,16 +165,16 @@ - (void)promptAuthorization [itemRep setObject:[SHKFacebook storedImagePath:item.image] forKey:@"imagePath"]; } [[NSUserDefaults standardUserDefaults] setObject:itemRep forKey:kSHKStoredItemKey]; - if ((! SHKFacebookLocalAppID) || [SHKFacebookLocalAppID isEqualToString:@""]) { - [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", - @"offline_access", nil] - delegate:self]; - } else { - [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", - @"offline_access", nil] - delegate:self - localAppId:SHKFacebookLocalAppID]; - } +#ifdef SHKFacebookLocalAppID + [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", + @"offline_access", nil] + delegate:self + localAppId:SHKFacebookLocalAppID]; +#else + [[SHKFacebook facebook] authorize:[NSArray arrayWithObjects:@"publish_stream", + @"offline_access", nil] + delegate:self]; +#endif } - (void)authFinished:(SHKRequest *)req