alexjp-blackbook_csv 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. data/CHANGES.markdown +44 -0
  2. data/Manifest.txt +59 -0
  3. data/README.markdown +72 -0
  4. data/Rakefile +39 -0
  5. data/debug_blackbook.rb +10 -0
  6. data/init.rb +1 -0
  7. data/lib/blackbook/exporter/base.rb +16 -0
  8. data/lib/blackbook/exporter/vcf.rb +45 -0
  9. data/lib/blackbook/exporter/xml.rb +28 -0
  10. data/lib/blackbook/importer/aol.rb +83 -0
  11. data/lib/blackbook/importer/base.rb +39 -0
  12. data/lib/blackbook/importer/csv.rb +87 -0
  13. data/lib/blackbook/importer/gmail.rb +66 -0
  14. data/lib/blackbook/importer/hotmail.rb +124 -0
  15. data/lib/blackbook/importer/page_scraper.rb +86 -0
  16. data/lib/blackbook/importer/yahoo.rb +61 -0
  17. data/lib/blackbook.rb +76 -0
  18. data/test/fixtures/aol_application_page.html +566 -0
  19. data/test/fixtures/aol_bad_login_response_stage_3.html +565 -0
  20. data/test/fixtures/aol_contacts.html +90 -0
  21. data/test/fixtures/aol_login_response_stage_1.html +158 -0
  22. data/test/fixtures/aol_login_response_stage_2.html +559 -0
  23. data/test/fixtures/aol_login_response_stage_3.html +61 -0
  24. data/test/fixtures/aol_login_response_stage_4.html +48 -0
  25. data/test/fixtures/aol_login_response_stage_5.html +404 -0
  26. data/test/fixtures/aol_new_contacts.html +431 -0
  27. data/test/fixtures/gmail.csv +3 -0
  28. data/test/fixtures/gmail_bad_login_response_stage_2.html +560 -0
  29. data/test/fixtures/gmail_contacts.html +228 -0
  30. data/test/fixtures/gmail_login_response_stage_1.html +556 -0
  31. data/test/fixtures/gmail_login_response_stage_2.html +1 -0
  32. data/test/fixtures/gmail_login_response_stage_2a.html +1 -0
  33. data/test/fixtures/gmail_login_response_stage_3.html +249 -0
  34. data/test/fixtures/hotmail_bad_login_response_stage_2.html +31 -0
  35. data/test/fixtures/hotmail_contacts.html +191 -0
  36. data/test/fixtures/hotmail_login_response_stage_1.html +31 -0
  37. data/test/fixtures/hotmail_login_response_stage_2.html +1 -0
  38. data/test/fixtures/hotmail_login_response_stage_3.html +380 -0
  39. data/test/fixtures/yahoo_bad_login_response_stage_2.html +443 -0
  40. data/test/fixtures/yahoo_contacts.csv +3 -0
  41. data/test/fixtures/yahoo_contacts_not_logged_in.html +432 -0
  42. data/test/fixtures/yahoo_contacts_stage_1.html +399 -0
  43. data/test/fixtures/yahoo_login_response_stage_1.html +433 -0
  44. data/test/fixtures/yahoo_login_response_stage_2.html +16 -0
  45. data/test/scripts/live_test.rb +25 -0
  46. data/test/test_blackbook.rb +60 -0
  47. data/test/test_blackbook_exporter_base.rb +16 -0
  48. data/test/test_blackbook_exporter_vcf.rb +52 -0
  49. data/test/test_blackbook_exporter_xml.rb +16 -0
  50. data/test/test_blackbook_importer_aol.rb +113 -0
  51. data/test/test_blackbook_importer_base.rb +24 -0
  52. data/test/test_blackbook_importer_csv.rb +60 -0
  53. data/test/test_blackbook_importer_gmail.rb +117 -0
  54. data/test/test_blackbook_importer_hotmail.rb +147 -0
  55. data/test/test_blackbook_importer_page_scraper.rb +51 -0
  56. data/test/test_blackbook_importer_yahoo.rb +97 -0
  57. data/test/test_helper.rb +69 -0
  58. data/vendor/plugins/blackbook/lib/autotest/blackbook.rb +27 -0
  59. data/vendor/plugins/blackbook/lib/autotest/discover.rb +3 -0
  60. metadata +176 -0
