def sendMessage(self, chat_id, message, key_markup="SAME", keyboard_short=True, preview=True, markdown=False, reply_to=None):
		"""
		Sends a text message to Telegram user
		:param keyboard_short: If True, the buttons on custom keyboard will be lower in height.
		Might be useful if there are many rows of buttons and the kyboard fills the screen.
		:param chat_id: ID of chat
		:param message: text to send
		:param key_markup: a list representing a custom keyboard markup to show to user.
		If "SAME", use the same markup as before.
		If None, hide the custom keyboard.
		:param preview: Should a link in a message generate a page preview within a message?
		:type preview: bool
		:param markdown: Should a message support markdown formatting?
		:type markdown: bool
		:param reply_to: An id of an existing message. A sent message will be a reply to that message.
		:return: None
		"""
		def markup(m):
			if not m:
				return telegram.ReplyKeyboardHide()
			elif m == "SAME":
				return None
			else:
				return telegram.ReplyKeyboardMarkup(m, resize_keyboard=keyboard_short)

		logging.warning("Replying to " + str(chat_id) + ": " + message)
		fulltext = self.breakLongMessage(message)
		for text in fulltext:
			# iterating over parts of a long split message
			while True:
				try:
					if text:
						self.bot.sendChatAction(chat_id, telegram.ChatAction.TYPING)
						self.bot.sendMessage(chat_id=chat_id,
											text=text,
											parse_mode='Markdown' if markdown else None,
											disable_web_page_preview=(not preview),
											reply_markup=markup(key_markup),
											reply_to_message_id=reply_to
											)
				except KeyboardInterrupt:
					raise KeyboardInterrupt
				except Exception as e:
					if "Message is too long" in str(e):
						self.sendMessage(chat_id=chat_id, message="Error: Message is too long!")
					elif ("urlopen error" in str(e)) or ("timed out" in str(e)):
						logging.error("Could not send message. Retrying! Error: " + 
							full_traceback()
							)
						sleep(3)
						continue
					else:
						logging.error(
								"Could not send message. Error: " + full_traceback())
				break
	def getUpdates(self):
		"""
		Gets updates. Updates are basically messages sent to bot from users.
		Retries if it fails.
		:return: a list of update objects
		"""
		# if getting updates fails - retry
		updates = []
		while True:
			try:
				updates = self.bot.getUpdates(offset=self.LAST_UPDATE_ID)
				pass
			except KeyboardInterrupt:
				raise KeyboardInterrupt
			except Exception:
				logging.error("Could not read updates. Retrying! Error: " + full_traceback())
				sleep(1)
				continue
			break
		return updates
	def sendPic(self, chat_id, pic, caption=None):
		"""
		Sends a picture in a Telegram message to a user. Retries if fails.
		:param chat_id: ID of chat
		:param pic: a picture file. Preferably the object created with open()
		:param caption: a text that goes together with picture ina message.
		:return: None
		"""
		while True:
			try:
				logging.debug("Picture: " + str(pic))
				self.bot.sendChatAction(chat_id, telegram.ChatAction.UPLOAD_PHOTO)
				# set file read cursor to the beginning.
				# This ensures that if a file needs to be re-read (may happen due to exception), it is read from the beginning.
				pic.seek(0)
				self.bot.sendPhoto(chat_id=chat_id, photo=pic, caption=caption)
			except KeyboardInterrupt:
				raise KeyboardInterrupt
			except Exception:
				logging.error("Could not send picture. Retrying! Error: " + full_traceback())
				sleep(1)
				continue
			break
	def processUpdate(self, u):
		bot = self.bot
		Message = u.message
		message = Message.text
		message_id = Message.message_id
		chat_id = Message.chat_id

		subs = self.user_params

		subs.initializeUser(chat_id=chat_id, data=INITIAL_SUBSCRIBER_PARAMS)

		# language support class for convenience
		LS = LanguageSupport(subs.getEntry(chat_id=chat_id, param="lang"))
		lS = LS.languageSupport
		allv = LS.allVariants
		MMKM = lS(MAIN_MENU_KEY_MARKUP)

		if message == "/start":
			bot.sendMessage(chat_id=chat_id
							, message=lS(START_MESSAGE)
							, key_markup=MMKM
							)
		elif message == "/help" or message in allv(HELP_BUTTON):
			bot.sendMessage(chat_id=chat_id
							, message=lS(HELP_MESSAGE).format(lS(GET_TIMETABLE_BUTTON), lS(ALL_DAYS_BUTTON),
															  lS(MY_EVENTS_BUTTON), lS(SUBSCRIBE_BUTTON))
							, key_markup=MMKM
							, markdown=True
							)
		elif message == "/about" or message in allv(ABOUT_BUTTON):
			bot.sendMessage(chat_id=chat_id
							, message=lS(ABOUT_MESSAGE).format(".".join([str(i) for i in VERSION_NUMBER]))
							, key_markup=MMKM
							, markdown=True
							)
		elif message == "/otherbots" or message in allv(OTHER_BOTS_BUTTON):
			bot.sendMessage(chat_id=chat_id
							, message=lS(OTHER_BOTS_MESSAGE)
							, key_markup=MMKM
							)
		elif message == "/map" or message in allv(MAP_BUTTON):
			map_filepath = path.join(SCRIPT_FOLDER, RESOURCES_FOLDER_NAME, MAP_FILENAME)
			if path.isfile(map_filepath):
				bot.sendPic(chat_id=chat_id
						, pic=open(map_filepath, "rb")
						, caption=MAP_MESSAGE
								)
			else:
				# There is no map file, notify user
				bot.sendMessage(chat_id=chat_id
							, message=lS(NO_MAP_FILE_MESSAGE)
							, key_markup=MMKM
							)
		elif message == "/timetable" or message in allv(GET_TIMETABLE_BUTTON):
			bot.sendMessage(chat_id=chat_id
							, message=lS(GET_TIMETABLE_MESSAGE)
							, key_markup=self.timetable_db.getTimetableMarkup()
							)
		elif TimetableDatabase.isDate(message):
			# it is a date, show day timetable
			print('message', message)
			response = lS(CURRENT_TIME_MESSAGE).format(self.timetable_db.getOffsetTime().strftime("%H:%M")) \
			+ "\n\n" \
			+ self.timetable_db.getDayTimetable(message)
			bot.sendMessage(chat_id=chat_id
							, message=response
							, key_markup=MMKM
							)
			#If a graphical file in format YYYY-MM-DD.png exists, send it as well
			try:
				filepath = path.join(SCRIPT_FOLDER, RESOURCES_FOLDER_NAME, message) + ".png"
				with open(filepath, "rb") as pic:
						bot.sendPic(chat_id=chat_id
						, pic=pic
						, caption=message
								)
			except FileNotFoundError as e:
				print("Graph file not found")
				print(full_traceback())

		elif message == '/all' or message in allv(ALL_DAYS_BUTTON):
			# it is a date, show day timetable
			response = lS(CURRENT_TIME_MESSAGE).format(self.timetable_db.getOffsetTime().strftime("%H:%M")) \
			+ "\n\n" \
			+ self.timetable_db.getAllDaysTimetable()

			bot.sendMessage(chat_id=chat_id
							, message=response
							, key_markup=MMKM
							)
		elif re.match("^/event[0-9]+$", message):
			# Event link is pressed
			event_info = self.timetable_db.getEventInfo(message[6:])
			response = lS(CURRENT_TIME_MESSAGE).format(self.timetable_db.getOffsetTime().strftime("%H:%M")) \
			+ "\n\n" \
			+ lS(event_info)
			bot.sendMessage(chat_id=chat_id
						, message=response
						, key_markup=MMKM
						, markdown="html"
						)
		elif message == "/subscribe" or message in allv(SUBSCRIBE_BUTTON):
			if self.user_params.getEntry(chat_id, "subscribed") == 0:
				self.user_params.setEntry(chat_id, "subscribed", 1)
				bot.sendMessage(chat_id=chat_id
							, message=lS(SUBSCRIBED_MESSAGE)
							, key_markup=MMKM
							)
			else:
				bot.sendMessage(chat_id=chat_id
							, message=lS(ALREADY_SUBSCRIBED_MESSAGE)
							, key_markup=MMKM
							)
		elif message == "/unsubscribe" or message in allv(UNSUBSCRIBE_BUTTON):
			if self.user_params.getEntry(chat_id, "subscribed") == 1:
				self.user_params.setEntry(chat_id, "subscribed", 0)
				bot.sendMessage(chat_id=chat_id
							, message=lS(UNSUBSCRIBED_MESSAGE)
							, key_markup=MMKM
							)
			else:
				bot.sendMessage(chat_id=chat_id
							, message=lS(ALREADY_UNSUBSCRIBED_MESSAGE)
							, key_markup=MMKM
							)
		elif message == "/myevents" or message in allv(MY_EVENTS_BUTTON):
			# show a table of events to which a user is subscribed
			user_timetable = self.timetable_db.getUserTimetable(chat_id=chat_id)
			if user_timetable:
				response = lS(CURRENT_TIME_MESSAGE).format(self.timetable_db.getOffsetTime().strftime("%H:%M")) \
				+ "\n\n" \
				+ self.timetable_db.getUserTimetable(chat_id=chat_id)
			else:
				response = "Your personal timetable is empty!"

			bot.sendMessage(chat_id=chat_id
				, message=response
				, key_markup=MMKM
				)

		elif re.match("^/sub[0-9]+$",message):
			event_index = message[4:]
			if self.timetable_db.eventIndexExists(event_index):
				# Event exists
				event_name = self.timetable_db.getEventData(event_index)['name']
				if not self.timetable_db.subscriptionExists(chat_id, event_index):
					self.timetable_db.addSubscription(chat_id, event_index)
					bot.sendMessage(chat_id=chat_id
									, message="You have subscribed to the event: {0}".format(event_name, event_index)
									, key_markup=MMKM
									)
				else:
					self.timetable_db.deleteSubscription(chat_id,event_index)
					bot.sendMessage(chat_id=chat_id
									, message="Subscription deleted: {0}".format(event_name, event_index)
									, key_markup=MMKM
									)
			else:
				# such event doesn't exist
				bot.sendMessage(chat_id=chat_id
							, message="Event with index {0} doesn't exist!".format(event_index)
							, key_markup=MMKM
							, reply_to=message_id
							)
		elif re.match("^[0-9]+$",message):
			remind_period = int(message)
			if remind_period < 1:
				self.user_params.setEntry(chat_id, 'remind_period', 1)
				bot.sendMessage(chat_id=chat_id
							, message="The minimum remind period possible is 1 minute. Setting to 1 minute."
							, key_markup=MMKM
							)
			elif remind_period > 1439:
				self.user_params.setEntry(chat_id, 'remind_period', 1439)
				bot.sendMessage(chat_id=chat_id
							, message="The minimum remind period possible is 1439 minutes. Setting to 1439 minutes."
							, key_markup=MMKM
							)
			else:
				self.user_params.setEntry(chat_id, 'remind_period', remind_period)
				bot.sendMessage(chat_id=chat_id
							, message="Preliminary reminder period has been set to {0}".format(message)
							, key_markup=MMKM
							)
		elif message == RU_LANG_BUTTON:
			self.assignBotLanguage(chat_id, 'RU')
			LS = LanguageSupport(subs.getEntry(chat_id=chat_id, param="lang"))
			key_markup = LS.languageSupport(message=MAIN_MENU_KEY_MARKUP)
			bot.sendMessage(chat_id=chat_id
							, message="Сообщения бота будут отображаться на русском языке."
							, key_markup=key_markup
							)
		elif message == EN_LANG_BUTTON:
			self.assignBotLanguage(chat_id, 'EN')
			LS = LanguageSupport(subs.getEntry(chat_id=chat_id, param="lang"))
			key_markup = LS.languageSupport(message=MAIN_MENU_KEY_MARKUP)
			bot.sendMessage(chat_id=chat_id
							, message="Bot messages will be shown in English."
							, key_markup=key_markup
							)

		# admin tools
		elif bot.isDocument(u) and self.user_params.getEntry(chat_id, 'admin') == 1:
			# check if it is a timetable
			if re.search("^.*{0}$".format(EVENT_TIMETABLE_FILENAME), bot.getDocumentFileName(u)):
				# It's a text file with timetable
				full_path = path.join(TEMP_FOLDER, EVENT_TIMETABLE_FILENAME)
				bot.downloadFile(bot.getFileID(u), full_path)

				try:
					with open(full_path, "r") as f:
						data = f.read()
						print(data)
						self.timetable_db.parseTimetable(data)

					os.remove(full_path)

					bot.sendMessage(chat_id=chat_id
								, message="Events added!"
								, key_markup=MMKM
								)
				except IndexError:
						bot.sendMessage(chat_id=chat_id
								, message="Parsing failed! Are all fields present in the file?"
								, key_markup=MMKM
								)
			if re.search("^.*{0}$".format(EVENT_TIMETABLE_XLS_FILENAME), bot.getDocumentFileName(u)):
				# It's a XLS sheet with a timetable
				full_path = path.join(TEMP_FOLDER, EVENT_TIMETABLE_XLS_FILENAME)
				bot.downloadFile(bot.getFileID(u), full_path)

				self.timetable_db.parseTimetableXLS(full_path)
				os.remove(full_path)

				bot.sendMessage(chat_id=chat_id
								, message="Events added!"
								, key_markup=MMKM
								)

		elif re.match("^TZ(\+|-)([0-9]|[0-1][0-9]|2[0-3])$", message) and self.user_params.getEntry(chat_id, 'admin') == 1:
			# Setting the timezone parameter
			timezone = int(message[2:])
			self.server_params.setParam('timezone', timezone)
			bot.sendMessage(chat_id=chat_id
							, message="Timezone set to UTC{0}{1}".format("+" if timezone >= 0 else "", timezone)
							, key_markup=MMKM
							)
		elif message == "/revoke" and self.user_params.getEntry(chat_id, 'admin') == 1:
			# revoke admin rights
			self.user_params.setEntry(chat_id, 'admin', 0)
			bot.sendMessage(chat_id=chat_id
							, message="Admin rights revoked"
							, key_markup=MMKM
							)
		else:
			bot.sendMessage(chat_id=chat_id
							, message="Unknown command!"
							, key_markup=MMKM
							)
