diff --git a/buddy.py b/buddy.py new file mode 100644 index 0000000..b244801 --- /dev/null +++ b/buddy.py @@ -0,0 +1,140 @@ +from Spectrum2 import protocol_pb2 +from Yowsup.Contacts.contacts import WAContactsSyncRequest + +import logging + +class Number(): + + def __init__(self, number, state, db): + self.number = number + self.db = db + self.state = state + + cur = self.db.cursor() + cur.execute("SELECT id FROM numbers WHERE number = %s AND state = %s", (self.number, self.state)) + if (cur.rowcount): + self.id = cur.fetchone()[0] + else: + cur.execute("REPLACE numbers (number, state) VALUES (%s, %s)", (self.number, self.state)) + self.db.commit() + self.id = cur.lastrowid + + def __str__(self): + return "%s (id=%s)" % (self.number, self.id) + + +class Buddy(): + def __init__(self, owner, number, nick, groups, id, db): + self.id = id + self.db = db + + self.nick = nick + self.owner = owner + self.number = number + self.groups = groups + + def update(self, nick, groups): + self.nick = nick + self.groups = groups + + groups = u",".join(groups).encode("latin-1") + cur = self.db.cursor() + cur.execute("UPDATE buddies SET nick = %s, groups = %s WHERE owner_id = %s AND buddy_id = %s", (self.nick, groups, self.owner.id, self.number.id)) + self.db.commit() + + def delete(self): + cur = self.db.cursor() + cur.execute("DELETE FROM buddies WHERE owner_id = %s AND buddy_id = %s", (self.owner.id, self.number.id)) + self.db.commit() + self.id = None + + @staticmethod + def create(owner, number, nick, groups, db): + groups = u",".join(groups).encode("latin-1") + cur = db.cursor() + cur.execute("REPLACE buddies (owner_id, buddy_id, nick, groups) VALUES (%s, %s, %s, %s)", (owner.id, number.id, nick, groups)) + db.commit() + + return Buddy(owner, number, nick, groups, cur.lastrowid, db) + + def __str__(self): + return "%s (nick=%s, id=%s)" % (self.number, self.nick, self.id) + +class BuddyList(dict): + + def __init__(self, owner, db): + self.db = db + self.owner = Number(owner, 1, db) + + def load(self): + self.clear() + + cur = self.db.cursor() + cur.execute("""SELECT + b.id AS id, + n.number AS number, + b.nick AS nick, + b.groups AS groups, + n.state AS state + FROM buddies AS b + LEFT JOIN numbers AS n + ON b.buddy_id = n.id + WHERE + b.owner_id IN (%s, 0) + AND n.state >= 1 + ORDER BY b.owner_id DESC""", self.owner.id) + + for i in range(cur.rowcount): + id, number, nick, groups, state = cur.fetchone() + self[number] = Buddy(self.owner, Number(number, state, self.db), nick.decode('latin1'), groups.split(","), id, self.db) + + def update(self, number, nick, groups): + if number in self: + buddy = self[number] + buddy.update(nick, groups) + else: + buddy = self.add(number, nick, groups, 1) + + return buddy + + def add(self, number, nick, groups = [], state = 0): + return Buddy.create(self.owner, Number(number, state, self.db), nick, groups, self.db) + + def remove(self, number): + buddy = self[number] + buddy.delete() + + return buddy + + def prune(self): + cur = self.db.cursor() + cur.execute("DELETE FROM buddies WHERE owner_id = %s", self.owner.id) + self.db.commit() + + def sync(self, user, password): + cur = self.db.cursor() + cur.execute("""SELECT + n.number AS number, + n.state AS state + FROM buddies AS r + LEFT JOIN numbers AS n + ON r.buddy_id = n.id + WHERE + r.owner_id = %s""", self.owner.id) + + # prefix every number with leading 0 to force internation format + numbers = dict([("+" + number, state) for number, state in cur.fetchall()]) + + if len(numbers) == 0: + return 0 + + result = WAContactsSyncRequest(user, password, numbers.keys()).send() + + using = 0 + for number in result['c']: + cur = self.db.cursor() + cur.execute("UPDATE numbers SET state = %s WHERE number = %s", (number['w'], number['n'])) + self.db.commit() + using += number['w'] + + return using diff --git a/roster.py b/roster.py deleted file mode 100644 index 297bb4d..0000000 --- a/roster.py +++ /dev/null @@ -1,90 +0,0 @@ - -import logging - -class Number(): - - def __init__(self, number, db): - self.number = number - self.db = db - - cur = self.db.cursor() - cur.execute("SELECT id FROM numbers WHERE number = %s", self.number) - if (cur.rowcount): - self.id = cur.fetchone()[0] - logging.info("sql: found existing number %s (id=%s)", self.number, self.id) - else: - cur.execute("INSERT INTO numbers (number) VALUES (%s)", (self.number)) - self.db.commit() - self.id = cur.lastrowid - logging.info("sql: added new number %s (id=%s)", self.number, self.id) - - def __str__(self): - return "%s (id=%s)" % (self.number, self.id) - - -class Buddy(): - - def __init__(self, owner, number, nick, id, db): - self.owner = owner - self.number = number - self.nick = nick - self.id = id - self.db = db - - def update(self, nick): - self.nick = nick - cur = self.db.cursor() - cur.execute("UPDATE roster SET nick = %s WHERE owner_id = %s AND buddy_id = %s", (self.nick, self.owner.id, self.number.id)) - self.db.commit() - - def delete(self): - cur = self.db.cursor() - cur.execute("DELETE FROM roster WHERE owner_id = %s AND buddy_id = %s", (self.owner.id, self.number.id)) - self.db.commit() - self.id = None - - @staticmethod - def create(owner, number, nick, db): - cur = db.cursor() - cur.execute("INSERT INTO roster (owner_id, buddy_id, nick) VALUES (%s, %s, %s)", (owner.id, number.id, nick)) - db.commit() - - return Buddy(owner, number, nick, cur.lastrowid, db) - - def __str__(self): - return "%s (nick=%s, id=%s)" % (self.number, self.nick, self.id) - -class Roster(): - - def __init__(self, owner, db): - self.db = db - self.owner = Number(owner, db) - self.buddies = { } - - def load(self): - cur = self.db.cursor() - cur.execute("""SELECT - r.id AS id, - nb.number AS number, - r.nick AS nick - FROM roster AS r - LEFT JOIN numbers AS nb - ON r.buddy_id = nb.id - WHERE - r.owner_id = %s""", self.owner.id) - - for i in range(cur.rowcount): - id, number, nick, = cur.fetchone() - buddy = Buddy(self.owner, Number(number, self.db), nick.decode('latin1'), id, self.db) - self.buddies[number] = buddy - logging.info("roster load: %s", buddy) - - def add(self, number, nick): - buddy = Buddy.create(self.owner, Number(number, self.db), nick, self.db) - self.buddies[number] = buddy - logging.info("roster add: %s <- %s", self.owner, buddy) - - def remove(self, number): - logging.info("roster delete: %s", number) - self.buddies[number].delete() - del self.buddies[number]