Example #1
0
    def _get_qss_files(self, paths=[]):
        """
        Get qss files.

        :param list path: ist of paths to add to the scan.

        :returns: dictionary of stylesheet names/filenames.
        :rtype: dict
        """
        qss_files = dict()
        if not paths:
            return []

        for path in paths:
            for fn in os.listdir(path):
                bn, fext = os.path.splitext(fn)
                if fext.lower() in ['.qss', '.css']:
                    qss_file = os.path.join(path, fn)
                    if qss_file not in qss_files.values():
                        style_name = self._parse_stylesheet_name(qss_file)
                        if style_name is None:
                            log.warning('cannot parse style name from "%s".' %
                                        qss_file)
                            style_name = 'no-style'

                        log.debug('adding stylesheet "%s" from "%s".' %
                                  (style_name, qss_file))

                        if style_name not in qss_files:
                            qss_files[style_name] = qss_file
        return qss_files
Example #2
0
    def discard_lowest():
        """Discard lowest card, any suit (last resort)

        Note: always returns value, can be last in ruleset
        """
        mincard = None
        minlevel = ace['level']
        savecards = []  # attempt to preserve, only discard if no alternatives
        for idx in range(len(suitcards)):
            if idx == tru_idx:
                continue
            # avoid unguarding doubleton king, while making sure that A-K doubleton
            # takes precedence (if also present)
            if suitcount[idx] == 2 and king in (c.rank for c in suitcards[idx]):
                savecards.append(suitcards[idx][0])
                continue
            # otherwise we just pick the first card found at the lowest level; chances
            # are that there is no other meaninful logic to apply here (e.g. choosing
            # between green suit doubletons)
            if suitcards[idx]:
                if suitcards[idx][0].level < minlevel:
                    mincard = suitcards[idx][0]
                    minlevel = mincard.level
                elif suitcards[idx][0].level == minlevel:
                    # may need to stow an ace, if only outstanding card
                    savecards.append(suitcards[idx][0])
        assert mincard or savecards
        if not mincard:
            mincard = min(savecards, key=lambda c: c.level)
            log.debug("Have to unguard doubleton king or discard from A/A-K, oh well...")
        log.debug("Discard %s if %s trump, lowest card" % (mincard.tag, trump['tag']))
        return mincard
Example #3
0
    def read_connect(self):
        buff = self.read_bin()
        if not buff:
            return

        msg = Message()
        r = msg.decode(buff)
        if r != 0:
            return
        if r < 0:
            self.close()
            return

        c = self.conn_proxy
        log.debug(0, '*%d read message: %s', c.index, msg)

        cmd = msg.get(0)
        if cmd != 'connect rsp':
            log.error(0, 'invalid command. msg:%s', msg)
            return

        err = msg.get(1)
        if err != 'ok':
            log.error(0, 'accept fail. msg:%s', msg)
            self.close()
            return

        Bridge(self.conn, self.conn_proxy)
        self.conn = None
        self.conn_proxy = None

        if self.timer:
            del_timer(self.timer)
            self.timer = None
Example #4
0
    def ready_connect_target(self):
        c = self.conn_target
        log.debug(0, '*%d connect: %s', c.index, c.addr.text)
        del_conn(c, WRITE_EVENT)

        self.ready_target = True
        self.check_ready()
Example #5
0
    def read(self):
        buff = self.read_bin()
        if not buff:
            return

        msg = Message()
        r = msg.decode(buff)
        if r != 0:
            return
        if r < 0:
            self.close()
            return

        c = self.conn_proxy
        log.debug(0, '*%d read message. msg:%s', c.index, msg)

        cmd = msg.get(0)
        if cmd != 'accept rsp':
            log.error(0, 'invalid message. msg:%s', msg)
            self.close()
            return

        err = msg.get(1)
        if err != 'ok':
            log.error(0, 'accept fail. msg:%s', msg)
            self.close()
            return
        self.ready_proxy = True
        del_conn(c, WRITE_EVENT)
        self.check_ready()
