!c99Shell v. 1.0 pre-release build #16!

Software: Apache/2.2.3 (CentOS). PHP/5.1.6 

uname -a: Linux mx-ll-110-164-51-230.static.3bb.co.th 2.6.18-194.el5PAE #1 SMP Fri Apr 2 15:37:44
EDT 2010 i686
 

uid=48(apache) gid=48(apache) groups=48(apache) 

Safe-mode: OFF (not secure)

/usr/lib/rhythmbox/plugins/magnatune/   drwxr-xr-x
Free 51.91 GB of 127.8 GB (40.62%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     MagnatuneSource.py (21.93 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# -*- Mode: python; coding: utf-8; tab-width: 8; indent-tabs-mode: t; -*-
#
# Copyright (C) 2006 Adam Zimmerman  <adam_zimmerman@sfu.ca>
# Copyright (C) 2006 James Livingston  <doclivingston@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# The Rhythmbox authors hereby grants permission for non-GPL compatible
# GStreamer plugins to be used and distributed together with GStreamer
# and Rhythmbox. This permission is above and beyond the permissions granted
# by the GPL license by which Rhythmbox is covered. If you modify this code
# you may extend this exception to your version of the code, but you are not
# obligated to do so. If you do not wish to do so, delete this exception
# statement from your version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.

import rb, rhythmdb
from TrackListHandler import TrackListHandler
from BuyAlbumHandler import BuyAlbumHandler, MagnatunePurchaseError

import gobject
import gtk.glade
import gnomevfs, gnome, gconf
import xml
import urllib, zipfile

has_gnome_keyring = False

#try:
#    import gnomekeyring
#    has_gnome_keyring = True
#except:
#    pass


magnatune_partner_id = "rhythmbox"

# URIs
magnatune_dir = gnome.user_dir_get() + "rhythmbox/magnatune/"
magnatune_song_info_uri = gnomevfs.URI("http://magnatune.com/info/song_info_xml.zip")
local_song_info_uri = gnomevfs.URI(magnatune_dir + "song_info.xml")
local_song_info_temp_uri = gnomevfs.URI(magnatune_dir + "song_info.xml.zip.tmp")
ALBUM_ART_URL = 'http://www.magnatune.com/music/%s/%s/cover.jpg'

class MagnatuneSource(rb.BrowserSource):
    __gproperties__ = {
        'plugin': (rb.Plugin, 'plugin', 'plugin', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
    }

    __client = gconf.client_get_default()


    def __init__(self):

        rb.BrowserSource.__init__(self, name=_("Magnatune"))
        self.__db = None

        # track data
        self.__sku_dict = {}
        self.__home_dict = {}
        self.__buy_dict = {}
        self.__art_dict = {}

        # catalogue stuff
        self.__activated = False
        self.__notify_id = 0
        self.__update_id = 0
        self.__xfer_handle = None
        self.__info_screen = None
        self.__updating = True
        self.__has_loaded = False
        self.__load_handle = None
        self.__load_current_size = 0
        self.__load_total_size = 0

        self.__downloads = {} # keeps track of amount downloaded for each file
        self.__downloading = False # keeps track of whether we are currently downloading an album
        self.__download_progress = 0.0 # progress of current download(s)
        self.purchase_filesize = 0 # total amount of bytes to download


    def do_set_property(self, property, value):
        if property.name == 'plugin':
            self.__plugin = value
        else:
            raise AttributeError, 'unknown property %s' % property.name

    #
    # RBSource methods
    #

    def do_impl_show_entry_popup(self):
        self.show_source_popup ("/MagnatuneSourceViewPopup")

    def do_impl_get_status(self):
        if self.__updating:
            if self.__load_total_size > 0:
                progress = min (float(self.__load_current_size) / self.__load_total_size, 1.0)
            else:
                progress = -1.0
            return (_("Loading Magnatune catalogue"), None, progress)
        elif self.__downloading:
            progress = min (self.__download_progress, 1.0)
            return (_("Downloading Magnatune Album(s)"), None, progress)
        else:
            qm = self.get_property("query-model")
            return (qm.compute_status_normal("%d song", "%d songs"), None, 0.0)

    def do_impl_get_ui_actions(self):
        return ["MagnatunePurchaseAlbum",
            "MagnatunePurchaseCD",
            "MagnatuneArtistInfo",
            "MagnatuneCancelDownload"]

    def do_impl_activate(self):
        if not self.__activated:
            shell = self.get_property('shell')
            self.__db = shell.get_property('db')
            self.__entry_type = self.get_property('entry-type')

            self.__activated = True
            self.__show_loading_screen (True)
            self.__load_catalogue()

            # start our catalogue updates
            self.__update_id = gobject.timeout_add(6 * 60 * 60 * 1000, self.__update_catalogue)
            self.__update_catalogue()

            self.get_entry_view().set_sorting_type(self.__client.get_string("/apps/rhythmbox/plugins/magnatune/sorting"))

        rb.BrowserSource.do_impl_activate (self)

    def do_impl_get_browser_key (self):
        return "/apps/rhythmbox/plugins/magnatune/show_browser"

    def do_impl_get_paned_key (self):
        return "/apps/rhythmbox/plugins/magnatune/paned_position"

    def do_impl_pack_paned (self, paned):
        self.__paned_box = gtk.VBox(False, 5)
        self.pack_start(self.__paned_box)
        self.__paned_box.pack_start(paned)


    def do_impl_delete_thyself(self):
        if self.__update_id != 0:
            gobject.source_remove (self.__update_id)
            self.__update_id = 0

        if self.__notify_id != 0:
            gobject.source_remove (self.__notify_id)
            self.__notify_id = 0

        if self.__xfer_handle is not None:
            self.__xfer_handle.cancel()
            self.__xfer_handle = None

        self.__client.set_string("/apps/rhythmbox/plugins/magnatune/sorting", self.get_entry_view().get_sorting_type())

        rb.BrowserSource.do_impl_delete_thyself (self)

    #
    # methods for use by plugin and UI
    #

    def display_artist_info(self):
        tracks = self.get_entry_view().get_selected_entries()
        urls = set([])

        for tr in tracks:
            sku = self.__sku_dict[self.__db.entry_get(tr, rhythmdb.PROP_LOCATION)]
            url = self.__home_dict[sku]
            if url not in urls:
                gnomevfs.url_show(url)
                urls.add(url)

    def buy_cd(self):
        tracks = self.get_entry_view().get_selected_entries()
        urls = set([])

        for tr in tracks:
            sku = self.__sku_dict[self.__db.entry_get(tr, rhythmdb.PROP_LOCATION)]
            url = self.__buy_dict[sku]
            if url not in urls:
                gnomevfs.url_show(url)
                urls.add(url)

    def radio_toggled(self, gladexml):
        gc = gladexml.get_widget("radio_gc").get_active()
        gladexml.get_widget("remember_cc_details").set_sensitive(not gc)
        gladexml.get_widget("name_entry").set_sensitive(not gc)
        gladexml.get_widget("cc_entry").set_sensitive(not gc)
        gladexml.get_widget("mm_entry").set_sensitive(not gc)
        gladexml.get_widget("yy_entry").set_sensitive(not gc)
        
        gladexml.get_widget("gc_entry").set_sensitive(gc)
        if not gc:
            gladexml.get_widget("gc_entry").set_text("")
    
    def purchase_album(self):
        try:
            library_location = self.__client.get_list("/apps/rhythmbox/library_locations", gconf.VALUE_STRING)[0] # Just use the first library location
        except IndexError, e:
            rb.error_dialog(title = _("Couldn't purchase album"),
                        message = _("You must have a library location set to purchase an album."))
            return

        tracks = self.get_entry_view().get_selected_entries()
        skus = []

        for track in tracks:
            sku = self.__sku_dict[self.__db.entry_get(track, rhythmdb.PROP_LOCATION)]
            if sku in skus:
                continue
            skus.append(sku)
            artist = self.__db.entry_get(track, rhythmdb.PROP_ARTIST)
            album = self.__db.entry_get(track, rhythmdb.PROP_ALBUM)

            gladexml = gtk.glade.XML(self.__plugin.find_file("magnatune-purchase.glade"))
            cb_dict = {"rb_magnatune_on_radio_cc_toggled_cb":lambda w:self.radio_toggled(gladexml)}
            gladexml.signal_autoconnect(cb_dict)
            
            gladexml.get_widget("gc_entry").set_sensitive(False)
            gladexml.get_widget("pay_combobox").set_active(self.__client.get_int(self.__plugin.gconf_keys['pay']) - 5)
            gladexml.get_widget("audio_combobox").set_active(self.__plugin.format_list.index(self.__client.get_string(self.__plugin.gconf_keys['format'])))
            gladexml.get_widget("info_label").set_markup(_("Would you like to purchase the album <i>%(album)s</i> by '%(artist)s'?") % {"album":album, "artist":artist})
            gladexml.get_widget("remember_cc_details").props.visible = has_gnome_keyring

            try:
                (ccnumber, ccyear, ccmonth, name, email) = self.__plugin.get_cc_details()
                gladexml.get_widget("cc_entry").set_text(ccnumber)
                gladexml.get_widget("yy_entry").set_text(ccyear)
                gladexml.get_widget("mm_entry").set_active(ccmonth-1)
                gladexml.get_widget("name_entry").set_text(name)
                gladexml.get_widget("email_entry").set_text(email)

                gladexml.get_widget("remember_cc_details").set_active(True)
            except Exception, e:
                print e

                gladexml.get_widget("cc_entry").set_text("")
                gladexml.get_widget("yy_entry").set_text("")
                gladexml.get_widget("mm_entry").set_active(0)
                gladexml.get_widget("name_entry").set_text("")
                gladexml.get_widget("email_entry").set_text("")

                gladexml.get_widget("remember_cc_details").set_active(False)

            window = gladexml.get_widget("purchase_dialog")
            if window.run() == gtk.RESPONSE_ACCEPT:
                amount = gladexml.get_widget("pay_combobox").get_active() + 5
                format = self.__plugin.format_list[gladexml.get_widget("audio_combobox").get_active()]
                ccnumber = gladexml.get_widget("cc_entry").get_text()
                ccyear = gladexml.get_widget("yy_entry").get_text()
                ccmonth = str(gladexml.get_widget("mm_entry").get_active() + 1).zfill(2)
                name = gladexml.get_widget("name_entry").get_text()
                email = gladexml.get_widget("email_entry").get_text()
                gc = gladexml.get_widget("radio_gc").get_active()
                gc_text = gladexml.get_widget("gc_entry").get_text()

                if gladexml.get_widget("remember_cc_details").props.active:
                    self.__plugin.store_cc_details(ccnumber, ccyear, ccmonth, name, email)
                else:
                    self.__plugin.clear_cc_details()

                self.__buy_album (sku, amount, format, ccnumber, ccyear, ccmonth, name, email, gc, gc_text)

            window.destroy()

    #
    # internal catalogue downloading and loading
    #
    def __load_catalogue_read_cb (self, handle, data, exc_type, bytes_requested, parser):
        if exc_type:
            if issubclass (exc_type, gnomevfs.EOFError):
                def finish_loadscreen():
                    # successfully loaded
                    gtk.gdk.threads_enter()
                    self.__show_loading_screen (False)

                    in_progress_dir = gnomevfs.DirectoryHandle(gnomevfs.URI(magnatune_dir))
                    in_progress = in_progress_dir.next()
                    while True:
                        if in_progress.name[0:12] == "in_progress_":
                            in_progress = gnomevfs.read_entire_file(magnatune_dir + in_progress.name)
                            for uri in in_progress.split("\n"):
                                if uri == '':
                                    continue
                                self.__download_album(gnomevfs.URI(uri))
                        try:
                            in_progress = in_progress_dir.next()
                        except:
                            break
                    gtk.gdk.threads_leave()
                gobject.idle_add (finish_loadscreen)
            else:
                # error reading file
                raise exc_type

            parser.close()
            handle.close(lambda handle, exc: None) # FIXME: report it?
            self.__load_handle = None
            self.__updating = False
            self.__notify_status_changed()
         else:

            parser.feed(data)
            handle.read(64 * 1024, self.__load_catalogue_read_cb, parser)

        self.__notify_status_changed()

    def __load_catalogue_open_cb (self, handle, exc_type):
        if exc_type:
            self.__load_handle = None
            self.__notify_status_changed()

            if gnomevfs.exists(local_song_info_uri):
                raise exc_type
            else:
                return

        parser = xml.sax.make_parser()
        parser.setContentHandler(TrackListHandler(self.__db, self.__entry_type, self.__sku_dict, self.__home_dict, self.__buy_dict, self.__art_dict))
        handle.read (64 * 1024, self.__load_catalogue_read_cb, parser)

    def __load_catalogue(self):
        self.__notify_status_changed()
        self.__load_handle = gnomevfs.async.open (local_song_info_uri, self.__load_catalogue_open_cb)

    def __find_song_info(self, catalogue):
        for info in catalogue.infolist():
            if info.filename.endswith("song_info.xml"):
                return info.filename;
        return None

    def __download_update_cb (self, _reserved, info, moving):
        self.__load_current_size = info.bytes_copied
        self.__load_total_size = info.bytes_total
        self.__notify_status_changed()

        if info.phase == gnomevfs.XFER_PHASE_COMPLETED:
            # done downloading, unzip to real location
            catalog = zipfile.ZipFile(local_song_info_temp_uri.path)
            out = create_if_needed(local_song_info_uri, gnomevfs.OPEN_WRITE)
            filename = self.__find_song_info(catalog)
            if filename is None:
                rb.error_dialog(title="Unable to load catalogue", message=_("Rhythmbox could not understand the Magnatune catalogue, please file a bug."))
                return
            out.write(catalog.read(filename))
            out.close()
            catalog.close()
            gnomevfs.unlink(local_song_info_temp_uri)
            self.__updating = False
            self.__load_catalogue()
            self.__xfer_handle = None
        else:
            #print info
            pass

        return 1

    def __download_catalogue(self):
        self.__updating = True
        create_if_needed(local_song_info_temp_uri, gnomevfs.OPEN_WRITE).close()
        self.__xfer_handle = gnomevfs.async.xfer (source_uri_list = [magnatune_song_info_uri],
                              target_uri_list = [local_song_info_temp_uri],
                              xfer_options = gnomevfs.XFER_FOLLOW_LINKS_RECURSIVE,
                              error_mode = gnomevfs.XFER_ERROR_MODE_ABORT,
                              overwrite_mode = gnomevfs.XFER_OVERWRITE_MODE_REPLACE,
                              progress_update_callback = self.__download_update_cb,
                              update_callback_data = False)
                              

    def __update_catalogue(self):
        def info_cb (handle, results):
            (remote_uri, remote_exc, remote_info) = results[0]
            (local_uri, local_exc, local_info) = results[1]

            if remote_exc:
                # error locating remote file
                print "error locating remote catalogue", remote_exc
            elif local_exc:
                if issubclass (local_exc, gnomevfs.NotFoundError):
                    # we haven't got it yet
                    print "no local copy of catalogue"
                    self.__download_catalogue()
                else:
                    # error locating local file
                    print "error locating local catalogue", local_exc
                    self.__download_catalogue()
            else:
                try:
                    if remote_info.mtime > local_info.mtime:
                        # newer version available
                        self.__download_catalogue()
                    else:
                        # up to date
                        pass
                except ValueError, e:
                    # couldn't get the mtimes. download?
                    print "error checking times", e
                    self.__download_catalogue()
            return

        gnomevfs.async.get_file_info ((magnatune_song_info_uri, local_song_info_uri), info_cb)

    def __show_loading_screen(self, show):
        if self.__info_screen is None:
            # load the glade stuff
            gladexml = gtk.glade.XML(self.__plugin.find_file("magnatune-loading.glade"), root="magnatune_loading_scrolledwindow")
            self.__info_screen = gladexml.get_widget("magnatune_loading_scrolledwindow")
            self.pack_start(self.__info_screen)
            self.get_entry_view().set_no_show_all (True)
            self.__info_screen.set_no_show_all (True)

        self.__info_screen.set_property("visible", show)
        self.__paned_box.set_property("visible", not show)

    def __notify_status_changed(self):
        def change_idle_cb():
            self.notify_status_changed()
            self.__notify_id = 0
            return False

        if self.__notify_id == 0:
            self.__notify_id = gobject.idle_add(change_idle_cb)

    #
    # internal purchasing code
    #
    def __buy_album(self, sku, pay, format, ccnumber, ccyear, ccmonth, name, email, gc, gc_text): # http://magnatune.com/info/api#purchase
        print "purchasing tracks:", sku, pay, format, name, email
        url_dict = {
                        'id':    magnatune_partner_id,
                        'sku':    sku,
                        'amount': pay,
                        'name': name,
                        'email':email
            }
        if gc:
            url_dict['gc'] = gc
        else:
            url_dict['cc'] = ccnumber
            url_dict['yy'] = ccyear
            url_dict['mm'] = ccmonth
        url = "https://magnatune.com/buy/buy_dl_cc_xml?"
        url = url + urllib.urlencode(url_dict)

        buy_album_handler = BuyAlbumHandler(format) # so we can get the url and auth info
        auth_parser = xml.sax.make_parser()
        auth_parser.setContentHandler(buy_album_handler)

        self.__wait_dlg = gtk.Dialog(title="Authorizing Purchase", flags=gtk.DIALOG_NO_SEPARATOR|gtk.DIALOG_DESTROY_WITH_PARENT)
        lbl = gtk.Label("Authorizing purchase with the Magnatune server. Please wait...")
        self.__wait_dlg.vbox.pack_start(lbl)
        lbl.show()
        self.__wait_dlg.show()
        gnomevfs.async.open(gnomevfs.URI(url), self.__auth_open_cb, data=(buy_album_handler, auth_parser))

    def __auth_open_cb(self, handle, exc_type, data):
        if exc_type:
            raise exc_type

        handle.read(64 * 1024, self.__auth_read_cb, data)


    def __auth_read_cb (self, handle, data, exc_type, bytes_requested, parser):
        buy_album_handler = parser[0]
        auth_parser = parser[1]
        data = data.replace("<br>", "") # get rid of any stray <br> tags that will mess up the parser
        if exc_type:
            if issubclass (exc_type, gnomevfs.EOFError):
                def start_download ():
                    # successfully loaded
                    gtk.gdk.threads_enter()
                    audio_dl_uri = gnomevfs.URI(buy_album_handler.url)
                    audio_dl_uri = gnomevfs.URI(buy_album_handler.url[0:buy_album_handler.url.rfind("/") + 1] + urllib.quote(audio_dl_uri.short_name))
                    audio_dl_uri.user_name = str(buy_album_handler.username) # URI objects don't like unicode strings
                    audio_dl_uri.password = str(buy_album_handler.password)

                    in_progress = create_if_needed(gnomevfs.URI(magnatune_dir + "in_progress_" + audio_dl_uri.short_name), gnomevfs.OPEN_WRITE)
                    in_progress.write(str(audio_dl_uri))
                    in_progress.close()
                    self.__download_album(audio_dl_uri)
                    self.__wait_dlg.destroy()
                    gtk.gdk.threads_leave()
                gobject.idle_add (start_download)
            else:
                # error reading file
                raise exc_type

            auth_parser.close()
            handle.close(lambda handle, exc: None) # FIXME: report it?

         else:
            try :
                print data
                auth_parser.feed(data)
                handle.read(64 * 1024, self.__auth_read_cb, parser)
            except MagnatunePurchaseError, e:
                self.__wait_dlg.destroy()
                rb.error_dialog(title = _("Purchase Error"),
                        message = _("An error occurred while trying to purchase the album.\nThe Magnatune server returned:\n%s") % str(e))
            except Exception, e:
                self.__wait_dlg.destroy()
                rb.error_dialog(title = _("Error"),
                        message = _("An error occurred while trying to purchase the album.\nThe error text is:\n%s") % str(e))

    def __download_album(self, audio_dl_uri):
            library_location = self.__client.get_list("/apps/rhythmbox/library_locations", gconf.VALUE_STRING)[0] # Just use the first library location
            to_file_uri = gnomevfs.URI(magnatune_dir + audio_dl_uri.short_name)

            shell = self.get_property('shell')
            manager = shell.get_player().get_property('ui-manager')
            manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(True)
            self.__downloading = True
            self.cancelled = False
            gtk.gdk.threads_leave()
            self.purchase_filesize += gnomevfs.get_file_info(audio_dl_uri).size
            gtk.gdk.threads_enter()
            create_if_needed(to_file_uri, gnomevfs.OPEN_WRITE).close()
            gnomevfs.async.xfer (source_uri_list = [audio_dl_uri],
                            target_uri_list = [to_file_uri],
                            xfer_options = gnomevfs.XFER_FOLLOW_LINKS_RECURSIVE,
                            error_mode = gnomevfs.XFER_ERROR_MODE_ABORT,
                            overwrite_mode = gnomevfs.XFER_OVERWRITE_MODE_REPLACE,
                            progress_update_callback = self.__purchase_download_update_cb,
                            update_callback_data = (to_file_uri, library_location, audio_dl_uri),
                            progress_sync_callback = self.__purchase_download_progress_cb,
                            sync_callback_data = (to_file_uri, audio_dl_uri))

    def __purchase_download_update_cb(self, _reserved, info, data):
        if (info.phase == gnomevfs.XFER_PHASE_COMPLETED):
            to_file_uri = data[0]
            library_location = data[1]
            audio_dl_uri = data[2]

            try:
                del self.__downloads[str(audio_dl_uri)]
            except:
                return 0
            self.purchase_filesize -= gnomevfs.get_file_info(audio_dl_uri).size
            album = zipfile.ZipFile(to_file_uri.path)
            for track in album.namelist():
                track_uri = gnomevfs.URI(library_location + "/" + track)
                out = create_if_needed(track_uri, gnomevfs.OPEN_WRITE)
                out.write(album.read(track))
                out.close()
            album.close()
            gnomevfs.unlink(gnomevfs.URI(magnatune_dir + "in_progress_" + to_file_uri.short_name))
            gnomevfs.unlink(to_file_uri)
            if self.purchase_filesize == 0:
                self.__downloading = False
            self.__db.add_uri("file://" + urllib.quote(track_uri.dirname))
        return 1

    def __purchase_download_progress_cb(self, info, data):
        to_file_uri = data[0]
        audio_dl_uri = data[1]

        if self.cancelled:
            try:
                del self.__downloads[str(audio_dl_uri)]
                self.purchase_filesize -= gnomevfs.get_file_info(audio_dl_uri).size
                gnomevfs.unlink(gnomevfs.URI(magnatune_dir + "in_progress_" + to_file_uri.short_name))
                gnomevfs.unlink(to_file_uri)
            except: # this may get run more than once
                pass
            if self.purchase_filesize == 0:
                self.__downloading = False
            return 0

        self.__downloads[str(audio_dl_uri)] = info.bytes_copied
        purchase_downloaded = 0
        for i in self.__downloads.values():
            purchase_downloaded += i
        self.__download_progress = purchase_downloaded / float(self.purchase_filesize)
        self.__notify_status_changed()
        return 1

    def cancel_downloads(self):
        self.cancelled = True
        shell = self.get_property('shell')
        manager = shell.get_player().get_property('ui-manager')
        manager.get_action("/MagnatuneSourceViewPopup/MagnatuneCancelDownload").set_sensitive(False)

    def playing_entry_changed (self, entry):
        if not self.__db or not entry:
            return

        if entry.get_entry_type() != self.__db.entry_type_get_by_name("MagnatuneEntryType"):
            return

        gobject.idle_add (self.emit_cover_art_uri, entry)

    def emit_cover_art_uri (self, entry):
        sku = self.__sku_dict[self.__db.entry_get(entry, rhythmdb.PROP_LOCATION)]
        url = self.__art_dict[sku]
        self.__db.emit_entry_extra_metadata_notify (entry, 'rb:coverArt-uri', url)
        return False

gobject.type_register(MagnatuneSource)


def create_if_needed(uri, mode):
    if not gnomevfs.exists(uri):
        for directory in URIIterator(uri):
            if not gnomevfs.exists(directory):
                gnomevfs.make_directory(directory, 0755)
        out = gnomevfs.create(uri, open_mode=mode)
    else:
        out = gnomevfs.open(uri, open_mode=mode)
    return out

class URIIterator:
    def __init__(self, uri):
        self.uri_list = uri.dirname.split("/")[1:] # dirname starts with /
        self.counter = 0
    def __iter__(self):
        return self
    def next(self):
        if self.counter == len(self.uri_list) + 1:
            raise StopIteration
        value = "file://"
        for i in range(self.counter):
            value += "/" + self.uri_list[i]
        self.counter += 1
        return gnomevfs.URI(value)

:: Command execute ::

Enter:
 
Select:
 

:: Shadow's tricks :D ::

Useful Commands
 
Warning. Kernel may be alerted using higher levels
Kernel Info:

:: Preddy's tricks :D ::

Php Safe-Mode Bypass (Read Files)

File:

eg: /etc/passwd

Php Safe-Mode Bypass (List Directories):

Dir:

eg: /etc/

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c999shell v. 1.0 pre-release build #16 Modded by Shadow & Preddy | RootShell Security Group | r57 c99 shell | Generation time: 0.0122 ]--