@@ -0,0 +1,433 @@
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
9
+ <html>
10
+ <head>
11
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
12
+ <title>Sign in to Yahoo!</title>
13
+ <!-- Refresh login page every 15 minutes -->
14
+ <meta http-equiv="Pragma" content="no-cache">
15
+ <meta http-equiv="Expires" content="0">
16
+ <meta http-equiv="refresh" content="900">
17
+
18
+ <link rel="stylesheet" type="text/css" href="https://a248.e.akamai.net/sec.yimg.com/lib/common/css/fonts_2.0.0-b2.css">
19
+ <style type="text/css">
20
+
21
+
22
+
23
+ @import url(https://a248.e.akamai.net/sec.yimg.com/lib/reg/css/yregbase_sec_200704191234.css);
24
+ .ct{background:transparent url(https://a248.e.akamai.net/sec.yimg.com/i/reg/cr_gg_ne.gif) no-repeat top right;top:-1px}
25
+ .ct .cl{background:transparent url(https://a248.e.akamai.net/sec.yimg.com/i/reg/cr_gg_nw.gif) no-repeat top left}
26
+ .cb{background:transparent url(https://a248.e.akamai.net/sec.yimg.com/i/reg/cr_gg_se.gif) no-repeat bottom right;bottom:-1px}
27
+ .cb .cl{background:transparent url(https://login.yahoo.com/i/reg/cr_gg_sw.gif) no-repeat bottom left}
28
+ .clear{clear:both}
29
+ #yreglg select, #yreglg input, #yreglg p, #yreglgtb td, #yreglgtb th{font-size:93%}
30
+ div.yregdsilu h2.yregdnt, div.yregdsilu p.yregsueasy{width:110px}
31
+ /*popup template css */
32
+ #yregtpopup #yregtxt {width:260px;margin:0 0 10px} /* popup template */
33
+ #yregtpopup #yregwp, #yregtpopup #yregmst{width:525px}
34
+ #yregtpopup #yregmst{margin-bottom:5px}
35
+ #yregtpopup #yreglg{margin-bottom:0}
36
+ #yregtpopup #yregft{padding-top:5px}
37
+ /* adding login_verify popup css */
38
+ #yregtgen #yregct{margin-right:15px}
39
+ #yregtgen #yregtxt h2, #yregtpopup #yregtxt h2, #yregpmtxt h3{font:bold 152%/152% arial;color:#333;margin:0}
40
+ #yregtgen #yregtxt p.yregpti, #yregtpopup #yregtxt p.yregpti {color:#666;margin:0 0 2px;font:bold 100%/100% arial}
41
+ #yregtgen #yregtxt, #yregtpopup #yregtxt{margin-bottom:20px}
42
+ #yregtgen #yregtxt #yreghtxt h3, #yregtpopup #yregtxt #yreghtxt h3{margin:0;font:bold 107%/114% arial;color:#8C57A1}
43
+ #yregtgen #yregtxt li h3, #yregtpopup #yregtxt li h3{font:bold 114%/122% arial}
44
+ #yregtgen #yregtxt p, #yregtpopup #yregtxt p{margin:0 0 0.8em;line-height:129%}
45
+ #yregtgen #yregtxt .yregbpt li, #yregtpopup #yregtxt .yregbpt li{margin:0 0 10px 4px;padding:0 0 10px 22px;background:url(https://a248.e.akamai.net/sec.yimg.com/i/reg/purple_arrow.gif) no-repeat 1px 4px}
46
+ #yregtgen.yregab #yregtxt{width:380px}
47
+ #yregtpopup.yregab #yregtxt{width:180px}
48
+ #yregtgen #yregtxt #yreghtxt h2, #yregtpopup #yregtxt #yreghtxt h2{color:#7A067F}
49
+ .yregbx{z-index:3;margin-right:0!important}
50
+ .flicker h3 span {color:#ff0084;font-weight:bold}
51
+ .flicker h3 a {text-decoration:underline;}
52
+
53
+ /* persistency message right above "sign in" bottom */
54
+ em.nwred a {font-style: normal; font-size: 85%; color:#c00; vertical-align:5px;}
55
+ .kmsibold {font-weight:bold; font-size: 114%;}
56
+ p#sigcopys {text-align: left; font-size: 85%; float: right; padding: .4em; margin: .6em .4em 1em 0; border-bottom: 1px dotted #9D9C9D; border-top: 1px dotted #9D9C9D;}
57
+ #sigcopys label{display:block; margin:-1.5em 0 0 2em;}
58
+ input#persistent {margin-bottom: -0em;}
59
+ .subperstxt {line-height:1.75em;}
60
+ .subperstxt2 {margin: 0 0 0 2em; display:block;}
61
+ /* #yregft p.yregfb { font-size:120%; padding-bottom: 5px; padding-up: 5px} */
62
+
63
+ .yreglgsb{margin-top:0}
64
+ </style>
65
+
66
+
67
+
68
+ <!--[if IE]>
69
+ <style type="text/css">
70
+ .yregclb{height:1%}
71
+ #yreglgtb td{text-align:left}
72
+ #yreglgtb td input{width:110px}
73
+ #yregtxt #banner div{position:static} /* ie z-index context stacking bug work-around */
74
+ #yregtpopup #yregtxt{clear:both; float:left;}
75
+ #yregct{padding:0 0 30px}
76
+ </style>
77
+ <![endif]-->
78
+
79
+ <!--[if lte IE 6]>
80
+ <style type="text/css">
81
+ .yregclb{height:30em}
82
+ #yregtxt {height:1%}
83
+ p#sigcopys {margin-right:0.2em}
84
+ </style>
85
+ <![endif]-->
86
+
87
+ </head>
88
+ <!-- ads: 150001456 INT.OFFSET: 0 -->
89
+ <body id="yregtgen">
90
+
91
+ <div id="yregwp">
92
+ <!-- begin header -->
93
+ <table id="yregmst" width="750" cellpadding="0" cellspacing="0" border="0"><tr valign="top">
94
+ <td width="100%"><table width="100%" cellspacing="0" border="0"><tr valign="top">
95
+ <td width="1%"><img src="https://a248.e.akamai.net/sec.yimg.com/i/yahoo.gif" alt="Yahoo!" width=147 height=31 border=0></td>
96
+ <td><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr valign="top">
97
+ <td align="right" id="ygmaproplinks" style="padding-right:3px;line-height:12px;"><font face="verdana,geneva,sans-serif" size="-2"><a href="http://www.yahoo.com " target="www" class="header" title="Click here to go to Yahoo! homepage">Yahoo!</a> - <a href="http://help.yahoo.com/help/us/edit/" class="header" target="yhelp" title="Click here for help">Help</a></font></td>
98
+ </tr></table></td></tr></table></td>
99
+ <td align="right" style="padding: 6px 0 0 4px;">
100
+ </td></tr></table>
101
+
102
+
103
+ <!-- end header -->
104
+ <span id="cache"></span>
105
+
106
+
107
+ <script type="text/javascript">
108
+
109
+ function FlashDetector_Detect(targetVersion)
110
+ {
111
+ var pObj = null;
112
+ var tokens, len, curr_tok;
113
+ var hasVersion = -1;
114
+ var playable = false;
115
+ if(navigator.mimeTypes && navigator.mimeTypes['application/x-shockwave-flash'])
116
+ {
117
+ pObj = navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin;
118
+ }
119
+ if(pObj != null)
120
+ {
121
+ tokens = navigator.plugins['Shockwave Flash'].description.split(' ');
122
+ len = tokens.length;
123
+ while(len--)
124
+ {
125
+ curr_tok = tokens[len];
126
+ if(!isNaN(parseInt(curr_tok)))
127
+ {
128
+ hasVersion = curr_tok;
129
+ FlashDetector_Version = curr_tok;
130
+ break;
131
+ }
132
+ }
133
+ if(hasVersion >= targetVersion)
134
+ {
135
+ playable = true;
136
+ }
137
+ else
138
+ {
139
+ playable = false;
140
+ }
141
+ }
142
+ return playable;
143
+ }
144
+
145
+ var flashDetector_Playable = false;
146
+ var flashDetector_targetVersion = '8';
147
+
148
+ var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
149
+ var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
150
+ var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
151
+
152
+ if (isIE && isWin && !isOpera) {
153
+ document.write('<scr' + 'ipt language="VBScript"\> \n');
154
+ document.write('on error resume next \n');
155
+ document.write('flashDetector_Playable = ( IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash." & flashDetector_targetVersion)))\n');
156
+ document.write('</scr' + 'ipt\> \n');
157
+ } else {
158
+ flashDetector_Playable = FlashDetector_Detect(flashDetector_targetVersion);
159
+ }
160
+
161
+ var flashCode = '';
162
+
163
+ if(flashDetector_Playable) {
164
+
165
+ var ts = (new Date()).getTime( );
166
+
167
+ flashCode = '<object type="application/x-shockwave-flash" data="https://login.yahoo.com/login/dataCache.swf" width="0" height="0" id="flashCache"> <param name="allowScriptAccess" value="sameDomain" /> <param name="movie" value="https://login.yahoo.com/login/dataCache.swf?' + ts + '" /> <param name="bgColor" value="#fff" /> </object> ';
168
+
169
+ }
170
+ document.write(flashCode);
171
+
172
+ </script>
173
+
174
+
175
+ <script language="JavaScript">
176
+
177
+ function checkBrowser(){
178
+ var appName = navigator.appName;
179
+ if( appName == "Microsoft Internet Explorer" )
180
+ {
181
+ // this only works in IE 5 for windows and higher ...
182
+ if( navigator.appVersion.indexOf("Windows") == -1 )
183
+ return -1;
184
+ var appVersionAry = navigator.appVersion.split("(");
185
+ if( appVersionAry.length < 2 )
186
+ return -1;
187
+ var appVersion = appVersionAry[1];
188
+ appVersionAry = appVersion.split("; ");
189
+ if( appVersionAry.length < 2 )
190
+ return -1;
191
+ appVersion = appVersionAry[1];
192
+ appVersionAry = appVersion.split(" ");
193
+ if( appVersionAry.length < 2 )
194
+ return -1;
195
+ appVersion = appVersionAry[1];
196
+ var appVersionNumber = parseInt(appVersion);
197
+
198
+ if( appVersionNumber < 5 )
199
+ return -1;
200
+ }
201
+ else
202
+ {
203
+ return -1;
204
+ }
205
+ }
206
+
207
+ </script>
208
+
209
+ <script language="JavaScript">
210
+
211
+ function flashCacheReady (initialized){ //invoked directly by Flash
212
+ getCache();
213
+
214
+ }
215
+ </script>
216
+
217
+
218
+ <script language="JavaScript">
219
+
220
+ var inCache = false;
221
+
222
+ // Get the info from flash
223
+ function getCache(){
224
+ var o={};
225
+ o=(document.getElementById("flashCache")).getCache(o);
226
+ if(o != null) inCache = true;
227
+ else return;
228
+
229
+ if(o.YL != 'null' && o.YL != null) {
230
+ document.cookie = o.YL + ";expires=Thu, 15 Apr 2037 20:00:00 GMT;domain=login.yahoo.com;path=/";
231
+ }
232
+
233
+ if(o.F != 'null' && o.F != null) {
234
+ document.cookie = o.F + ";expires=Thu, 15 Apr 2037 20:00:00 GMT;domain=.yahoo.com;path=/";
235
+ }
236
+
237
+ if(o.YLS != 'null' && o.YLS != null) {
238
+ if((o.YLS.match("n=0")) != null) {
239
+ o.YLS = o.YLS.replace("n=0", "n=9");
240
+ } else {
241
+ o.YLS = o.YLS.concat("&n=9");
242
+ }
243
+ document.cookie = o.YLS + ";expires=Thu, 15 Apr 2037 20:00:00 GMT;domain=.yahoo.com;path=/";
244
+ }
245
+
246
+ if(((o.YL != 'null') && (o.YL != null)) || ((o.F != 'null') && (o.F != null))) {
247
+ document.location.reload();
248
+ }
249
+ }
250
+
251
+ // If the browser is IE, get from the xml cache as well.
252
+
253
+ if((checkBrowser() != -1) && (inCache == false)) {
254
+ function getXML(cookieName,header,spanName)
255
+ {
256
+ var span = document.getElementById("cache");
257
+ span.style.behavior = "url('#default#userData')";
258
+ span.load(spanName);
259
+
260
+ var ckyDate = new Date;
261
+ ckyDate.setDate(ckyDate.getDate( ) + 7);
262
+
263
+ var saved = span.getAttribute("saved"+cookieName);
264
+
265
+ if((saved == null ) || (saved == "")) return -1;
266
+ var cookieStr = saved;
267
+ if(cookieName == "YLS") {
268
+ if((cookieStr.match("n=0")) != null) {
269
+ cookieStr = cookieStr.replace("n=0", "n=9");
270
+ } else {
271
+ cookieStr = cookieStr.concat("&n=9");
272
+ }
273
+ }
274
+ if (header != ""){
275
+ cookieStr = cookieStr + ';' + header;
276
+ }
277
+ document.cookie = cookieStr;
278
+ return 0;
279
+ }
280
+
281
+ var ylRes = getXML("YL", "expires = Thu, 15 Apr 2037 20:00:00 GMT; domain=login.yahoo.com; path=/", "YL");
282
+ var fRes = getXML("F", "expires = Thu, 15 Apr 2037 20:00:00 GMT; domain=.yahoo.com; path=/", "YL");
283
+ var ylsRes = getXML("YLS", "expires = Thu, 15 Apr 2037 20:00:00 GMT; domain=.yahoo.com; path=/", "YL");
284
+
285
+ if(ylRes == 0 || fRes == 0) {
286
+ document.location.reload();
287
+ }
288
+ }
289
+ </script>
290
+
291
+
292
+
293
+ <div id="yregct" class="yregclb">
294
+ <div id="yreglg">
295
+ <!-- login box goes here -->
296
+ <div class="top yregbx">
297
+ <script type="text/javascript">if(top == self) { document.write("<div class=\"\">")}</script> <span class="ct"><span class="cl"></span></span>
298
+ <div class="yregbxi">
299
+ <script type="text/javascript">if(top == self) { document.write("") } else { top.location.href = "http://www.yahoo.com" }</script> <p>To access Yahoo!...</p>
300
+ <!-- <p>you need a Yahoo! ID.</p> -->
301
+ <div class="yregdsilu">
302
+ <h2 class="yregdnt">Don't have a Yahoo! ID?</h2>
303
+ <p class="yregsueasy">Signing up is easy.</p>
304
+ <p class="yreglgsut"><a href="https://edit.yahoo.com/config/eval_register?.intl=us&new=1&.done=http%3A//my.yahoo.com&.src=&.v=0&.u=co9n5j13pngot&partner=&.partner=&pkg=&stepid=&.p=&promo=&.last=">Sign Up</a></p>
305
+ </div>
306
+ <h2>Already have a Yahoo! ID?</h2>
307
+ <p>Sign in.</p>
308
+
309
+
310
+ <fieldset>
311
+ <legend>Login Form</legend>
312
+ <form method="post" action="https://login.yahoo.com/config/login?" autocomplete="off" name="login_form">
313
+ <input type="hidden" name=".tries" value="1">
314
+ <input type="hidden" name=".src" value="">
315
+ <input type="hidden" name=".md5" value="">
316
+ <input type="hidden" name=".hash" value="">
317
+ <input type="hidden" name=".js" value="">
318
+ <input type="hidden" name=".last" value="">
319
+ <input type="hidden" name="promo" value="">
320
+ <input type="hidden" name=".intl" value="us">
321
+ <input type="hidden" name=".bypass" value="">
322
+ <input type="hidden" name=".partner" value="">
323
+ <input type="hidden" name=".u" value="co9n5j13pngot">
324
+ <input type="hidden" name=".v" value="0">
325
+ <input type="hidden" name=".challenge" value="tf2oNCy4Xxgedai3km.6HIeEF_8I">
326
+ <input type="hidden" name=".yplus" value="">
327
+ <input type="hidden" name=".emailCode" value="">
328
+ <input type="hidden" name="pkg" value="">
329
+ <input type="hidden" name="stepid" value="">
330
+ <input type="hidden" name=".ev" value="">
331
+ <input type="hidden" name="hasMsgr" value="0">
332
+ <input type="hidden" name=".chkP" value="Y">
333
+ <input type="hidden" name=".done" value="http://my.yahoo.com">
334
+ <input type="hidden" name=".pd" value="_ver=0&c=">
335
+ <table id="yreglgtb" summary="form: login information">
336
+ <tr>
337
+ <th><label for="username">Yahoo! ID:</label></th>
338
+ <td><input name="login" id="username" value="" size="17" class="yreg_ipt" type="text"></td>
339
+ <script language="JavaScript" type="text/javascript">if(document.getElementById) document.getElementById('username').focus();</script>
340
+ </tr>
341
+ <tr>
342
+ <th><label for="passwd">Password:</label></th>
343
+ <td><input name="passwd" id="passwd" value="" size="17" class="yreg_ipt" type="password"></td>
344
+ </tr>
345
+
346
+ </table>
347
+
348
+ <p id="sigcopys"><input type="checkbox" id="persistent" name=".persistent" value="y"
349
+ >
350
+ <label for="persistent"> <span class="kmsibold">Keep me signed in</span><br><span class="subperstxt">for 2 weeks unless I sign out.</span> <em class="nwred"><a href="http://us.rd.yahoo.com/reg/login1/suli/pst_help/us//*https://login.yahoo.com/config/login?.src=&.intl=us&.help=4&.v=0&.u=co9n5j13pngot&.last=&promo=&.bypass=&.partner=&pkg=&stepid=&.pd=_ver%3d0%26c=&.ab=&.done=http%3A//my.yahoo.com" tabindex="99999">New!</a></em></label>
351
+ <span class="subperstxt2">[Uncheck if on a shared computer]</span>
352
+ </p>
353
+ <div class="clear"></div>
354
+ <p class="yreglgsb"><input type="submit" name=".save" value="Sign In"></p>
355
+ </form>
356
+ </fieldset>
357
+ <a href="http://us.rd.yahoo.com/reg/login1/suli/forgot_lib/us//*https://edit.yahoo.com/config/eval_forgot_pw?new=1&.done=http%3A//my.yahoo.com&.src=&partner=&.intl=us&pkg=&stepid=&.pd=_ver%3d0%26c=&.ab=&.last=">Forget your ID or password?</a> | <a href="http://us.rd.yahoo.com/reg/login1/suli/sih_lib/us//*https://login.yahoo.com/config/login?.src=&.intl=us&.help=1&.v=0&.u=co9n5j13pngot&.last=&.last=&promo=&.bypass=&.partner=&pkg=&stepid=&.pd=_ver%3d0%26c=&.ab=&.done=http%3A//my.yahoo.com">Help</a>
358
+ </p>
359
+
360
+ </div>
361
+ <span class="cb"><span class="cl"></span></span>
362
+ <script type="text/javascript">document.write("</div>")</script>
363
+ </div>
364
+
365
+ <!-- end login box -->
366
+ </div>
367
+ <div id="yregtxt">
368
+ <!-- begin left side content -->
369
+ <div id="yregptxt">
370
+ <p class="yregpti">Welcome to Yahoo!</p>
371
+ <h2>Enjoy all the benefits of Yahoo!.</h2>
372
+ <ul class="list">
373
+ <li>Stay in touch with <strong>free Mail and Messenger</strong>.</li>
374
+ <li><strong>Protect</strong> your PC with <strong>free Anti-Spy</strong> and <strong>Pop-Up Blocker</strong>.</li>
375
+ <li><strong>Get weather forecasts</strong> and current conditions for your area.</li>
376
+
377
+ <li>Tune in to the latest in <strong>music, entertainment, and sports</strong>.</li>
378
+ </ul>
379
+ </div>
380
+ <div id="yregpmtxt">
381
+ <h3>Get all the best with one Yahoo! ID.</h3>
382
+ <p>Your Yahoo! ID gives you access to powerful communications tools like mail and instant messaging, security features like email AntiVirus and Pop-Up Blocker, and favorites like online photos and music &#151; <strong>all for free</strong>.</p>
383
+ </div> <!-- Content module end -->
384
+
385
+ <!-- end left side content -->
386
+ </div>
387
+ </div>
388
+ <!-- begin footer -->
389
+
390
+ <div id="yregft">
391
+ <p>Copyright &copy; 2008 Yahoo! Inc. All rights reserved. <a href="http://docs.yahoo.com/info/copyright/copyright.html" target="cp">Copyright/IP Policy</a> | <a href="http://docs.yahoo.com/info/terms/" target="tos">Terms of Service</a> | <a href="http://security.yahoo.com/" target="sc">Guide to Online Security</a></p>
392
+ <p>NOTICE: We collect personal information on this site.</p>
393
+ <p>To learn more about how we use your information, see our <a href="http://privacy.yahoo.com/" target="_new" title="Click here to view Yahoo! Privacy Policy">Privacy Policy</a></p>
394
+ </div>
395
+
396
+
397
+ <!-- end footer -->
398
+ </div>
399
+ </div>
400
+ <script type="text/javascript">
401
+ browser_string = navigator.appVersion + " " + navigator.userAgent;
402
+ if ( browser_string.indexOf("MSIE") < 0 ) {
403
+ if (navigator.mimeTypes) {
404
+ for (i = 0 ; i < navigator.mimeTypes.length ; i++) {
405
+ if (navigator.mimeTypes[i].suffixes.indexOf("yps") > -1) {
406
+ doGotIt();
407
+ }
408
+ }
409
+ } else {
410
+ dontGotIt();
411
+ }
412
+ } else {
413
+ if (browser_string.indexOf("Windows")>=0) {
414
+ doGotIt();
415
+ document.write('<object classid="clsid:41695A8E-6414-11D4-8FB3-00D0B7730277" CODEBASE="javascript:dontGotIt();" ID="Ymsgr" width="1" height="1">');
416
+ document.write('</object>');
417
+ }
418
+ }
419
+ hasMsgr = 0;
420
+ function dontGotIt(){
421
+ hasMsgr = 0;
422
+ document.login_form.hasMsgr.value=0;
423
+ }
424
+ function doGotIt(){
425
+ hasMsgr = 1;
426
+ document.login_form.hasMsgr.value=1;
427
+ }
428
+ </script>
429
+
430
+ <!-- spaceid: 150001456 INT.OFFSET: 0 --><!-- SpaceID=0 robot -->
431
+
432
+ </body>
433
+ </html>
@@ -0,0 +1,16 @@
1
+ <html>
2
+ <head>
3
+ <script language="JavaScript">
4
+ <!--
5
+ window.location.replace("http://my.yahoo.com");
6
+ // -->
7
+ </script>
8
+ <meta http-equiv="Refresh" content="0; url=http://my.yahoo.com">
9
+ </head>
10
+ <body>
11
+ If you are seeing this page, your browser settings prevent you
12
+ from automatically redirecting to a new URL.
13
+ <p>
14
+ Please <a href="http://my.yahoo.com">click here</a> to continue.
15
+ </body>
16
+ </html>
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ require File.join( File.dirname(__FILE__), '../../lib/blackbook.rb' )
3
+ require 'optparse'
4
+
5
+ options = {}
6
+ importer = :auto
7
+
8
+ opts = OptionParser.new do |opts|
9
+ opts.on("-u USERNAME") do |username|
10
+ options[:username] = username
11
+ end
12
+ opts.on("-p PASSWORD") do |password|
13
+ options[:password] = password
14
+ end
15
+ opts.on("-i [IMPORTER]") do |importer_name|
16
+ importer = importer_name.to_sym
17
+ end
18
+ opts.on("-x [EXPORTER]") do |exporter_name|
19
+ options[:as] = exporter_name.to_sym
20
+ end
21
+ end
22
+
23
+ opts.parse!(ARGV)
24
+
25
+ puts contacts = Blackbook.get( importer, options )
@@ -0,0 +1,60 @@
1
+ require File.join( File.dirname(__FILE__), '../lib/blackbook.rb' )
2
+ require File.join( File.dirname(__FILE__), 'test_helper.rb' )
3
+ require 'test/unit'
4
+ require 'mocha'
5
+
6
+ class TestBlackbook < Test::Unit::TestCase
7
+
8
+ include TestHelper
9
+
10
+ def test_class_get
11
+ Blackbook.any_instance.expects(:get)
12
+ Blackbook.get
13
+ end
14
+
15
+ def test_class_instance
16
+ assert Blackbook.instance.is_a?(Blackbook)
17
+ end
18
+
19
+ def test_class_register
20
+ Blackbook.register(:base, Blackbook::Exporter::Base)
21
+ assert Blackbook.instance.exporters[:base].is_a?(Blackbook::Exporter::Base)
22
+
23
+ Blackbook.register(:base, Blackbook::Importer::Base)
24
+ assert Blackbook.instance.importers[:base].is_a?(Blackbook::Importer::Base)
25
+ end
26
+
27
+ def test_class_register_raises_on_bad_register
28
+ assert_raises(ArgumentError) do
29
+ Blackbook.register(:bad, String)
30
+ end
31
+ end
32
+
33
+ def test_export
34
+ importer = Blackbook::Importer::Base.new
35
+ exporter = Blackbook::Exporter::Base.new
36
+ importer.expects(:import)
37
+ exporter.expects(:export)
38
+ Blackbook.instance.export( importer, exporter, {} )
39
+ end
40
+
41
+ def test_find_importer
42
+ base = Blackbook::Importer::Base.new
43
+ base.stubs(:=~).returns(true)
44
+ Blackbook.any_instance.stubs(:importers).returns({:basic => base})
45
+ assert_equal base, Blackbook.instance.find_importer(:as => :basic)
46
+
47
+ base.stubs(:=~).returns(false)
48
+ assert_nil Blackbook.instance.find_importer(:as => :basic)
49
+ end
50
+
51
+ def test_get
52
+ cards = Blackbook.instance.get( :csv, :file => fixture_file('gmail.csv') )
53
+ assert_equal 2, cards.size
54
+ assert cards.detect{|card| card[:name] == "Joe User"}
55
+ assert cards.detect{|card| card[:name] == "Some Guy"}
56
+ assert cards.detect{|card| card[:email] == "joeuser@example.com"}
57
+ assert cards.detect{|card| card[:email] == "someguy@example.com"}
58
+ end
59
+
60
+ end
@@ -0,0 +1,16 @@
1
+ require File.join( File.dirname(__FILE__), '../lib/blackbook.rb' )
2
+ require File.join( File.dirname(__FILE__), 'test_helper.rb' )
3
+ require 'test/unit'
4
+ require 'mocha'
5
+
6
+ class TestBlackbookExporterBase < Test::Unit::TestCase
7
+
8
+ include TestHelper
9
+
10
+ def test_export
11
+ exporter = Blackbook::Exporter::Base.new
12
+ contacts = [{ :name => 'Test', :email => 'test@domain.com' }]
13
+ assert_equal contacts, exporter.export(contacts)
14
+ end
15
+
16
+ end
@@ -0,0 +1,52 @@
1
+ require File.join( File.dirname(__FILE__), '../lib/blackbook.rb' )
2
+ require File.join( File.dirname(__FILE__), 'test_helper.rb' )
3
+ require 'test/unit'
4
+ require 'mocha'
5
+
6
+ class TestBlackbookExporterVcf < Test::Unit::TestCase
7
+
8
+ include TestHelper
9
+
10
+ def setup
11
+ @card = Blackbook::Exporter::Vcf::Vcard.new(
12
+ {'first' => 'joe', 'last' => 'user',
13
+ 'email' => 'joe.user@example.com'})
14
+ @exporter = Blackbook::Exporter::Vcf.new
15
+ end
16
+
17
+ def test_vcard
18
+ assert_equal 'joe', @card.first
19
+ assert_equal 'user', @card.last
20
+ assert_equal 'joe.user@example.com', @card.email
21
+ end
22
+
23
+ def test_vcard_to_s
24
+ card = %q!BEGIN:VCARD
25
+ N:user;joe
26
+ EMAIL:joe.user@example.com
27
+ END:VCARD
28
+ !
29
+ assert_equal card, @card.to_s
30
+ assert_equal 'user', @card.last
31
+ assert_equal 'joe.user@example.com', @card.email
32
+ end
33
+
34
+ def test_export
35
+ contacts = [{ :name => 'Test', :email => 'test@example.com' }]
36
+ expected = <<VCF
37
+ BEGIN:VCARD
38
+ N:;Test
39
+ EMAIL:test@example.com
40
+ END:VCARD
41
+ VCF
42
+ exported = @exporter.export(contacts)
43
+ assert_equal 1, exported.size
44
+ assert_equal expected, exported.first.to_s
45
+ end
46
+
47
+ def test_export_when_contacts_blank
48
+ assert_nil @exporter.export()
49
+ assert_nil @exporter.export([])
50
+ end
51
+
52
+ end
@@ -0,0 +1,16 @@
1
+ require File.join( File.dirname(__FILE__), '../lib/blackbook.rb' )
2
+ require File.join( File.dirname(__FILE__), 'test_helper.rb' )
3
+ require 'test/unit'
4
+ require 'mocha'
5
+
6
+ class TestBlackbookExporterXml < Test::Unit::TestCase
7
+
8
+ include TestHelper
9
+
10
+ def test_export
11
+ exporter = Blackbook::Exporter::Xml.new
12
+ contacts = [{ :name => 'Test', :email => 'test@domain.com' }]
13
+ assert_equal "<?xml version='1.0'?><contacts><contact><name>Test</name><email>test@domain.com</email></contact></contacts>", exporter.export(contacts)
14
+ end
15
+
16
+ end