Example #6
0
    def _get_config_files(self, paths=[]):
        """
        Get config files.

        :param list path: ist of paths to add to the scan.

        :returns: dictionary of config names/filenames.
        :rtype: dict
        """
        cfg_files = dict()
        if not paths:
            return []

        for path in paths:
            for fn in os.listdir(path):
                bn, fext = os.path.splitext(fn)
                if fext.lower() in ['.ini', '.cfg']:
                    cfg_file = os.path.join(path, fn)

                    names = bn.split('-')
                    if len(names) < 2:
                        log.warning('improperly named config file: "%s"' %
                                    cfg_file)
                        continue

                    style_name, cfg_type = names
                    if style_name not in cfg_files:
                        cfg_files[style_name] = dict(fonts=None, palette=None)

                    log.debug('adding %s config "%s" from "%s".' %
                              (cfg_type, style_name, cfg_file))
                    cfg_files[style_name][cfg_type] = cfg_file
        return cfg_files
Example #7
0
 def play_low_trump():
     """Play lowest trump (assumes no non-trump remaining)
     """
     if trump_cards and len(trump_cards) == len(analysis.cards):
         # REVISIT: are there cases where we want to play a higher trump???
         log.debug("Play lowest trump")
         return trump_cards[0]
Example #8
0
    def accept(self):
        try:
            if not is_cygwin:
                s, sockaddr = self.socket().accept()
            else:
                begin = time.time()
                s, sockaddr = self.socket().accept()
                end = time.time()
                if end - begin > 1:
                    log.info(0, 'accept cost %f seconds', end - begin)
                    exit(-1)
        except IOError as exc:
            err = exc.errno
            if err != errno.EAGAIN and err != errno.EINTR:
                log.error(exc, 'accept() fail')
            return None
        except Exception as exc:
            log.error(exc, 'accept() fail')
            return None

        c = Connection()
        c.socket(s)
        c.listening = self
        c.nonblocking()
        c.keepalive()

        c.addr = Addr(self.addr)
        c.addr.parse_sockaddr(sockaddr)

        log.debug(0, '*%d accept: %s', c.index, c.addr.text)
        self.handler(c)

        return self
Example #9
0
 def all_trump_case():
     """Handle all trump case (get it out of the way)
     """
     if suitcount[tru_idx] == len(analysis.cards):
         discard = min(suitcards[tru_idx][0], turncard, key=lambda c: c.level)
         log.debug("Discard %s if %s trump, lowest trump" % (discard.tag, trump['tag']))
         return discard
Example #10
0
    def listen(self, addr, backlog=32):
        if not isinstance(addr, Addr):
            addr = Addr(addr)

        s = self.socket(addr)
        if not s:
            return None

        if not self.reuse():
            self.close()
            return None

        try:
            s.bind(addr.sockaddr)
        except Exception as exc:
            log.error(exc, '*%d bind(%s) fail', self.index, addr.text)
            self.close()
            return None

        try:
            s.listen(backlog)
        except Exception as exc:
            log.error(exc, '*%d listen(%s) fail', self.index, addr.text)
            self.close()
            return None

        log.debug(0, '*%d listen: %s', self.index, addr.text)
        self.nonblocking()
        self.addr = addr
        self.backlog = backlog
        return self
Example #11
0
 def follow_suit_low():
     """Follow suit low
     """
     if analysis.suitcards[lead_idx]:
         # REVISIT: are there cases where we want to try and take the lead???
         log.debug("Follow suit low")
         return analysis.suitcards[lead_idx][0]
Example #12
0
 def update(self, grid, data):
     session = DBSession()
     session.query(self.model).filter(self.model.grid == grid).update(data)
     try:
         session.commit()
     except Exception as e:
         log.debug("Ocorreu um erro ao salvar as configurações !\n" + e)
         session.rollback()
Example #13
0
    def lead_random_card():
        """This is a catchall, though we should look at cases where this happens and
        see if there is a better rule to insert before

        Note: always returns value, can be last in ruleset
        """
        log.debug("Lead random card")
        return random.choice(analysis.cards)