Esempio n. 5
0
    def processUpdate(self, u):
        def sendParamsToThread(**kwargs):
            # process photo
            thread_params = dict(bot=bot,
                                 update=u,
                                 chat_id=chat_id,
                                 message_id=message_id)
            # save params to file
            self.queue_saver.append_to_list(thread_params, save=True)
            # send params to Queue for thread to process
            self.uploader_queue.put(thread_params)

        bot = self.bot
        Message = u.message
        message = Message.text
        message_id = Message.message_id
        chat_id = Message.chat_id
        subs = self.h_subscribers

        # try initializing user. If it exists, ignore (no forcing).
        user_folder_token = hex(getrandbits(128))[2:]
        while user_folder_token in [
                subs.subscribers[chatid]['folder_token']
                for chatid in subs.subscribers.keys()
        ]:
            # it is highly improbable, but if suddenly the folder token is generated - try again!
            user_folder_token = hex(getrandbits(128))[2:]
        subs.init_user(chat_id, params={"folder_token": user_folder_token})

        # language support class for convenience
        LS = LanguageSupport(subs.get_param(chat_id=chat_id, param="lang"))
        lS = LS.languageSupport
        MMKM = lS(MAIN_MENU_KEY_MARKUP)

        if message == "/start":
            bot.sendMessage(chat_id=chat_id,
                            message=lS(START_MESSAGE),
                            key_markup=MMKM)
        elif message == "/help" or message == lS(HELP_BUTTON):
            bot.sendMessage(chat_id=chat_id,
                            message=lS(HELP_MESSAGE).format(
                                lS(DB_STORAGE_LINK_BUTTON),
                                lS(FREE_DB_SPACE_BUTTON)),
                            key_markup=MMKM,
                            markdown=True)
        elif message == "/about" or message == lS(ABOUT_BUTTON):
            bot.sendMessage(chat_id=chat_id,
                            message=lS(ABOUT_MESSAGE),
                            key_markup=MMKM,
                            markdown=True)
        elif message == "/otherbots" or message == lS(OTHER_BOTS_BUTTON):
            bot.sendMessage(chat_id=chat_id,
                            message=lS(OTHER_BOTS_MESSAGE),
                            key_markup=MMKM)
        elif message == "/dblink" or message == lS(DB_STORAGE_LINK_BUTTON):
            bot.sendMessage(
                chat_id=chat_id,
                message=lS(DB_STORAGE_LINK_MESSAGE) %
                (DB_STORAGE_PUBLIC_LINK,
                 subs.get_param(chat_id=chat_id, param="folder_token")),
                key_markup=MMKM,
                preview=False)
        elif message == "/free" or message == lS(FREE_DB_SPACE_BUTTON):
            bot.sendMessage(chat_id=chat_id,
                            message=lS(FREE_DB_SPACE_MESSAGE) %
                            self.get_free_dbx_space(),
                            key_markup=MMKM)
        elif message == "/set_name" or message == lS(SET_USERNAME_BUTTON):
            subs.set_param(chat_id=chat_id, param="input_mode", value=1)
            bot.sendMessage(chat_id=chat_id,
                            message=lS(SET_USERNAME_MESSAGE),
                            key_markup=MMKM)
        elif message == "/set_comment" or message == lS(SET_COMMENT_BUTTON):
            subs.set_param(chat_id=chat_id, param="input_mode", value=2)
            bot.sendMessage(chat_id=chat_id,
                            message=lS(SET_COMMENT_MESSAGE),
                            key_markup=MMKM)
        elif message == "/toggle_infofile" or message == lS(
                TOGGLE_INFOFILE_BUTTON):
            InfofileThread(bot, self.dbx, chat_id,
                           subs.get_param(chat_id, "folder_token"),
                           subs.get_param(chat_id, "username"),
                           subs.get_param(chat_id, "comment"),
                           subs.get_param(chat_id, "lang"))
        elif message == RU_LANG_BUTTON:
            self.assignBotLanguage(chat_id, 'RU')
            LS = LanguageSupport(subs.get_param(chat_id=chat_id, param="lang"))
            key_markup = LS.languageSupport(message=MAIN_MENU_KEY_MARKUP)
            bot.sendMessage(
                chat_id=chat_id,
                message="Сообщения бота будут отображаться на русском языке.",
                key_markup=key_markup)
        elif message == EN_LANG_BUTTON:
            self.assignBotLanguage(chat_id, 'EN')
            LS = LanguageSupport(subs.get_param(chat_id=chat_id, param="lang"))
            key_markup = LS.languageSupport(message=MAIN_MENU_KEY_MARKUP)
            bot.sendMessage(chat_id=chat_id,
                            message="Bot messages will be shown in English.",
                            key_markup=key_markup)
        elif bot.isPhoto(u):
            print("Sending params to thread on message. photo")  # debug
            sendParamsToThread(bot=bot,
                               update=u,
                               chat_id=chat_id,
                               message_id=message_id)
        elif bot.isDocument(u):
            if ALLOW_FILES:
                try:
                    # check supported file formats
                    if not (bot.getFileExt(u, no_dot=True).lower()
                            in SUPPORTED_FILE_FORMATS):
                        bot.sendMessage(
                            chat_id=chat_id,
                            message=lS(WRONG_FILE_FORMAT_MESSAGE).format(
                                ", ".join(SUPPORTED_FILE_FORMATS)),
                            reply_to=message_id)
                    # limit filesize
                    elif bot.getFileSize(u) > MAX_FILE_SIZE:
                        bot.sendMessage(
                            chat_id=chat_id,
                            message=lS(FILE_TOO_BIG_MESSAGE).format(
                                MAX_FILE_SIZE / 1024**2),
                            reply_to=message_id)
                    else:
                        print("Sending params to thread on message. Document"
                              )  # debug
                        sendParamsToThread(bot=bot,
                                           update=u,
                                           chat_id=chat_id,
                                           message_id=message_id)
                except TelegramError:
                    logging.error("Could not process file.\n" +
                                  full_traceback())
                    bot.sendMessage(chat_id=chat_id,
                                    message="Failed to process file",
                                    reply_to=message_id)
            else:
                bot.sendMessage(chat_id=chat_id,
                                message=lS(FILES_NOT_ALLOWED_MESSAGE),
                                reply_to=message_id)
        else:
            if subs.get_param(chat_id, "input_mode") == 1:
                # Username input mode
                subs.set_param(chat_id, param="username", value=message)
                subs.set_param(chat_id, param="input_mode", value=0)
                bot.sendMessage(chat_id=chat_id,
                                message="Username set!",
                                key_markup=MMKM)
                InfofileThread(bot,
                               self.dbx,
                               chat_id,
                               subs.get_param(chat_id, "folder_token"),
                               subs.get_param(chat_id, "username"),
                               subs.get_param(chat_id, "comment"),
                               subs.get_param(chat_id, "lang"),
                               recreate=True)
            elif subs.get_param(chat_id, "input_mode") == 2:
                # Comment input mode
                subs.set_param(chat_id, param="comment", value=message)
                subs.set_param(chat_id, param="input_mode", value=0)
                bot.sendMessage(chat_id=chat_id,
                                message="Comment set!",
                                key_markup=MMKM)
                InfofileThread(bot,
                               self.dbx,
                               chat_id,
                               subs.get_param(chat_id, "folder_token"),
                               subs.get_param(chat_id, "username"),
                               subs.get_param(chat_id, "comment"),
                               subs.get_param(chat_id, "lang"),
                               recreate=True)
            else:
                bot.sendMessage(chat_id=chat_id,
                                message="Unknown command!",
                                key_markup=MMKM)
