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. # Get network of the file
  168. self._network = os.getenv("NETWORK")
  169.  
  170. # The file is not yet committed. You will need to commit it
  171. # before trying to move it. If we do not have authentication
  172. # assume that auto commit is enabled
  173. self._committed = False
  174. if not self._authentication_available:
  175. self._committed = True
  176. else:
  177. self.commit ()
  178.  
  179. # Construct the path of the file; this will be the real
  180. # path after it will be committed!
  181. self._dest_path = os.path.join(os.getenv("HOME"), self._incoming)
  182. self._dest_path = os.path.join(self._dest_path, self._filename)
  183.  
  184. # It seems that mldonkey can confuse about directory and files.
  185. if not os.path.exists(self._dest_path) and "directories" in self._dest_path:
  186. self._dest_path = self._dest_path.replace("directories", "files")
  187. if not os.path.exists(self._dest_path) and "files" in self._dest_path:
  188. self._dest_path = self._dest_path.replace("files", "directories")
  189.  
  190. # If we get called with a non-existant file as argument that
  191. # is really a problem.
  192. if not os.path.exists(self._dest_path):
  193. self._notify_error ("Selected file does not exists: %s" % self._dest_path)
  194.  
  195. try:
  196. self._type = FileType(self._filename)
  197. except Exception, e:
  198. self._type = "other"
  199.  
  200.  
  201. def __repr__(self):
  202. return "<Download '%s'>" % self._filename
  203.  
  204. def _authentication_command (self):
  205. if not self._authentication_available:
  206. self._notify_error("Authentication data is not available, I can't authenticate to mldonkey")
  207. return None
  208. return "auth %s %s" % (self._username, self._password)
  209.  
  210. def commit(self):
  211. """Commit the file, i.e. save it to the hard disk
  212. in its final position. This should be the first
  213. thing you do"""
  214.  
  215. authentication = self._authentication_command ()
  216. if not authentication:
  217. return None
  218.  
  219. commands = [ authentication,
  220. "commit" ]
  221. self.send_command (commands)
  222. self._committed = True
  223.  
  224.  
  225.  
  226. def send_command(self, command_list):
  227. """You can send a command, or a list of command
  228. to the daemon. Note that the every call to this
  229. function will open a connection to the daemon, so
  230. you will need to authenticate every time.
  231. """
  232. if isinstance(command_list, str):
  233. command_list = [ command_list ]
  234.  
  235. # Open the connection
  236. try:
  237. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  238. s.connect(("localhost", 4000))
  239. except Exception, e:
  240. self._notify_error("Unable to connect to mldonkey daemon: %s" % e)
  241.  
  242. # Costruct the command line
  243. command_line = "\n".join(command_list)
  244. # and execute it
  245. s.send(command_line + "\n")
  246.  
  247. # Cleanup
  248. s.send("quit\n")
  249. s.close ()
  250.  
  251. def move(self, destination_folder, filename = None):
  252. """Move the file to destination. destination_folder MUST be
  253. a folder. You could change the filename with the optional
  254. filename parameter"""
  255.  
  256. if not filename:
  257. filename = self._filename
  258.  
  259. # Assicuriamoci che il file sia stato creato
  260. if not self._committed:
  261. self.commit ()
  262.  
  263. # Be sure that this is a directory
  264. if not destination_folder.endswith(os.path.sep):
  265. destination_folder += os.path.sep
  266.  
  267. if not os.path.exists(destination_folder):
  268. self._notify_error("Destination directory %s does not exists" % destination_folder)
  269. return
  270.  
  271. # Move the downladed file
  272. shutil.move (self._dest_path, destination_folder + filename)
  273.  
  274. # If the file was downloaded via Bittorrent try to symlink the file back
  275. # in the incoming folder so mldonkey does not stop seeding
  276. if self._network == "BitTorrent":
  277. os.symlink (destination_folder + filename, self._dest_path)
  278.  
  279. # Update _dest_path
  280. self._dest_path = destination_folder + filename
  281.  
  282. def copy(self, destination, track = False):
  283. """
  284. Copy the file to another destination. Destination could be a folder
  285. to move the file in, or a complete path. The script will keep track
  286. only of the original file, i.e. if you call move() it will move the
  287. original file; if this is not what you want, move() the file to the
  288. right location and then copy() it around."""
  289.  
  290. if not self._committed:
  291. self.commit()
  292.  
  293. shutil.copy(self._dest_path, destination)
  294.  
  295. def make_group_writable(self):
  296. """
  297. Chmod the file so that group users can move it. This can be useful
  298. because often mldonkey user is not the user that needs to organize
  299. the downloads
  300. """
  301. os.chmod(self._dest_path, stat.S_IRGRP)
  302. os.chmod(self._dest_path, stat.S_IWGRP)
  303.  
  304. def make_public(self):
  305. """Make the file public, i.e. let anyone modify it."""
  306. os.chmod(self._dest_path, stat.S_IROTH)
  307. os.chmod(self._dest_path, stat.S_IWOTH)
  308.  
  309. def rsync(self, remote_destination):
  310. """Rsync the file to the remote destination. There must be an ssh key
  311. in the remote server otherwise nothing will happen. The script will
  312. automatically try a bunch of time to retransfer the file if
  313. the connection fail."""
  314. if not self._committed:
  315. self.commit ()
  316.  
  317. errors = ""
  318.  
  319. # Initialize internal counter of the times we have tried to move the file
  320. self._rsync_counter = 0
  321. s = subprocess.Popen("rsync --partial -zrLptgoD --compress-level=9 \"%s\" \"%s\"" % (self._dest_path,
  322. remote_destination),
  323. shell = True, stderr = subprocess.PIPE, stdout = subprocess.PIPE)
  324.  
  325. errors += "\n" + s.communicate ()[1]
  326. ret_code = s.wait ()
  327.  
  328. # If we fail call this funtion recursively to retry...wait for 60 seconds and then go (it could
  329. # be only a network problem)
  330. if ret_code != 0:
  331. self._rsync_counter += 1
  332. if self._rsync_counter < rsync_tries:
  333. time.sleep (60)
  334. self.rsync(remote_destination)
  335. else:
  336. self._notify_error("Rsync transfer of file %s failed more than %s times, aborting\n\n%s" % (self._filename, rsync_tries, errors))
  337.  
  338. def _notify_error(self, message):
  339. """Notify error via email"""
  340. self._send_email (error_recipients, "[mlmanager] An error occurred",
  341. message)
  342.  
  343. def notify_email(self, recipients, subject, message):
  344. """Notify something to some people via email"""
  345. self._send_email (recipients, subject, message)
  346.  
  347. def _send_email(self, recipients, subject, message):
  348. """Low level function to send an e-mail."""
  349.  
  350. msg = MIMEText(message)
  351. msg.set_charset ("utf-8")
  352. msg['From'] = from_addr
  353.  
  354. # If recipients is a string make it a list
  355. if isinstance(recipients, str):
  356. recipients = [ recipients ]
  357.  
  358. # Add user email if requested, and if present in the
  359. # profile of the user
  360. if "owner" in recipients:
  361. recipients.remove("owner")
  362. if self._user_email is not None:
  363. recipients.append(self._user_email)
  364.  
  365. msg['To'] = ", ".join(recipients)
  366. msg['Subject'] = subject
  367.  
  368. # Obtain message data
  369. data = msg.as_string ()
  370.  
  371. # Open a connection to the SMTP server
  372. try:
  373. s = smtplib.SMTP( host = mail_server )
  374. s.sendmail (from_addr, recipients, data)
  375. s.quit ()
  376. except Exception, e:
  377. raise RuntimeError("Error while notifying you of an error: %s" % e)
  378.  
  379. def is_in_group(self, group):
  380. """Return True if file is part of the selected group,
  381. False otherwise"""
  382. return (self._group == group)
  383.  
  384.  
  385. def get_type(self):
  386. """
  387. Return the type of the selected file, it could be
  388. video, audio, image, cdimage, archive or other, if none matches.
  389. """
  390. return str(self._type)
  391.  
  392. def get_filename(self):
  393. """Return filename"""
  394. return self._filename
  395.  
  396. def get_group(self):
  397. """Return group"""
  398. return self._group
  399.  
  400. def get_user(self):
  401. """Return duration"""
  402. return self._owner
  403.  
  404. def get_duration(self):
  405. """
  406. Obtain the duration as a tuple (hours, minutes, seconds)
  407. """
  408. d = int(self._duration)
  409. seconds = d % 60
  410. minutes = (d - seconds)/60 % 60
  411. hours = (d - seconds - 60*minutes)/3600
  412.  
  413. return (hours, minutes, seconds)
  414.