def handle_join(event, message):
	client=Client.findByNick(message.source)
	if(client is None): return
	chan=Channel.findByName(message.parameters[0])
	if(chan is None):
		chan=Channel(message.parameters[0], time.time())
		Channel.addChannel(chan)
	chan.addClient(client)
	log.debug("%s has joined %s", client.nick, chan.name)
def handle_join(event, message):
    client = Client.findByNick(message.source)
    if (client is None): return
    chan = Channel.findByName(message.parameters[0])
    if (chan is None):
        chan = Channel(message.parameters[0], time.time())
        Channel.addChannel(chan)
    chan.addClient(client)
    log.debug("%s has joined %s", client.nick, chan.name)
Example #16
0
    def do_register(self, msg):
        err = msg.get(1)
        if err != 'ok':
            log.error(0, 'register fail. msg:%s', msg)
            self.send_msg(['register req', self.key])
            return

        self.registered = True
        log.debug(0, 'register succ. key:%s', self.key)
Example #17
0
 def lead_suit_winner():
     """Try to lead winner (non-trump)
     """
     if my_high_cards:
         my_high_cards.sort(key=lambda c: c.efflevel[tru_idx])
         log.debug("Try and lead suit winner")
         # REVISIT: is this the right logic (perhaps makes no sense if preceded by
         # off-ace rule)???  Should also examine remaining cards in suit!!!
         return my_high_cards[-1] if trick_no <= 3 else my_high_cards[0]
Example #18
0
 def model_to_fields(self, model: PersonGroup):
     self.check_active.SetValue(True if model.flag == 'A' else False)
     for k, v in model.__dict__.items():
         try:
             prop = 'text_' + k
             self.prop.SetValue(v)
         except Exception as exc:
             log.debug(exc)
     self.grid = model.grid
     self.text_code.SetValue(model.code)
Example #19
0
    def lead_low_from_long_suit():
        """Lead low from long suit (favor green if defeending?)

        Note: always returns value, can be last in ruleset
        """
        suitcards = analysis.suitcards.copy()
        suitcards.sort(key=lambda s: len(s))
        # TODO: a little more logic in choosing suit (perhaps avoid trump, if possible)!!!
        log.debug("Lead low from longest suit")
        return suitcards[-1][0]
Example #20
0
 def discard_from_next():
     """Discard next if loner call from third seat (REVISIT: not sure it makes sense
     to extend this to the general, non-voiding, non-third-seat-loner case!!!)
     """
     if suitcount[nxt_idx] == 2:
         # don't unguard doubleton king or break up A-K
         if king not in (c.rank for c in suitcards[nxt_idx]):
             discard = suitcards[nxt_idx][0]
             log.debug("Discard %s if %s trump, reducing next" % (discard.tag, trump['tag']))
             return discard
Example #21
0
 def throw_off_low():
     """Throw off lowest non-trump card
     """
     if len(trump_cards) < len(analysis.cards):
         # NOTE: this will always pick the "lowest" suit in case multiple cards at min level
         non_trump_cards = [
             c for c in analysis.cards if c.suit['idx'] != tru_idx
         ]
         non_trump_cards.sort(key=lambda c: c.efflevel[tru_idx])
         log.debug("Throw-off lowest non-trump")
         return non_trump_cards[0]
Example #22
0
 def lead_low_non_trump():
     """If still trump in hand, lead lowest card (non-trump)
     """
     if trump_cards and len(trump_cards) < len(analysis.cards):
         # NOTE: will always pick the "lowest" suit if multiple cards at min level
         non_trump_cards = [
             c for c in analysis.cards if c.suit['idx'] != tru_idx
         ]
         non_trump_cards.sort(key=lambda c: c.efflevel[tru_idx])
         log.debug("Lead lowest non-trump")
         return non_trump_cards[0]
