source: trollforge/dsp-trollforge/MovableType/Blogpost.py @ 212

Revision 41, 7.9 KB checked in by sam, 8 years ago (diff)
  • DSP's trollforge snapshot.
  • Property svn:executable set to *
  • Property svn:keywords set to Id
Line 
1#!/usr/bin/env python
2#
3# blogpost.py:
4#   Post a comment on any Drupal/MovableType blog entry. Also defeats stupid
5#   SCode "security" check that is so annoying when using a text browser.
6#
7# Usage:
8#   blogpost.py "story_url" "nick" "valid@email.com" "comment"
9#
10# Copyright: (c) 2004 Sam Hocevar <sam@zoy.org>
11#   This program is free software; you can redistribute it and/or
12#   modify it under the terms of the Do What The Fuck You Want To
13#   Public License as published by Banlu Kemiyatorn. See
14#   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
15#
16# Changelog:
17#   2004/12/26: first release
18#               tested on http://www.parablog.com/mt/mt-comments.cgi?entry_id=876
19#   2004/12/26: defeat captchas with uneven bottom lines
20#               tested on http://ramk.net/archives/000118.html
21#   2004/12/27: work on Drupal instead of only MovableType
22#               tested on http://james.seng.cc/archives/000145.html
23#   2004/12/27: do not send empty POST data
24#               fixes http://underscorebleach.net/content/jotsheet/2004/10/combat_mt_comment_spam_captcha
25#
26
27import gd, urllib, urllib2, sys, re, time
28
29# Debug stuff?
30debug = 1
31
32# Behave nicely, like MSIE
33user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)"
34referer = ""
35cookie = ""
36
37# Guess a glyph from its bounding box in the picture. This function is very,
38# very naive. But since mt-scode is very, very naive as well, it's more than
39# enough.
40def guess_glyph(im, xmin, xmax):
41    (w,h) = im.size()
42    # Find ymin/ymax bounding box
43    ymin = -1
44    ymax = -1
45    for y in range(h):
46        found = 0
47        for x in range(xmin, xmax):
48            p = im.getPixel((x,y))
49            if p == 1:
50                found = 1
51                break
52        if found:
53            if ymin == -1:
54                ymin = y
55            else:
56                ymax = y + 1
57    # Compute simple glyph checksum
58    values = [162, 131, 150, 139, 155, 159, 181, 90, 180, 170]
59    count = 0
60    for x in range(xmin, xmax):
61        for y in range(ymin, ymax):
62            count += im.getPixel((x,y)) * (y - ymin)
63    if count not in values:
64        return "?"
65    return values.index(count)
66
67# Remove background stuff from an scode picture
68def remove_background(im):
69    (w,h) = im.size()
70    # Stats on first 3 lines to determine background colours
71    stats = [0, 0, 0, 0]
72    fg = -1
73    bg = -1
74    for y in range(3):
75        for x in range(w):
76            p = im.getPixel((x,y))
77            if p < 4:
78                stats[p] += 1
79    for y in range(h):
80        for x in range(w):
81            p = im.getPixel((x,y))
82            if not stats[p]:
83                fg = p
84    # Unify background colours
85    for y in range(h):
86        for x in range(w):
87            p = im.getPixel((x,y))
88            if p == fg:
89                im.setPixel((x,y),1)
90            else:
91                im.setPixel((x,y),0)
92
93# Decode an scode picture from its URL
94def sdecode(url):
95    if debug:
96        print "getting", url
97    r = urllib2.Request(url)
98    r.add_header('User-Agent', user_agent)
99    r.add_header('Referer', referer)
100    if cookie != "":
101        r.add_header('Cookie', cookie)
102    f = urllib2.build_opener().open(r)
103    im = gd.image(f, "png")
104    (w,h) = im.size()
105    f.close()
106    chars = [' ', '.', ':', '@']
107    for y in range(h):
108        line = ""
109        for x in range(w):
110            p = im.getPixel((x,y))
111            line += chars[p]
112        if debug:
113            print line
114    remove_background(im)
115    # Read character cells
116    result = ""
117    incell = 0
118    for x in range(w):
119        found = 0
120        for y in range(h):
121            p = im.getPixel((x,y))
122            if p == 1:
123                found = 1
124                break
125        if found and not incell:
126            incell = 1
127            xmin = x
128        if not found and incell:
129            incell = 0
130            result += str(guess_glyph(im, xmin, x))
131    return result
132
133def mt_post(url, nick, email, comment, data):
134    global referer, cookie
135    re_base = re.compile('.*<base.*href="([^"]*)".*\n')
136    re_startform = re.compile('.*action="([^"]*comment[^"]*)".*\n')
137    re_endform = re.compile('.*</form>.*\n')
138    re_captcha = re.compile('.*src="([^"]*(scode|captcha)[^"]*)".*\n')
139    re_captchatext = re.compile('.*name="([^"]*(scode|captcha)[^"]*)".*\n')
140    re_hidden = re.compile('.*type="hidden".*name="([^"]*)".*value="([^"]*)".*\n')
141    re_submit = re.compile('.*type="submit".*name="([^"]*)".*value="([^"]*)".*\n')
142    if debug:
143        print "getting", url
144    if data:
145        r = urllib2.Request(url, urllib.urlencode(data))
146    else:
147        r = urllib2.Request(url)
148    r.add_header('User-Agent', user_agent)
149    if referer != url:
150        r.add_header('Referer', referer)
151    if cookie != "":
152        r.add_header('Cookie', cookie)
153    referer = url
154    f = urllib2.build_opener().open(r)
155    info = f.info()
156    if info.has_key('set-cookie'):
157        cookie = info['set-cookie'].split(';')[0]
158        if debug:
159            print "got cookie!"
160    else:
161        if debug:
162            print "no cookie!"
163    inform = 0
164    canpost = 0
165    base = ""
166    scode = ""
167    captchatext = "scode"
168    while True:
169        l = f.readline()
170        if not l:
171            break
172        # Detect base URL
173        m = re_base.match(l)
174        if m:
175            base = m.group(1)
176        # Detect start of form
177        m = re_startform.match(l)
178        if m:
179            target = m.group(1)
180            inform = 1
181        if not inform:
182            continue
183        # Detect end of form
184        m = re_endform.match(l)
185        if m:
186            inform = 0
187            continue
188        # Detect a captcha image
189        m = re_captcha.match(l)
190        if m:
191            captcha = base + m.group(1)
192            scode = sdecode(captcha)
193            if debug:
194                print "found captcha", captcha, "decoded to", scode
195        # Detect a captcha entry
196        m = re_captchatext.match(l)
197        if m:
198            captchatext = m.group(1)
199        # Detect a hidden input
200        m = re_hidden.match(l)
201        if m:
202            if debug:
203                print 'hidden item "' + m.group(1) + '" value "' + m.group(2) + '"'
204            data[m.group(1)] = m.group(2)
205        # Detect a submit button
206        m = re_submit.match(l)
207        if m:
208            if debug:
209                print 'submit item "' + m.group(1) + '" value "' + m.group(2) + '"'
210            if re.match(".*[pP]ost.*", m.group(1) + " " + m.group(2)):
211                canpost = 1
212            if re.match(".*[pP]review.*", m.group(1) + " " + m.group(2)):
213                preview = 1
214                if not canpost:
215                    data[m.group(1)] = m.group(2)
216                elif debug:
217                    print "ignoring because we have a post button"
218            else:
219                data[m.group(1)] = m.group(2)
220    f.close()
221    if scode != "":
222        data[captchatext] = scode
223    data['author'] = nick
224    data['edit[name]'] = nick
225    data['email'] = email
226    data['edit[mail]'] = email
227    data['homepage'] = ""
228    data['edit[homepage]'] = ""
229    data['text'] = comment
230    data['edit[comment]'] = comment
231    url = base + target
232    if not canpost:
233        mt_post(url, nick, email, comment, data)
234    else:
235        if debug:
236            print "getting", url
237        r = urllib2.Request(url, urllib.urlencode(data))
238        r.add_header('User-Agent', user_agent)
239        r.add_header('Referer', referer)
240        if cookie != "":
241            r.add_header('Cookie', cookie)
242        f = urllib2.build_opener().open(r)
243        while True:
244            l = f.readline()
245            if not l:
246                break
247            #sys.stdout.write(l)
248        f.close()
249
250mt_post(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], {})
Note: See TracBrowser for help on using the repository browser.