viewgit/index.php:465 Only variables should be passed by reference [2048]

viewgit/index.php:466 Non-static method GeSHi::get_language_name_from_extension() should not be called statically [2048]

  1. # -*- coding: utf-8 -*-
  2. #
  3. # mlmanager is a python package that aims to "organize"
  4. # your mldonkey downloads.
  5. #
  6. # You can easily write a script that take care of moving
  7. # a file in the right place and to write emails to the right
  8. # people that need to know about the download.
  9. #
  10. #
  11. # It is released under the GNU General Public License Version 3
  12. #
  13. # Author: Leonardo Robol <leo@robol.it>
  14. #
  15. #
  16. #
  17. # In this section of the file we set some internal variables to their
  18. # default value. Users can customize them after loading the package.
  19. #
  20. # The fully qualified (or not fully qualified - it really doesn't matter)
  21. # domain that the server is part of.
  22. domain = "example.com"
  23.  
  24. # This is the mail address that will be set as sender for all
  25. # the emails generated by the script.
  26. from_addr = "mldonkey <mldonkey@%s>" % domain
  27.  
  28. # Mail server that the script will use to deliver emails. It must be properly
  29. # configured to relay mail from the domain selected.
  30. mail_server = "localhost"
  31.  
  32. # Users that should be notified when an error occurs in the script. You
  33. # can use the wildcard "owner" to match the owner of the file downladed.
  34. # This is generally true for every email function in mlmanager
  35. error_recipients = [ "owner" ]
  36.  
  37. # Number of times that rsync should try to transfer the file before
  38. # giving up.
  39. rsync_tries = 5
  40.  
  41. # Set file extensions to match. You can add extensions in every category
  42. video_extensions = ['avi', 'mpeg', 'mpg', 'mkv', 'm2v', 'divx', 'xvid', 'mov']
  43. audio_extensions = ['mp3', 'ogg', 'wav', 'flac', 'aac' ]
  44. text_extensions = ['pdf', 'doc', 'odt', 'ods', 'odp', 'ppt', 'rtf',
  45. 'pps', 'xls' , 'txt' ]
  46. cdimage_extensions = [ 'iso', 'nrg', 'ccd']
  47. archive_extensions = [ 'rar', 'zip', '7z', 'tar.gz', 'tar.bz2', 'lzo' ]
  48.  
  49.  
  50. __author__ = "Leonardo Robol <leo@robol.it>"
  51.  
  52. import os, sys, socket, shutil, subprocess, time, smtplib, stat
  53. from email.mime.text import MIMEText
  54.  
  55. class FileType():
  56. """
  57. This class represent the type of a file, i.e you
  58. can check if it is a video, a text, an image...
  59. It can be:
  60. - video
  61. - audio
  62. - text
  63. - archive
  64. - other
  65. """
  66.  
  67. def __init__(self, filename):
  68. self._filename = filename
  69. self._detect_type ()
  70.  
  71.  
  72. def _test_extension(self, extension):
  73. return self._filename.lower().endswith(extension)
  74.  
  75. def _detect_type(self):
  76. """Detect the type of the file and save it in the internal
  77. varaible _type"""
  78. if len(filter(self._test_extension, video_extensions)) > 0:
  79. self._type = "video"
  80. elif len(filter(self._test_extension, audio_extensions)) > 0:
  81. self._type = "audio"
  82. elif len(filter(self._test_extension, text_extensions)) > 0:
  83. self._type = "text"
  84. elif len(filter(self._test_extension, cdimage_extensions)) > 0:
  85. self._type = "cdimage"
  86. elif len(filter(self._test_extension, archive_extensions)) > 0:
  87. self._type = "archive"
  88. else:
  89. self._type = "other"
  90.  
  91. def is_video(self):
  92. return (self._type == "video")
  93.  
  94. def is_image(self):
  95. return (self._type == "audio")
  96.  
  97. def is_text(self):
  98. return (self._type == "text")
  99.  
  100. def is_cdimage(self):
  101. return (self._type == "cdimage")
  102.  
  103. def is_archive(self):
  104. return (self._type == "archive")
  105.  
  106. def __str__(self):
  107. return self._type
  108.  
  109. def __repr__(self):
  110. return "<FileType '%s'>" % self._type
  111.  
  112.  
  113. class Download():
  114. """
  115. This class represent a file or a folder downloaded via mldonkey.
  116. You should create an instance of this calling
  117.  
  118. d = Download()
  119.  
  120. or, if you want
  121.  
  122. d = Download(username = "admin", password = "mysecretpassword")
  123.  
  124. This allow the script to connect to the mldonkey daemon and ensure
  125. that the file have been committed. It is not needed for mldonkey
  126. >= 2.7, but IT IS REQUIRED if you run an earlier mldonkey!
  127. """
  128.  
  129. def __init__(self, username = None, password = None, filename = None, group = None):
  130. """Perform some heuristic to determine the filetype,
  131. filename, groups and similar"""
  132.  
  133. # Set username and password
  134. self._username = username
  135. self._password = password
  136.  
  137. # If you do not provide username or password we can't
  138. # execute any command
  139. if not self._username or not self._password:
  140. self._authentication_available = False
  141.  
  142. self._filename = filename
  143. self._group = group
  144.  
  145. # If filename is not set then we can recover it
  146. # from the environment variables.
  147. if self._filename is None:
  148. self._filename = os.getenv("FILENAME")
  149.  
  150. # La durata del download in secondi
  151. self._duration = os.getenv("DURATION")
  152.  
  153. # Recover other data from environment
  154. if not self._group:
  155. self._group = os.getenv("FILE_GROUP")
  156.  
  157. self._owner = os.getenv("FILE_OWNER")
  158.  
  159. self._incoming = os.getenv("INCOMING")
  160.  
  161. # This could be none, and if it's empty
  162. # we should set it to None
  163. self._user_email = os.getenv("USER_EMAIL")
  164. if self._user_email is "":
  165. self._user_email = None
  166.  
  167. # The file is not yet committed. You will need to commit it
  168. # before trying to move it. If we do not have authentication
  169. # assume that auto commit is enabled
  170. self._committed = False
  171. if not self._authentication_available:
  172. self._committed = True
  173. else:
  174. self.commit ()
  175.  
  176. # Construct the path of the file; this will be the real
  177. # path after it will be committed!
  178. self._dest_path = os.path.join(os.getenv("HOME"), self._incoming)
  179. self._dest_path = os.path.join(self._dest_path, self._filename)
  180.  
  181. # It seems that mldonkey can confuse about directory and files.
  182. if not os.path.exists(self._dest_path) and "directories" in self._dest_path:
  183. self._dest_path = self._dest_path.replace("directories", "files")
  184. if not os.path.exists(self._dest_path) and "files" in self._dest_path:
  185. self._dest_path = self._dest_path.replace("files", "directories")
  186.  
  187. # If we get called with a non-existant file as argument that
  188. # is really a problem.
  189. if not os.path.exists(self._dest_path):
  190. self._notify_error ("Selected file does not exists: %s" % self._dest_path)
  191.  
  192. try:
  193. self._type = FileType(self._filename)
  194. except Exception, e:
  195. self._type = "other"
  196.  
  197.  
  198. def __repr__(self):
  199. return "<Download '%s'>" % self._filename
  200.  
  201. def _authentication_command (self):
  202. if not self._authentication_available:
  203. self._notify_error("Authentication data is not available, I can't authenticate to mldonkey")
  204. return None
  205. return "auth %s %s" % (self._username, self._password)
  206.  
  207. def commit(self):
  208. """Commit the file, i.e. save it to the hard disk
  209. in its final position. This should be the first
  210. thing you do"""
  211.  
  212. authentication = self._authentication_command ()
  213. if not authentication:
  214. return None
  215.  
  216. commands = [ authentication,
  217. "commit" ]
  218. self.send_command (commands)
  219. self._committed = True
  220.  
  221.  
  222.  
  223. def send_command(self, command_list):
  224. """You can send a command, or a list of command
  225. to the daemon. Note that the every call to this
  226. function will open a connection to the daemon, so
  227. you will need to authenticate every time.
  228. """
  229. if isinstance(command_list, str):
  230. command_list = [ command_list ]
  231.  
  232. # Open the connection
  233. try:
  234. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  235. s.connect(("localhost", 4000))
  236. except Exception, e:
  237. self._notify_error("Unable to connect to mldonkey daemon: %s" % e)
  238.  
  239. # Costruct the command line
  240. command_line = "\n".join(command_list)
  241. # and execute it
  242. s.send(command_line + "\n")
  243.  
  244. # Cleanup
  245. s.send("quit\n")
  246. s.close ()
  247.  
  248. def move(self, destination_folder, filename = None):
  249. """Move the file to destination. destination_folder MUST be
  250. a folder. You could change the filename with the optional
  251. filename parameter"""
  252.  
  253. if not filename:
  254. filename = self._filename
  255.  
  256. # Assicuriamoci che il file sia stato creato
  257. if not self._committed:
  258. self.commit ()
  259.  
  260. # Be sure that this is a directory
  261. if not destination_folder.endswith(os.path.sep):
  262. destination_folder += os.path.sep
  263.  
  264. if not os.path.exists(destination_folder):
  265. self._notify_error("Destination directory %s does not exists" % destination_folder)
  266. return
  267.  
  268. shutil.move (self._dest_path, destination_folder + filename)
  269.  
  270. # Update _dest_path
  271. self._dest_path = destination_folder + filename
  272.  
  273. def copy(self, destination, track = False):
  274. """
  275. Copy the file to another destination. Destination could be a folder
  276. to move the file in, or a complete path. The script will keep track
  277. only of the original file, i.e. if you call move() it will move the
  278. original file; if this is not what you want, move() the file to the
  279. right location and then copy() it around."""
  280.  
  281. if not self._committed:
  282. self.commit()
  283.  
  284. shutil.copy(self._dest_path, destination)
  285.  
  286. def make_group_writable(self):
  287. """
  288. Chmod the file so that group users can move it. This can be useful
  289. because often mldonkey user is not the user that needs to organize
  290. the downloads
  291. """
  292. os.chmod(self._dest_file, stat.S_IRGRP)
  293. os.chmod(self._dest_file, stat.S_IWGRP)
  294.  
  295. def make_public(self):
  296. """Make the file public, i.e. let anyone modify it."""
  297. os.chmod(self._dest_file, stat.S_IROTH)
  298. os.chmod(self._dest_file, stat.S_IWOTH)
  299.  
  300. def rsync(self, remote_destination):
  301. """Rsync the file to the remote destination. There must be an ssh key
  302. in the remote server otherwise nothing will happen. The script will
  303. automatically try a bunch of time to retransfer the file if
  304. the connection fail."""
  305. if not self._committed:
  306. self.commit ()
  307.  
  308. errors = ""
  309.  
  310. # Initialize internal counter of the times we have tried to move the file
  311. self._rsync_counter = 0
  312. s = subprocess.Popen("rsync --partial -az --compress-level=9 \"%s\" \"%s\"" % (self._dest_path,
  313. remote_destination),
  314. shell = True, stderr = subprocess.PIPE, stdout = subprocess.PIPE)
  315.  
  316. errors += "\n" + s.communicate ()[1]
  317. ret_code = s.wait ()
  318.  
  319. # If we fail call this funtion recursively to retry...wait for 60 seconds and then go (it could
  320. # be only a network problem)
  321. if ret_code != 0:
  322. self._rsync_counter += 1
  323. if self._rsync_counter < rsync_tries:
  324. time.sleep (60)
  325. self.rsync(remote_destination)
  326. else:
  327. self._notify_error("Rsync transfer of file %s failed more than 5 times, aborting\n\n%s" % (self._filename, errors))
  328.  
  329. def _notify_error(self, message):
  330. """Notify error via email"""
  331. self._send_email (error_recipients, "[mlmanager] An error occurred",
  332. message)
  333.  
  334. def notify_email(self, recipients, subject, message):
  335. """Notify something to some people via email"""
  336. self._send_email (recipients, subject, message)
  337.  
  338. def _send_email(self, recipients, subject, message):
  339. """Low level function to send an e-mail."""
  340.  
  341. msg = MIMEText(message)
  342. msg.set_charset ("utf-8")
  343. msg['From'] = from_addr
  344.  
  345. # If recipients is a string make it a list
  346. if isinstance(recipients, str):
  347. recipients = [ recipients ]
  348.  
  349. # Add user email if requested, and if present in the
  350. # profile of the user
  351. if "owner" in recipients:
  352. recipients.remove("owner")
  353. if self._user_email is not None:
  354. recipients.append(self._user_email)
  355.  
  356. msg['To'] = ", ".join(recipients)
  357. msg['Subject'] = subject
  358.  
  359. # Obtain message data
  360. data = msg.as_string ()
  361.  
  362. # Open a connection to the SMTP server
  363. try:
  364. s = smtplib.SMTP( host = mail_server )
  365. s.sendmail (from_addr, recipients, data)
  366. s.quit ()
  367. except Exception, e:
  368. raise RuntimeError("Error while notifying you of an error: %s" % e)
  369.  
  370. def is_in_group(self, group):
  371. """Return True if file is part of the selected group,
  372. False otherwise"""
  373. return (self._group == group)
  374.  
  375.  
  376. def get_type(self):
  377. """
  378. Return the type of the selected file, it could be
  379. video, audio, image, cdimage, archive or other, if none matches.
  380. """
  381. return str(self._type)
  382.  
  383. def get_filename(self):
  384. """Return filename"""
  385. return self._filename
  386.  
  387. def get_group(self):
  388. """Return group"""
  389. return self._group
  390.  
  391. def get_user(self):
  392. """Return duration"""
  393. return self._owner
  394.  
  395. def get_duration(self):
  396. """
  397. Obtain the duration as a tuple (hours, minutes, seconds)
  398. """
  399. d = int(self._duration)
  400. seconds = d % 60
  401. minutes = (d - seconds)/60 % 60
  402. hours = (d - seconds - 60*minutes)/3600
  403.  
  404. return (hours, minutes, seconds)
  405.