├── .github └── FUNDING.yml ├── .gitignore ├── Makefile ├── README.md ├── autoload └── webapi │ ├── atom.vim │ ├── base64.vim │ ├── bit.vim │ ├── feed.vim │ ├── hmac.vim │ ├── html.vim │ ├── http.vim │ ├── json.vim │ ├── jsonrpc.vim │ ├── metaWeblog.vim │ ├── oauth.vim │ ├── sha1.vim │ ├── soap.vim │ ├── ucs.vim │ ├── xml.vim │ └── xmlrpc.vim ├── doc ├── webapi-html.txt ├── webapi-http.txt ├── webapi-json.txt ├── webapi-xml.txt └── webapi.txt ├── example ├── gistview.vim ├── google-buzz.vim ├── hatenadiary.vim ├── jugem.vim ├── livedoor.vim ├── rss.vim ├── twitter.vim └── weather.vim └── webapi.vim.vimup /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: mattn # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | doc/tags 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all : webapi-vim.zip 2 | 3 | remove-zip: 4 | -rm -f doc/tags 5 | -rm -f webapi-vim.zip 6 | 7 | webapi-vim.zip: remove-zip 8 | zip -r webapi-vim.zip autoload doc README 9 | 10 | release: webapi-vim.zip 11 | vimup update-script webapi.vim 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webapi-vim 2 | 3 | An Interface to WEB APIs. 4 | 5 | ## Description 6 | 7 | Currently this library supports the following protocols: 8 | 9 | * Basic HTTP 10 | * OAuth 11 | * Atompub 12 | * SOAP (in progress) 13 | * XMLRPC 14 | * MetaWeblog API 15 | 16 | This library contains: 17 | 18 | * XML Parser 19 | * HTML Parser(Hack Way) 20 | * JSON Parser 21 | * BASE64 Hash Algorithm 22 | * SHA1 Hash Algorithm 23 | * HMAC HASH Algorithm 24 | * Bit Operation Library 25 | * Converter for "UTF-8 to Unicode" 26 | 27 | ## Installation 28 | 29 | Copy the files in this library to your `.vim` directory. Alternatively, if you 30 | use pathogen, copy this folder to your `.vim/bundle` directory. 31 | 32 | ## Requirements 33 | 34 | You need the `curl` command, which can be downloaded from here: http://curl.haxx.se/ 35 | 36 | \*or\* 37 | 38 | the `wget` command, available here: https://www.gnu.org/software/wget/ 39 | 40 | ## Thanks 41 | 42 | Yukihiro Nakadaira : http://sites.google.com/site/yukihironakadaira/ 43 | 44 | * autoload/base64.vim (I added small changes) 45 | * autoload/hmac.vim 46 | * autoload/sha1.vim 47 | 48 | ## License 49 | 50 | Public Domain 51 | 52 | ## Project Authors 53 | 54 | Yasuhiro Matsumoto (a.k.a mattn) 55 | -------------------------------------------------------------------------------- /autoload/webapi/atom.vim: -------------------------------------------------------------------------------- 1 | " atom 2 | " Last Change: 2010-09-10 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " http://tools.ietf.org/rfc/rfc5023.txt 7 | 8 | let s:save_cpo = &cpo 9 | set cpo&vim 10 | 11 | let s:system = function(get(g:, 'webapi#system_function', 'system')) 12 | 13 | let s:author_template = { 14 | \ "name": "", 15 | \} 16 | 17 | let s:link_template = { 18 | \ "rel": "", 19 | \ "href": "", 20 | \} 21 | 22 | let s:category_template = { 23 | \ "term": "", 24 | \ "scheme": "", 25 | \ "label": "", 26 | \} 27 | 28 | let s:feed_template = { 29 | \ "id": "", 30 | \ "icon": "", 31 | \ "logo": "", 32 | \ "title": "", 33 | \ "link": [], 34 | \ "category": [], 35 | \ "author": [], 36 | \ "contirubutor": [], 37 | \ "entry": [], 38 | \} 39 | 40 | let s:entry_template = { 41 | \ "id": "", 42 | \ "icon": "", 43 | \ "logo": "", 44 | \ "title": "", 45 | \ "link": [], 46 | \ "category": [], 47 | \ "app:control": {}, 48 | \ "author": [], 49 | \ "contirubutor": [], 50 | \ "copyright": "", 51 | \ "content": "", 52 | \ "content.type": "text/plain", 53 | \ "content.mode": "escaped", 54 | \ "summary": "", 55 | \ "created": "", 56 | \ "updated": "", 57 | \} 58 | 59 | for s:name in ['author', 'link', 'category', 'feed', 'entry'] 60 | for s:key in keys(eval('s:'.s:name.'_template')) 61 | let key = substitute(s:key, '\.\(.\)', '\=toupper(submatch(1))', '') 62 | let key = substitute(key, ':\(.\)', '\=toupper(submatch(1))', '') 63 | exe "function s:".s:name."_template.set".toupper(key[0]).key[1:]."(v) dict\n" 64 | \. " let self['".s:key."'] = a:v\n" 65 | \. "endfunction\n" 66 | exe "function s:".s:name."_template.get".toupper(key[0]).key[1:]."() dict\n" 67 | \. " return self['".s:key."']\n" 68 | \. "endfunction\n" 69 | endfor 70 | endfor 71 | function s:entry_template.setContentFromFile(file) dict abort 72 | let quote = &shellxquote == '"' ? "'" : '"' 73 | let bits = substitute(s:system("xxd -ps ".quote.a:file.quote), "[ \n\r]", '', 'g') 74 | let self['mode'] = "base64" 75 | let self['content'] = webapi#base64#b64encodebin(bits) 76 | endfunction 77 | 78 | unlet s:name 79 | unlet s:key 80 | 81 | function! webapi#atom#newEntry() abort 82 | return deepcopy(s:entry_template) 83 | endfunction 84 | 85 | function! s:createXml(entry) abort 86 | let entry = webapi#xml#createElement("entry") 87 | let entry.attr["xmlns"] = "http://purl.org/atom/ns#" 88 | let entry.attr["xmlns:app"] = "http://www.w3.org/2007/app" 89 | 90 | for key in keys(a:entry) 91 | let l:keytype = type(a:entry[key]) 92 | if l:keytype == 1 && key !~ '\.' 93 | let node = webapi#xml#createElement(key) 94 | call node.value(a:entry[key]) 95 | if key == "content" 96 | let node.attr["type"] = a:entry['content.type'] 97 | let node.attr["mode"] = a:entry['content.mode'] 98 | endif 99 | call add(entry.child, node) 100 | elseif l:keytype == 3 101 | if key == "category" 102 | for l:category in a:entry['category'] 103 | let node = webapi#xml#createElement(key) 104 | let node.attr["term"] = l:category 105 | call add(entry.child, node) 106 | endfor 107 | endif 108 | elseif l:keytype == 4 109 | let node = webapi#xml#createElement(key) 110 | if key == "app:control" 111 | let l:draft_node = webapi#xml#createElement("app:draft") 112 | if exists("a:entry['app:control']['app:draft']") 113 | call l:draft_node.value(a:entry['app:control']['app:draft']) 114 | else 115 | call l:draft_node.value('no') 116 | endif 117 | call add(node.child, l:draft_node) 118 | endif 119 | call add(entry.child, node) 120 | endif 121 | endfor 122 | let xml = '' . entry.toString() 123 | return iconv(xml, &encoding, "utf-8") 124 | endfunction 125 | 126 | function! s:createWsse(user, pass) abort 127 | let now = localtime() 128 | let nonce = webapi#sha1#sha1(now . " " . now)[0:28] 129 | let created = strftime("%Y-%m-%dT%H:%M:%SZ", now) 130 | let passworddigest = webapi#base64#b64encodebin(webapi#sha1#sha1(nonce.created.a:pass)) 131 | let nonce = webapi#base64#b64encode(nonce) 132 | return 'UsernameToken Username="'.a:user.'", PasswordDigest="'.passworddigest.'", Nonce="'.nonce.'", Created="'.created.'"' 133 | endfunction 134 | 135 | function! webapi#atom#deleteEntry(uri, user, pass) abort 136 | let res = webapi#http#post(a:uri, "", 137 | \ { 138 | \ "Content-Type": "application/x.atom+xml", 139 | \ "X-WSSE": s:createWsse(a:user, a:pass) 140 | \ }, "DELETE") 141 | return res 142 | endfunction 143 | 144 | function! webapi#atom#updateEntry(uri, user, pass, entry, ...) abort 145 | let headdata = a:0 > 0 ? a:000[0] : {} 146 | let headdata["Content-Type"] = "application/x.atom+xml" 147 | let headdata["X-WSSE"] = s:createWsse(a:user, a:pass) 148 | let res = webapi#http#post(a:uri, s:createXml(a:entry), headdata, "PUT") 149 | let location = filter(res.header, 'v:val =~ "^Location:"') 150 | if len(location) 151 | return split(location[0], '\s*:\s\+')[1] 152 | endif 153 | return '' 154 | endfunction 155 | 156 | function! webapi#atom#createEntry(uri, user, pass, entry, ...) abort 157 | let headdata = a:0 > 0 ? a:000[0] : {} 158 | let headdata["Content-Type"] = "application/x.atom+xml" 159 | let headdata["X-WSSE"] = s:createWsse(a:user, a:pass) 160 | let headdata["WWW-Authenticate"] = "WSSE profile=\"UsernameToken\"" 161 | let res = webapi#http#post(a:uri, s:createXml(a:entry), headdata, "POST") 162 | let location = filter(res.header, 'v:val =~ "^Location:"') 163 | if len(location) 164 | return split(location[0], '\s*:\s\+')[1] 165 | endif 166 | return '' 167 | endfunction 168 | 169 | function! s:parse_node(target, parent) abort 170 | for node in a:parent.child 171 | if type(node) != 4 || !has_key(a:target, node.name) 172 | unlet node 173 | continue 174 | endif 175 | if node.name == 'content' 176 | let a:target[node.name] = node.value() 177 | if has_key(node.attr, 'type') 178 | let a:target['content.type'] = node.attr['type'] 179 | endif 180 | if has_key(node.attr, 'type') 181 | let a:target['content.type'] = node.attr['type'] 182 | endif 183 | elseif node.name == 'link' 184 | let link = deepcopy(s:link_template) 185 | for attr in keys(node.attr) 186 | if !has_key(link, attr) 187 | continue 188 | endif 189 | let link[attr] = node.attr[attr] 190 | endfor 191 | call add(a:target.link, link) 192 | elseif node.name == 'author' 193 | let author = deepcopy(s:author_template) 194 | for item in node.child 195 | if type(item) == 4 && has_key(author, item.name) 196 | let author[item.name] = item.value() 197 | endif 198 | unlet item 199 | endfor 200 | call add(a:target.author, author) 201 | elseif node.name == 'entry' 202 | let entry = deepcopy(s:entry_template) 203 | call s:parse_node(entry, node) 204 | call add(a:target.entry, entry) 205 | elseif node.name == 'category' 206 | let l:category = deepcopy(s:category_template) 207 | let l:category['term'] = has_key(node.attr, 'term') ? node.attr['term'] : '' 208 | let l:category['scheme'] = has_key(node.attr, 'scheme') ? node.attr['scheme'] : '' 209 | let l:category['label'] = has_key(node.attr, 'label') ? node.attr['label'] : '' 210 | call add(a:target.category, l:category) 211 | elseif node.name == 'app:control' 212 | for l:item in node.child 213 | if type(l:item) == 4 && l:item.name == 'app:draft' 214 | let a:target['app:control'] = {'app:draft': l:item.child[0]} 215 | endif 216 | unlet l:item 217 | endfor 218 | elseif type(a:target[node.name]) == 3 219 | call add(a:target[node.name], a:parent.value()) 220 | else 221 | let a:target[node.name] = node.value() 222 | endif 223 | unlet node 224 | endfor 225 | endfunction 226 | 227 | function! webapi#atom#getFeed(uri, user, pass) abort 228 | let headdata = {} 229 | if len(a:user) > 0 && len(a:pass) > 0 230 | let headdata["X-WSSE"] = s:createWsse(a:user, a:pass) 231 | endif 232 | let res = webapi#http#get(a:uri, {}, headdata) 233 | let dom = webapi#xml#parse(res.content) 234 | let feed = deepcopy(s:feed_template) 235 | call s:parse_node(feed, dom) 236 | return feed 237 | endfunction 238 | 239 | function! webapi#atom#getService(uri, user, pass) abort 240 | let headdata = {} 241 | if len(a:user) > 0 && len(a:pass) > 0 242 | let headdata["X-WSSE"] = s:createWsse(a:user, a:pass) 243 | endif 244 | let res = webapi#http#get(a:uri, {}, headdata) 245 | return webapi#xml#parse(res.content) 246 | endfunction 247 | 248 | function! webapi#atom#getEntry(uri, user, pass) abort 249 | let headdata = {} 250 | if len(a:user) > 0 && len(a:pass) > 0 251 | let headdata["X-WSSE"] = s:createWsse(a:user, a:pass) 252 | endif 253 | let res = webapi#http#get(a:uri, {}, headdata) 254 | let dom = webapi#xml#parse(res.content) 255 | let entry = deepcopy(s:entry_template) 256 | call s:parse_node(entry, dom) 257 | return entry 258 | endfunction 259 | 260 | let &cpo = s:save_cpo 261 | unlet s:save_cpo 262 | 263 | " vim:set et: 264 | -------------------------------------------------------------------------------- /autoload/webapi/base64.vim: -------------------------------------------------------------------------------- 1 | " base64 codec 2 | " Last Change: 2010-07-25 3 | " Maintainer: Yukihiro Nakadaira 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " [The Base16, Base32, and Base64 Data Encodings] 7 | " http://tools.ietf.org/rfc/rfc3548.txt 8 | 9 | let s:save_cpo = &cpo 10 | set cpo&vim 11 | 12 | function! webapi#base64#b64encode(data) abort 13 | let b64 = s:b64encode(s:str2bytes(a:data), s:standard_table, '=') 14 | return join(b64, '') 15 | endfunction 16 | 17 | function! webapi#base64#b64encodebin(data) abort 18 | let b64 = s:b64encode(s:binstr2bytes(a:data), s:standard_table, '=') 19 | return join(b64, '') 20 | endfunction 21 | 22 | function! webapi#base64#b64decode(data) abort 23 | let bytes = s:b64decode(split(a:data, '\zs'), s:standard_table, '=') 24 | return s:bytes2str(bytes) 25 | endfunction 26 | 27 | function! webapi#base64#test() abort 28 | if webapi#base64#b64encode("hello, world") ==# "aGVsbG8sIHdvcmxk" 29 | echo "test1: ok" 30 | else 31 | echoerr "test1: failed" 32 | endif 33 | if webapi#base64#b64encode("hello, worldx") ==# "aGVsbG8sIHdvcmxkeA==" 34 | echo "test2: ok" 35 | else 36 | echoerr "test2: failed" 37 | endif 38 | if webapi#base64#b64encode("hello, worldxx") ==# "aGVsbG8sIHdvcmxkeHg=" 39 | echo "test3: ok" 40 | else 41 | echoerr "test3: falied" 42 | endif 43 | if webapi#base64#b64encode("hello, worldxxx") ==# "aGVsbG8sIHdvcmxkeHh4" 44 | echo "test4: ok" 45 | else 46 | echoerr "test4: falied" 47 | endif 48 | if webapi#base64#b64decode(webapi#base64#b64encode("hello, world")) ==# "hello, world" 49 | echo "test5: ok" 50 | else 51 | echoerr "test5: failed" 52 | endif 53 | if webapi#base64#b64decode(webapi#base64#b64encode("hello, worldx")) ==# "hello, worldx" 54 | echo "test6: ok" 55 | else 56 | echoerr "test6: failed" 57 | endif 58 | if webapi#base64#b64decode(webapi#base64#b64encode("hello, worldxx")) ==# "hello, worldxx" 59 | echo "test7: ok" 60 | else 61 | echoerr "test7: failed" 62 | endif 63 | if webapi#base64#b64decode(webapi#base64#b64encode("hello, worldxxx")) ==# "hello, worldxxx" 64 | echo "test8: ok" 65 | else 66 | echoerr "test8: failed" 67 | endif 68 | endfunction 69 | 70 | let s:standard_table = [ 71 | \ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P", 72 | \ "Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f", 73 | \ "g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v", 74 | \ "w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/"] 75 | 76 | let s:urlsafe_table = [ 77 | \ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P", 78 | \ "Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f", 79 | \ "g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v", 80 | \ "w","x","y","z","0","1","2","3","4","5","6","7","8","9","-","_"] 81 | 82 | function! s:b64encode(bytes, table, pad) abort 83 | let b64 = [] 84 | for i in range(0, len(a:bytes) - 1, 3) 85 | let n = a:bytes[i] * 0x10000 86 | \ + get(a:bytes, i + 1, 0) * 0x100 87 | \ + get(a:bytes, i + 2, 0) 88 | call add(b64, a:table[n / 0x40000]) 89 | call add(b64, a:table[n / 0x1000 % 0x40]) 90 | call add(b64, a:table[n / 0x40 % 0x40]) 91 | call add(b64, a:table[n % 0x40]) 92 | endfor 93 | if len(a:bytes) % 3 == 1 94 | let b64[-1] = a:pad 95 | let b64[-2] = a:pad 96 | endif 97 | if len(a:bytes) % 3 == 2 98 | let b64[-1] = a:pad 99 | endif 100 | return b64 101 | endfunction 102 | 103 | function! s:b64decode(b64, table, pad) abort 104 | let a2i = {} 105 | for i in range(len(a:table)) 106 | let a2i[a:table[i]] = i 107 | endfor 108 | let bytes = [] 109 | for i in range(0, len(a:b64) - 1, 4) 110 | let n = a2i[a:b64[i]] * 0x40000 111 | \ + a2i[a:b64[i + 1]] * 0x1000 112 | \ + (a:b64[i + 2] == a:pad ? 0 : a2i[a:b64[i + 2]]) * 0x40 113 | \ + (a:b64[i + 3] == a:pad ? 0 : a2i[a:b64[i + 3]]) 114 | call add(bytes, n / 0x10000) 115 | call add(bytes, n / 0x100 % 0x100) 116 | call add(bytes, n % 0x100) 117 | endfor 118 | if a:b64[-1] == a:pad 119 | unlet a:b64[-1] 120 | endif 121 | if a:b64[-2] == a:pad 122 | unlet a:b64[-1] 123 | endif 124 | return bytes 125 | endfunction 126 | 127 | function! s:binstr2bytes(str) abort 128 | return map(range(len(a:str)/2), 'eval("0x".a:str[v:val*2 : v:val*2+1])') 129 | endfunction 130 | 131 | function! s:str2bytes(str) abort 132 | return map(range(len(a:str)), 'char2nr(a:str[v:val])') 133 | endfunction 134 | 135 | function! s:bytes2str(bytes) abort 136 | return eval('"' . join(map(copy(a:bytes), 'printf(''\x%02x'', v:val)'), '') . '"') 137 | endfunction 138 | 139 | let &cpo = s:save_cpo 140 | unlet s:save_cpo 141 | -------------------------------------------------------------------------------- /autoload/webapi/bit.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | function! webapi#bit#dec2bin(v) abort 5 | let v = a:v 6 | if v == 0 | return 0 | endif 7 | let ret = "" 8 | while v > 0 9 | let i = v % 2 10 | let ret = i . ret 11 | let v = v / 2 12 | endwhile 13 | return ret 14 | endfunction 15 | 16 | function! webapi#bit#bin2dec(v) abort 17 | let v = a:v 18 | if len(v) == 0 | return 0 | endif 19 | let i = 1 20 | let ret = "" 21 | for n in reverse(split(v, '\zs')) 22 | if n == 1 23 | let ret = ret + i 24 | endif 25 | let i = i * 2 26 | endfor 27 | return ret 28 | endfunction 29 | 30 | if exists('*or') 31 | function! webapi#bit#or(a,b) abort 32 | return or(a:a, a:b) 33 | endfunction 34 | else 35 | function! webapi#bit#or(a,b) abort 36 | let a = webapi#bit#dec2bin(a:a) 37 | let b = webapi#bit#dec2bin(a:b) 38 | return webapi#bit#bin2dec(tr((a + b), '2', '1')) 39 | endfunction 40 | endif 41 | 42 | if exists('*and') 43 | function! webapi#bit#and(a,b) abort 44 | return and(a:a, a:b) 45 | endfunction 46 | else 47 | function! webapi#bit#and(a,b) abort 48 | let a = webapi#bit#dec2bin(a:a) 49 | let b = webapi#bit#dec2bin(a:b) 50 | return webapi#bit#bin2dec(tr((a + b), '21', '10')) 51 | endfunction 52 | endif 53 | 54 | if exists('*xor') 55 | function! webapi#bit#xor(a,b) abort 56 | return xor(a:a, a:b) 57 | endfunction 58 | else 59 | function! webapi#bit#xor(a,b) abort 60 | let a = webapi#bit#dec2bin(a:a) 61 | let b = webapi#bit#dec2bin(a:b) 62 | return webapi#bit#bin2dec(tr((a + b), '21', '01')) 63 | endfunction 64 | endif 65 | 66 | if exists('*xor') 67 | if has('num64') 68 | function! webapi#bit#not(a) abort 69 | return xor(a:a, 0xFFFFFFFFFFFFFFFF) 70 | endfunction 71 | else 72 | function! webapi#bit#not(a) abort 73 | return xor(a:a, 0xFFFFFFFF) 74 | endfunction 75 | endif 76 | else 77 | function! webapi#bit#not(a) abort 78 | let a = webapi#bit#dec2bin(a:a) 79 | return webapi#bit#bin2dec(tr(a, '01', '10')) 80 | endfunction 81 | endif 82 | 83 | function! webapi#bit#shift(a,b) abort 84 | let a = webapi#bit#dec2bin(a:a) 85 | if has('num64') 86 | let a = repeat('0', 64-len(a)) . a 87 | if a:b < 0 88 | let a = (repeat('0', -a:b) . a[: a:b-1])[-64:] 89 | elseif a:b > 0 90 | let a = (a . repeat('0', a:b))[-64:] 91 | endif 92 | else 93 | let a = repeat('0', 32-len(a)) . a 94 | if a:b < 0 95 | let a = (repeat('0', -a:b) . a[: a:b-1])[-32:] 96 | elseif a:b > 0 97 | let a = (a . repeat('0', a:b))[-32:] 98 | endif 99 | endif 100 | return webapi#bit#bin2dec(a) 101 | endfunction 102 | 103 | let &cpo = s:save_cpo 104 | unlet s:save_cpo 105 | 106 | " vim:set et: 107 | -------------------------------------------------------------------------------- /autoload/webapi/feed.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | function! s:attr(node, name) abort 5 | let n = a:node.childNode(a:name) 6 | if empty(n) 7 | return "" 8 | endif 9 | return n.value() 10 | endfunction 11 | 12 | function! webapi#feed#parseURL(url) abort 13 | let dom = webapi#xml#parseURL(a:url) 14 | let items = [] 15 | if dom.name == 'rss' 16 | let channel = dom.childNode('channel') 17 | for item in channel.childNodes('item') 18 | call add(items, { 19 | \ "title": s:attr(item, 'title'), 20 | \ "link": s:attr(item, 'link'), 21 | \ "content": s:attr(item, 'description'), 22 | \ "id": s:attr(item, 'guid'), 23 | \ "date": s:attr(item, 'pubDate'), 24 | \}) 25 | endfor 26 | elseif dom.name == 'rdf:RDF' 27 | for item in dom.childNodes('item') 28 | call add(items, { 29 | \ "title": s:attr(item, 'title'), 30 | \ "link": s:attr(item, 'link'), 31 | \ "content": s:attr(item, 'description'), 32 | \ "id": s:attr(item, 'guid'), 33 | \ "date": s:attr(item, 'dc:date'), 34 | \}) 35 | endfor 36 | elseif dom.name == 'feed' 37 | for item in dom.childNodes('entry') 38 | call add(items, { 39 | \ "title": s:attr(item, 'title'), 40 | \ "link": item.childNode('link').attr['href'], 41 | \ "content": s:attr(item, 'content'), 42 | \ "id": s:attr(item, 'id'), 43 | \ "date": s:attr(item, 'updated'), 44 | \}) 45 | endfor 46 | endif 47 | return items 48 | endfunction 49 | 50 | let &cpo = s:save_cpo 51 | unlet s:save_cpo 52 | 53 | " vim:set et: 54 | -------------------------------------------------------------------------------- /autoload/webapi/hmac.vim: -------------------------------------------------------------------------------- 1 | " This is a port of rfc2104 hmac function. 2 | " http://www.ietf.org/rfc/rfc2104.txt 3 | " Last Change: 2010-02-13 4 | " Maintainer: Yukihiro Nakadaira 5 | " License: This file is placed in the public domain. 6 | 7 | " @param mixed key List or String 8 | " @param mixed text List or String 9 | " @param Funcref hash function digest_hex(key:List, text:List):String 10 | " @param Number blocksize 11 | function webapi#hmac#hmac(key, text, hash, blocksize) abort 12 | let key = (type(a:key) == type("")) ? s:str2bytes(a:key) : a:key 13 | let text = (type(a:text) == type("")) ? s:str2bytes(a:text) : a:text 14 | return s:Hmac(key, text, a:hash, a:blocksize) 15 | endfunction 16 | 17 | function webapi#hmac#md5(key, text) abort 18 | return webapi#hmac#hmac(a:key, a:text, 'webapi#md5#md5bin', 64) 19 | endfunction 20 | 21 | function webapi#hmac#sha1(key, text) abort 22 | return webapi#hmac#hmac(a:key, a:text, 'webapi#sha1#sha1bin', 64) 23 | endfunction 24 | 25 | " http://www.ietf.org/rfc/rfc2202.txt 26 | " Test Cases for HMAC-MD5 and HMAC-SHA-1 27 | function webapi#hmac#test() abort 28 | " Test Cases for HMAC-MD5 29 | call s:test("md5: 1", "webapi#hmac#md5", 30 | \ repeat("\x0b", 16), 31 | \ "Hi There", 32 | \ "9294727a3638bb1c13f48ef8158bfc9d") 33 | call s:test("md5: 2", "webapi#hmac#md5", 34 | \ "Jefe", 35 | \ "what do ya want for nothing?", 36 | \ "750c783e6ab0b503eaa86e310a5db738") 37 | call s:test("md5: 3", "webapi#hmac#md5", 38 | \ repeat("\xaa", 16), 39 | \ repeat("\xdd", 50), 40 | \ "56be34521d144c88dbb8c733f0e8b3f6") 41 | call s:test("md5: 4", "webapi#hmac#md5", 42 | \ s:hex2bytes("0102030405060708090a0b0c0d0e0f10111213141516171819"), 43 | \ repeat([0xcd], 50), 44 | \ "697eaf0aca3a3aea3a75164746ffaa79") 45 | call s:test("md5: 5", "webapi#hmac#md5", 46 | \ repeat("\x0c", 16), 47 | \ "Test With Truncation", 48 | \ "56461ef2342edc00f9bab995690efd4c") 49 | call s:test("md5: 6", "webapi#hmac#md5", 50 | \ repeat("\xaa", 80), 51 | \ "Test Using Larger Than Block-Size Key - Hash Key First", 52 | \ "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd") 53 | call s:test("md5: 7", "webapi#hmac#md5", 54 | \ repeat("\xaa", 80), 55 | \ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 56 | \ "6f630fad67cda0ee1fb1f562db3aa53e") 57 | 58 | " Test Cases for HMAC-SHA1 59 | call s:test("sha1: 1", "webapi#hmac#sha1", 60 | \ repeat("\x0b", 20), 61 | \ "Hi There", 62 | \ "b617318655057264e28bc0b6fb378c8ef146be00") 63 | call s:test("sha1: 2", "webapi#hmac#sha1", 64 | \ "Jefe", 65 | \ "what do ya want for nothing?", 66 | \ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79") 67 | call s:test("sha1: 3", "webapi#hmac#sha1", 68 | \ repeat("\xaa", 20), 69 | \ repeat("\xdd", 50), 70 | \ "125d7342b9ac11cd91a39af48aa17b4f63f175d3") 71 | call s:test("sha1: 4", "webapi#hmac#sha1", 72 | \ s:hex2bytes("0102030405060708090a0b0c0d0e0f10111213141516171819"), 73 | \ repeat([0xcd], 50), 74 | \ "4c9007f4026250c6bc8414f9bf50c86c2d7235da") 75 | call s:test("sha1: 5", "webapi#hmac#sha1", 76 | \ repeat("\x0c", 20), 77 | \ "Test With Truncation", 78 | \ "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04") 79 | call s:test("sha1: 6", "webapi#hmac#sha1", 80 | \ repeat("\xaa", 80), 81 | \ "Test Using Larger Than Block-Size Key - Hash Key First", 82 | \ "aa4ae5e15272d00e95705637ce8a3b55ed402112") 83 | call s:test("sha1: 7", "webapi#hmac#sha1", 84 | \ repeat("\xaa", 80), 85 | \ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 86 | \ "e8e99d0f45237d786d6bbaa7965c7808bbff1a91") 87 | endfunction 88 | 89 | function s:test(name, func, key, data, digest) abort 90 | let result = call(a:func, [a:key, a:data]) 91 | echo "test_case:" a:name 92 | echo "expect:" a:digest 93 | echo "result:" result 94 | if a:digest ==? result 95 | echo "test: OK" 96 | else 97 | echohl Error 98 | echo "test: NG" 99 | echohl None 100 | endif 101 | endfunction 102 | 103 | " @param List key 104 | " @param List text 105 | " @param Funcref hash 106 | " @param Number blocksize 107 | function! s:Hmac(key, text, hash, blocksize) abort 108 | let key = a:key 109 | if len(key) > a:blocksize 110 | let key = s:hex2bytes(call(a:hash, [key])) 111 | endif 112 | let k_ipad = repeat([0], a:blocksize) 113 | let k_opad = repeat([0], a:blocksize) 114 | for i in range(a:blocksize) 115 | let k_ipad[i] = xor(get(key, i, 0), 0x36) 116 | let k_opad[i] = xor(get(key, i, 0), 0x5c) 117 | endfor 118 | let hash1 = s:hex2bytes(call(a:hash, [k_ipad + a:text])) 119 | let hmac = call(a:hash, [k_opad + hash1]) 120 | return hmac 121 | endfunction 122 | 123 | function! s:str2bytes(str) abort 124 | return map(range(len(a:str)), 'char2nr(a:str[v:val])') 125 | endfunction 126 | 127 | function! s:hex2bytes(str) abort 128 | return map(split(a:str, '..\zs'), 'str2nr(v:val, 16)') 129 | endfunction 130 | -------------------------------------------------------------------------------- /autoload/webapi/html.vim: -------------------------------------------------------------------------------- 1 | " html 2 | " Last Change: 2010-09-10 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " 7 | let s:save_cpo = &cpo 8 | set cpo&vim 9 | 10 | function! s:nr2byte(nr) abort 11 | if a:nr < 0x80 12 | return nr2char(a:nr) 13 | elseif a:nr < 0x800 14 | return nr2char(a:nr/64+192).nr2char(a:nr%64+128) 15 | else 16 | return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128) 17 | endif 18 | endfunction 19 | 20 | function! s:nr2enc_char(charcode) abort 21 | if &encoding == 'utf-8' 22 | return nr2char(a:charcode) 23 | endif 24 | let char = s:nr2byte(a:charcode) 25 | if strlen(char) > 1 26 | let char = strtrans(iconv(char, 'utf-8', &encoding)) 27 | endif 28 | return char 29 | endfunction 30 | 31 | function! webapi#html#decodeEntityReference(str) abort 32 | let str = a:str 33 | let str = substitute(str, '>', '>', 'g') 34 | let str = substitute(str, '<', '<', 'g') 35 | let str = substitute(str, '"', '"', 'g') 36 | let str = substitute(str, ''', "'", 'g') 37 | let str = substitute(str, ' ', ' ', 'g') 38 | let str = substitute(str, '¥', '\¥', 'g') 39 | let str = substitute(str, '&#\(\d\+\);', '\=s:nr2enc_char(submatch(1))', 'g') 40 | let str = substitute(str, '&', '\&', 'g') 41 | let str = substitute(str, '»', '>', 'g') 42 | let str = substitute(str, '«', '<', 'g') 43 | return str 44 | endfunction 45 | 46 | function! webapi#html#encodeEntityReference(str) abort 47 | let str = a:str 48 | let str = substitute(str, '&', '\&', 'g') 49 | let str = substitute(str, '>', '\>', 'g') 50 | let str = substitute(str, '<', '\<', 'g') 51 | let str = substitute(str, "\n", '\ ', 'g') 52 | let str = substitute(str, '"', '\"', 'g') 53 | let str = substitute(str, "'", '\'', 'g') 54 | let str = substitute(str, ' ', '\ ', 'g') 55 | return str 56 | endfunction 57 | 58 | function! webapi#html#parse(html) abort 59 | let html = substitute(a:html, '<\(area\|base\|basefont\|br\|nobr\|col\|frame\|hr\|img\|input\|isindex\|link\|meta\|param\|embed\|keygen\|command\)\([^>]*[^/]\|\)>', '<\1\2/>', 'g') 60 | return webapi#xml#parse(html) 61 | endfunction 62 | 63 | function! webapi#html#parseFile(fname) abort 64 | return webapi#html#parse(join(readfile(a:fname), "\n")) 65 | endfunction 66 | 67 | function! webapi#html#parseURL(url) abort 68 | return webapi#html#parse(webapi#http#get(a:url).content) 69 | endfunction 70 | 71 | let &cpo = s:save_cpo 72 | unlet s:save_cpo 73 | 74 | " vim:set et: 75 | -------------------------------------------------------------------------------- /autoload/webapi/http.vim: -------------------------------------------------------------------------------- 1 | " http 2 | " Last Change: 2010-09-10 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | 7 | let s:save_cpo = &cpo 8 | set cpo&vim 9 | 10 | let s:system = function(get(g:, 'webapi#system_function', 'system')) 11 | 12 | function! s:nr2byte(nr) abort 13 | if a:nr < 0x80 14 | return nr2char(a:nr) 15 | elseif a:nr < 0x800 16 | return nr2char(a:nr/64+192).nr2char(a:nr%64+128) 17 | elseif a:nr < 0x10000 18 | return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128) 19 | elseif a:nr < 0x200000 20 | return nr2char(a:nr/262144%16+240).nr2char(a:nr/4096/16+128).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128) 21 | elseif a:nr < 0x4000000 22 | return nr2char(a:nr/16777216%16+248).nr2char(a:nr/262144%16+128).nr2char(a:nr/4096/16+128).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128) 23 | else 24 | return nr2char(a:nr/1073741824%16+252).nr2char(a:nr/16777216%16+128).nr2char(a:nr/262144%16+128).nr2char(a:nr/4096/16+128).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128) 25 | endif 26 | endfunction 27 | 28 | function! s:nr2enc_char(charcode) abort 29 | if &encoding == 'utf-8' 30 | return nr2char(a:charcode) 31 | endif 32 | let char = s:nr2byte(a:charcode) 33 | if strlen(char) > 1 34 | let char = strtrans(iconv(char, 'utf-8', &encoding)) 35 | endif 36 | return char 37 | endfunction 38 | 39 | function! s:nr2hex(nr) abort 40 | let n = a:nr 41 | let r = '' 42 | while n 43 | let r = '0123456789ABCDEF'[n % 16] . r 44 | let n = n / 16 45 | endwhile 46 | return r 47 | endfunction 48 | 49 | function! s:urlencode_char(c, ...) abort 50 | let is_binary = get(a:000, 1) 51 | if !is_binary 52 | let c = iconv(a:c, &encoding, 'utf-8') 53 | if c == '' 54 | let c = a:c 55 | endif 56 | endif 57 | let s = '' 58 | for i in range(strlen(c)) 59 | let s .= printf('%%%02X', char2nr(c[i])) 60 | endfor 61 | return s 62 | endfunction 63 | 64 | function! webapi#http#decodeURI(str) abort 65 | let ret = a:str 66 | let ret = substitute(ret, '+', ' ', 'g') 67 | let ret = substitute(ret, '%\(\x\x\)', '\=printf("%c", str2nr(submatch(1), 16))', 'g') 68 | return ret 69 | endfunction 70 | 71 | function! webapi#http#escape(str) abort 72 | return substitute(a:str, '[^a-zA-Z0-9_./-]', '\=s:urlencode_char(submatch(0))', 'g') 73 | endfunction 74 | 75 | function! webapi#http#encodeURI(items, ...) abort 76 | let is_binary = get(a:000, 1) 77 | let ret = '' 78 | if type(a:items) == 4 79 | for key in sort(keys(a:items)) 80 | if strlen(ret) | let ret .= '&' | endif 81 | let ret .= key . '=' . webapi#http#encodeURI(a:items[key]) 82 | endfor 83 | elseif type(a:items) == 3 84 | for item in sort(a:items) 85 | if strlen(ret) | let ret .= '&' | endif 86 | let ret .= item 87 | endfor 88 | else 89 | let ret = substitute(a:items, '[^a-zA-Z0-9_.~-]', '\=s:urlencode_char(submatch(0), is_binary)', 'g') 90 | endif 91 | return ret 92 | endfunction 93 | 94 | function! webapi#http#encodeURIComponent(items) abort 95 | let ret = '' 96 | if type(a:items) == 4 97 | for key in sort(keys(a:items)) 98 | if strlen(ret) | let ret .= '&' | endif 99 | let ret .= key . '=' . webapi#http#encodeURIComponent(a:items[key]) 100 | endfor 101 | elseif type(a:items) == 3 102 | for item in sort(a:items) 103 | if strlen(ret) | let ret .= '&' | endif 104 | let ret .= item 105 | endfor 106 | else 107 | let items = iconv(a:items, &enc, 'utf-8') 108 | let len = strlen(items) 109 | let i = 0 110 | while i < len 111 | let ch = items[i] 112 | if ch =~# '[0-9A-Za-z-._~!''()*]' 113 | let ret .= ch 114 | elseif ch == ' ' 115 | let ret .= '+' 116 | else 117 | let ret .= '%' . substitute('0' . s:nr2hex(char2nr(ch)), '^.*\(..\)$', '\1', '') 118 | endif 119 | let i = i + 1 120 | endwhile 121 | endif 122 | return ret 123 | endfunction 124 | 125 | function! webapi#http#get(url, ...) abort 126 | let getdata = a:0 > 0 ? a:000[0] : {} 127 | let headdata = a:0 > 1 ? a:000[1] : {} 128 | let follow = a:0 > 2 ? a:000[2] : 1 129 | let url = a:url 130 | let getdatastr = webapi#http#encodeURI(getdata) 131 | if strlen(getdatastr) 132 | let url .= '?' . getdatastr 133 | endif 134 | if executable('curl') 135 | let command = printf('curl -q %s -s -k -i', follow ? '-L' : '') 136 | let quote = &shellxquote == '"' ? "'" : '"' 137 | for key in keys(headdata) 138 | if has('win32') 139 | let command .= ' -H ' . quote . key . ': ' . substitute(headdata[key], '"', '"""', 'g') . quote 140 | else 141 | let command .= ' -H ' . quote . key . ': ' . headdata[key] . quote 142 | endif 143 | endfor 144 | let command .= ' '.quote.url.quote 145 | let res = s:system(command) 146 | elseif executable('wget') 147 | let command = printf('wget -O- --save-headers --server-response -q %s', follow ? '-L' : '') 148 | let quote = &shellxquote == '"' ? "'" : '"' 149 | for key in keys(headdata) 150 | if has('win32') 151 | let command .= ' --header=' . quote . key . ': ' . substitute(headdata[key], '"', '"""', 'g') . quote 152 | else 153 | let command .= ' --header=' . quote . key . ': ' . headdata[key] . quote 154 | endif 155 | endfor 156 | let command .= ' '.quote.url.quote 157 | let res = s:system(command) 158 | else 159 | throw 'require `curl` or `wget` command' 160 | endif 161 | if follow != 0 162 | let mx = 'HTTP/\%(1\.[01]\|2\%(\.0\)\?\)' 163 | while res =~# '^' . mx . ' 3' || res =~# '^' . mx . ' [0-9]\{3} .\+\n\r\?\n' . mx . ' .\+' 164 | let pos = stridx(res, "\r\n\r\n") 165 | if pos != -1 166 | let res = strpart(res, pos+4) 167 | else 168 | let pos = stridx(res, "\n\n") 169 | let res = strpart(res, pos+2) 170 | endif 171 | endwhile 172 | endif 173 | let pos = stridx(res, "\r\n\r\n") 174 | if pos != -1 175 | let content = strpart(res, pos+4) 176 | else 177 | let pos = stridx(res, "\n\n") 178 | let content = strpart(res, pos+2) 179 | endif 180 | let header = split(res[:pos-1], '\r\?\n') 181 | let matched = matchlist(get(header, 0), '^HTTP/\%(1\.[01]\|2\%(\.0\)\?\)\s\+\(\d\+\)\s*\(.*\)') 182 | if !empty(matched) 183 | let [status, message] = matched[1 : 2] 184 | call remove(header, 0) 185 | else 186 | if v:shell_error || len(matched) 187 | let [status, message] = ['500', "Couldn't connect to host"] 188 | else 189 | let [status, message] = ['200', 'OK'] 190 | endif 191 | endif 192 | return { 193 | \ 'status' : status, 194 | \ 'message' : message, 195 | \ 'header' : header, 196 | \ 'content' : content 197 | \} 198 | endfunction 199 | 200 | function! webapi#http#post(url, ...) abort 201 | let postdata = a:0 > 0 ? a:000[0] : {} 202 | let headdata = a:0 > 1 ? a:000[1] : {} 203 | let method = a:0 > 2 ? a:000[2] : 'POST' 204 | let follow = a:0 > 3 ? a:000[3] : 1 205 | let url = a:url 206 | if type(postdata) == 4 207 | let postdatastr = webapi#http#encodeURI(postdata) 208 | else 209 | let postdatastr = postdata 210 | endif 211 | let file = tempname() 212 | if executable('curl') 213 | let command = printf('curl -q %s -s -k -i -X %s', (follow ? '-L' : ''), len(method) ? method : 'POST') 214 | let quote = &shellxquote == '"' ? "'" : '"' 215 | for key in keys(headdata) 216 | if has('win32') 217 | let command .= ' -H ' . quote . key . ': ' . substitute(headdata[key], '"', '"""', 'g') . quote 218 | else 219 | let command .= ' -H ' . quote . key . ': ' . headdata[key] . quote 220 | endif 221 | endfor 222 | let command .= ' '.quote.url.quote 223 | call writefile(split(postdatastr, "\n"), file, 'b') 224 | let res = s:system(command . ' --data-binary @' . quote.file.quote) 225 | elseif executable('wget') 226 | let command = printf('wget -O- --save-headers --server-response -q %s', follow ? '-L' : '') 227 | let headdata['X-HTTP-Method-Override'] = method 228 | let quote = &shellxquote == '"' ? "'" : '"' 229 | for key in keys(headdata) 230 | if has('win32') 231 | let command .= ' --header=' . quote . key . ': ' . substitute(headdata[key], '"', '"""', 'g') . quote 232 | else 233 | let command .= ' --header=' . quote . key . ': ' . headdata[key] . quote 234 | endif 235 | endfor 236 | let command .= ' '.quote.url.quote 237 | call writefile(split(postdatastr, "\n"), file, 'b') 238 | let res = s:system(command . ' --post-data @' . quote.file.quote) 239 | else 240 | throw "require `curl` or `wget` command" 241 | endif 242 | call delete(file) 243 | if follow != 0 244 | let mx = 'HTTP/\%(1\.[01]\|2\%(\.0\)\?\)' 245 | while res =~# '^' . mx . ' 3' || res =~# '^' . mx . ' [0-9]\{3} .\+\n\r\?\n' . mx . ' .\+' 246 | let pos = stridx(res, "\r\n\r\n") 247 | if pos != -1 248 | let res = strpart(res, pos+4) 249 | else 250 | let pos = stridx(res, "\n\n") 251 | let res = strpart(res, pos+2) 252 | endif 253 | endwhile 254 | endif 255 | let pos = stridx(res, "\r\n\r\n") 256 | if pos != -1 257 | let content = strpart(res, pos+4) 258 | else 259 | let pos = stridx(res, "\n\n") 260 | let content = strpart(res, pos+2) 261 | endif 262 | let header = split(res[:pos-1], '\r\?\n') 263 | let matched = matchlist(get(header, 0), '^HTTP/\%(1\.[01]\|2\%(\.0\)\?\)\s\+\(\d\+\)\s*\(.*\)') 264 | if !empty(matched) 265 | let [status, message] = matched[1 : 2] 266 | call remove(header, 0) 267 | else 268 | if v:shell_error || len(matched) 269 | let [status, message] = ['500', "Couldn't connect to host"] 270 | else 271 | let [status, message] = ['200', 'OK'] 272 | endif 273 | endif 274 | return { 275 | \ 'status' : status, 276 | \ 'message' : message, 277 | \ 'header' : header, 278 | \ 'content' : content 279 | \} 280 | endfunction 281 | 282 | function! webapi#http#send(req) abort 283 | let postdata = get(a:req, 'data', '') 284 | let method = get(a:req, 'method', postdata == '' ? 'GET': 'POST') 285 | let headdata = get(a:req, 'header', {}) 286 | let follow = get(a:req, 'follow', 1) 287 | let url = get(a:req, 'url', '') 288 | if type(postdata) == 4 289 | let postdatastr = webapi#http#encodeURI(postdata) 290 | else 291 | let postdatastr = postdata 292 | endif 293 | if empty(postdatastr) 294 | let file = '' 295 | else 296 | let file = tempname() 297 | endif 298 | if executable('curl') 299 | let command = printf('curl -q %s -s -k -i -X %s', (follow ? '-L' : ''), len(method) ? method : 'POST') 300 | let quote = &shellxquote == '"' ? "'" : '"' 301 | for key in keys(headdata) 302 | if has('win32') 303 | let command .= ' -H ' . quote . key . ': ' . substitute(headdata[key], '"', '"""', 'g') . quote 304 | else 305 | let command .= ' -H ' . quote . key . ': ' . headdata[key] . quote 306 | endif 307 | endfor 308 | let command .= ' '.quote.url.quote 309 | if file == '' 310 | let res = s:system(command) 311 | else 312 | call writefile(split(postdatastr, "\n"), file, 'b') 313 | let res = s:system(command . ' --data-binary @' . quote.file.quote) 314 | call delete(file) 315 | endif 316 | elseif executable('wget') 317 | let command = printf('wget -O- --save-headers --server-response -q %s', follow ? '-L' : '') 318 | let headdata['X-HTTP-Method-Override'] = method 319 | let quote = &shellxquote == '"' ? "'" : '"' 320 | for key in keys(headdata) 321 | if has('win32') 322 | let command .= ' --header=' . quote . key . ': ' . substitute(headdata[key], '"', '"""', 'g') . quote 323 | else 324 | let command .= ' --header=' . quote . key . ': ' . headdata[key] . quote 325 | endif 326 | endfor 327 | let command .= ' '.quote.url.quote 328 | if file == '' 329 | let res = s:system(command) 330 | else 331 | call writefile(split(postdatastr, "\n"), file, 'b') 332 | let res = s:system(command . ' --post-data @' . quote.file.quote) 333 | call delete(file) 334 | endif 335 | else 336 | throw "require `curl` or `wget` command" 337 | endif 338 | if follow != 0 339 | let mx = 'HTTP/\%(1\.[01]\|2\%(\.0\)\?\)' 340 | while res =~# '^' . mx . ' 3' || res =~# '^' . mx . ' [0-9]\{3} .\+\n\r\?\n' . mx . ' .\+' 341 | let pos = stridx(res, "\r\n\r\n") 342 | if pos != -1 343 | let res = strpart(res, pos+4) 344 | else 345 | let pos = stridx(res, "\n\n") 346 | let res = strpart(res, pos+2) 347 | endif 348 | endwhile 349 | endif 350 | let pos = stridx(res, "\r\n\r\n") 351 | if pos != -1 352 | let content = strpart(res, pos+4) 353 | else 354 | let pos = stridx(res, "\n\n") 355 | let content = strpart(res, pos+2) 356 | endif 357 | let header = split(res[:pos-1], '\r\?\n') 358 | let matched = matchlist(get(header, 0), '^HTTP/\%(1\.[01]\|2\%(\.0\)\?\)\s\+\(\d\+\)\s*\(.*\)') 359 | if !empty(matched) 360 | let [status, message] = matched[1 : 2] 361 | call remove(header, 0) 362 | else 363 | if v:shell_error || len(matched) 364 | let [status, message] = ['500', "Couldn't connect to host"] 365 | else 366 | let [status, message] = ['200', 'OK'] 367 | endif 368 | endif 369 | return { 370 | \ 'status' : status, 371 | \ 'message' : message, 372 | \ 'header' : header, 373 | \ 'content' : content 374 | \} 375 | endfunction 376 | 377 | function! webapi#http#stream(req) abort 378 | let postdata = get(a:req, 'data', '') 379 | let method = get(a:req, 'method', postdata == '' ? 'GET': 'POST') 380 | let headdata = get(a:req, 'header', {}) 381 | let follow = get(a:req, 'follow', 1) 382 | let url = get(a:req, 'url', '') 383 | let mode = get(a:req, 'mode', 'nl') 384 | if type(postdata) == 4 385 | let postdatastr = webapi#http#encodeURI(postdata) 386 | else 387 | let postdatastr = postdata 388 | endif 389 | if empty(postdatastr) 390 | let file = '' 391 | else 392 | let file = tempname() 393 | endif 394 | if executable('curl') 395 | let command = printf('curl -q %s -s -k -X %s', (follow ? '-L' : ''), len(method) ? method : 'POST') 396 | let quote = &shellxquote == '"' ? "'" : '"' 397 | for key in keys(headdata) 398 | if has('win32') 399 | let command .= ' -H ' . quote . key . ': ' . substitute(headdata[key], '"', '"""', 'g') . quote 400 | else 401 | let command .= ' -H ' . quote . key . ': ' . headdata[key] . quote 402 | endif 403 | endfor 404 | let command .= ' '.quote.url.quote 405 | if file == '' 406 | let job = job_start(command) 407 | else 408 | call writefile(split(postdatastr, "\n"), file, 'b') 409 | let job = job_start(command . ' --data-binary @' . quote.file.quote) 410 | call delete(file) 411 | endif 412 | elseif executable('wget') 413 | let command = printf('wget -O- -q %s', follow ? '-L' : '') 414 | let headdata['X-HTTP-Method-Override'] = method 415 | let quote = &shellxquote == '"' ? "'" : '"' 416 | for key in keys(headdata) 417 | if has('win32') 418 | let command .= ' --header=' . quote . key . ': ' . substitute(headdata[key], '"', '"""', 'g') . quote 419 | else 420 | let command .= ' --header=' . quote . key . ': ' . headdata[key] . quote 421 | endif 422 | endfor 423 | let command .= ' '.quote.url.quote 424 | if file == '' 425 | let job = job_start(command) 426 | else 427 | call writefile(split(postdatastr, "\n"), file, 'b') 428 | let job = job_start(command . ' --post-data @' . quote.file.quote) 429 | call delete(file) 430 | endif 431 | else 432 | throw "require `curl` or `wget` command" 433 | endif 434 | call job_setoptions(job, 435 | \{ 436 | \ 'exit_cb': function('webapi#http#exit_cb', [a:req]), 437 | \ 'stoponexit': 'kill', 438 | \}) 439 | let a:req['job'] = job 440 | 441 | let channel = job_getchannel(job) 442 | call ch_setoptions(channel, 443 | \{ 444 | \ 'out_cb': function('webapi#http#out_cb', [a:req]), 445 | \ 'mode': mode, 446 | \}) 447 | let a:req['channel'] = channel 448 | let a:req['file'] = file 449 | endfunction 450 | 451 | function! webapi#http#exit_cb(req, job, code) abort 452 | let file = get(a:req, 'file') 453 | if file != '' 454 | call delete(file) 455 | endif 456 | let Fexit_cb = get(a:req, 'exit_cb', v:none) 457 | if Fexit_cb != v:none 458 | call Fexit_cb(a:code) 459 | endif 460 | endfunction 461 | 462 | function! webapi#http#out_cb(req, ch, data) abort 463 | let Fout_cb = get(a:req, 'out_cb', v:none) 464 | if Fout_cb != v:none 465 | call Fout_cb(a:data) 466 | endif 467 | endfunction 468 | 469 | let &cpo = s:save_cpo 470 | unlet s:save_cpo 471 | 472 | " vim:set et: 473 | -------------------------------------------------------------------------------- /autoload/webapi/json.vim: -------------------------------------------------------------------------------- 1 | " json 2 | " Last Change: 2012-03-08 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " 7 | let s:save_cpo = &cpo 8 | set cpo&vim 9 | 10 | function! webapi#json#null() abort 11 | return 0 12 | endfunction 13 | 14 | function! webapi#json#true() abort 15 | return 1 16 | endfunction 17 | 18 | function! webapi#json#false() abort 19 | return 0 20 | endfunction 21 | 22 | function! s:nr2byte(nr) abort 23 | if a:nr < 0x80 24 | return nr2char(a:nr) 25 | elseif a:nr < 0x800 26 | return nr2char(a:nr/64+192).nr2char(a:nr%64+128) 27 | else 28 | return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128) 29 | endif 30 | endfunction 31 | 32 | function! s:nr2enc_char(charcode) abort 33 | if &encoding == 'utf-8' 34 | return nr2char(a:charcode) 35 | endif 36 | let char = s:nr2byte(a:charcode) 37 | if strlen(char) > 1 38 | let char = strtrans(iconv(char, 'utf-8', &encoding)) 39 | endif 40 | return char 41 | endfunction 42 | 43 | function! s:fixup(val, tmp) abort 44 | if type(a:val) == 0 45 | return a:val 46 | elseif type(a:val) == 1 47 | if a:val == a:tmp.'null' 48 | return function('webapi#json#null') 49 | elseif a:val == a:tmp.'true' 50 | return function('webapi#json#true') 51 | elseif a:val == a:tmp.'false' 52 | return function('webapi#json#false') 53 | endif 54 | return a:val 55 | elseif type(a:val) == 2 56 | return a:val 57 | elseif type(a:val) == 3 58 | return map(a:val, 's:fixup(v:val, a:tmp)') 59 | elseif type(a:val) == 4 60 | return map(a:val, 's:fixup(v:val, a:tmp)') 61 | else 62 | return string(a:val) 63 | endif 64 | endfunction 65 | 66 | function! webapi#json#decode(json) abort 67 | let json = iconv(a:json, "utf-8", &encoding) 68 | if get(g:, 'webapi#json#parse_strict', 1) == 1 && substitute(substitute(substitute( 69 | \ json, 70 | \ '\\\%(["\\/bfnrt]\|u[0-9a-fA-F]\{4}\)', '\@', 'g'), 71 | \ '"[^\"\\\n\r]*\"\|true\|false\|null\|-\?\d\+' 72 | \ . '\%(\.\d*\)\?\%([eE][+\-]\{-}\d\+\)\?', ']', 'g'), 73 | \ '\%(^\|:\|,\)\%(\s*\[\)\+', '', 'g') !~ '^[\],:{} \t\n]*$' 74 | throw json 75 | endif 76 | let json = join(split(json, "\n"), "") 77 | let json = substitute(json, '\\x22\|\\u0022', '\\"', 'g') 78 | if v:version >= 703 && has('patch780') 79 | let json = substitute(json, '\\u\(\x\x\x\x\)', '\=iconv(nr2char(str2nr(submatch(1), 16), 1), "utf-8", &encoding)', 'g') 80 | else 81 | let json = substitute(json, '\\u\(\x\x\x\x\)', '\=s:nr2enc_char("0x".submatch(1))', 'g') 82 | endif 83 | if get(g:, 'webapi#json#allow_nil', 0) != 0 84 | let tmp = '__WEBAPI_JSON__' 85 | while 1 86 | if stridx(json, tmp) == -1 87 | break 88 | endif 89 | let tmp .= '_' 90 | endwhile 91 | let [null,true,false] = [ 92 | \ tmp.'null', 93 | \ tmp.'true', 94 | \ tmp.'false'] 95 | sandbox let ret = eval(json) 96 | call s:fixup(ret, tmp) 97 | else 98 | let [null,true,false] = [0,1,0] 99 | sandbox let ret = eval(json) 100 | endif 101 | return ret 102 | endfunction 103 | 104 | function! webapi#json#encode(val) abort 105 | if type(a:val) == 0 106 | return a:val 107 | elseif type(a:val) == 1 108 | let json = '"' . escape(a:val, '\"') . '"' 109 | let json = substitute(json, "\r", '\\r', 'g') 110 | let json = substitute(json, "\n", '\\n', 'g') 111 | let json = substitute(json, "\t", '\\t', 'g') 112 | let json = substitute(json, '\([[:cntrl:]]\)', '\=printf("\x%02d", char2nr(submatch(1)))', 'g') 113 | return iconv(json, &encoding, "utf-8") 114 | elseif type(a:val) == 2 115 | let s = string(a:val) 116 | if s == "function('webapi#json#null')" 117 | return 'null' 118 | elseif s == "function('webapi#json#true')" 119 | return 'true' 120 | elseif s == "function('webapi#json#false')" 121 | return 'false' 122 | endif 123 | elseif type(a:val) == 3 124 | return '[' . join(map(copy(a:val), 'webapi#json#encode(v:val)'), ',') . ']' 125 | elseif type(a:val) == 4 126 | return '{' . join(map(keys(a:val), 'webapi#json#encode(v:val).":".webapi#json#encode(a:val[v:val])'), ',') . '}' 127 | else 128 | return string(a:val) 129 | endif 130 | endfunction 131 | 132 | let &cpo = s:save_cpo 133 | unlet s:save_cpo 134 | 135 | " vim:set et: 136 | -------------------------------------------------------------------------------- /autoload/webapi/jsonrpc.vim: -------------------------------------------------------------------------------- 1 | " jsonrpc 2 | " Last Change: 2012-03-08 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " http://tools.ietf.org/rfc/rfc4627.txt 7 | 8 | let s:save_cpo = &cpo 9 | set cpo&vim 10 | 11 | function! webapi#jsonrpc#call(uri, func, args, ...) abort 12 | let opts = a:0 > 0 ? a:000[0] : {} 13 | let data = webapi#json#encode({ 14 | \ 'jsonrpc': '2.0', 15 | \ 'method': a:func, 16 | \ 'params': a:args, 17 | \ 'id': has_key(opts, 'id') ? opts['id'] : 0, 18 | \}) 19 | let res = webapi#http#post(a:uri, data, {"Content-Type": "application/json"}) 20 | let obj = webapi#json#decode(res.content) 21 | if has_key(obj, 'error') 22 | if type(obj.error) == 0 && obj.error != 0 23 | throw obj.error 24 | elseif type(obj.error) == 1 && obj.error != '' 25 | throw obj.error 26 | elseif type(obj.error) == 2 && string(obj.error) != "function('webapi#json#null')" 27 | throw obj.error 28 | endif 29 | endif 30 | if has_key(obj, 'result') 31 | return obj.result 32 | endif 33 | throw "Parse Error" 34 | endfunction 35 | 36 | function! webapi#jsonrpc#wrap(contexts) abort 37 | let api = {} 38 | for context in a:contexts 39 | let target = api 40 | let namespaces = split(context.name, '\.')[:-2] 41 | if len(namespaces) > 0 42 | for ns in namespaces 43 | if !has_key(target, ns) 44 | let target[ns] = {".uri": context.uri} 45 | endif 46 | let target = target[ns] 47 | endfor 48 | endif 49 | if !has_key(context, 'argnames') 50 | let context['argnames'] = ['args'] 51 | let arglist = 'a:args' 52 | else 53 | if len(context.argnames) && context.argnames[-1] == '...' 54 | let arglist = '[' . join(map(copy(context.argnames[:-2]),'"a:".v:val'),',') . ']+a:000' 55 | else 56 | let arglist = '[' . join(map(copy(context.argnames),'"a:".v:val'),',') . ']' 57 | endif 58 | endif 59 | if has_key(context, 'alias') 60 | exe "function api.".context.alias."(".join(context.argnames,",").") dict\n" 61 | \. " return webapi#jsonrpc#call(self['.uri'], '".context.name."', ".arglist.")\n" 62 | \. "endfunction\n" 63 | else 64 | exe "function api.".context.name."(".join(context.argnames,",").") dict\n" 65 | \. " return webapi#jsonrpc#call('".context.uri."', '".context.name."', ".arglist.")\n" 66 | \. "endfunction\n" 67 | endif 68 | endfor 69 | return api 70 | endfunction 71 | 72 | let &cpo = s:save_cpo 73 | unlet s:save_cpo 74 | 75 | " vim:set et: 76 | -------------------------------------------------------------------------------- /autoload/webapi/metaWeblog.vim: -------------------------------------------------------------------------------- 1 | " metaweblog 2 | " Last Change: 2010-09-10 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " http://tools.ietf.org/rfc/rfc3529.txt 7 | 8 | let s:save_cpo = &cpo 9 | set cpo&vim 10 | 11 | let s:template = {"uri" : ""} 12 | 13 | function! s:template.newPost(blogid, username, password, content, publish) dict abort 14 | return webapi#xmlrpc#call(self.uri, 'metaWeblog.newPost', [a:blogid, a:username, a:password, a:content, a:publish]) 15 | endfunction 16 | 17 | function! s:template.editPost(postid, username, password, content, publish) dict abort 18 | return webapi#xmlrpc#call(self.uri, 'metaWeblog.editPost', [a:postid, a:username, a:password, a:content, a:publish]) 19 | endfunction 20 | 21 | function! s:template.getPost(postid, username, password) dict abort 22 | return webapi#xmlrpc#call(self.uri, 'metaWeblog.getPost', [a:postid, a:username, a:password]) 23 | endfunction 24 | 25 | function! s:template.getRecentPosts(blogid, username, password, numberOfPosts) dict abort 26 | return webapi#xmlrpc#call(self.uri, 'metaWeblog.getRecentPosts', [a:blogid, a:username, a:password, a:numberOfPosts]) 27 | endfunction 28 | 29 | function! s:template.deletePost(appkey, postid, username, password, ...) dict abort 30 | return webapi#xmlrpc#call(self.uri, 'blogger.deletePost', [a:apikey, a:postid, a:username, a:password]) 31 | endfunction 32 | 33 | function! s:template.newMediaObject(blogid, username, password, file) dict abort 34 | return webapi#xmlrpc#call(self.uri, 'metaWeblog.newMediaObject', [a:blogid, a:username, a:password, a:file]) 35 | endfunction 36 | 37 | function! webapi#metaWeblog#proxy(uri) abort 38 | let ctx = deepcopy(s:template) 39 | let ctx.uri = a:uri 40 | return ctx 41 | endfunction 42 | 43 | let &cpo = s:save_cpo 44 | unlet s:save_cpo 45 | 46 | " vim:set et: 47 | -------------------------------------------------------------------------------- /autoload/webapi/oauth.vim: -------------------------------------------------------------------------------- 1 | " oauth 2 | " Last Change: 2010-09-10 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " http://tools.ietf.org/rfc/rfc5849.txt 7 | 8 | let s:save_cpo = &cpo 9 | set cpo&vim 10 | 11 | function! webapi#oauth#request_token(url, ctx, ...) abort 12 | let params = a:0 > 0 ? a:000[0] : {} 13 | let query = {} 14 | let time_stamp = localtime() 15 | let nonce = time_stamp . " " . time_stamp 16 | let nonce = webapi#sha1#sha1(nonce)[0:28] 17 | let query["oauth_consumer_key"] = a:ctx.consumer_key 18 | let query["oauth_nonce"] = nonce 19 | let query["oauth_request_method"] = "POST" 20 | let query["oauth_signature_method"] = "HMAC-SHA1" 21 | let query["oauth_timestamp"] = time_stamp 22 | let query["oauth_version"] = "1.0" 23 | for key in keys(params) 24 | let query[key] = params[key] 25 | endfor 26 | let query_string = "POST&" 27 | let query_string .= webapi#http#encodeURI(a:url) 28 | let query_string .= "&" 29 | let query_string .= webapi#http#encodeURI(webapi#http#encodeURI(query)) 30 | let hmacsha1 = webapi#hmac#sha1(webapi#http#encodeURI(a:ctx.consumer_secret) . "&", query_string) 31 | let query["oauth_signature"] = webapi#base64#b64encodebin(hmacsha1) 32 | let res = webapi#http#post(a:url, query, {}) 33 | if res.status != '200' 34 | let a:ctx['response'] = res 35 | return -1 36 | endif 37 | let a:ctx.request_token = webapi#http#decodeURI(substitute(filter(split(res.content, "&"), "v:val =~ '^oauth_token='")[0], '^[^=]*=', '', '')) 38 | let a:ctx.request_token_secret = webapi#http#decodeURI(substitute(filter(split(res.content, "&"), "v:val =~ '^oauth_token_secret='")[0], '^[^=]*=', '', '')) 39 | return a:ctx 40 | endfunction 41 | 42 | function! webapi#oauth#access_token(url, ctx, ...) abort 43 | let params = a:0 > 0 ? a:000[0] : {} 44 | let query = {} 45 | let time_stamp = localtime() 46 | let nonce = time_stamp . " " . time_stamp 47 | let nonce = webapi#sha1#sha1(nonce)[0:28] 48 | let query["oauth_consumer_key"] = a:ctx.consumer_key 49 | let query["oauth_nonce"] = nonce 50 | let query["oauth_request_method"] = "POST" 51 | let query["oauth_signature_method"] = "HMAC-SHA1" 52 | let query["oauth_timestamp"] = time_stamp 53 | let query["oauth_token"] = a:ctx.request_token 54 | let query["oauth_token_secret"] = a:ctx.request_token_secret 55 | let query["oauth_version"] = "1.0" 56 | for key in keys(params) 57 | let query[key] = params[key] 58 | endfor 59 | let query_string = "POST&" 60 | let query_string .= webapi#http#encodeURI(a:url) 61 | let query_string .= "&" 62 | let query_string .= webapi#http#encodeURI(webapi#http#encodeURI(query)) 63 | let hmacsha1 = webapi#hmac#sha1(webapi#http#encodeURI(a:ctx.consumer_secret) . "&" . webapi#http#encodeURI(a:ctx.request_token_secret), query_string) 64 | let query["oauth_signature"] = webapi#base64#b64encodebin(hmacsha1) 65 | let res = webapi#http#post(a:url, query, {}) 66 | let a:ctx.access_token = webapi#http#decodeURI(substitute(filter(split(res.content, "&"), "v:val =~ '^oauth_token='")[0], '^[^=]*=', '', '')) 67 | let a:ctx.access_token_secret = webapi#http#decodeURI(substitute(filter(split(res.content, "&"), "v:val =~ '^oauth_token_secret='")[0], '^[^=]*=', '', '')) 68 | return a:ctx 69 | endfunction 70 | 71 | function! webapi#oauth#get(url, ctx, ...) abort 72 | let params = a:0 > 0 ? a:000[0] : {} 73 | let getdata = a:0 > 1 ? a:000[1] : {} 74 | let headdata = a:0 > 2 ? a:000[2] : {} 75 | let query = {} 76 | let time_stamp = localtime() 77 | let nonce = time_stamp . " " . time_stamp 78 | let nonce = webapi#sha1#sha1(nonce)[0:28] 79 | let query["oauth_consumer_key"] = a:ctx.consumer_key 80 | let query["oauth_nonce"] = nonce 81 | let query["oauth_request_method"] = "GET" 82 | let query["oauth_signature_method"] = "HMAC-SHA1" 83 | let query["oauth_timestamp"] = time_stamp 84 | let query["oauth_token"] = a:ctx.access_token 85 | let query["oauth_version"] = "1.0" 86 | if type(params) == 4 87 | for key in keys(params) 88 | let query[key] = params[key] 89 | endfor 90 | endif 91 | if type(getdata) == 4 92 | for key in keys(getdata) 93 | let query[key] = getdata[key] 94 | endfor 95 | endif 96 | let query_string = query["oauth_request_method"] . "&" 97 | let query_string .= webapi#http#encodeURI(a:url) 98 | let query_string .= "&" 99 | let query_string .= webapi#http#encodeURI(webapi#http#encodeURI(query)) 100 | let hmacsha1 = webapi#hmac#sha1(webapi#http#encodeURI(a:ctx.consumer_secret) . "&" . webapi#http#encodeURI(a:ctx.access_token_secret), query_string) 101 | let query["oauth_signature"] = webapi#base64#b64encodebin(hmacsha1) 102 | if type(getdata) == 4 103 | for key in keys(getdata) 104 | call remove(query, key) 105 | endfor 106 | endif 107 | let auth = 'OAuth ' 108 | for key in sort(keys(query)) 109 | let auth .= key . '="' . webapi#http#encodeURI(query[key]) . '", ' 110 | endfor 111 | let auth = auth[:-3] 112 | let headdata["Authorization"] = auth 113 | let res = webapi#http#get(a:url, getdata, headdata) 114 | return res 115 | endfunction 116 | 117 | function! webapi#oauth#post(url, ctx, ...) abort 118 | let params = a:0 > 0 ? a:000[0] : {} 119 | let postdata = a:0 > 1 ? a:000[1] : {} 120 | let headdata = a:0 > 2 ? a:000[2] : {} 121 | let query = {} 122 | let time_stamp = localtime() 123 | let nonce = time_stamp . " " . time_stamp 124 | let nonce = webapi#sha1#sha1(nonce)[0:28] 125 | let query["oauth_consumer_key"] = a:ctx.consumer_key 126 | let query["oauth_nonce"] = nonce 127 | let query["oauth_request_method"] = "POST" 128 | let query["oauth_signature_method"] = "HMAC-SHA1" 129 | let query["oauth_timestamp"] = time_stamp 130 | let query["oauth_token"] = a:ctx.access_token 131 | let query["oauth_version"] = "1.0" 132 | if type(params) == 4 133 | for key in keys(params) 134 | let query[key] = params[key] 135 | endfor 136 | endif 137 | if type(postdata) == 4 138 | for key in keys(postdata) 139 | let query[key] = postdata[key] 140 | endfor 141 | endif 142 | let query_string = query["oauth_request_method"] . "&" 143 | let query_string .= webapi#http#encodeURI(a:url) 144 | let query_string .= "&" 145 | let query_string .= webapi#http#encodeURI(webapi#http#encodeURI(query)) 146 | let hmacsha1 = webapi#hmac#sha1(webapi#http#encodeURI(a:ctx.consumer_secret) . "&" . webapi#http#encodeURI(a:ctx.access_token_secret), query_string) 147 | let query["oauth_signature"] = webapi#base64#b64encodebin(hmacsha1) 148 | if type(postdata) == 4 149 | for key in keys(postdata) 150 | call remove(query, key) 151 | endfor 152 | endif 153 | let auth = 'OAuth ' 154 | for key in sort(keys(query)) 155 | let auth .= webapi#http#escape(key) . '="' . webapi#http#escape(query[key]) . '",' 156 | endfor 157 | let auth = auth[:-2] 158 | let headdata["Authorization"] = auth 159 | let res = webapi#http#post(a:url, postdata, headdata) 160 | return res 161 | endfunction 162 | 163 | let &cpo = s:save_cpo 164 | unlet s:save_cpo 165 | 166 | " vim:set et: 167 | -------------------------------------------------------------------------------- /autoload/webapi/sha1.vim: -------------------------------------------------------------------------------- 1 | " sha1 digest calculator 2 | " This is a port of rfc3174 sha1 function. 3 | " http://www.ietf.org/rfc/rfc3174.txt 4 | " Last Change: 2010-02-13 5 | " Maintainer: Yukihiro Nakadaira 6 | " Original Copyright: 7 | " Copyright (C) The Internet Society (2001). All Rights Reserved. 8 | " 9 | " This document and translations of it may be copied and furnished to 10 | " others, and derivative works that comment on or otherwise explain it 11 | " or assist in its implementation may be prepared, copied, published 12 | " and distributed, in whole or in part, without restriction of any 13 | " kind, provided that the above copyright notice and this paragraph are 14 | " included on all such copies and derivative works. However, this 15 | " document itself may not be modified in any way, such as by removing 16 | " the copyright notice or references to the Internet Society or other 17 | " Internet organizations, except as needed for the purpose of 18 | " developing Internet standards in which case the procedures for 19 | " copyrights defined in the Internet Standards process must be 20 | " followed, or as required to translate it into languages other than 21 | " English. 22 | " 23 | " The limited permissions granted above are perpetual and will not be 24 | " revoked by the Internet Society or its successors or assigns. 25 | " 26 | " This document and the information contained herein is provided on an 27 | " "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING 28 | " TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING 29 | " BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION 30 | " HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF 31 | " MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 32 | 33 | let s:save_cpo = &cpo 34 | set cpo&vim 35 | 36 | function! webapi#sha1#sha1(str) abort 37 | return s:SHA1Digest(s:str2bytes(a:str)) 38 | endfunction 39 | 40 | function! webapi#sha1#sha1bin(bin) abort 41 | return s:SHA1Digest(a:bin) 42 | endfunction 43 | 44 | function! webapi#sha1#test() abort 45 | call s:main() 46 | endfunction 47 | 48 | function! s:SHA1Digest(bytes) abort 49 | let sha = deepcopy(s:SHA1Context, 1) 50 | let Message_Digest = repeat([0], 20) 51 | 52 | let err = s:SHA1Reset(sha) 53 | if err 54 | throw printf("SHA1Reset Error %d", err) 55 | endif 56 | 57 | let err = s:SHA1Input(sha, a:bytes) 58 | if err 59 | throw printf("SHA1Input Error %d", err) 60 | endif 61 | 62 | let err = s:SHA1Result(sha, Message_Digest) 63 | if err 64 | throw printf("SHA1Result Error %d", err) 65 | endif 66 | 67 | return join(map(Message_Digest, 'printf("%02x", v:val)'), '') 68 | endfunction 69 | 70 | " 71 | " sha1.h 72 | " 73 | " Description: 74 | " This is the header file for code which implements the Secure 75 | " Hashing Algorithm 1 as defined in FIPS PUB 180-1 published 76 | " April 17, 1995. 77 | " 78 | " Many of the variable names in this code, especially the 79 | " single character names, were used because those were the names 80 | " used in the publication. 81 | " 82 | " Please read the file sha1.c for more information. 83 | 84 | " 85 | " If you do not have the ISO standard stdint.h header file, then you 86 | " must typdef the following: 87 | " name meaning 88 | " uint32_t unsigned 32 bit integer 89 | " uint8_t unsigned 8 bit integer (i.e., unsigned char) 90 | " int_least16_t integer of >= 16 bits 91 | " 92 | " 93 | 94 | " enum 95 | let s:shaSuccess = 0 96 | let s:shaNull = 1 " Null pointer parameter 97 | let s:shaInputTooLong = 2 " input data too long 98 | let s:shaStateError = 3 " called Input after Result 99 | 100 | " define 101 | let s:SHA1HashSize = 20 102 | 103 | " 104 | " This structure will hold context information for the SHA-1 105 | " hashing operation 106 | " 107 | " struct 108 | let s:SHA1Context = {} 109 | " uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ 110 | let s:SHA1Context.Intermediate_Hash = repeat([0], s:SHA1HashSize / 4) 111 | " uint32_t Length_Low; /* Message length in bits */ 112 | let s:SHA1Context.Length_Low = 0 113 | " uint32_t Length_High; /* Message length in bits */ 114 | let s:SHA1Context.Length_High = 0 115 | " /* Index into message block array */ 116 | " int_least16_t Message_Block_Index; 117 | let s:SHA1Context.Message_Block_Index = 0 118 | " uint8_t Message_Block[64]; /* 512-bit message blocks */ 119 | let s:SHA1Context.Message_Block = repeat([0], 64) 120 | " int Computed; /* Is the digest computed? */ 121 | let s:SHA1Context.Computed = 0 122 | " int Corrupted; /* Is the message digest corrupted? */ 123 | let s:SHA1Context.Corrupted = 0 124 | 125 | " 126 | " sha1.c 127 | " 128 | " Description: 129 | " This file implements the Secure Hashing Algorithm 1 as 130 | " defined in FIPS PUB 180-1 published April 17, 1995. 131 | " 132 | " The SHA-1, produces a 160-bit message digest for a given 133 | " data stream. It should take about 2**n steps to find a 134 | " message with the same digest as a given message and 135 | " 2**(n/2) to find any two messages with the same digest, 136 | " when n is the digest size in bits. Therefore, this 137 | " algorithm can serve as a means of providing a 138 | " "fingerprint" for a message. 139 | " 140 | " Portability Issues: 141 | " SHA-1 is defined in terms of 32-bit "words". This code 142 | " uses (included via "sha1.h" to define 32 and 8 143 | " bit unsigned integer types. If your C compiler does not 144 | " support 32 bit unsigned integers, this code is not 145 | " appropriate. 146 | " 147 | " Caveats: 148 | " SHA-1 is designed to work with messages less than 2^64 bits 149 | " long. Although SHA-1 allows a message digest to be generated 150 | " for messages of any number of bits less than 2^64, this 151 | " implementation only works with messages with a length that is 152 | " a multiple of the size of an 8-bit character. 153 | " 154 | " 155 | 156 | " 157 | " Define the SHA1 circular left shift macro 158 | " 159 | "#define SHA1CircularShift(bits,word) \ 160 | " (((word) << (bits)) | ((word) >> (32-(bits)))) 161 | function s:SHA1CircularShift(bits, word) abort 162 | return or(s:bitwise_lshift(a:word, a:bits), s:bitwise_rshift(a:word, 32 - a:bits)) 163 | endfunction 164 | 165 | " 166 | " SHA1Reset 167 | " 168 | " Description: 169 | " This function will initialize the SHA1Context in preparation 170 | " for computing a new SHA1 message digest. 171 | " 172 | " Parameters: 173 | " context: [in/out] 174 | " The context to reset. 175 | " 176 | " Returns: 177 | " sha Error Code. 178 | " 179 | " 180 | " int SHA1Reset(SHA1Context *context) 181 | function s:SHA1Reset(context) abort 182 | if empty(a:context) 183 | return s:shaNull 184 | endif 185 | 186 | let a:context.Length_Low = 0 187 | let a:context.Length_High = 0 188 | let a:context.Message_Block_Index = 0 189 | 190 | let a:context.Intermediate_Hash[0] = 0x67452301 191 | let a:context.Intermediate_Hash[1] = 0xEFCDAB89 192 | let a:context.Intermediate_Hash[2] = 0x98BADCFE 193 | let a:context.Intermediate_Hash[3] = 0x10325476 194 | let a:context.Intermediate_Hash[4] = 0xC3D2E1F0 195 | 196 | let a:context.Computed = 0 197 | let a:context.Corrupted = 0 198 | 199 | return s:shaSuccess 200 | endfunction 201 | 202 | " 203 | " SHA1Result 204 | " 205 | " Description: 206 | " This function will return the 160-bit message digest into the 207 | " Message_Digest array provided by the caller. 208 | " NOTE: The first octet of hash is stored in the 0th element, 209 | " the last octet of hash in the 19th element. 210 | " 211 | " Parameters: 212 | " context: [in/out] 213 | " The context to use to calculate the SHA-1 hash. 214 | " Message_Digest: [out] 215 | " Where the digest is returned. 216 | " 217 | " Returns: 218 | " sha Error Code. 219 | " 220 | " 221 | "int SHA1Result( SHA1Context *context, 222 | " uint8_t Message_Digest[SHA1HashSize]) 223 | function s:SHA1Result(context, Message_Digest) abort 224 | if empty(a:context) || empty(a:Message_Digest) 225 | return s:shaNull 226 | endif 227 | 228 | if a:context.Corrupted 229 | return a:context.Corrupted 230 | endif 231 | 232 | if !a:context.Computed 233 | call s:SHA1PadMessage(a:context) 234 | for i in range(64) 235 | " message may be sensitive, clear it out 236 | let a:context.Message_Block[i] = 0 237 | endfor 238 | let a:context.Length_Low = 0 " and clear length 239 | let a:context.Length_High = 0 240 | let a:context.Computed = 1 241 | endif 242 | 243 | for i in range(s:SHA1HashSize) 244 | let a:Message_Digest[i] = s:uint8( 245 | \ s:bitwise_rshift( 246 | \ a:context.Intermediate_Hash[s:bitwise_rshift(i, 2)], 247 | \ 8 * (3 - and(i, 0x03)) 248 | \ ) 249 | \ ) 250 | endfor 251 | 252 | return s:shaSuccess 253 | endfunction 254 | 255 | " 256 | " SHA1Input 257 | " 258 | " Description: 259 | " This function accepts an array of octets as the next portion 260 | " of the message. 261 | " 262 | " Parameters: 263 | " context: [in/out] 264 | " The SHA context to update 265 | " message_array: [in] 266 | " An array of characters representing the next portion of 267 | " the message. 268 | " length: [in] 269 | " The length of the message in message_array 270 | " 271 | " Returns: 272 | " sha Error Code. 273 | " 274 | " 275 | "int SHA1Input( SHA1Context *context, 276 | " const uint8_t *message_array, 277 | " unsigned length) 278 | function s:SHA1Input(context, message_array) abort 279 | if !len(a:message_array) 280 | return s:shaSuccess 281 | endif 282 | 283 | if empty(a:context) || empty(a:message_array) 284 | return s:shaNull 285 | endif 286 | 287 | if a:context.Computed 288 | let a:context.Corrupted = s:shaStateError 289 | return s:shaStateError 290 | endif 291 | 292 | if a:context.Corrupted 293 | return a:context.Corrupted 294 | endif 295 | 296 | for x in a:message_array 297 | if a:context.Corrupted 298 | break 299 | endif 300 | let a:context.Message_Block[a:context.Message_Block_Index] = and(x, 0xFF) 301 | let a:context.Message_Block_Index += 1 302 | 303 | let a:context.Length_Low += 8 304 | if a:context.Length_Low == 0 305 | let a:context.Length_High += 1 306 | if a:context.Length_High == 0 307 | " Message is too long 308 | let a:context.Corrupted = 1 309 | endif 310 | endif 311 | 312 | if a:context.Message_Block_Index == 64 313 | call s:SHA1ProcessMessageBlock(a:context) 314 | endif 315 | endfor 316 | 317 | return s:shaSuccess 318 | endfunction 319 | 320 | " 321 | " SHA1ProcessMessageBlock 322 | " 323 | " Description: 324 | " This function will process the next 512 bits of the message 325 | " stored in the Message_Block array. 326 | " 327 | " Parameters: 328 | " None. 329 | " 330 | " Returns: 331 | " Nothing. 332 | " 333 | " Comments: 334 | " Many of the variable names in this code, especially the 335 | " single character names, were used because those were the 336 | " names used in the publication. 337 | " 338 | " 339 | " 340 | " void SHA1ProcessMessageBlock(SHA1Context *context) 341 | function s:SHA1ProcessMessageBlock(context) abort 342 | " Constants defined in SHA-1 343 | let K = [ 344 | \ 0x5A827999, 345 | \ 0x6ED9EBA1, 346 | \ 0x8F1BBCDC, 347 | \ 0xCA62C1D6 348 | \ ] 349 | let t = 0 " Loop counter 350 | let temp = 0 " Temporary word value 351 | let W = repeat([0], 80) " Word sequence 352 | let [A, B, C, D, E] = [0, 0, 0, 0, 0] " Word buffers 353 | 354 | " 355 | " Initialize the first 16 words in the array W 356 | " 357 | for t in range(16) 358 | let W[t] = s:bitwise_lshift(a:context.Message_Block[t * 4], 24) 359 | let W[t] = or(W[t], s:bitwise_lshift(a:context.Message_Block[t * 4 + 1], 16)) 360 | let W[t] = or(W[t], s:bitwise_lshift(a:context.Message_Block[t * 4 + 2], 8)) 361 | let W[t] = or(W[t], a:context.Message_Block[t * 4 + 3]) 362 | endfor 363 | 364 | for t in range(16, 79) 365 | let W[t] = s:SHA1CircularShift(1, xor(xor(xor(W[t-3], W[t-8]), W[t-14]), W[t-16])) 366 | endfor 367 | 368 | let A = a:context.Intermediate_Hash[0] 369 | let B = a:context.Intermediate_Hash[1] 370 | let C = a:context.Intermediate_Hash[2] 371 | let D = a:context.Intermediate_Hash[3] 372 | let E = a:context.Intermediate_Hash[4] 373 | 374 | for t in range(20) 375 | let temp = s:SHA1CircularShift(5,A) + 376 | \ or(and(B, C), and(s:bitwise_not(B), D)) + 377 | \ E + W[t] + K[0] 378 | let E = D 379 | let D = C 380 | let C = s:SHA1CircularShift(30,B) 381 | let B = A 382 | let A = temp 383 | endfor 384 | 385 | for t in range(20, 39) 386 | let temp = s:SHA1CircularShift(5,A) + xor(xor(B, C), D) + E + W[t] + K[1] 387 | let E = D 388 | let D = C 389 | let C = s:SHA1CircularShift(30,B) 390 | let B = A 391 | let A = temp 392 | endfor 393 | 394 | for t in range(40, 59) 395 | let temp = s:SHA1CircularShift(5,A) + 396 | \ or(or(and(B, C), and(B, D)), and(C, D)) + 397 | \ E + W[t] + K[2] 398 | let E = D 399 | let D = C 400 | let C = s:SHA1CircularShift(30,B) 401 | let B = A 402 | let A = temp 403 | endfor 404 | 405 | for t in range(60, 79) 406 | let temp = s:SHA1CircularShift(5,A) + 407 | \ xor(xor(B, C), D) + E + W[t] + K[3] 408 | let E = D 409 | let D = C 410 | let C = s:SHA1CircularShift(30,B) 411 | let B = A 412 | let A = temp 413 | endfor 414 | 415 | let a:context.Intermediate_Hash[0] += A 416 | let a:context.Intermediate_Hash[1] += B 417 | let a:context.Intermediate_Hash[2] += C 418 | let a:context.Intermediate_Hash[3] += D 419 | let a:context.Intermediate_Hash[4] += E 420 | 421 | let a:context.Message_Block_Index = 0 422 | endfunction 423 | 424 | 425 | " 426 | " SHA1PadMessage 427 | " 428 | " Description: 429 | " According to the standard, the message must be padded to an even 430 | " 512 bits. The first padding bit must be a '1'. The last 64 431 | " bits represent the length of the original message. All bits in 432 | " between should be 0. This function will pad the message 433 | " according to those rules by filling the Message_Block array 434 | " accordingly. It will also call the ProcessMessageBlock function 435 | " provided appropriately. When it returns, it can be assumed that 436 | " the message digest has been computed. 437 | " 438 | " Parameters: 439 | " context: [in/out] 440 | " The context to pad 441 | " ProcessMessageBlock: [in] 442 | " The appropriate SHA*ProcessMessageBlock function 443 | " Returns: 444 | " Nothing. 445 | " 446 | " 447 | " void SHA1PadMessage(SHA1Context *context) 448 | function s:SHA1PadMessage(context) abort 449 | " 450 | " Check to see if the current message block is too small to hold 451 | " the initial padding bits and length. If so, we will pad the 452 | " block, process it, and then continue padding into a second 453 | " block. 454 | " 455 | if a:context.Message_Block_Index > 55 456 | let a:context.Message_Block[a:context.Message_Block_Index] = 0x80 457 | let a:context.Message_Block_Index += 1 458 | while a:context.Message_Block_Index < 64 459 | let a:context.Message_Block[a:context.Message_Block_Index] = 0 460 | let a:context.Message_Block_Index += 1 461 | endwhile 462 | 463 | call s:SHA1ProcessMessageBlock(a:context) 464 | 465 | while a:context.Message_Block_Index < 56 466 | let a:context.Message_Block[a:context.Message_Block_Index] = 0 467 | let a:context.Message_Block_Index += 1 468 | endwhile 469 | else 470 | let a:context.Message_Block[a:context.Message_Block_Index] = 0x80 471 | let a:context.Message_Block_Index += 1 472 | while a:context.Message_Block_Index < 56 473 | let a:context.Message_Block[a:context.Message_Block_Index] = 0 474 | let a:context.Message_Block_Index += 1 475 | endwhile 476 | endif 477 | 478 | " 479 | " Store the message length as the last 8 octets 480 | " 481 | let a:context.Message_Block[56] = s:uint8(s:bitwise_rshift(a:context.Length_High, 24)) 482 | let a:context.Message_Block[57] = s:uint8(s:bitwise_rshift(a:context.Length_High, 16)) 483 | let a:context.Message_Block[58] = s:uint8(s:bitwise_rshift(a:context.Length_High, 8)) 484 | let a:context.Message_Block[59] = s:uint8(a:context.Length_High) 485 | let a:context.Message_Block[60] = s:uint8(s:bitwise_rshift(a:context.Length_Low, 24)) 486 | let a:context.Message_Block[61] = s:uint8(s:bitwise_rshift(a:context.Length_Low, 16)) 487 | let a:context.Message_Block[62] = s:uint8(s:bitwise_rshift(a:context.Length_Low, 8)) 488 | let a:context.Message_Block[63] = s:uint8(a:context.Length_Low) 489 | 490 | call s:SHA1ProcessMessageBlock(a:context) 491 | endfunction 492 | 493 | " 494 | " sha1test.c 495 | " 496 | " Description: 497 | " This file will exercise the SHA-1 code performing the three 498 | " tests documented in FIPS PUB 180-1 plus one which calls 499 | " SHA1Input with an exact multiple of 512 bits, plus a few 500 | " error test checks. 501 | " 502 | " Portability Issues: 503 | " None. 504 | " 505 | " 506 | 507 | " 508 | " Define patterns for testing 509 | " 510 | let s:TEST1 = "abc" 511 | let s:TEST2a = "abcdbcdecdefdefgefghfghighijhi" 512 | let s:TEST2b = "jkijkljklmklmnlmnomnopnopq" 513 | let s:TEST2 = s:TEST2a . s:TEST2b 514 | let s:TEST3 = "a" 515 | let s:TEST4a = "01234567012345670123456701234567" 516 | let s:TEST4b = "01234567012345670123456701234567" 517 | " an exact multiple of 512 bits 518 | let s:TEST4 = s:TEST4a . s:TEST4b 519 | let s:testarray = [ 520 | \ s:TEST1, 521 | \ s:TEST2, 522 | \ s:TEST3, 523 | \ s:TEST4 524 | \ ] 525 | let s:repeatcount = [1, 1, 1000000, 10] 526 | let s:resultarray = [ 527 | \ "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D", 528 | \ "84 98 3E 44 1C 3B D2 6E BA AE 4A A1 F9 51 29 E5 E5 46 70 F1", 529 | \ "34 AA 97 3C D4 C4 DA A4 F6 1E EB 2B DB AD 27 31 65 34 01 6F", 530 | \ "DE A3 56 A2 CD DD 90 C7 A7 EC ED C5 EB B5 63 93 4F 46 04 52" 531 | \ ] 532 | 533 | function s:main() abort 534 | let sha = deepcopy(s:SHA1Context, 1) 535 | let Message_Digest = repeat([0], 20) 536 | 537 | " 538 | " Perform SHA-1 tests 539 | " 540 | for j in range(len(s:testarray)) 541 | if j == 2 542 | echo "Test 3 will take about 1 hour. Press CTRL-C to skip." 543 | endif 544 | echo "" 545 | echo printf("Test %d: %d, '%s'", 546 | \ j+1, 547 | \ s:repeatcount[j], 548 | \ s:testarray[j]) 549 | 550 | let err = s:SHA1Reset(sha) 551 | if err 552 | echo printf("SHA1Reset Error %d.", err ) 553 | break " out of for j loop 554 | endif 555 | 556 | try 557 | for i in range(s:repeatcount[j]) 558 | let err = s:SHA1Input(sha, s:str2bytes(s:testarray[j])) 559 | if err 560 | echo printf("SHA1Input Error %d.", err ) 561 | break " out of for i loop */ 562 | endif 563 | endfor 564 | catch /^Vim:Interrupt$/ 565 | echo "Skip ..." 566 | while getchar(0) | endwhile 567 | continue 568 | endtry 569 | 570 | let err = s:SHA1Result(sha, Message_Digest) 571 | if err 572 | echo printf("SHA1Result Error %d, could not compute message digest.", err) 573 | else 574 | echo "\t" 575 | for i in range(20) 576 | echon printf("%02X ", Message_Digest[i]) 577 | endfor 578 | echo "" 579 | endif 580 | echo "Should match:" 581 | echo printf("\t%s", s:resultarray[j]) 582 | endfor 583 | 584 | " Test some error returns 585 | let err = s:SHA1Input(sha, s:str2bytes(s:testarray[1][0:0])) 586 | echo printf("\nError %d. Should be %d.", err, s:shaStateError) 587 | let err = s:SHA1Reset(0) 588 | echo printf("\nError %d. Should be %d.", err, s:shaNull) 589 | endfunction 590 | 591 | 592 | 593 | "--------------------------------------------------------------------- 594 | " misc 595 | function! s:str2bytes(str) abort 596 | return map(range(len(a:str)), 'char2nr(a:str[v:val])') 597 | endfunction 598 | 599 | function! s:cmp(a, b) abort 600 | let a = printf("%08x", a:a) 601 | let b = printf("%08x", a:b) 602 | return a < b ? -1 : a > b ? 1 : 0 603 | endfunction 604 | 605 | function! s:uint8(n) abort 606 | return and(a:n, 0xFF) 607 | endfunction 608 | 609 | let s:k = [ 610 | \ 0x1, 0x2, 0x4, 0x8, 611 | \ 0x10, 0x20, 0x40, 0x80, 612 | \ 0x100, 0x200, 0x400, 0x800, 613 | \ 0x1000, 0x2000, 0x4000, 0x8000, 614 | \ 0x10000, 0x20000, 0x40000, 0x80000, 615 | \ 0x100000, 0x200000, 0x400000, 0x800000, 616 | \ 0x1000000, 0x2000000, 0x4000000, 0x8000000, 617 | \ 0x10000000, 0x20000000, 0x40000000, 0x80000000, 618 | \ ] 619 | 620 | function! s:bitwise_lshift(a, n) abort 621 | return and(a:a * s:k[a:n], 0xFFFFFFFF) 622 | endfunction 623 | 624 | function! s:bitwise_rshift(a, n) abort 625 | let a = and(a:a, 0xFFFFFFFF) 626 | let a = a < 0 ? a - 0x80000000 : a 627 | let a = a / s:k[a:n] 628 | if a:a < 0 629 | let a += 0x40000000 / s:k[a:n - 1] 630 | endif 631 | return and(a, 0xFFFFFFFF) 632 | endfunction 633 | 634 | function! s:bitwise_not(a) abort 635 | return xor(a:a, 0xFFFFFFFF) 636 | endfunction 637 | 638 | let &cpo = s:save_cpo 639 | unlet s:save_cpo 640 | -------------------------------------------------------------------------------- /autoload/webapi/soap.vim: -------------------------------------------------------------------------------- 1 | " soap 2 | " Last Change: 2010-09-10 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " http://tools.ietf.org/rfc/rfc4743.txt 7 | 8 | let s:save_cpo = &cpo 9 | set cpo&vim 10 | 11 | function! s:soap_call(url, func, ...) abort 12 | let envelope = webapi#xml#createElement("soap:Envelope") 13 | let envelope.attr["xmlns:soap"] = "http://schemas.xmlsoap.org/soap/envelope/" 14 | let envelope.attr["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance" 15 | 16 | let body = webapi#xml#createElement("soap:Body") 17 | call add(envelope.child, body) 18 | let func = webapi#xml#createElement(a:func) 19 | call add(body.child, func) 20 | 21 | let n = 1 22 | for a in a:000 23 | let arg = webapi#xml#createElement("param".n) 24 | let arg.attr["xsi:type"] = "xsd:string" 25 | call arg.value(a) 26 | call add(func.child, arg) 27 | let n += 1 28 | endfor 29 | 30 | let str = '' . envelope.toString() 31 | let res = webapi#http#post(a:url, str) 32 | let dom = webapi#xml#parse(res.content) 33 | return s:parse_return(dom.find("return")) 34 | endfunction 35 | 36 | function! s:parse_return(node) abort 37 | if a:node.attr["xsi:type"] =~ ":Array$" 38 | let arr = [] 39 | for item in a:node.child 40 | call add(ret, s:parse_return(item.child)) 41 | endfor 42 | let ret = arr 43 | elseif a:node.attr["xsi:type"] =~ ":Map$" 44 | let ret = {} 45 | for item in a:node.childNodes("item") 46 | let val = item.childNode("value") 47 | if val.attr["xsi:type"] =~ ":Map$" 48 | let ret[item.childNode("key").value()] = s:parse_return(val) 49 | else 50 | let ret[item.childNode("key").value()] = item.childNode("value").value() 51 | endif 52 | endfor 53 | else 54 | if len(a:node.child) 55 | let arr = [] 56 | for item in a:node.child 57 | call add(arr, s:parse_return(item)) 58 | endfor 59 | let ret = arr 60 | else 61 | let ret = s:parse_return(a:node) 62 | endif 63 | endif 64 | return ret 65 | endfunction 66 | 67 | function! s:get_convert_code(arg) abort 68 | let code = '' 69 | let arg = a:arg 70 | if arg.type == "xsd:string" 71 | let code .= "let ".arg.name." = a:".arg.name 72 | elseif arg.type == "xsd:int" 73 | let code .= "let ".arg.name." = 0+a:".arg.name 74 | elseif arg.type == "xsd:boolean" 75 | let code .= "let ".arg.name." = (0+a:".arg.name.") ? 'true' : 'false'" 76 | elseif arg.type == "xsd:float" 77 | let code .= "let ".arg.name." = nr2float(0+a:".arg.name.")" 78 | elseif arg.type =~ ":Array$" 79 | let code .= "let ".arg.name." = a:".arg.name 80 | else 81 | throw "unknown type:". arg.type 82 | endif 83 | return code 84 | endfunction 85 | 86 | function! webapi#soap#proxy(url) abort 87 | let dom = webapi#xml#parseURL(a:url) 88 | let l:api = {} 89 | let ns = substitute(dom.name, ':\zs.*', '', '') 90 | let service = dom.childNode(ns."service") 91 | if empty(service) 92 | let action = '' 93 | else 94 | let address = dom.childNode(ns."service").find("soap:address") 95 | if empty(address) 96 | let action = '' 97 | else 98 | let action = dom.childNode(ns."service").find("soap:address").attr["location"] 99 | endif 100 | endif 101 | if action == "" 102 | return {} 103 | endif 104 | let operations = dom.childNode(ns."portType").childNodes(ns."operation") 105 | for operation in operations 106 | let name = operation.attr["name"] 107 | let inp = substitute(operation.childNode(ns."input").attr["message"], "^tns:", "", "") 108 | let out = substitute(operation.childNode(ns."output").attr["message"], "^tns:", "", "") 109 | let message = dom.childNode(ns."message", {"name": inp}) 110 | let args = [] 111 | for part in message.childNodes(ns."part") 112 | call add(args, {"name": part.attr["name"], "type": has_key(part.attr, "type") ? part.attr["type"] : "xsd:string"}) 113 | endfor 114 | let argnames = [] 115 | let code = "" 116 | for arg in args 117 | call add(argnames, arg.name) 118 | let code .= " ".s:get_convert_code(arg)."\n" 119 | endfor 120 | let code .= " return s:soap_call(".string(action).", ".string(name).", ".join(argnames, ",").")\n" 121 | let source = "function! l:api.".name."(".join(argnames, ",").") dict\n" 122 | let source .= code 123 | let source .= "endfunction\n" 124 | exe source 125 | endfor 126 | return api 127 | endfunction 128 | 129 | let &cpo = s:save_cpo 130 | unlet s:save_cpo 131 | 132 | " vim:set et: 133 | -------------------------------------------------------------------------------- /autoload/webapi/ucs.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:utf8len = [ 5 | \ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 6 | \ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 7 | \ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 8 | \ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9 | \ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 10 | \ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11 | \ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 12 | \ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0, 13 | \] 14 | 15 | function! webapi#ucs#byte2nr(byte) abort 16 | let p = a:byte 17 | let n0 = char2nr(p[0]) 18 | if n0 < 0x80 19 | return n0 20 | endif 21 | let l = s:utf8len[n0] 22 | let n1 = char2nr(p[1]) 23 | if l > 1 && webapi#bit#and(n1, 0xc0) == 0x80 24 | if l == 2 25 | return webapi#bit#shift(webapi#bit#and(n0, 0x1f), 6) + webapi#bit#and(n1, 0x3f) 26 | endif 27 | let n2 = char2nr(p[2]) 28 | if webapi#bit#and(n2, 0xc0) == 0x80 29 | if l == 3 30 | return webapi#bit#shift(webapi#bit#and(n0, 0x0f), 12) + webapi#bit#shift(webapi#bit#and(n1, 0x3f), 6) + webapi#bit#and(n2, 0x3f) 31 | endif 32 | let n3 = char2nr(p[3]) 33 | if webapi#bit#and(n3, 0xc0) == 0x80 34 | if l == 4 35 | return webapi#bit#shift(webapi#bit#and(n0, 0x07), 18) + webapi#bit#shift(webapi#bit#and(n1, 0x3f), 12) + webapi#bit#shift(webapi#bit#and(n2, 0x3f), 6) + webapi#bit#and(n3, 0x3f) 36 | endif 37 | let n4 = char2nr(p[4]) 38 | if webapi#bit#and(n4, 0xc0) == 0x80 39 | if (l == 5) 40 | return webapi#bit#shift(webapi#bit#and(n0, 0x03), 24) + webapi#bit#shift(webapi#bit#and(n1, 0x3f), 18) + webapi#bit#shift(webapi#bit#and(n2, 0x3f), 12) + webapi#bit#shift(webapi#bit#and(n3, 0x3f), 6) + webapi#bit#and(n4, 0x3f) 41 | endif 42 | let n5 = char2nr(p[5]) 43 | if webapi#bit#and(n5, 0xc0) == 0x80 && l == 6 44 | return webapi#bit#shift(webapi#bit#and(n0, 0x01), 30) + webapi#bit#shift(webapi#bit#and(n1, 0x3f), 24) + webapi#bit#shift(webapi#bit#and(n2, 0x3f), 18) + webapi#bit#shift(webapi#bit#and(n3, 0x3f), 12) + webapi#bit#shift(webapi#bit#and(n4, 0x3f), 6) + webapi#bit#and(n5, 0x3f) 45 | endif 46 | endif 47 | endif 48 | endif 49 | endif 50 | return n0 51 | endfunction 52 | 53 | let &cpo = s:save_cpo 54 | unlet s:save_cpo 55 | 56 | " vim:set et: 57 | -------------------------------------------------------------------------------- /autoload/webapi/xml.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let s:template = { 'name': '', 'attr': {}, 'child': [] } 5 | 6 | function! s:nr2byte(nr) abort 7 | if a:nr < 0x80 8 | return nr2char(a:nr) 9 | elseif a:nr < 0x800 10 | return nr2char(a:nr/64+192).nr2char(a:nr%64+128) 11 | else 12 | return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128) 13 | endif 14 | endfunction 15 | 16 | function! s:nr2enc_char(charcode) abort 17 | if &encoding == 'utf-8' 18 | return nr2char(a:charcode) 19 | endif 20 | let char = s:nr2byte(a:charcode) 21 | if strlen(char) > 1 22 | let char = strtrans(iconv(char, 'utf-8', &encoding)) 23 | endif 24 | return char 25 | endfunction 26 | 27 | function! s:nr2hex(nr) abort 28 | let n = a:nr 29 | let r = "" 30 | while n 31 | let r = '0123456789ABCDEF'[n % 16] . r 32 | let n = n / 16 33 | endwhile 34 | return r 35 | endfunction 36 | 37 | function! s:decodeEntityReference(str, ...) abort 38 | if a:str ==# '' 39 | return a:str 40 | endif 41 | let str = a:str 42 | let str = substitute(str, '>', '>', 'g') 43 | let str = substitute(str, '<', '<', 'g') 44 | if get(g:, 'webapi#xml#decodeAsHTML', 0) 45 | let str = substitute(str, '"', '"', 'g') 46 | let str = substitute(str, ''', "'", 'g') 47 | let str = substitute(str, ' ', ' ', 'g') 48 | let str = substitute(str, '¥', '\¥', 'g') 49 | endif 50 | let str = substitute(str, '&#x\([0-9a-fA-F]\+\);', '\=s:nr2enc_char("0x".submatch(1))', 'g') 51 | let str = substitute(str, '&#\(\d\+\);', '\=s:nr2enc_char(submatch(1))', 'g') 52 | let str = substitute(str, '&', '\&', 'g') 53 | return str 54 | endfunction 55 | 56 | function! s:encodeEntityReference(str) abort 57 | if a:str ==# '' 58 | return a:str 59 | endif 60 | let str = a:str 61 | let str = substitute(str, '&', '\&', 'g') 62 | let str = substitute(str, '>', '\>', 'g') 63 | let str = substitute(str, '<', '\<', 'g') 64 | let str = substitute(str, '"', '\"', 'g') 65 | "let str = substitute(str, "\n", '\ ', 'g') 66 | "let str = substitute(str, '"', '"', 'g') 67 | "let str = substitute(str, "'", ''', 'g') 68 | "let str = substitute(str, ' ', ' ', 'g') 69 | return str 70 | endfunction 71 | 72 | function! s:matchNode(node, cond) abort 73 | if type(a:cond) == 1 && a:node.name == a:cond 74 | return 1 75 | endif 76 | if type(a:cond) == 2 77 | return a:cond(a:node) 78 | endif 79 | if type(a:cond) == 3 80 | let ret = 1 81 | for l:R in a:cond 82 | if !s:matchNode(a:node, l:R) | let ret = 0 | endif 83 | unlet l:R 84 | endfor 85 | return ret 86 | endif 87 | if type(a:cond) == 4 88 | for k in keys(a:cond) 89 | if has_key(a:node.attr, k) && a:node.attr[k] == a:cond[k] | return 1 | endif 90 | endfor 91 | endif 92 | return 0 93 | endfunction 94 | 95 | function! s:template.childNode(...) dict abort 96 | for c in self.child 97 | if type(c) == 4 && s:matchNode(c, a:000) 98 | return c 99 | endif 100 | unlet c 101 | endfor 102 | return {} 103 | endfunction 104 | 105 | function! s:template.childNodes(...) dict abort 106 | let ret = [] 107 | for c in self.child 108 | if type(c) == 4 && s:matchNode(c, a:000) 109 | let ret += [c] 110 | endif 111 | unlet c 112 | endfor 113 | return ret 114 | endfunction 115 | 116 | function! s:template.value(...) dict abort 117 | if a:0 118 | let self.child = a:000 119 | return 120 | endif 121 | let ret = '' 122 | for c in self.child 123 | if type(c) <= 1 || type(c) == 5 124 | let ret .= c 125 | elseif type(c) == 4 126 | let ret .= c.value() 127 | endif 128 | unlet c 129 | endfor 130 | return ret 131 | endfunction 132 | 133 | function! s:template.find(...) dict abort 134 | for c in self.child 135 | if type(c) == 4 136 | if s:matchNode(c, a:000) 137 | return c 138 | endif 139 | unlet! ret 140 | let ret = c.find(a:000) 141 | if !empty(ret) 142 | return ret 143 | endif 144 | endif 145 | unlet c 146 | endfor 147 | return {} 148 | endfunction 149 | 150 | function! s:template.findAll(...) dict abort 151 | let ret = [] 152 | for c in self.child 153 | if type(c) == 4 154 | if s:matchNode(c, a:000) 155 | call add(ret, c) 156 | endif 157 | let ret += c.findAll(a:000) 158 | endif 159 | unlet c 160 | endfor 161 | return ret 162 | endfunction 163 | 164 | function! s:template.toString() dict abort 165 | let xml = '<' . self.name 166 | for attr in keys(self.attr) 167 | let xml .= ' ' . attr . '="' . s:encodeEntityReference(self.attr[attr]) . '"' 168 | endfor 169 | if len(self.child) 170 | let xml .= '>' 171 | for c in self.child 172 | if type(c) == 4 173 | let xml .= c.toString() 174 | elseif type(c) > 1 175 | let xml .= s:encodeEntityReference(string(c)) 176 | else 177 | let xml .= s:encodeEntityReference(c) 178 | endif 179 | unlet c 180 | endfor 181 | let xml .= '' 182 | else 183 | let xml .= ' />' 184 | endif 185 | return xml 186 | endfunction 187 | 188 | function! webapi#xml#createElement(name) abort 189 | let node = deepcopy(s:template) 190 | let node.name = a:name 191 | return node 192 | endfunction 193 | 194 | function! s:parse_tree(ctx, top) abort 195 | let node = a:top 196 | let stack = [a:top] 197 | let pos = 0 198 | " content accumulates the text only tags 199 | let content = "" 200 | let append_content_to_parent = 'if len(stack) && content != "" | call add(stack[-1].child, content) | let content ="" | endif' 201 | 202 | let mx = '^\s*\(]\+>\)' 203 | if a:ctx['xml'] =~ mx 204 | let match = matchstr(a:ctx['xml'], mx) 205 | let a:ctx['xml'] = a:ctx['xml'][stridx(a:ctx['xml'], match) + len(match):] 206 | let mx = 'encoding\s*=\s*["'']\{0,1}\([^"'' \t]\+\|[^"'']\+\)["'']\{0,1}' 207 | let matches = matchlist(match, mx) 208 | if len(matches) 209 | let encoding = matches[1] 210 | if len(encoding) && len(a:ctx['encoding']) == 0 211 | let a:ctx['encoding'] = encoding 212 | let a:ctx['xml'] = iconv(a:ctx['xml'], encoding, &encoding) 213 | endif 214 | endif 215 | endif 216 | 217 | " this regex matches 218 | " 1) the remaining until the next tag begins 219 | " 2) maybe closing "/" of tag name 220 | " 3) tagname 221 | " 4) the attributes of the text (optional) 222 | " 5) maybe closing "/" (end of tag name) 223 | " or 224 | " 6) CDATA or '' 225 | " 7) text content of CDATA 226 | " 8) the remaining text after the tag (rest) 227 | " (These numbers correspond to the indexes in matched list m) 228 | let tag_mx = '^\(\_.\{-}\)\%(\%(<\(/\?\)\([^!/>[:space:]]\+\)\(\%([[:space:]]*[^/>=[:space:]]\+[[:space:]]*=[[:space:]]*\%([^"'' />\t]\+\|"[^"]*"\|''[^'']*''\)\|[[:space:]]\+[^/>=[:space:]]\+[[:space:]]*\)*\)[[:space:]]*\(/\?\)>\)\|\%(\)\|\(\)\)' 229 | 230 | while len(a:ctx['xml']) > 0 231 | let m = matchlist(a:ctx.xml, tag_mx) 232 | if empty(m) | break | endif 233 | let a:ctx.xml = a:ctx.xml[len(m[0]) :] 234 | let is_end_tag = m[2] == '/' && m[5] == '' 235 | let is_start_and_end_tag = m[2] == '' && m[5] == '/' 236 | let tag_name = m[3] 237 | let attrs = m[4] 238 | 239 | let content .= s:decodeEntityReference(m[1]) 240 | 241 | if is_end_tag 242 | " closing tag: pop from stack and continue at upper level 243 | exec append_content_to_parent 244 | 245 | if len(stack) " TODO: checking whether opened tag is exist. 246 | call remove(stack, -1) 247 | endif 248 | continue 249 | endif 250 | 251 | " comment tag 252 | if m[8] != '' 253 | continue 254 | endif 255 | 256 | " if element is a CDATA 257 | if m[6] != '' 258 | let content .= m[7] 259 | continue 260 | endif 261 | 262 | let node = deepcopy(s:template) 263 | let node.name = tag_name 264 | let attr_mx = '\([^=[:space:]]\+\)\s*\%(=\s*''\([^'']*\)''\|=\s*"\([^"]*\)"\|=\s*\(\w\+\)\|\)' 265 | while len(attrs) > 0 266 | let attr_match = matchlist(attrs, attr_mx) 267 | if len(attr_match) == 0 268 | break 269 | endif 270 | let name = attr_match[1] 271 | let value = len(attr_match[2]) ? attr_match[2] : len(attr_match[3]) ? attr_match[3] : len(attr_match[4]) ? attr_match[4] : "" 272 | let node.attr[name] = s:decodeEntityReference(value) 273 | let attrs = attrs[stridx(attrs, attr_match[0]) + len(attr_match[0]):] 274 | endwhile 275 | 276 | exec append_content_to_parent 277 | 278 | if len(stack) 279 | call add(stack[-1].child, node) 280 | endif 281 | if !is_start_and_end_tag 282 | " opening tag, continue parsing its contents 283 | call add(stack, node) 284 | endif 285 | endwhile 286 | endfunction 287 | 288 | function! webapi#xml#parse(xml) abort 289 | let top = deepcopy(s:template) 290 | let oldmaxmempattern=&maxmempattern 291 | let oldmaxfuncdepth=&maxfuncdepth 292 | let &maxmempattern=2000000 293 | let &maxfuncdepth=2000 294 | "try 295 | call s:parse_tree({'xml': a:xml, 'encoding': ''}, top) 296 | for node in top.child 297 | if type(node) == 4 298 | return node 299 | endif 300 | unlet node 301 | endfor 302 | "catch /.*/ 303 | "endtry 304 | let &maxmempattern=oldmaxmempattern 305 | let &maxfuncdepth=oldmaxfuncdepth 306 | throw "Parse Error" 307 | endfunction 308 | 309 | function! webapi#xml#parseFile(fname) abort 310 | return webapi#xml#parse(join(readfile(a:fname), "\n")) 311 | endfunction 312 | 313 | function! webapi#xml#parseURL(url) abort 314 | return webapi#xml#parse(webapi#http#get(a:url).content) 315 | endfunction 316 | 317 | let &cpo = s:save_cpo 318 | unlet s:save_cpo 319 | 320 | " vim:set et: 321 | -------------------------------------------------------------------------------- /autoload/webapi/xmlrpc.vim: -------------------------------------------------------------------------------- 1 | " xmlrpc 2 | " Last Change: 2010-11-05 3 | " Maintainer: Yasuhiro Matsumoto 4 | " License: This file is placed in the public domain. 5 | " Reference: 6 | " http://tools.ietf.org/rfc/rfc3529.txt 7 | 8 | let s:save_cpo = &cpo 9 | set cpo&vim 10 | 11 | let s:system = function(get(g:, 'webapi#system_function', 'system')) 12 | 13 | function! webapi#xmlrpc#nil() abort 14 | return 0 15 | endfunction 16 | 17 | function! webapi#xmlrpc#true() abort 18 | return 1 19 | endfunction 20 | 21 | function! webapi#xmlrpc#false() abort 22 | return 0 23 | endfunction 24 | 25 | function! s:get_childNode(node) abort 26 | let child = a:node.childNode('value').childNode() 27 | if empty(child) 28 | let child = a:node.childNode('value') 29 | endif 30 | return child 31 | endfunction 32 | 33 | function! s:from_value(value) abort 34 | let value = a:value 35 | if value.name == 'methodResponse' 36 | let param = value.childNode('params').childNodes('param') 37 | if len(param) == 1 38 | return s:from_value(s:get_childNode(param[0])) 39 | else 40 | let ret = [] 41 | for v in param 42 | call add(ret, s:from_value(s:get_childNode(v))) 43 | endfor 44 | return ret 45 | endif 46 | elseif value.name == 'string' 47 | return value.value() 48 | elseif value.name == 'base64' 49 | return value.value() 50 | elseif value.name == 'dateTime.iso8601' 51 | return value.value() 52 | elseif value.name == 'boolean' 53 | return 0+substitute(value.value(), "[ \n\r]", '', 'g') 54 | elseif value.name == 'int' 55 | return 0+substitute(value.value(), "[ \n\r]", '', 'g') 56 | elseif value.name == 'i4' 57 | return 0+substitute(value.value(), "[ \n\r]", '', 'g') 58 | elseif value.name == 'double' 59 | return str2float(substitute(value.value(), "[ \n\r]", '', 'g')) 60 | elseif value.name == 'struct' 61 | let ret = {} 62 | for member in value.childNodes('member') 63 | let ret[member.childNode('name').value()] = s:from_value(s:get_childNode(member)) 64 | endfor 65 | return ret 66 | elseif value.name == 'array' 67 | let ret = [] 68 | for v in value.childNode('data').childNodes('value') 69 | let child = v.childNode() 70 | if !empty(child) 71 | call add(ret, s:from_value(child)) 72 | else 73 | call add(ret, v.value()) 74 | endif 75 | endfor 76 | return ret 77 | elseif value.name == 'nil' 78 | if get(g:, 'webapi#xmlrpc#allow_nil', 0) != 0 79 | return function('webapi#xmlrpc#nil') 80 | endif 81 | return 0 82 | elseif value.name == 'value' 83 | return value.value() 84 | else 85 | throw "unknown type: ".value.name 86 | endif 87 | endfunction 88 | 89 | function! s:to_value(content) abort 90 | if type(a:content) == 4 91 | if has_key(a:content, 'bits') 92 | let struct = webapi#xml#createElement("struct") 93 | 94 | let member = webapi#xml#createElement("member") 95 | call add(struct.child, member) 96 | let name = webapi#xml#createElement("name") 97 | call add(member.child, name) 98 | call name.value("name") 99 | let value = webapi#xml#createElement("value") 100 | call add(member.child, value) 101 | call add(value.child, s:to_value(a:content["name"])) 102 | 103 | let member = webapi#xml#createElement("member") 104 | call add(struct.child, member) 105 | let name = webapi#xml#createElement("name") 106 | call name.value("bits") 107 | call add(member.child, name) 108 | let value = webapi#xml#createElement("value") 109 | call add(member.child, value) 110 | let base64 = webapi#xml#createElement("base64") 111 | call add(value.child, base64) 112 | if has_key(a:content, "bits") && len(a:content["bits"]) 113 | call base64.value(a:content["bits"]) 114 | elseif has_key(a:content, "path") 115 | let quote = &shellxquote == '"' ? "'" : '"' 116 | let bits = substitute(s:system("xxd -ps ".quote.a:content["path"].quote), "[ \n\r]", '', 'g') 117 | call base64.value(webapi#base64#b64encodebin(bits)) 118 | endif 119 | return struct 120 | else 121 | let struct = webapi#xml#createElement("struct") 122 | for key in keys(a:content) 123 | let member = webapi#xml#createElement("member") 124 | let name = webapi#xml#createElement("name") 125 | call name.value(key) 126 | call add(member.child, name) 127 | let value = webapi#xml#createElement("value") 128 | call add(value.child, s:to_value(a:content[key])) 129 | call add(member.child, value) 130 | call add(struct.child, member) 131 | endfor 132 | return struct 133 | endif 134 | elseif type(a:content) == 3 135 | let array = webapi#xml#createElement("array") 136 | let data = webapi#xml#createElement("data") 137 | for item in a:content 138 | let value = webapi#xml#createElement("value") 139 | call add(value.child, s:to_value(item)) 140 | call add(data.child, value) 141 | endfor 142 | call add(array.child, data) 143 | return array 144 | elseif type(a:content) == 2 145 | if a:content == function('webapi#xmlrpc#true') 146 | let true = webapi#xml#createElement("boolean") 147 | call true.value('true') 148 | return true 149 | elseif a:content == function('webapi#xmlrpc#false') 150 | let false = webapi#xml#createElement("boolean") 151 | call false.value('false') 152 | return false 153 | else 154 | return webapi#xml#createElement("nil") 155 | endif 156 | elseif type(a:content) <= 1 || type(a:content) == 5 157 | if type(a:content) == 0 158 | let int = webapi#xml#createElement("int") 159 | call int.value(a:content) 160 | return int 161 | elseif type(a:content) == 1 162 | let str = webapi#xml#createElement("string") 163 | call str.value(a:content) 164 | return str 165 | elseif type(a:content) == 5 166 | let double = webapi#xml#createElement("double") 167 | call double.value(a:content) 168 | return double 169 | endif 170 | endif 171 | return {} 172 | endfunction 173 | 174 | function! s:to_fault(dom) abort 175 | let struct = a:dom.find('struct') 176 | let faultCode = "" 177 | let faultString = "" 178 | for member in struct.childNodes('member') 179 | if member.childNode('name').value() == "faultCode" 180 | let faultCode = member.childNode('value').value() 181 | elseif member.childNode('name').value() == "faultString" 182 | let faultString = member.childNode('value').value() 183 | endif 184 | endfor 185 | return faultCode.":".faultString 186 | endfunction 187 | 188 | "add_node_params 189 | "Add list of args on the xml tree. 190 | "input: list of args 191 | "output: none 192 | function! s:add_node_params(args) abort 193 | let params = webapi#xml#createElement("params") 194 | for Arg in a:args 195 | let param = webapi#xml#createElement("param") 196 | let value = webapi#xml#createElement("value") 197 | call value.value(s:to_value(Arg)) 198 | call add(param.child, value) 199 | call add(params.child, param) 200 | unlet Arg 201 | endfor 202 | return params 203 | endfunction 204 | 205 | function! webapi#xmlrpc#call(uri, func, args) abort 206 | let methodCall = webapi#xml#createElement("methodCall") 207 | let methodName = webapi#xml#createElement("methodName") 208 | call methodName.value(a:func) 209 | call add(methodCall.child, methodName) 210 | if !empty(a:args) 211 | call add(methodCall.child, s:add_node_params(a:args)) 212 | endif 213 | let xml = '' 214 | let xml .= iconv(methodCall.toString(), &encoding, "utf-8") 215 | let res = webapi#http#post(a:uri, xml, {"Content-Type": "text/xml"}) 216 | let dom = webapi#xml#parse(res.content) 217 | if len(dom.find('fault')) 218 | throw s:to_fault(dom) 219 | else 220 | return s:from_value(dom) 221 | endif 222 | endfunction 223 | 224 | function! webapi#xmlrpc#wrap(contexts) abort 225 | let api = {} 226 | for context in a:contexts 227 | let target = api 228 | let namespaces = split(context.name, '\.')[:-2] 229 | if len(namespaces) > 0 230 | for ns in namespaces 231 | if !has_key(target, ns) 232 | let target[ns] = {".uri": context.uri} 233 | endif 234 | let target = target[ns] 235 | let api['.uri'] = target['.uri'] 236 | endfor 237 | endif 238 | if len(context.argnames) && context.argnames[-1] == '...' 239 | let arglist = '[' . join(map(copy(context.argnames[:-2]),'"a:".v:val'),',') . ']+a:000' 240 | else 241 | let arglist = '[' . join(map(copy(context.argnames),'"a:".v:val'),',') . ']' 242 | endif 243 | if has_key(context, 'alias') 244 | exe "function api.".context.alias."(".join(context.argnames,",").") dict\n" 245 | \. " return webapi#xmlrpc#call(self['.uri'], '".context.name."', ".arglist.")\n" 246 | \. "endfunction\n" 247 | else 248 | exe "function api.".context.name."(".join(context.argnames,",").") dict\n" 249 | \. " return webapi#xmlrpc#call('".context.uri."', '".context.name."', ".arglist.")\n" 250 | \. "endfunction\n" 251 | endif 252 | endfor 253 | return api 254 | endfunction 255 | 256 | let &cpo = s:save_cpo 257 | unlet s:save_cpo 258 | 259 | " vim:set et: 260 | -------------------------------------------------------------------------------- /doc/webapi-html.txt: -------------------------------------------------------------------------------- 1 | *webapi-html.txt* HTML parser written in pure vimscript. 2 | 3 | Maintainer: mattn 4 | 5 | ============================================================================== 6 | CONTENTS *webapi-html-contents* 7 | 8 | INTRODUCTION |webapi-html-introduction| 9 | INTERFACE |webapi-html-interface| 10 | Functions |webapi-html-functions| 11 | Structures |webapi-html-structures| 12 | 13 | ============================================================================== 14 | INTRODUCTION *webapi-html-introduction* 15 | 16 | *webapi-html* is HTML parser Library. 17 | 18 | ============================================================================== 19 | INTERFACE *webapi-html-interface* 20 | ------------------------------------------------------------------------------ 21 | FUNCTIONS *webapi-html-functions* 22 | 23 | parse(content) *webapi-html.parse()* 24 | Parse content into DOM object. 25 | 26 | parseFile(file) *webapi-html.parseFile()* 27 | Parse html file into DOM object. 28 | 29 | parseURL(url) *webapi-html.parseURL()* 30 | Get and parse html into DOM object. 31 | 32 | ------------------------------------------------------------------------------ 33 | STRUCTURES *webapi-html-structures* 34 | 35 | DOM object is structured as |Directory| like following. 36 | > 37 | { 38 | "name": "a", 39 | "attr": { 40 | "href": "http://example.com", 41 | "title": "example", 42 | }, 43 | "child": [...] 44 | } 45 | < 46 | ============================================================================== 47 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 48 | -------------------------------------------------------------------------------- /doc/webapi-http.txt: -------------------------------------------------------------------------------- 1 | *webapi-http.txt* simple HTTP client library. 2 | 3 | Maintainer: mattn 4 | 5 | ============================================================================== 6 | CONTENTS *webapi-http-contents* 7 | 8 | INTRODUCTION |webapi-http-introduction| 9 | INTERFACE |webapi-http-interface| 10 | Functions |webapi-http-functions| 11 | Response |webapi-http-response| 12 | 13 | ============================================================================== 14 | INTRODUCTION *webapi-http-introduction* 15 | 16 | *webapi-http* is HTTP Utilities Library. It provides simple HTTP client. 17 | 18 | ============================================================================== 19 | INTERFACE *webapi-http-interface* 20 | ------------------------------------------------------------------------------ 21 | FUNCTIONS *webapi-http-functions* 22 | 23 | get(url, param, header) *webapi-http.get()* 24 | Send GET request to url. 25 | 26 | post(url, param, header) *webapi-http.post()* 27 | Send POST request to url. 28 | 29 | encodeURI(param) *webapi-http.encodeURI()* 30 | Encode params as URI query. 31 | 32 | decodeURI(str) *webapi-http.decodeURI()* 33 | Decode string as URI params. 34 | 35 | encodeURIComponent(str) *webapi-http.encodeURIComponent()* 36 | Encode param as URI components. 37 | 38 | ------------------------------------------------------------------------------ 39 | RESPONSE *webapi-http-response* 40 | 41 | |webapi-http.get| and |webapi-http.post| return data structure as 42 | |Directory| like following. 43 | > 44 | { 45 | "header": [ 46 | "Content-Type: text/html", 47 | "Content-Length: 310" 48 | ], 49 | "content": " ....." 50 | } 51 | < 52 | ============================================================================== 53 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 54 | -------------------------------------------------------------------------------- /doc/webapi-json.txt: -------------------------------------------------------------------------------- 1 | *webapi-json.txt* JSON parser written in pure vimscript. 2 | 3 | Maintainer: mattn 4 | 5 | ============================================================================== 6 | CONTENTS *webapi-json-contents* 7 | 8 | INTRODUCTION |webapi-json-introduction| 9 | INTERFACE |webapi-json-interface| 10 | Functions |webapi-json-functions| 11 | 12 | ============================================================================== 13 | INTRODUCTION *webapi-json-introduction* 14 | 15 | *webapi-json* is JSON parser Library. 16 | 17 | ============================================================================== 18 | INTERFACE *webapi-json-interface* 19 | ------------------------------------------------------------------------------ 20 | FUNCTIONS *webapi-json-functions* 21 | 22 | encode(object) *webapi-json.encode()* 23 | Encode object into JSON string. 24 | 25 | decode(json) *webapi-json.decode()* 26 | Decode JSON string into variable that vim can treat. 27 | 28 | ============================================================================== 29 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 30 | -------------------------------------------------------------------------------- /doc/webapi-xml.txt: -------------------------------------------------------------------------------- 1 | *webapi-xml.txt* XML parser written in pure vimscript. 2 | 3 | Maintainer: mattn 4 | 5 | ============================================================================== 6 | CONTENTS *webapi-xml-contents* 7 | 8 | INTRODUCTION |webapi-xml-introduction| 9 | INTERFACE |webapi-xml-interface| 10 | Functions |webapi-xml-functions| 11 | Structures |webapi-xml-structures| 12 | 13 | ============================================================================== 14 | INTRODUCTION *webapi-xml-introduction* 15 | 16 | *webapi-xml* is XML parser Library. 17 | 18 | ============================================================================== 19 | INTERFACE *webapi-xml-interface* 20 | ------------------------------------------------------------------------------ 21 | FUNCTIONS *webapi-xml-functions* 22 | 23 | parse(content) *webapi-xml.parse()* 24 | Parse content into DOM object. 25 | 26 | parseFile(file) *webapi-xml.parseFile()* 27 | Parse html file into DOM object. 28 | 29 | parseURL(url) *webapi-xml.parseURL()* 30 | Get and parse html into DOM object. 31 | 32 | ------------------------------------------------------------------------------ 33 | STRUCTURES *webapi-xml-structures* 34 | 35 | DOM object is structured as |Directory| like following. 36 | > 37 | { 38 | "name": "a", 39 | "attr": { 40 | "href": "http://example.com", 41 | "title": "example", 42 | }, 43 | "child": [...] 44 | } 45 | < 46 | ============================================================================== 47 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 48 | -------------------------------------------------------------------------------- /doc/webapi.txt: -------------------------------------------------------------------------------- 1 | *webapi.txt* Interface to Web API 2 | 3 | Author: Yasuhiro Matsumoto 4 | WebSite: http://mattn.kaoriya.net/ 5 | Repository: http://github.com/mattn/webapi-vim 6 | License: Public Domain 7 | 8 | ============================================================================== 9 | CONTENTS *webapi-contents* *webapi* *web-api* 10 | 11 | XML Parser |webapi-xml| 12 | HTML Parser |webapi-html| 13 | JSON Parser |webapi-json| 14 | 15 | ============================================================================== 16 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 17 | -------------------------------------------------------------------------------- /example/gistview.vim: -------------------------------------------------------------------------------- 1 | function! s:dump(node, syntax) 2 | let syntax = a:syntax 3 | if type(a:node) == 1 && empty(a:node) 4 | if len(syntax) | exe "echohl ".syntax | endif 5 | echon webapi#html#decodeEntityReference(a:node) 6 | echohl None 7 | elseif type(a:node) == 3 8 | for n in a:node 9 | call s:dump(n, syntax) 10 | endfor 11 | return 12 | elseif type(a:node) == 4 && !empty(a:node) 13 | "echo a:node.name 14 | "echo a:node.attr 15 | let syndef = {'kt' : 'Type', 'mi' : 'Number', 'nb' : 'Statement', 'kp' : 'Statement', 'nn' : 'Define', 'nc' : 'Constant', 'no' : 'Constant', 'k' : 'Include', 's' : 'String', 's1' : 'String', 'err': 'Error', 'kd' : 'StorageClass', 'c1' : 'Comment', 'ss' : 'Delimiter', 'vi' : 'Identifier'} 16 | for a in keys(syndef) 17 | if has_key(a:node.attr, 'class') && a:node.attr['class'] == a | let syntax = syndef[a] | endif 18 | endfor 19 | if has_key(a:node.attr, 'class') && a:node.attr['class'] == 'line' | echon "\n" | endif 20 | for c in a:node.child 21 | call s:dump(c, syntax) 22 | unlet c 23 | endfor 24 | endif 25 | endfunction 26 | 27 | let no = 357275 28 | let res = webapi#http#get(printf('https://gist.github.com/%d.json', no)) 29 | let obj = webapi#json#decode(res.content) 30 | let dom = webapi#html#parse(obj.div) 31 | echo "-------------------------------------------------" 32 | for file in dom.childNodes('div') 33 | unlet! meta 34 | let meta = file.childNodes('div') 35 | if len(meta) > 1 36 | echo "URL:".meta[1].find('a').attr['href'] 37 | endif 38 | echo "\n" 39 | call s:dump(file, '') 40 | echo "-------------------------------------------------" 41 | endfor 42 | 43 | " vim: set et: 44 | -------------------------------------------------------------------------------- /example/google-buzz.vim: -------------------------------------------------------------------------------- 1 | set rtp+=. 2 | 3 | let ctx = {} 4 | let configfile = expand('~/.google-buzz-vim') 5 | if filereadable(configfile) 6 | let ctx = eval(join(readfile(configfile), "")) 7 | else 8 | let ctx.consumer_key = input("consumer_key:") 9 | let ctx.consumer_secret = input("consumer_secret:") 10 | let ctx.domain = input("domain:") 11 | let ctx.callback = input("callback:") 12 | 13 | let request_token_url = "https://www.google.com/accounts/OAuthGetRequestToken" 14 | let auth_url = "https://www.google.com/accounts/OAuthAuthorizeToken" 15 | let access_token_url = "https://www.google.com/accounts/OAuthGetAccessToken" 16 | 17 | let ctx = webapi#oauth#request_token(request_token_url, ctx, {"scope": "https://www.googleapis.com/auth/buzz", "oauth_callback": ctx.callback}) 18 | if has("win32") || has("win64") 19 | exe "!start rundll32 url.dll,FileProtocolHandler ".auth_url."?oauth_token=".ctx.request_token."&domain=".ctx.domain."&scope=https://www.googleapis.com/auth/buzz" 20 | else 21 | call system("xdg-open '".auth_url."?oauth_token=".ctx.request_token. "&domain=".ctx.domain."&scope=https://www.googleapis.com/auth/buzz'") 22 | endif 23 | let verifier = input("VERIFIER:") 24 | let ctx = webapi#oauth#access_token(access_token_url, ctx, {"oauth_verifier": verifier}) 25 | call writefile([string(ctx)], configfile) 26 | endif 27 | 28 | let post_url = "https://www.googleapis.com/buzz/v1/activities/@me/@self" 29 | let data = '' 30 | \.'' 34 | \.' ' 35 | \.' http://activitystrea.ms/schema/1.0/note' 36 | \.' ばず! ばず!' 37 | \.' ' 38 | \.'' 39 | let ret = webapi#oauth#post(post_url, ctx, {}, data, {"Content-Type": "application/atom+xml", "GData-Version": "2.0"}) 40 | echo ret 41 | -------------------------------------------------------------------------------- /example/hatenadiary.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | let hatena_id = 'your-hatena-id' 4 | let password = 'your-hatena-password' 5 | 6 | " write entry 7 | let entry = atom#newEntry() 8 | call entry.setTitle("title of entry") 9 | call entry.setContentType("text/html") 10 | call entry.setContent("") 11 | 12 | " post draft 13 | let id = atom#createEntry("http://d.hatena.ne.jp/".hatena_id."/atom/draft", hatena_id, password, entry) 14 | 15 | " modify it. publish it. 16 | call entry.setContent("") 17 | let id = atom#updateEntry(id, hatena_id, password, entry, {"X-HATENA-PUBLISH": 1}) 18 | 19 | " get the entry. 20 | let entry = atom#getEntry(id, hatena_id, password) 21 | echo entry.getTitle() 22 | echo entry.getContent() 23 | 24 | " delete the entry. 25 | call atom#deleteEntry(id, hatena_id, password) 26 | 27 | " vim:set ft=vim: 28 | -------------------------------------------------------------------------------- /example/jugem.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | let jugem_id = 'your-jugem-id' 4 | let password = 'your-jugem-password' 5 | let imageName = "my-image.gif" 6 | let imagePath = "/path/to/images/my-image.gif" 7 | 8 | let api = metaWeblog#proxy("http://".jugem_id.".jugem.jp/admin/xmlrpc.php") 9 | 10 | let imgurl = api.newMediaObject(jugem_id, jugem_id, password, { 11 | \ "name": imageName, 12 | \ "path": imagePath, 13 | \}) 14 | 15 | let text = "How about this?
" 16 | 17 | echo api.newPost(jugem_id, jugem_id, password, { 18 | \ "title": "post from webpi-vim", 19 | \ "description": text, 20 | \ "dateCreated": "", 21 | \ "categories": ["test"], 22 | \}, 1) 23 | 24 | " vim:set ft=vim: 25 | -------------------------------------------------------------------------------- /example/livedoor.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | let livedoor_id = 'your-livedoor-id' 4 | let password = 'your-livedoor-password' 5 | 6 | " write entry 7 | let entry = atom#newEntry() 8 | call entry.setTitle("title of entry") 9 | call entry.setContentType("text/html") 10 | call entry.setContent("") 11 | 12 | let postUrl = "http://cms.blog.livedoor.com/atom" 13 | echo atom#createEntry(postUrl, livedoor_id, password, entry) 14 | 15 | " vim:set ft=vim: 16 | -------------------------------------------------------------------------------- /example/rss.vim: -------------------------------------------------------------------------------- 1 | for item in webapi#feed#parseURL('http://rss.slashdot.org/Slashdot/slashdot') 2 | echo item.link 3 | echo " " item.title 4 | endfor 5 | -------------------------------------------------------------------------------- /example/twitter.vim: -------------------------------------------------------------------------------- 1 | set rtp+=webapi-vim 2 | 3 | function! s:tweet(status) abort 4 | let ctx = {} 5 | let configfile = expand('~/.twitter-vim') 6 | if filereadable(configfile) 7 | let ctx = eval(join(readfile(configfile), '')) 8 | else 9 | let ctx.consumer_key = input('consumer_key:') 10 | if ctx.consumer_key == '' 11 | return 12 | endif 13 | let ctx.consumer_secret = input('consumer_secret:') 14 | if ctx.consumer_secret == '' 15 | return 16 | endif 17 | 18 | let request_token_url = 'https://api.twitter.com/oauth/request_token' 19 | let auth_url = 'https://twitter.com/oauth/authorize' 20 | let access_token_url = 'https://api.twitter.com/oauth/access_token' 21 | 22 | let ctx = webapi#oauth#request_token(request_token_url, ctx, {'oauth_callback': 'oob', 'dummy': 1}) 23 | if type(ctx) != type({}) 24 | echomsg ctx.response.content 25 | return 26 | endif 27 | if has('win32') || has('win64') 28 | exe printf('!start rundll32 url.dll,FileProtocolHandler %s?oauth_token=%s', auth_url, ctx.request_token) 29 | else 30 | call system(printf("xdg-open '%s?oauth_token=%s'", auth_url, ctx.request_token)) 31 | endif 32 | let pin = input('PIN:') 33 | let ctx = webapi#oauth#access_token(access_token_url, ctx, {'oauth_verifier': pin}) 34 | call writefile([string(ctx)], configfile) 35 | endif 36 | 37 | let post_url = 'https://api.twitter.com/1.1/statuses/update.json' 38 | let ret = webapi#oauth#post(post_url, ctx, {}, {'status': a:status}) 39 | return ret 40 | endfunction 41 | 42 | call s:tweet('tweeeeeeeeet') 43 | -------------------------------------------------------------------------------- /example/weather.vim: -------------------------------------------------------------------------------- 1 | let loc = 'Osaka' 2 | let dom = webapi#xml#parseURL(printf('http://www.google.com/ig/api?weather=%s', webapi#http#encodeURIComponent(loc))) 3 | echo loc.'''s current weather is '.dom.find('current_conditions').childNode('condition').attr['data'] 4 | -------------------------------------------------------------------------------- /webapi.vim.vimup: -------------------------------------------------------------------------------- 1 | script_name: WebAPI.vim 2 | script_id: '4019' 3 | script_type: utility 4 | script_package: webapi-vim.zip 5 | script_version: '0.3' 6 | required_vim_version: '7.0' 7 | summary: vimscript for gist 8 | 9 | detailed_description: | 10 | Interface to Web APIs 11 | 12 | webapi-vim include: 13 | 14 | * XML parser Library. 15 | * HTML parser Library. 16 | * JSON parser Library. 17 | * HTTP client. 18 | 19 | and some utility functions. 20 | 21 | install_details: | 22 | copy it to your plugin directory. 23 | 24 | versions: 25 | - '0.3': | 26 | Bug fixes. 27 | - '0.2': | 28 | Bug fixes. 29 | - '0.1': | 30 | First post. 31 | 32 | # __END__ 33 | # vim: filetype=yaml 34 | --------------------------------------------------------------------------------