diff --git a/ignore-me_perl6/LibFpdbImport.pm b/ignore-me_perl6/LibFpdbImport.pm deleted file mode 100644 index ac7db336..00000000 --- a/ignore-me_perl6/LibFpdbImport.pm +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/pugs - -#Copyright 2008 Steffen Jobbagy-Felso -#This program is free software: you can redistribute it and/or modify -#it under the terms of the GNU Affero General Public License as published by -#the Free Software Foundation, version 3 of the License. -# -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. -# -#You should have received a copy of the GNU Affero General Public License -#along with this program. If not, see . -#In the "official" distribution you can find the license in -#agpl-3.0.txt in the docs folder of the package. - -module LibFpdbImport; -use v6; -#use strict; -use LibFpdbShared; -#use LibFpdbImport2; - -class Player { - has Str $name; - has Int $start_cash; - has Card @.cards; - has Char $position; - - submethod BUILD (Str @strings) { - say "todo: implement Player.BUILD"; - }#end Player.BUILD - - our Player method find_players(@strings) { - #todo: i think this should be sub since its a class method not an instance method - say "todo: implement Player.find_players"; - } -}#end class Player - -class Line { - has Str $line; - has Bool $processed; - - our protected submethod BUILD() { - say "todo: implement Line.BUILD?" - }#end Line.BUILD - - our Line method recognise_and_parse(@strings) { - #todo: i think this should be sub since its a class method not an instance method - say "todo: implement Line.recognise_and_parse"; - }#end Line.recognise_and_parse -}#end class Line - -class ActionLine is Line { - has Player $player; - has Str $type; - has Int $amount; - has Bool $all_in; - has Int $action_no; -}#end class ActionLine - -class WinLine is Line { - has Player $player; - has Int $amount; -}#end class WinLine - -class RakeLine is Line { - has Int $amount; -}#end class RakeLine - -class CardLine is Line { - has Bool $board_line; - has Player $player; - has Card @cards; -}#end class CardLine - -#for useless lines -class CrapLine is Line { - has Str $type; -}#end class CrapLine - -class Hand { - has Line @.lines; - #has Str @strings; - has Site $site; - has Str $currency; - - has Str $type; - has Str $category; - has Str $limit_type;#todo: above ; missing causes error, but that doesnt list ; as a possibility - has Player @.players; - has Card @.board; - has Int $db_id; - - submethod BUILD(Str @strings) { - Util.debug("running Hand.BUILD"); - say "strings:",@strings; - #this contructor automatically parses the hand. call .store for storing - - @.players=Player.find_players(@strings); - @.lines=Line.recognise_and_parse(@strings); - - for @strings -> $line { - if class_of(line)==CardLine { - if line.board { - board=line.cards; - } else { - for player in players { - if line.player==player { - player.cards=line.cards; - } - } - } - } - } - }#end Hand.BUILD - - our Bool method is_holdem(){ - if category==("holdem"|"omahahi"|"omahahilo") { - return True; - } else { - return False; - } - }#end Hand.is_holdem - - our Bool method is_stud(){ - return not is_holdem(); - }#end Hand.is_stud - - our Bool method store($db) { - say "todo: Hand.store"; - }#end Hand.store -}#end class Hand - -class Importer { -#todo: be Thread? - submethod BUILD (Database $db, Str $filename) { - Util.debug("running Importer.BUILD"); - if (not ($db.is_connected())) { - Util.fatal("not connected to DB"); - } - - my IO $?filehandle=$filename; - #for =$filehandle -> $line {say $line} - my Str @lines =$filehandle; - - my Int $hand_start=0; - my Int $hand_end=0; - my Int $loopcount=0; - loop {#one loop of this per hand - $loopcount++; - say "loopcount", $loopcount; - my Int $current_line_index=$hand_end+1; #previous hand end is new hand start - for (my Int $i, $i<5, $i++) {#remove blank hands - if (@lines[$current_line_index].bytes) < 6 { - $current_line_index++; - } else { - $hand_start=$current_line_index; - break; - } - } - my Bool $continue=True; #todo: this is dumb, find out correct loop - while $continue {#loop through the lines to find end of hand - $current_line_index++; - if (@lines[$current_line_index].bytes) < 6 { - $hand_end=$current_line_index; - $continue=False; - } - }#end of find end of hand loop - my Str @handlines=@lines[$hand_start..$hand_end]; - my Hand $hand .= new(:lines(@handlines)); - $hand.store($db); - say "todo: record \$db_id"; - say "todo: terminate on EOF"; - } - }#end new Importer -}#end class Importer - diff --git a/ignore-me_perl6/LibFpdbShared.pm b/ignore-me_perl6/LibFpdbShared.pm deleted file mode 100644 index abf2eb69..00000000 --- a/ignore-me_perl6/LibFpdbShared.pm +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/pugs - -#Copyright 2008 Steffen Jobbagy-Felso -#This program is free software: you can redistribute it and/or modify -#it under the terms of the GNU Affero General Public License as published by -#the Free Software Foundation, version 3 of the License. -# -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. -# -#You should have received a copy of the GNU Affero General Public License -#along with this program. If not, see . -#In the "official" distribution you can find the license in -#agpl-3.0.txt in the docs folder of the package. - -module LibFpdbShared; -use v6; -#use strict; - -class Util { - method debug(Str $string) { - #todo: i think this should be sub since its a class method not an instance method - say "debug notice: ", $string; - }#end debug_msg - - sub warn(Str $string) { - say "todo: Util.warning"; - }#end warning - - sub fatal(Str $string, Database $db) { - say "todo: Util.fatal_error"; - }#end fatal_error -}#end class Util - -class Database { - has Str $backend; - has Str $host; - has Str $name; - has Str $user; - my Str $password; - submethod BUILD (Str $!backend, Str $!host, Str $!name, Str $!user, Str $!password) { - Util.debug("running Database.BUILD"); - self.connect(); - }#end new Database - - our method connect() { - say "todo: db.connect"; - }#end connect - - method disconnect() { - say "todo: db.disconnect"; - }#end disconnect - - method cancel_import() { - say "todo: db.cancel_import"; - }#end cancel_import - - my method drop_tables() { - #todo: make this one private - say "todo: db.drop_tables"; - }#end drop_tables - - method recreate_tables() { - say "todo: db.recreate_tables"; - }#end recreate_tables - - #returns the id of the insert - our Int method insert(Str $sql_command) { - #todo: is it a bug that i need the "our" above? - say "todo: db.insert"; - return 0; - }#end insert - - our Str method fetch(Str $sql_command) { - say "todo: db.fetch"; - }#end fetch - - our Bool method is_connected() { - say "todo: db.is_connected"; - }#end -}#end class Database - diff --git a/ignore-me_perl6/LibFpdbView.pm b/ignore-me_perl6/LibFpdbView.pm deleted file mode 100644 index e4f994d1..00000000 --- a/ignore-me_perl6/LibFpdbView.pm +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/pugs - -#Copyright 2008 Steffen Jobbagy-Felso -#This program is free software: you can redistribute it and/or modify -#it under the terms of the GNU Affero General Public License as published by -#the Free Software Foundation, version 3 of the License. -# -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. -# -#You should have received a copy of the GNU Affero General Public License -#along with this program. If not, see . -#In the "official" distribution you can find the license in -#agpl-3.0.txt in the docs folder of the package. - diff --git a/ignore-me_perl6/RunFpdbCLI.perl6 b/ignore-me_perl6/RunFpdbCLI.perl6 deleted file mode 100644 index dbbad9a7..00000000 --- a/ignore-me_perl6/RunFpdbCLI.perl6 +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/pugs - -#Copyright 2008 Steffen Jobbagy-Felso -#This program is free software: you can redistribute it and/or modify -#it under the terms of the GNU Affero General Public License as published by -#the Free Software Foundation, version 3 of the License. -# -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. -# -#You should have received a copy of the GNU Affero General Public License -#along with this program. If not, see . -#In the "official" distribution you can find the license in -#agpl-3.0.txt in the docs folder of the package. - -use v6; -#use strict; -use LibFpdbImport; -use LibFpdbShared; - - -my Database $db .= new(:backend, :host, :database, :user, :password); -#todo: below doesnt work -my Importer $imp .= new(:db($db), :filename); -#perlbug?: adding another named argument that isnt listed in the constructor gave very weird error. -say $imp; - diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 06d4f5d8..1d93f3f1 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -485,6 +485,9 @@ class Config: try: db['db-server'] = self.supported_databases[name].db_server except: pass + try: db['db-type'] = self.supported_databases[name].db_type + except: pass + if string.lower(self.supported_databases[name].db_server) == 'mysql': db['db-backend'] = 2 elif string.lower(self.supported_databases[name].db_server) == 'postgresql': diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index ca4e5996..76052d54 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -27,6 +27,7 @@ Create and manage the database objects. import sys import traceback from datetime import datetime, date, time, timedelta +import string # pyGTK modules @@ -37,15 +38,21 @@ import Card class Database: def __init__(self, c, db_name, game): - if c.supported_databases[db_name].db_server == 'postgresql': - # psycopg2 database module for posgres via DB-API - import psycopg2 + db_params = c.get_db_parameters() + if (string.lower(db_params['db-server']) == 'postgresql' or + string.lower(db_params['db-server']) == 'postgres'): + import psycopg2 # posgres via DB-API + import psycopg2.extensions + psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) try: - self.connection = psycopg2.connect(host = c.supported_databases[db_name].db_ip, - user = c.supported_databases[db_name].db_user, - password = c.supported_databases[db_name].db_pass, - database = c.supported_databases[db_name].db_name) + if db_params['db-host'] == 'localhost' or db_params['db-host'] == '127.0.0.1': + self.connection = psycopg2.connect(database = db_params['db-databaseName']) + else: + self.connection = psycopg2.connect(host = db_params['db-host'], + user = db_params['db-user'], + password = db_params['db-password'], + database = db_params['db-databaseName']) except: print "Error opening database connection %s. See error log file." % (file) traceback.print_exc(file=sys.stderr) @@ -53,14 +60,13 @@ class Database: sys.stdin.readline() sys.exit() - elif c.supported_databases[db_name].db_server == 'mysql': - # mysql bindings - import MySQLdb + elif string.lower(db_params['db-server']) == 'mysql': + import MySQLdb # mysql bindings try: - self.connection = MySQLdb.connect(host = c.supported_databases[db_name].db_ip, - user = c.supported_databases[db_name].db_user, - passwd = c.supported_databases[db_name].db_pass, - db = c.supported_databases[db_name].db_name) + self.connection = MySQLdb.connect(host = db_params['db-host'], + user = db_params['db-user'], + passwd = db_params['db-password'], + db = db_params['db-databaseName']) cur_iso = self.connection.cursor() cur_iso.execute('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED') cur_iso.close() @@ -78,11 +84,10 @@ class Database: print "press enter to continue" sys.exit() - self.db_server = c.supported_databases[db_name].db_server - self.type = c.supported_databases[db_name].db_type - self.sql = SQL.Sql(game = game, type = self.type, db_server = self.db_server) + self.type = db_params['db-type'] + self.sql = SQL.Sql(game = game, type = self.type) self.connection.rollback() - + # To add to config: self.hud_style = 'T' # A=All-time # S=Session @@ -193,20 +198,20 @@ class Database: # cards += "xx" # else: # cards += ranks[d['card' + str(i) + 'Value']] + d['card' +str(i) + 'Suit'] - cv = "card%dValue" % i + cv = "card%dvalue" % i if cv not in d or d[cv] == None: break elif d[cv] == 0: cards += "xx" else: - cs = "card%dSuit" % i + cs = "card%dsuit" % i cards = "%s%s%s" % (cards, ranks[d[cv]], d[cs]) return cards def get_action_from_hand(self, hand_no): action = [ [], [], [], [], [] ] c = self.connection.cursor() - c.execute(self.sql.query['get_action_from_hand'], (hand_no)) + c.execute(self.sql.query['get_action_from_hand'], (hand_no, )) for row in c.fetchall(): street = row[0] act = row[1:] @@ -217,7 +222,7 @@ class Database: """Returns a hash of winners:amount won, given a hand number.""" winners = {} c = self.connection.cursor() - c.execute(self.sql.query['get_winners_from_hand'], (hand)) + c.execute(self.sql.query['get_winners_from_hand'], (hand, )) for row in c.fetchall(): winners[row[0]] = row[1] return winners @@ -299,7 +304,6 @@ class Database: return stat_dict def get_player_id(self, config, site, player_name): - print "site = %s, player name = %s" % (site, player_name) c = self.connection.cursor() c.execute(self.sql.query['get_player_id'], {'player': player_name, 'site': site}) row = c.fetchone() @@ -329,12 +333,13 @@ if __name__=="__main__": for p in stat_dict.keys(): print p, " ", stat_dict[p] - #print "nutOmatics stats:" - #stat_dict = db_connection.get_stats_from_hand(h, hero) - #for p in stat_dict.keys(): - # print p, " ", stat_dict[p] +# print "nutOmatics stats:" +# stat_dict = db_connection.get_stats_from_hand(h, hero) +# for p in stat_dict.keys(): +# print p, " ", stat_dict[p] +>>>>>>> 7ef6a533ec6c73d5815ace42168067a6f8c26e3a:pyfpdb/Database.py - print "cards =", db_connection.get_cards(73525) + print "cards =", db_connection.get_cards(u'1') db_connection.close_connection print "press enter to continue" diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 5d34e409..64cafaf8 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -148,7 +148,6 @@ class HUD_main(object): if new_hand_id == "": # blank line means quit self.destroy() break # this thread is not always killed immediately with gtk.main_quit() - # get basic info about the new hand from the db # if there is a db error, complain, skip hand, and proceed try: diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 9bad1918..a36f812d 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -543,11 +543,16 @@ class Sql: self.query['get_common_cards'] = """ select - card1Value, card1Suit, - card2Value, card2Suit, - card3Value, card3Suit, - card4Value, card4Suit, - card5Value, card5Suit + card1Value AS card1value, + card1Suit AS card1suit, + card2Value AS card2value, + card2Suit AS card2suit, + card3Value AS card3value, + card3Suit AS card3suit, + card4Value AS card4value, + card4Suit AS card4suit, + card5Value AS card5value, + card5Suit AS card5suit from BoardCards where handId = %s """ diff --git a/pyfpdb/Stats.py b/pyfpdb/Stats.py old mode 100644 new mode 100755 diff --git a/pyfpdb/TableWindow.py b/pyfpdb/TableWindow.py new file mode 100644 index 00000000..bf62a69c --- /dev/null +++ b/pyfpdb/TableWindow.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python +"""Discover_TableWindow.py + +Inspects the currently open windows and finds those of interest to us--that is +poker table windows from supported sites. Returns a list +of Table_Window objects representing the windows found. +""" +# Copyright 2008 - 2009, Ray E. Barker + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +######################################################################## + +# Standard Library modules +import os +import sys + +# pyGTK modules +import pygtk +import gtk +import gobject + +# FreePokerTools modules +import Configuration +#if os.name == "posix": +# import XTables +#elif os.name == "nt": +# import WinTables + +# Global used for figuring out the current game being played from the title +# The dict key is the fpdb name for the game +# The list is the names for those games used by the supported poker sites +# This is currently only used for HORSE, so it only needs to support those +# games on PokerStars and Full Tilt. +game_names = { #fpdb name Stars Name FTP Name + "holdem" : ("Hold\'em" , ), + "omahahilo" : ("Omaha H/L" , ), + "studhilo" : ("Stud H/L" , ), + "razz" : ("Razz" , ), + "studhi" : ("Stud" , "Stud Hi") + } + +# A window title might have our table name + one of theses words/ +# phrases. If it has this word in the title, it is not a table. +bad_words = ('History for table:', 'HUD:', 'Chat:') + +# Here are the custom signals we define for allowing the 'client watcher' +# thread to communicate with the gui thread. Any time a poker client is +# is moved, resized, or closed on of these signals is emitted to the +# HUD main window. +gobject.signal_new("client_moved", gtk.Window, + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,)) + +gobject.signal_new("client_resized", gtk.Window, + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,)) + +gobject.signal_new("client_destroyed", gtk.Window, + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,)) + +# Each TableWindow object must have the following attributes correctly populated: +# tw.name = the table name from the title bar, which must to match the table name +# from the corresponding hand history. +# tw.site = the site name, e.g. PokerStars, FullTilt. This must match the site +# name specified in the config file. +# tw.number = This is the system id number for the client table window in the +# format that the system presents it. This is Xid in Xwindows and +# hwnd in Microsoft Windows. +# tw.title = The full title from the window title bar. +# tw.width, tw.height = The width and height of the window in pixels. This is +# the internal width and height, not including the title bar and +# window borders. +# tw.x, tw.y = The x, y (horizontal, vertical) location of the window relative +# to the top left of the display screen. This also does not include the +# title bar and window borders. To put it another way, this is the +# screen location of (0, 0) in the working window. + +class Table_Window(object): + def __init__(self, table_name = None, tournament = None, table_number = None): + + if table_name != None: + search_string = table_name + self.name = table_name + self.tournament = None + self.table = None + elif tournament != None and table_number != None: + print "tournament %s, table %s" % (tournament, table_number) + self.tournament = int(tournament) + self.table = int(table_number) + self.name = "%s - %s" % (self.tournament, self.table) + search_string = "%s.+Table\s%s" % (tournament, table_number) + else: + return None + + self.find_table_parameters(search_string) + + def __str__(self): +# __str__ method for testing + temp = 'TableWindow object\n' + temp = temp + " name = %s\n site = %s\n number = %s\n title = %s\n" % (self.name, self.site, self.number, self.title) +# temp = temp + " game = %s\n structure = %s\n max = %s\n" % (self.game, self.structure, self.max) + temp = temp + " width = %d\n height = %d\n x = %d\n y = %d\n" % (self.width, self.height, self.x, self.y) + if getattr(self, 'tournament', 0): + temp = temp + " tournament = %d\n table = %d" % (self.tournament, self.table) + return temp + + def get_game(self): + title = self.get_window_title() + print title + for game, names in game_names.iteritems(): + for name in names: + if name in title: + return game + return None + + def check_geometry(self): + new_geo = self.get_geometry() + + if new_geo == None: # window destroyed + return "client_destroyed" + + elif self.x != new_geo['x'] or self.y != new_geo['y']: # window moved + self.x = new_geo['x'] + self.y = new_geo['y'] + return "client_moved" + + elif self.width != new_geo['width'] or self.height != new_geo['height']: # window resized + self.width = new_geo['width'] + self.height = new_geo['height'] + return "client_resized" + + else: return False # window not changed + + def check_bad_words(self, title): + for word in bad_words: + if word in title: return True + return False \ No newline at end of file diff --git a/pyfpdb/Tables_Demo.py b/pyfpdb/Tables_Demo.py new file mode 100644 index 00000000..ffc8d412 --- /dev/null +++ b/pyfpdb/Tables_Demo.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +"""Tables_Demo.py + +Main program module to test/demo the Tables subclasses. +""" +# Copyright 2008 - 2009, Ray E. Barker + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +######################################################################## + +# Standard Library modules +import sys +import os +import re + +# pyGTK modules +import pygtk +import gtk +import gobject + +# fpdb/free poker tools modules +# get the correct module for the current os +if os.name == 'posix': + import XTables as Tables +elif os.name == 'nt': + import WinTables as Tables + +# Main function used for testing +if __name__=="__main__": +# c = Configuration.Config() + + class fake_hud(object): + def __init__(self, table, dx = 100, dy = 100): + self.table = table + self.dx = dx + self.dy = dy + + self.main_window = gtk.Window() + self.main_window.connect("destroy", self.client_destroyed) + self.label = gtk.Label('Fake Fake Fake Fake\nFake\nFake\nFake') + self.main_window.add(self.label) + self.main_window.set_title("Fake HUD Main Window") + self.main_window.move(table.x + dx, table.y + dy) + self.main_window.show_all() + table.topify(self) + self.main_window.connect("client_moved", self.client_moved) + self.main_window.connect("client_resized", self.client_resized) + self.main_window.connect("client_destroyed", self.client_destroyed) + + def client_moved(self, widget, hud): + self.main_window.move(self.table.x + self.dx, self.table.y + self.dy) + + def client_resized(self, *args): + print "client resized" + + def client_destroyed(self, *args): # call back for terminating the main eventloop + gtk.main_quit() + + def check_on_table(table, hud): + result = table.check_geometry() + if result != False: + hud.main_window.emit(result, hud) + return True + + print "enter table name to find: ", + table_name = sys.stdin.readline() + if "," in table_name: # tournament + print "tournament" + (tour_no, tab_no) = table_name.split(",", 1) + tour_no = tour_no.rstrip() + tab_no = tab_no.rstrip() + table = Tables.Table(tournament = tour_no, table_number = tab_no) + else: # not a tournament + print "cash game" + table_name = table_name.rstrip() + table = Tables.Table(table_name = table_name) + + print "table =", table + print "game =", table.get_game() + + fake = fake_hud(table) + gobject.timeout_add(100, check_on_table, table, fake) + gtk.main() + diff --git a/pyfpdb/WinTables.py b/pyfpdb/WinTables.py new file mode 100644 index 00000000..1b064eef --- /dev/null +++ b/pyfpdb/WinTables.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +"""WinTables.py + +Routines for detecting and handling poker client windows for MS Windows. +""" +# Copyright 2008 - 2009, Ray E. Barker + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +######################################################################## + +# Standard Library modules +import re + +# pyGTK modules +import pygtk +import gtk + +# Other Library modules +import win32gui +import win32process +import win32api +import win32con +import win32security + +# FreePokerTools modules +from TableWindow import Table_Window + +# We don't know the border width or title bar height +# so we guess here. We can probably get these from a windows call. +b_width = 3 +tb_height = 29 + +class Table(Table_Window): + + def find_table_parameters(self, search_string): + """Finds poker client window with the given table name.""" + titles = {} + win32gui.EnumWindows(win_enum_handler, titles) + for hwnd in titles: + if re.search(search_string, titles[hwnd]): + if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window + if 'HUD:' in titles[hwnd]: continue # FPDB HUD window + if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows + self.window = hwnd + break + + if self.window == None: + print "Window %s not found. Skipping." % search_string + return None + + (x, y, width, height) = win32gui.GetWindowRect(hwnd) + print "x = %s y = %s width = %s height = %s" % (x, y, width, height) + self.x = int(x) + b_width + self.y = int(y) + tb_height + self.height = int(height) - b_width - tb_height + self.width = int(width) - 2*b_width + + self.exe = self.get_nt_exe(hwnd) + self.title = titles[hwnd] + self.site = "" + self.hud = None + self.number = gtk.gdk.window_foreign_new(long(self.window)) + + def get_geometry(self): + + if not win32gui.IsWindow(self.window): # window closed + return None + + try: + (x, y, width, height) = win32gui.GetWindowRect(hwnd) + return {'x' : int(x) + b_width, + 'y' : int(y) + tb_height, + 'width' : int(height) - b_width - tb_height, + 'height' : int(width) - 2*b_width + } + except: + return None + + def get_window_title(self): + return win32gui.GetWindowText(self.window) + + def get_nt_exe(self, hwnd): + """Finds the name of the executable that the given window handle belongs to.""" + + # Request privileges to enable "debug process", so we can later use PROCESS_VM_READ, retardedly required to GetModuleFileNameEx() + priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY + hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), priv_flags) + # enable "debug process" + privilege_id = win32security.LookupPrivilegeValue (None, win32security.SE_DEBUG_NAME) + old_privs = win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)]) + + # Open the process, and query it's filename + processid = win32process.GetWindowThreadProcessId(hwnd) + pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, processid[1]) + exename = win32process.GetModuleFileNameEx(pshandle, 0) + + # clean up + win32api.CloseHandle(pshandle) + win32api.CloseHandle(hToken) + + return exename +def win_enum_handler(hwnd, titles): + titles[hwnd] = win32gui.GetWindowText(hwnd) + +def topify_window(hud, window): + """Set the specified gtk window to stayontop in MS Windows.""" + + def windowEnumerationHandler(hwnd, resultList): + '''Callback for win32gui.EnumWindows() to generate list of window handles.''' + resultList.append((hwnd, win32gui.GetWindowText(hwnd))) + + unique_name = 'unique name for finding this window' + real_name = window.get_title() + window.set_title(unique_name) + tl_windows = [] + win32gui.EnumWindows(windowEnumerationHandler, tl_windows) + + for w in tl_windows: + if w[1] == unique_name: + hud.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(hud.table.number)) + hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) + hud.main_window.gdkhandle.set_transient_for(hud.main_window.parentgdkhandle) + + style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) + style |= win32con.WS_CLIPCHILDREN + win32gui.SetWindowLong(hud.table.number, win32con.GWL_EXSTYLE, style) + break + + window.set_title(real_name) + diff --git a/pyfpdb/XTables.py b/pyfpdb/XTables.py new file mode 100644 index 00000000..1e692209 --- /dev/null +++ b/pyfpdb/XTables.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python +"""Discover_Tables.py + +Inspects the currently open windows and finds those of interest to us--that is +poker table windows from supported sites. Returns a list +of Table_Window objects representing the windows found. +""" +# Copyright 2008 - 2009, Ray E. Barker + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +######################################################################## + +# Standard Library modules +import re + +# pyGTK modules +import pygtk +import gtk + +# Other Library modules +import Xlib +import Xlib.display + +# FreePokerTools modules +from TableWindow import Table_Window + +# We might as well do this once and make them globals +disp = Xlib.display.Display() +root = disp.screen().root + +class Table(Table_Window): + + def find_table_parameters(self, search_string): + self.window = None + done_looping = False + for outside in root.query_tree().children: + for inside in outside.query_tree().children: + if done_looping: break + if inside.get_wm_name() and re.search(search_string, inside.get_wm_name()): + if self.check_bad_words(inside.get_wm_name()): continue + self.window = inside + self.parent = outside + done_looping = True + break + + if self.window == None or self.parent == None: + print "Window %s not found. Skipping." % search_string + return None + + my_geo = self.window.get_geometry() + pa_geo = self.parent.get_geometry() + + self.x = pa_geo.x + my_geo.x + self.y = pa_geo.y + my_geo.y + self.width = my_geo.width + self.height = my_geo.height + self.exe = self.window.get_wm_class()[0] + self.title = self.window.get_wm_name() + self.site = "" + self.hud = None + + window_string = str(self.window) + mo = re.match('Xlib\.display\.Window\(([\dxabcdef]+)', window_string) + if not mo: + print "Not matched" + self.gdk_handle = None + else: + self.number = int( mo.group(1), 0) + self.gdk_handle = gtk.gdk.window_foreign_new(int(self.number)) + + def get_geometry(self): + try: + my_geo = self.window.get_geometry() + pa_geo = self.parent.get_geometry() + return {'x' : pa_geo.x + my_geo.x, + 'y' : pa_geo.y + my_geo.y, + 'width' : my_geo.width, + 'height' : my_geo.height + } + except: + return None + + def get_window_title(self): + return self.window.get_wm_name() + + def topify(self, hud): + hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(hud.main_window.window.xid) + hud.main_window.gdkhandle.set_transient_for(self.gdk_handle) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 583ecfc8..e0ccd813 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -172,27 +172,20 @@ class fpdb_db: raise fpdb_simple.FpdbError("MySQL connection failed") elif backend==self.PGSQL: import psycopg2 - import psycopg2.extensions + import psycopg2.extensions psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) # If DB connection is made over TCP, then the variables # host, user and password are required - # print "host=%s user=%s pass=%s." % (host, user, password) - if self.host and self.user and self.password: - try: - self.db = psycopg2.connect(host = host, - user = user, - password = password, - database = database) - except: - raise fpdb_simple.FpdbError("PostgreSQL connection failed") # For local domain-socket connections, only DB name is # needed, and everything else is in fact undefined and/or # flat out wrong + if self.host == "localhost" or self.host == "127.0.0.1": + self.db = psycopg2.connect(database = database) else: - try: - self.db = psycopg2.connect(database = database) - except: - raise fpdb_simple.FpdbError("PostgreSQL connection failed") + self.db = psycopg2.connect(host = host, + user = user, + password = password, + database = database) else: raise fpdb_simple.FpdbError("unrecognised database backend:"+backend) self.cursor=self.db.cursor() diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index cffe8598..9b779574 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -44,6 +44,9 @@ except: try: import psycopg2 pgsqlLibFound=True + import psycopg2.extensions + psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) + except: pass diff --git a/pyfpdb/fpdb_save_to_db.py b/pyfpdb/fpdb_save_to_db.py index 0dbcbf61..3c99d084 100644 --- a/pyfpdb/fpdb_save_to_db.py +++ b/pyfpdb/fpdb_save_to_db.py @@ -26,13 +26,14 @@ MYSQL_INNODB = 2 PGSQL = 3 SQLITE = 4 -fastStoreHudCache = False # set this to True to test the new storeHudCache routine +#fastStoreHudCache = False # set this to True to test the new storeHudCache routine +# +#saveActions = True # set this to False to avoid storing action data +# # Pros: speeds up imports +# # Cons: no action data is saved, so you need to keep the hand histories +# # variance not available on stats page +# # no graphs -saveActions = True # set this to False to avoid storing action data - # Pros: speeds up imports - # Cons: no action data is saved, so you need to keep the hand histories - # variance not available on stats page - # : No graphs #stores a stud/razz hand into the database def ring_stud(config, backend, db, cursor, base, category, site_hand_no, gametype_id, hand_start_time ,names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes diff --git a/utils/create-release.sh b/utils/create-release.sh index 21696c1a..0b720157 100755 --- a/utils/create-release.sh +++ b/utils/create-release.sh @@ -1,6 +1,7 @@ #!/bin/sh #Copyright 2008 Steffen Jobbagy-Felso +#Copyright 2009 Ray E. Barker #This program is free software: you can redistribute it and/or modify #it under the terms of the GNU Affero General Public License as published by #the Free Software Foundation, version 3 of the License. @@ -15,10 +16,22 @@ #In the "official" distribution you can find the license in #agpl-3.0.txt in the docs folder of the package. +# This script prepares the compressed distribution files for +# uploading to sourceforge. +# +# Run from the root of your git repo (the folder that has .git in it) + +# USAGE: $ utils/create-release.sh V +# where V is the current version. e.g. utils/create-release.sh 0.55 + #get rid of extraneous stuff rm regression-test/*.found.txt rm regression-test/*.pyc rm pyfpdb/*.pyc +rm pyfpdb/*~ +rm pyfpdb/fpdb-error-log.txt +rm pyfpdb/HUD-error.txt +rm pyfpdb/hand-errors.txt # make the fpdb_$1.zip file for windows echo "*** making zip file"