Example #23
0
 def create_doubleton():
     """Create doubletons, if possible (favor over creating singletons)
     """
     if suitcount.count(3) > 0:
         idx = suitcount.index(3)
         # REVISIT: perhaps only do if high card in suit is actually viable (like
         # queen or higher)!!!
         if idx != tru_idx:
             # note that first element is the loweest (cards sorted ascending)
             discard = suitcards[idx][0]
             log.debug("Discard %s if %s trump, creating doubleton" % (discard.tag, trump['tag']))
             return discard
Example #24
0
 def lead_to_create_void():
     """If trump in hand, try and void a suit
     """
     if trump_cards and singletons:
         # REVISIT: perhaps only makes sense in earlier rounds (2 and 3), and otherwise
         # add some logic for choosing if more than one singleton!!!
         if len(singletons) == 1:
             log.debug("Lead singleton to void suit")
             return singletons[0]
         else:
             log.debug("Lead singleton to void suit (random for now)")
             return random.choice(singletons)
Example #25
0
 def lead_off_ace():
     """Off-ace (short suit, or green if defending?)
     """
     if off_aces:
         # TODO: choose more wisely if more than one, or possibly preserve ace to
         # avoid being trumped!!!
         if len(off_aces) == 1:
             log.debug("Lead off-ace")
             return off_aces[0]
         else:
             log.debug("Lead off-ace (random choice)")
             return random.choice(off_aces)
Example #26
0
def main():
    db.connect(config.dbhost, config.dbuser, config.dbpass, config.dbname)
    
    hon_monitor = HoNStatus()
    
    test_count = 1
    while True:
        log.info("Running test #" + str(test_count))

        # Reconfigure the monitor.
        hon_monitor.configure()
        
        login_status, login_reason = hon_monitor.login_test()
        log.info("Login server: %s - %s" % (login_status, login_reason))
        chat_status, chat_reason = hon_monitor.chat_test()
        log.info("Chat Server: %s - %s" % (chat_status, chat_reason))
        
        # MotD data can be checked each test, regardless of the server statuses.
        try:
            hon_monitor.motd_parser()
        except MasterServerError, e:
            if e.code == 108:
                log.error('Could not obtain MotD data from the Master server')

        # Check that all tests returned good, otherwise the test fails and should
        # be re-attempted in 90 seconds
        if login_status is "Up" and chat_status is "Up":
            hon_monitor.logged_in = True
            timer = 0
            while hon_monitor.is_logged_in:
                timer += 1
                if timer >= 300:
                    hon_monitor.disconnect_logout()
                    break
                else:
                    time.sleep(1)

            # Client disconnected, cool down for a moment
            log.debug("Client disconnected, cooling..")
            time.sleep(2)
        else:
            # Start dropping the players online to zero once it's been determined that
            # the servers are down.
            if down_count > 5:
                db.execute("""INSERT INTO players (time, value) VALUES (%s, %s)""", [str(int(time.time())), 0])
            time.sleep(90)

        # Loop increment
        test_count += 1

        # And log back out again
        hon_monitor.logged_in = False
Example #27
0
def get_modules(path):
    """
    Returns all sub-modules of this package.

    :returns: list of module names in the current package.
    :rtype: list
    """
    mod_names = []
    modules = pkgutil.iter_modules(path=[path])
    for loader, mod_name, ispkg in modules:
        mod_names.append(mod_name)
        log.debug('reading module: "%s"' % mod_name)
    return sorted(mod_names)
Example #28
0
    def do_accept(self, msg):
        key = msg.get(1)
        if not key:
            log.error(0, 'invalid message: %s', msg)
            return

        if self.register_key:
            log.error(0, '*%d has registered. key:%s', self.register_key)
            self.send_msg([
                'connect rsp', 'error',
                'has registered. key:%s' % self.register_key
            ])
            return

        if self.connect_key:
            log.error(0, '*%d has connected. key:%s', self.connect_key)
            self.send_msg([
                'connect rsp', 'error',
                'has connected. key:%s' % self.connect_key
            ])
            return

        if not CONNECT.has_key(key):
            self.send_msg(
                ['accept rsp', 'error',
                 'has not connect. key:%s' % key])
            return

        e = CONNECT[key]
        log.debug(0, '*%d del connect: %s', e.conn.index, e.connect_key)
        del CONNECT[key]
        e.connect_key = None

        self.send_msg(['accept rsp', 'ok'])
        e.send_msg(['connect rsp', 'ok'])

        if e.conn and self.conn:
            Bridge(e.conn, self.conn)
            e.conn = None
            self.conn = None

            if e.timer:
                del_timer(e.timer)
                e.timer = None
            if self.timer:
                del_timer(self.timer)
                self.timer = None
        else:
            e.close()
            self.close()