Esempio n. 6
0
        def photoDownloadUpload(bot, update, chat_id, message_id):
            print("Queue size", queue.qsize())  # debug

            subs = self.h_subscribers

            # get a hex-created folder name
            DB_folder_name = subs.get_param(chat_id, "folder_token")

            if telegramHigh.isDocument(update):
                # for documents, preserve original filename. It already has an extension.
                full_filename = bot.getDocumentFileName(update)
            else:
                # if not a document, name a file with a datestamp. (Photo objects have weird filenames)
                file_name = datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
                # get an extension
                file_ext = bot.getFileExt(update)
                # sum them to get a full file name
                full_filename = file_name + file_ext

            # create a full path to the file in a temporary folder without extension
            full_filepath = path.join("/tmp", DB_folder_name, full_filename)
            # full path without file name
            full_dir_path = path.dirname(full_filepath)

            # download photo to temporary folder.
            while True:
                try:
                    bot.downloadFile(bot.getFileID(update),
                                     custom_filepath=full_filepath)
                    break
                except Exception:
                    logging.error(
                        "Could not download photo, retrying. Traceback:\n" +
                        full_traceback())
                    sleep(5)
                    pass

            # change to file's dir
            os.chdir(full_dir_path)

            # sometimes a file is downloaded with a different name. verify that it exists and renme if the name is wrong
            if not path.isfile(full_filepath):
                # list of files in a directory
                onlyfiles = [
                    fle for fle in listdir(full_dir_path) if path.isfile(fle)
                ]
                # Get the latest file in the directory
                wrong_file = max(onlyfiles, key=path.getctime)
                # Rename it
                os.rename(wrong_file, full_filename)

            # upload to dropbox
            while True:
                try:
                    # WARNING: files_upload is not usable for files over 140 MB
                    self.dbx.files_upload(
                        open(full_filepath, 'rb'),  # open file
                        "/" + DB_folder_name + "/" +
                        full_filename,  # set path in dropbox
                        autorename=True)
                    break
                except Exception:
                    logging.error(
                        "Could not upload to Dropbox, retrying. Traceback:\n" +
                        full_traceback())
                    sleep(5)

            # confirmation message
            bot.sendMessage(chat_id=chat_id,
                            message="Photo uploaded!",
                            reply_to=message_id)

            # remove all files from temp folder
            for i in listdir(full_dir_path):
                os.remove(i)

            # remove the data about this photo and update queue file
            self.queue_saver.pop_first(save=True)
	def processUpdate(self, u):
		def sendParamsToThread(**kwargs):
			# process photo
			thread_params = dict(bot=bot, update=u, chat_id=chat_id, message_id=message_id)
			# save params to file
			self.queue_saver.append_to_list(thread_params, save=True)
			# send params to Queue for thread to process
			self.uploader_queue.put(thread_params)

		bot = self.bot
		Message = u.message
		message = Message.text
		message_id = Message.message_id
		chat_id = Message.chat_id
		subs = self.h_subscribers

		# try initializing user. If it exists, ignore (no forcing).
		user_folder_token = hex(getrandbits(128))[2:]
		while user_folder_token in [subs.subscribers[chatid]['folder_token'] for chatid in subs.subscribers.keys()]:
			# it is highly improbable, but if suddenly the folder token is generated - try again!
			user_folder_token = hex(getrandbits(128))[2:]
		subs.init_user(chat_id, params={"folder_token": user_folder_token})

		# language support class for convenience
		LS = LanguageSupport(subs.get_param(chat_id=chat_id, param="lang"))
		lS = LS.languageSupport
		MMKM = lS(MAIN_MENU_KEY_MARKUP)

		if message == "/start":
			bot.sendMessage(chat_id=chat_id
							, message=lS(START_MESSAGE)
							, key_markup=MMKM
							)
		elif message == "/help" or message == lS(HELP_BUTTON):
			bot.sendMessage(chat_id=chat_id
							, message=lS(HELP_MESSAGE).format(MAX_FILE_SIZE/1024**2, ", ".join(SUPPORTED_FILE_FORMATS), lS(DB_STORAGE_LINK_BUTTON), lS(FREE_DB_SPACE_BUTTON))
							, key_markup=MMKM
							, markdown=True
							)
		elif message == "/about" or message == lS(ABOUT_BUTTON):
			bot.sendMessage(chat_id=chat_id
							, message=lS(ABOUT_MESSAGE)
							, key_markup=MMKM
							, markdown=True
							)
		elif message == "/otherbots" or message == lS(OTHER_BOTS_BUTTON):
			bot.sendMessage(chat_id=chat_id
							, message=lS(OTHER_BOTS_MESSAGE)
							, key_markup=MMKM
							)
		elif message == "/dblink" or message == lS(DB_STORAGE_LINK_BUTTON):
			bot.sendMessage(chat_id=chat_id
							, message=lS(DB_STORAGE_LINK_MESSAGE)
									  % (DB_STORAGE_PUBLIC_LINK, subs.get_param(chat_id=chat_id, param="folder_token"))
							, key_markup=MMKM
							, preview=False
							)
		elif message == "/free" or message == lS(FREE_DB_SPACE_BUTTON):
			bot.sendMessage(chat_id=chat_id
							, message=lS(FREE_DB_SPACE_MESSAGE) % self.get_free_dbx_space()
							, key_markup=MMKM
							)
		elif message == "/set_name" or message == lS(SET_USERNAME_BUTTON):
			subs.set_param(chat_id=chat_id,param="input_mode", value=1)
			bot.sendMessage(chat_id=chat_id
							, message=lS(SET_USERNAME_MESSAGE)
							, key_markup=MMKM
							)
		elif message == "/set_comment" or message == lS(SET_COMMENT_BUTTON):
			subs.set_param(chat_id=chat_id,param="input_mode", value=2)
			bot.sendMessage(chat_id=chat_id
							, message=lS(SET_COMMENT_MESSAGE)
							, key_markup=MMKM
							)
		elif message == "/toggle_infofile" or message == lS(TOGGLE_INFOFILE_BUTTON):
			InfofileThread(bot, self.dbx, chat_id, subs.get_param(chat_id, "folder_token"),
						subs.get_param(chat_id, "username"), subs.get_param(chat_id, "comment"),
						subs.get_param(chat_id, "lang"))
		elif message == RU_LANG_BUTTON:
			self.assignBotLanguage(chat_id, 'RU')
			LS = LanguageSupport(subs.get_param(chat_id=chat_id, param="lang"))
			key_markup = LS.languageSupport(message=MAIN_MENU_KEY_MARKUP)
			bot.sendMessage(chat_id=chat_id
							, message="Сообщения бота будут отображаться на русском языке."
							, key_markup=key_markup
							)
		elif message == EN_LANG_BUTTON:
			self.assignBotLanguage(chat_id, 'EN')
			LS = LanguageSupport(subs.get_param(chat_id=chat_id, param="lang"))
			key_markup = LS.languageSupport(message=MAIN_MENU_KEY_MARKUP)
			bot.sendMessage(chat_id=chat_id
							, message="Bot messages will be shown in English."
							, key_markup=key_markup
							)
		elif bot.isPhoto(u):
			print("Sending params to thread on message. photo")  # debug
			sendParamsToThread(bot=bot, update=u, chat_id=chat_id, message_id=message_id)
		elif bot.isDocument(u):
			try:
				# check supported file formats
				if not (bot.getFileExt(u, no_dot=True).lower() in SUPPORTED_FILE_FORMATS):
					bot.sendMessage(chat_id=chat_id
									, message=lS(WRONG_FILE_FORMAT_MESSAGE).format(", ".join(
									SUPPORTED_FILE_FORMATS))
									, reply_to=message_id
									)
				# limit filesize
				elif bot.getFileSize(u) > MAX_FILE_SIZE:
					bot.sendMessage(chat_id=chat_id
									, message=lS(FILE_TOO_BIG_MESSAGE).format(MAX_FILE_SIZE / 1024 ** 2)
									, reply_to=message_id
									)
				else:
					print("Sending params to thread on message. Document")  # debug
					sendParamsToThread(bot=bot, update=u, chat_id=chat_id, message_id=message_id)
			except TelegramError:
				logging.error("Could not process file.\n" + full_traceback())
				bot.sendMessage(chat_id=chat_id
								, message="Failed to process file"
								, reply_to=message_id
								)
		else:
			if subs.get_param(chat_id,"input_mode") == 1:
				# Username input mode
				subs.set_param(chat_id, param="username", value=message)
				subs.set_param(chat_id, param="input_mode", value=0)
				bot.sendMessage(chat_id=chat_id
								, message="Username set to " + message
								, key_markup=MMKM
								)
				InfofileThread(bot, self.dbx, chat_id, subs.get_param(chat_id, "folder_token"),
					subs.get_param(chat_id, "username"), subs.get_param(chat_id, "comment"),
					subs.get_param(chat_id, "lang"), recreate=True)
			elif subs.get_param(chat_id,"input_mode") == 2:
				# Comment input mode
				subs.set_param(chat_id, param="comment", value=message)
				subs.set_param(chat_id, param="input_mode", value=0)
				bot.sendMessage(chat_id=chat_id
								, message="Comment set!"
								, key_markup=MMKM
								)
				InfofileThread(bot, self.dbx, chat_id, subs.get_param(chat_id, "folder_token"),
					subs.get_param(chat_id, "username"), subs.get_param(chat_id, "comment"),
					subs.get_param(chat_id, "lang"), recreate=True)
			else:
				bot.sendMessage(chat_id=chat_id
								, message="Unknown command!"
								, key_markup=MMKM
								)
		def photoDownloadUpload(bot, update, chat_id, message_id):
			print("Queue size", queue.qsize())  # debug

			subs = self.h_subscribers

			# get a hex-created folder name
			DB_folder_name = subs.get_param(chat_id, "folder_token")

			if telegramHigh.isDocument(update):
				# for documents, preserve original filename. It already has an extension.
				full_filename = bot.getDocumentFileName(update)
			else:
				# if not a document, name a file with a datestamp. (Photo objects have weird filenames)
				file_name = datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
				# get an extension
				file_ext = bot.getFileExt(update)
				# sum them to get a full file name
				full_filename = file_name + file_ext

			# create a full path to the file in a temporary folder without extension
			full_filepath = path.join("/tmp", DB_folder_name, full_filename)
			# full path without file name
			full_dir_path = path.dirname(full_filepath)

			# download photo to temporary folder.
			while True:
				try:
					bot.downloadFile(bot.getFileID(update), custom_filepath=full_filepath)
					break
				except Exception:
					logging.error("Could not download photo, retrying. Traceback:\n" + full_traceback())
					sleep(5)
					pass

			# change to file's dir
			os.chdir(full_dir_path)

			# sometimes a file is downloaded with a different name. verify that it exists and renme if the name is wrong
			if not path.isfile(full_filepath):
				# list of files in a directory
				onlyfiles = [fle for fle in listdir(full_dir_path) if path.isfile(fle)]
				# Get the latest file in the directory
				wrong_file = max(onlyfiles, key=path.getctime)
				# Rename it
				os.rename(wrong_file, full_filename)

			# upload to dropbox
			while True:
				try:
					# WARNING: files_upload is not usable for files over 140 MB
					self.dbx.files_upload(
							open(full_filepath, 'rb'),  # open file
							"/" + DB_folder_name + "/" + full_filename,  # set path in dropbox
							autorename=True
					)
					break
				except Exception:
					logging.error("Could not upload to Dropbox, retrying. Traceback:\n" + full_traceback())
					sleep(5)

			# confirmation message
			bot.sendMessage(chat_id=chat_id, message="Photo uploaded!", reply_to=message_id)

			# remove all files from temp folder
			for i in listdir(full_dir_path):
				os.remove(i)

			# remove the data about this photo and update queue file
			self.queue_saver.pop_first(save=True)