Revision 104 (by alan, 2007/06/23 09:01:18) Ability to submit request from macro.
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - WhoisLookup Action

    PURPOSE:
        This action is used to perform Whois lookups from within the Wiki.

    MODIFICATION HISTORY:
        @copyright: 2007 by Alan Snelson (Alan@Wave2.org)
        @license: GNU GPL, see COPYING for details.
        Version: 0.1

        0.1 Initial concept based on http://sourceforge.net/projects/rwhois/

"""
import re, socket, string, sys
from MoinMoin import wikiutil
from MoinMoin.Page import Page
from MoinMoin.PageEditor import PageEditor
from MoinMoin.formatter.text_html import Formatter
from MoinMoin.action import ActionBase

class WhoisLookup(ActionBase):
    """ Whois Lookup action

    Note: the action name is the class name
    """

    def __init__(self, pagename, request):
        ActionBase.__init__(self, pagename, request)
        self.use_ticket = False
        _ = self._
        self.form_trigger = 'domaininame'
        self.form_trigger_label = _('Whois Lookup')

    def do_action(self):
        _ = self._
        form = self.form
        domainname = form.get('domain', [u''])[0]

        defaultserver='whois.verisign-grs.net'#'whois.networksolutions.com'
        whoiscommand=""
        whoismap={
        'org' : 'whois.pir.org' , \
        'edu' : 'whois.networksolutions.com' , \
        'biz' : 'whois.biz' , \
        'info': 'whois.afilias.info' , \
        'eu': 'whois.eu' , \
        'mobi': 'whois.dotmobiregistry.net' , \
        'us'  : 'whois.nic.us', \
        'de'  : 'whois.denic.de' , \
        'gov' : 'whois.nic.gov' , \
        'name': 'whois.nic.name' , \
        'pro': 'whois.nic.name' , \
        'museum': 'whois.museum' , \
        'int':  'whois.iana.org' , \
        'aero': 'whois.information.aero' , \
        'coop': 'whois.nic.coop' , \
        # See http://www.nic.gov/cgi-bin/whois 
        'mil' : 'whois.nic.mil' , \
        # See http://www.nic.mil/cgi-bin/whois
        'ca'  : 'whois.cdnnet.ca' , \
        'uk'  : 'whois.nic.uk' , \
        'au'  : 'whois.aunic.net' , \
        'hu'  : 'whois.nic.hu' , \
         # All the following are unverified/checked. 
        'be'  : 'whois.ripe.net',
        'it'  : 'whois.ripe.net' , \
        # also whois.nic.it
        'at'  : 'whois.ripe.net' , \
        # also www.nic.at, whois.aco.net
        'dk'  : 'whois.ripe.net' , \
        'fo'  : 'whois.ripe.net' , \
        'lt'  : 'whois.ripe.net' , \
        'no'  : 'whois.ripe.net' , \
        'sj'  : 'whois.ripe.net' , \
        'sk'  : 'whois.ripe.net' , \
        'tr'  : 'whois.ripe.net' , \
        # also whois.metu.edu.tr
        'il'  : 'whois.ripe.net' , \
        'bv'  : 'whois.ripe.net' , \
        'se'  : 'whois.nic-se.se' , \
        'br'  : 'whois.nic.br' , \
        'fr'  : 'whois.nic.fr' , \
        'sg'  : 'whois.nic.net.sg' , \
        'hm'  : 'whois.registry.hm' , \
        # see also whois.nic.hm
        'nz'  : 'domainz.waikato.ac.nz' , \
        'nl'  : 'whois.domain-registry.nl' , \
        # RIPE also handles other countries
        # See  http://www.ripe.net/info/ncc/rir-areas.html
        'ru'  : 'whois.ripn.net' , \
        'ch'  : 'whois.nic.ch' , \
        # see http://www.nic.ch/whois_readme.html
        'jp'  : 'whois.nic.ad.jp' , \
        'to'  : 'whois.tonic.to' , \
        'nu'  : 'whois.nic.nu' , \
        'fm'  : 'www.dot.fm' , \
        # http request http://www.dot.fm/search.html
        'am'  : 'whois.nic.am' , \
        'nu'  : 'www.nunames.nu' , \
        'af'  : 'whois.nic.af' , \
        'as'  : 'whois.nic.as' , \
        'li'  : 'whois.nic.li' , \
        'lk'  : 'whois.nic.lk' , \
        'mx'  : 'whois.nic.mx' , \
        'pw'  : 'whois.nic.pw' , \
        'sh'  : 'whois.nic.sh' , \
        # consistently resets connection
        'tj'  : 'whois.nic.tj' , \
        'tm'  : 'whois.nic.tm' , \
        'pt'  : 'whois.dns.pt' , \
        'kr'  : 'whois.nic.or.kr' , \
        # see also whois.krnic.net
        'kz'  : 'whois.nic.or.kr' , \
        # see also whois.krnic.net
        'al'  : 'whois.ripe.net' , \
        'az'  : 'whois.ripe.net' , \
        'ba'  : 'whois.ripe.net' , \
        'bg'  : 'whois.ripe.net' , \
        'by'  : 'whois.ripe.net' , \
        'cy'  : 'whois.ripe.net' , \
        'cz'  : 'whois.ripe.net' , \
        'dz'  : 'whois.ripe.net' , \
        'ee'  : 'whois.ripe.net' , \
        'eg'  : 'whois.ripe.net' , \
        'es'  : 'whois.ripe.net' , \
        'fi'  : 'whois.ripe.net' , \
        'gr'  : 'whois.ripe.net' , \
        'hr'  : 'whois.ripe.net' , \
        'lu'  : 'whois.ripe.net' , \
        'lv'  : 'whois.ripe.net' , \
        'ma'  : 'whois.ripe.net' , \
        'md'  : 'whois.ripe.net' , \
        'mk'  : 'whois.ripe.net' , \
        'mt'  : 'whois.ripe.net' , \
        'pl'  : 'whois.ripe.net' , \
        'ro'  : 'whois.ripe.net' , \
        'si'  : 'whois.ripe.net' , \
        'sm'  : 'whois.ripe.net' , \
        'su'  : 'whois.ripe.net' , \
        'tn'  : 'whois.ripe.net' , \
        'ua'  : 'whois.ripe.net' , \
        'va'  : 'whois.ripe.net' , \
        'yu'  : 'whois.ripe.net' , \
        'ac'  : 'whois.nic.ac' , \
        'cc'  : 'whois.nic.cc' , \
        'gs'  : 'whois.adamsnames.tc' , \
        'hk'  : 'whois.apnic.net' , \
        'ms'  : 'whois.adamsnames.tc' , \
        'my'  : 'whois.mynic.net' , \
        'st'  : 'whois.nic.st' , \
        'tc'  : 'whois.adamsnames.tc' , \
        'tf'  : 'whois.adamsnames.tc' , \
        'th'  : 'whois.thnic.net' , \
        'tw'  : 'whois.twnic.net' , \
        'us'  : 'whois.isi.edu' , \
        'vg'  : 'whois.adamsnames.tc' , \
        }

        defaultipwhois='whois.arin.net'
        ipwhoismap={
        41 : 'whois.afrinic.net' , \
        58 : 'whois.apnic.net' , \
        59 : 'whois.apnic.net' , \
        60 : 'whois.apnic.net' , \
        61 : 'whois.apnic.net' , \
        62 : 'whois.ripe.net' , \
        77 : 'whois.ripe.net' , \
        78 : 'whois.ripe.net' , \
        79 : 'whois.ripe.net' , \
        80 : 'whois.ripe.net' , \
        81 : 'whois.ripe.net' , \
        82 : 'whois.ripe.net' , \
        83 : 'whois.ripe.net' , \
        84 : 'whois.ripe.net' , \
        85 : 'whois.ripe.net' , \
        86 : 'whois.ripe.net' , \
        87 : 'whois.ripe.net' , \
        88 : 'whois.ripe.net' , \
        89 : 'whois.ripe.net' , \
        90 : 'whois.ripe.net' , \
        91 : 'whois.ripe.net' , \
        92 : 'whois.ripe.net' , \
        93 : 'whois.ripe.net' , \
        116 : 'whois.apnic.net' , \
        117 : 'whois.apnic.net' , \
        118 : 'whois.apnic.net' , \
        119 : 'whois.apnic.net' , \
        120 : 'whois.apnic.net' , \
        121 : 'whois.apnic.net' , \
        122 : 'whois.apnic.net' , \
        123 : 'whois.apnic.net' , \
        124 : 'whois.apnic.net' , \
        125 : 'whois.apnic.net' , \
        126 : 'whois.apnic.net' , \
        189 : 'whois.lacnic.net' , \
        190 : 'whois.lacnic.net' , \
        193 : 'whois.ripe.net' , \
        194 : 'whois.ripe.net' , \
        195 : 'whois.ripe.net' , \
        196 : 'whois.afrinic.net' , \
        200 : 'whois.lacnic.net' , \
        201 : 'whois.lacnic.net' , \
        202 : 'whois.apnic.net' , \
        203 : 'whois.apnic.net' , \
        210 : 'whois.apnic.net' , \
        211 : 'whois.apnic.net' , \
        212 : 'whois.ripe.net' , \
        213 : 'whois.ripe.net' , \
        217 : 'whois.ripe.net' , \
        218 : 'whois.apnic.net' , \
        219 : 'whois.apnic.net' , \
        220 : 'whois.apnic.net' , \
        221 : 'whois.apnic.net' , \
        222 : 'whois.apnic.net' , \
        }

        ipregex = re.compile('^(\d{1,3}\.){3}\d{1,3}$')
        if ipregex.match(domainname):
            addressblock = string.split(domainname, ".")[0]
            whoisserver = ipwhoismap.get(int(addressblock))
            if whoisserver==None:
                whoisserver=defaultipwhois
        else:
            toplevel = string.split(domainname, ".")[-1]
            whoisserver=whoismap.get(toplevel)
            if whoisserver==None:
                whoisserver=defaultserver
                whoiscommand="domain "

        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        except socket.error, e:
            print "Strange error creating socket: %s" % e

        while 1:
            try:
                s.connect((whoisserver, 43))
            except socket.error, (ecode, reason):
                if ecode==errno.EINPROGRESS:
                    continue
                elif ecode==errno.EALREADY:
                    continue
                else:
                    raise socket.error, (ecode, reason)
                    pass
            break

        s.send(whoiscommand + domainname + "\r\n")
        page = "Data downloaded from: " + whoisserver + "\n\n"
        while 1:
            data = s.recv(8196)
            if not data: break
            page = page + data
            pass
        s.close()
        return True, page

    def do_action_finish(self, success):
        if success:
            self.request.formatter = Formatter(self.request)
            self.request.http_headers()
            self.request.setContentLanguage(self.request.lang)
            wikiutil.send_title(self.request, self.pagename, pagename=self.pagename)
            self.request.write(self.request.formatter.startContent("content"))
            self.request.write(self.request.formatter.rawHTML("<pre>" + self.error + "</pre>"))
            self.request.write(self.request.formatter.endContent())
            wikiutil.send_footer(self.request, self.pagename)
        else:
            self.render_msg(self.make_form())

    def get_form_html(self, buttons_html):
        _ = self._
        d = {
            'pagename': self.pagename,
            'domain_label': _("Domain / IP"),
            'buttons_html': buttons_html,
        }
        return '''
<table>
    <tr>
        <td class="label"><label>%(domain_label)s</label></td>
        <td class="content">
            <input type="text" name="domain" maxlength="200">
        </td>
    </tr>
    <tr>
        <td></td>
        <td class="buttons">
            %(buttons_html)s
        </td>
    </tr>
</table>
''' % d

    def render(self):
        """ Render action - this is the main function called by action's
            execute() function.

            We usually render a form here, check for posted forms, etc.
        """
        _ = self._
        form = self.form

        if form.has_key(self.form_cancel):
            self.render_cancel()
            return

        # Validate allowance, user rights and other conditions.
        error = None
        if self.is_excluded():
            error = _('Action %(actionname)s is excluded in this wiki!') % {'actionname': self.actionname }
        elif not self.is_allowed():
            error = _('You are not allowed to use action %(actionname)s on thispage!') % {'actionname': self.actionname }
        if error is None:
            error = self.check_condition()
        if error:
            self.render_msg(error)
        elif form.has_key(self.form_trigger) or form.has_key('domain'): # user hit the trigger button
            if self.ticket_ok():
                success, self.error = self.do_action()
            else:
                success = False
                self.error = _('Please use the interactive user interface to use action %(actionname)s!') % {'actionname': self.actionname }
            self.do_action_finish(success)
        else:
            # Return a new form
            self.render_msg(self.make_form())

def execute(pagename, request):
    """ Glue code for actions """

    _ = request.getText
    thispage = Page(request, pagename)

    if request.user.valid:
        username = request.user.name
    else:
        username = ''

    if not username:
        return thispage.send_page(request,
            msg = _('Please log in first.'))

    WhoisLookup(pagename, request).render()