Example #29
0
 def throw_off_to_create_void():
     """Create void (if early in deal)--NOTE: this only matters if we've decided not
     to trump (e.g. to preserve for later)
     """
     if trump_cards and singletons:
         if len(singletons) == 1:
             log.debug("Throw off singleton to void suit (lowest)")
             return singletons[0]
         else:
             # REVISIT: perhaps only makes sense in earlier rounds (2 and 3), and also
             # reconsider selection if multiple (currently lowest valued)!!!
             singletons.sort(key=lambda c: c.efflevel[tru_idx])
             log.debug("Throw off singleton to void suit (lowest)")
             return singletons[0]
Example #30
0
    def play_random_card():
        """Play random card, but follow suit if possible

        Note: always returns value, can be last in ruleset
        """
        if plays:
            lead_card = plays[0][1]
            suit_idx = lead_card.suit['idx']
            if analysis.suitcards[suit_idx]:
                log.debug("Follow suit, random card")
                return random.choice(analysis.suitcards[suit_idx])

        log.debug("Play random card")
        return random.choice(analysis.cards)
Example #31
0
 def delete(self, grid):
     session = DBSession()
     session.query(self.model).filter(self.model.grid == grid).update(
         {'flag': 'D'})
     try:
         session.commit()
         log.info("Comando executado com sucesso !")
         log.info(session)
         return session
     except Exception as e:
         log.debug("Ocorreu um erro ao salvar as configurações !\n" +
                   e.__str__())
         session.rollback()
         return None
Example #32
0
    def process(self, msg):
        c = self.conn
        cmd = msg.get(0)
        if cmd != 'heartbeat req':
            log.debug(0, '*%d read message: %s', c.index, msg)
        else:
            log.trace(0, '*%d read message: %s', c.index, msg)

        if not self.DO_MAP.has_key(cmd):
            log.error(0, 'invalid command. msg:%s', msg)
            return

        if self.register_key:
            add_timer(self.timer, EXPIRE_TIME)
        self.DO_MAP[cmd](self, msg)
def handle_leave(event, message):
	source=Client.findByNick(message.source)
	if(source is None): source=Server.findByName(message.source)
	if(source is None): return
	targetchan=Channel.findByName(message.parameters[0])
	if(targetchan is None): return
	if(message.command=="PART"):
		targetuser=source
		reason=message.parameters[-1] if len(message.parameters)>1 else "[none]"
	elif(message.command=="KICK"):
		targetuser=Client.findByNick(message.parameters[1])
		if(targetuser is None): return
		reason=message.parameters[-1]
	log.debug("%s has left %s: %s: %s",
		targetuser.nick,
		targetchan.name,
		"kicked by "+(source.nick if source.__class__.__name__=="Client" else source.name) if message.command=="KICK" else "PART",
		reason
		)
	targetchan.removeClient(targetuser)
