#!/usr/bin/python -O # # Description: # ------------ # This is the client-side portion of the Trusted User package # manager. The TUs will use this program to upload packages into # the AUR. For more information, see the ../README.txt file. # # Python Indentation: # ------------------- # For a vim: line to be effective, it must be at the end of the # file. See the end of the file for more information. # import sys import socket import os import struct import os.path import cgi import urllib import md5 import getopt import ConfigParser class ClientFile: def __init__(self, pathname): self.pathname = pathname self.filename = os.path.basename(pathname) self.fd = open(pathname, "rb") self.fd.seek(0, 2) self.size = self.fd.tell() self.fd.seek(0) self.makeMd5() def makeMd5(self): md5sum = md5.new() while self.fd.tell() != self.size: md5sum.update(self.fd.read(1024)) self.md5 = md5sum.hexdigest() class ClientSocket: def __init__(self, files, host, port, username, password): self.files = files self.host = host self.port = port self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.username = username self.password = password def connect(self): self.socket.connect((self.host, self.port)) def reliableRead(self, size): totalread = "" while len(totalread) < size: read = self.socket.recv(size-len(totalread)) if read == 0: raise RuntimeError, "socket connection broken" totalread += read return totalread def sendMsg(self, msg): if type(msg) == dict: msg = urllib.urlencode(msg,1) length = struct.pack("H", socket.htons(len(msg))) self.socket.sendall(length) self.socket.sendall(msg) def readMsg(self, format=0): initsize = self.reliableRead(2) (length,) = struct.unpack("H", initsize) length = socket.ntohs(length) data = self.reliableRead(length) if format == 1: qs = cgi.parse_qs(data) return qs else: return data def close(self): self.socket.close() def auth(self): msg = {'username': self.username, 'password': self.password} self.sendMsg(msg) reply = self.readMsg(1) if reply['result'] == ["PASS"]: return 1 elif reply['result'] == ["SQLERR"]: print "SQL server-side error" return 0 else: return 0 def sendFileMeta(self): msg = {'numpkgs': len(self.files)} for i, v in enumerate(self.files): msg['name'+str(i)] = v.filename msg['size'+str(i)] = v.size msg['md5sum'+str(i)] = v.md5 self.sendMsg(msg) reply = self.readMsg(1) print reply for i in reply: if i[:4] == 'size': self.files[int(i[4:])].cur_done = int(reply[i][0]) def sendFiles(self): for i in self.files: i.fd.seek(i.cur_done) print "Uploading:", i.filename, str(i.size/1024), "kb" sdone = 0 while i.fd.tell() < i.size: sdone+=1 self.socket.sendall(i.fd.read(1024)) if sdone % 100 == 0: print "\r", print str(sdone), "of", str(i.size/1024), "kb", sys.stdout.flush() reply = self.readMsg(1) print reply self.sendMsg("ack") def usage(): print "usage: tupkg [options] " print "options:" print " -u, --user Connect with username" print " -P, --password Connect with password" print " -h, --host Connect to host" print " -p, --port Connect to host on port (default 1034)" print "May also use conf file: ~/.tupkg" def main(argv=None): if argv is None: argv = sys.argv confdict = {} conffile = os.path.join(os.getenv("HOME"),".tupkg") #try the standard location #Set variables from file now, may be overridden on command line if os.path.isfile(conffile): config = ConfigParser.ConfigParser() config.read(conffile) confdict['user'] = config.get('tupkg','username') confdict['password'] = config.get('tupkg','password') try: confdict['host'] = config.get('tupkg','host') except: confdict['host'] = 'aur.archlinux.org' try: confdict['port'] = config.getint('tupkg','port') except: confdict['port'] = 1034 else: confdict['user'] = "" confdict['password'] = "" confdict['host'] = 'aur.archlinux.org' confdict['port'] = 1034 if len(argv) == 1: #no config file and no args, bail usage() return 1 try: optlist, args = getopt.getopt(argv[1:], "u:P:h:p:", ["user=", "password=", "host=", "port="]) except getopt.GetoptError: usage() return 1 for i, k in optlist: if i in ('-u', '--user'): confdict['user'] = k if i in ('-P', '--password'): confdict['password'] = k if i in ('-h', '--host'): confdict['host'] = k if i in ('-p', '--port'): confdict['port'] = int(k) files = [] for i in args: try: files.append(ClientFile(i)) except IOError, err: print "Error: " + err.strerror + ": '" + err.filename + "'" usage() return 1 cs = ClientSocket(files, confdict['host'], confdict['port'], confdict['user'], confdict['password']) try: cs.connect() if not cs.auth(): print "Error authenticating you, you bastard" return 1 cs.sendFileMeta() cs.sendFiles() cs.close() except KeyboardInterrupt: print "Cancelling" cs.close() return 0 if __name__ == "__main__": sys.exit(main()) # Python Indentation: # ------------------- # Use tabs not spaces. If you use vim, the following comment will # configure it to use tabs. # # vim:noet:ts=2 sw=2 ft=python