Example #34
0
File: main.py Project: Joev-/HoNBot
    def parse_message(self, event, source, target, message):
        """
        Processes the message received and decides what a response would be.
            `event`     The type of message received. Either MSG_N, MSG_W or MSG_P.
            `source`    The location the message came from, usualy a player.
            `target`    The location the message went to. Either a channel, or one's self in the case of a whisper or PM.
            `message`   The actual message to be processed.
        """

        # Ignore the bot's own messages.
        if source == self.bot.nickname: return
        
        # Ignore empty messages
        if message == "": return

        # Search for commands or queries in the message
        if message[0] == "!":
            command = message[1:].split(" ")[0] # Split on spaces, and grab the first word, the command.
            args = message[2 + len(command):]   # Grab a list of arguments
            log.debug("(Command) %s: %s" % (command, ''.join(args)))
            if command in self.bot_commands:
                f = self.bot_commands[command]
                # Set the owner bit
                if strip_clan(source) in self.bot.owners:
                    owner = 1
                else:
                    owner = 0
                return f(source, target, args, owner)
        else:
            # If the bot is allowed to learn then let it learn!
            if (target in self.channels and self.channels[target]['learning']) or event == MSG_P or event == MSG_W:
                self.bot.learn(message)

            # Check if the bot is to reply with a generated response. 
            if ((target in self.channels and self.channels[target]['speaking']) or event == MSG_P or event == MSG_W) \
            and self.bot.check_replying(event, message):
                response = self.bot.create_reply(message)
                return response

        # If None is returned, then the bot does nothing.
        return None
def handle_sjoin(event, message):
	chan_name=message.parameters[1]
	timestamp=message.parameters[0]
	chan=Channel.findByName(chan_name)
	if(chan is None):
		chan=Channel(chan_name, timestamp)
		Channel.addChannel(chan)
	p_idx=2
	if(message.parameters[p_idx][0]=="+"):
		#we have modes
		if(chan.timestamp==timestamp):
			#merge modes
			chan.setModes(message.parameters[p_idx], message.parameters[p_idx+1:-1], True)
		elif(chan.timestamp>timestamp):
			#clear existing modes and use sjoin modes
			chan.clearModes()
			chan.setModes(message.parameters[p_idx], message.parameters[p_idx+1:-1])
		#else ignore sjoin modes
	
	new_modes=[]
	new_params=[]
	for item in message.parameters[-1].split():
		#this could be a channel member, ban, exemption, or invex -- very confusing!
		# *~@%+ are user statuses qaohv, respectively
		# & is a ban, " is an exemption, ' is an invex
		item_type=item[0]
		if(sjoin_prefix_to_mode.has_key(item_type)):
			item=item[1:]
			new_modes.append(sjoin_prefix_to_mode[item_type])
			new_params.append(item)
		
		if(not sjoin_prefix_to_mode.has_key(item_type) or item_type in ("*", "~", "@", "%", "+")):
			member=Client.findByNick(item)
			if(not member is None):
				log.debug("SJOIN: %s to %s", member.nick, chan.name)
				chan.addClient(member)
	
	if(len(new_modes)>0): chan.setModes("+"+"".join(new_modes), new_params)
Example #36
0
    def motd_parser(self):
        """ Retrieves the dictionary of message of the day(s(?)) 
            and replaces S2's colour formatting with html classes.
            Then places any new items into the database.
        """

        colour_map = ["00","1C","38","54","70","8C","A8","C4","E0","FF"]
        s2colours = lambda m: '<span style="color: #' + ''.join([colour_map[int(x)] for x in m.group(1)]) + '">'

        def urlfix(x):
            """ Replaces urls which only contain a 'www' with a 'http://wwww'. """
            if x.group(2) in ['http://', 'www']:
                colour = "y"
                url = x.group(1)
            else:
                colour = x.group(1)
                url = x.group(2)
            
            r = re.compile(r"(?<!http://)www")
            if r.match(url):
                url = 'http://' + ''.join(url)

            return '<a href=' + url + ' class=' + colour + ' target="_blank">' + url + '</a>'
        
        motd_data = self.motd_get()
        motd_list = motd_data['motd_list']

        ## NOTE: This entire thing is fairly broken due to glows, and when retards use rainbows in their text.

        # Iterate over the list in reverse because entries are retrieved in order newest -> oldest
        # and must be entered into the database oldest -> newest.
        for motd in motd_list[::-1]:

            # First find any un-coloured hyperlinks and fill them with html tags.
            # This regex matches any hyperlink which is not preceeded by a ^g formatter for EG.
            # It is not very accurate at the moment as it will match a http which has a ^* at the end.
            # http://gskinner.com/RegExr/?2u79l
            r = re.compile(r"(?<=[^\^a-zA-Z])((http://|(?<!http://)www)[-a-zA-Z0-9@:%_\+.~#?&//=]+)[^\^\*]")
            motd['body'] = r.sub(urlfix, motd['body'])

            # Then find all hyperlinks that contain colour formatting and replace with HTML tags.
            r = re.compile(r"\^([a-zA-Z])((http://|(?<!http://)www)[-a-zA-Z0-9@:%_\+.~#?&//=]+)(\^\*)")
            motd['body'] = r.sub(urlfix, motd['body'])

            # Find all coded colours eg ^428 and replace with inline html styling
            # ''.join([color_map[int(x)] for x in r.search(msg).group(1)])
            r = re.compile(r"\^([0-9]{3})")
            motd['body'] = r.sub(s2colours, motd['body'])

            # Replace the colours with HTML classes
            # Replace ^* with </span>
            motd['body'] = motd['body'].replace("^*", "</span>")

            # Find all basic colour codes eg ^y or ^r or ^o and replace with inline html
            r = re.compile(r"\^([a-z]{1})")
            motd['body'] = r.sub(r"<span class='\1'>", motd['body'])
            
            # Replace \r\n with <br />
            motd['body'] = motd['body'].replace("\r\n", "<br />")

            title_exists = db.query("""SELECT id FROM motds WHERE title = %s AND date = %s""", [motd['title'], motd['date']])
            msg_exists = db.query("""SELECT id, title FROM motds WHERE body = %s AND date = %s""", [motd['body'], motd['date']])

            if not title_exists:
                # Check if the message was simply updated by the staff.
                # If it's been changed then update it in the database automatically.
                # TODO: Is this level of comparison okay?
                if msg_exists:
                    # Title doesn't exist, but message body does, title changed.
                    db.execute("""UPDATE motds SET title=%s, author=%s, date=%s, body=%s WHERE id = %s""", [motd['title'], motd['author'], motd['date'], motd['body'], msg_exists[0][0]])
                    log.info("Updated motd #%s - %s. Title updated to %s" % (msg_exists[0][0], msg_exists[0][1], motd['title']))

            elif title_exists:
                log.debug("Duplicate title for motd id %s with title %s" % (title_exists[0][0], motd['title']))
                # This entry is already here, possibly it could have been updated.
                # Note: Seems they like to change the titles after publishing them.
                if not msg_exists:
                    # Title exists but the msg body doesn't, so it was likely updated.
                    db.execute("""UPDATE motds SET title=%s, author=%s, date=%s, body=%s WHERE id = %s""", [motd['title'], motd['author'], motd['date'], motd['body'], title_exists[0][0]])
                    log.info("Updated motd #%s - %s. Message updated" % (title_exists[0][0], motd['title']))

            if not msg_exists and not title_exists:
                    # Neither the title or message are there, either both are changed or this is a brand new motd
                    # Treat it as new for now.
                    # Add this motd to the database
                    db.execute("""INSERT INTO motds (title, author, date, body) VALUES(%s, %s, %s, %s)""", [motd['title'], motd['author'], motd['date'], motd['body']])
                    log.info("Added new message of the day - %s - %s" % (motd['title'], motd['date']))

        # Get the image from S2 for the motd.
        # Save it to static/img/motd/ if it does not exist.
        image_file = motd_data['image'].split("`")[0]
        image_name = re.search(r'\/([a-f0-9]+.jpg)', image_file).group(1)
        if not os.path.isfile(os.path.join(config.motd_img_dir, image_name)):
            urllib.urlretrieve(image_file, os.path.join(config.motd_img_dir, image_name)) 
            # Set the image name in the database so it can be retrieved.
            db.execute("""UPDATE `motd_extra` SET `value`=%s WHERE `key`=%s""", [image_name, 'image'])
            log.info("New MOTD image.")