Example #1
0
def CATALOG_ENTRY(item,
                  item_kind,
                  request_context,
                  updated,
                  catalog_name,
                  ignore_count=False,
                  add_kind=False):
    id_ = 'calibre:category:' + item.name
    iid = 'N' + item.name
    if item.id is not None:
        iid = 'I' + unicode_type(item.id)
        iid += ':' + item_kind
    href = request_context.url_for('/opds/category',
                                   category=as_hex_unicode(catalog_name),
                                   which=as_hex_unicode(iid))
    link = NAVLINK(href=href)
    if ignore_count:
        count = ''
    else:
        count = ngettext('one book', '{} books', item.count).format(item.count)
    if item.use_sort_as_name:
        name = item.sort
    else:
        name = item.name
    return E.entry(TITLE(name + ('' if not add_kind else ' (%s)' % item_kind)),
                   ID(id_), UPDATED(updated), E.content(count, type='text'),
                   link)
Example #2
0
    def launch_worker(self, gui=False, redirect_output=None, job_name=None):
        start = time.monotonic()
        id = next(self.launched_worker_counter)
        fd, rfile = tempfile.mkstemp(prefix='ipc_result_%d_%d_' %
                                     (self.id, id),
                                     dir=base_dir(),
                                     suffix='.pickle')
        os.close(fd)
        if redirect_output is None:
            redirect_output = not gui

        env = {
            'CALIBRE_WORKER_ADDRESS':
            environ_item(as_hex_unicode(msgpack_dumps(self.address))),
            'CALIBRE_WORKER_KEY':
            environ_item(as_hex_unicode(self.auth_key)),
            'CALIBRE_WORKER_RESULT':
            environ_item(as_hex_unicode(rfile)),
        }
        cw = self.do_launch(env,
                            gui,
                            redirect_output,
                            rfile,
                            job_name=job_name)
        if isinstance(cw, string_or_bytes):
            raise CriticalError('Failed to launch worker process:\n' +
                                force_unicode(cw))
        if DEBUG:
            print(
                'Worker Launch took: {:.2f} seconds'.format(time.monotonic() -
                                                            start))
        return cw
Example #3
0
def CATALOG_GROUP_ENTRY(item, category, request_context, updated):
    id_ = 'calibre:category-group:' + category + ':' + item.text
    iid = item.text
    link = NAVLINK(
        href=request_context.url_for('/opds/categorygroup',
                                     category=as_hex_unicode(category),
                                     which=as_hex_unicode(iid)))
    return E.entry(
        TITLE(item.text), ID(id_), UPDATED(updated),
        E.content(ngettext('one item', '{} items',
                           item.count).format(item.count),
                  type='text'), link)
Example #4
0
def create_worker(env, priority='normal', cwd=None, func='main'):
    from calibre.utils.ipc.server import create_listener
    auth_key = os.urandom(32)
    address, listener = create_listener(auth_key)

    env = dict(env)
    env.update({
        'CALIBRE_WORKER_ADDRESS': environ_item(as_hex_unicode(msgpack_dumps(address))),
        'CALIBRE_WORKER_KEY': environ_item(as_hex_unicode(auth_key)),
        'CALIBRE_SIMPLE_WORKER': environ_item('calibre.utils.ipc.simple_worker:%s' % func),
    })

    w = Worker(env)
    w(cwd=cwd, priority=priority)
    return listener, w
Example #5
0
def create_worker(env, priority='normal', cwd=None, func='main'):
    from calibre.utils.ipc.server import create_listener
    auth_key = os.urandom(32)
    address, listener = create_listener(auth_key)

    env = dict(env)
    env.update({
        'CALIBRE_WORKER_ADDRESS': environ_item(as_hex_unicode(msgpack_dumps(address))),
        'CALIBRE_WORKER_KEY': environ_item(as_hex_unicode(auth_key)),
        'CALIBRE_SIMPLE_WORKER': environ_item('calibre.utils.ipc.simple_worker:%s' % func),
    })

    w = Worker(env)
    w(cwd=cwd, priority=priority)
    return listener, w
Example #6
0
 def env(self):
     env = os.environ.copy()
     env[native_string_type('CALIBRE_WORKER')] = environ_item('1')
     td = as_hex_unicode(msgpack_dumps(base_dir()))
     env[native_string_type('CALIBRE_WORKER_TEMP_DIR')] = environ_item(td)
     env.update(self._env)
     return env
Example #7
0
 def set_email_settings(self, to_set):
     from_ = unicode_type(self.email_from.text()).strip()
     if to_set and not from_:
         error_dialog(self, _('Bad configuration'),
                      _('You must set the From email address')).exec_()
         return False
     username = unicode_type(self.relay_username.text()).strip()
     password = unicode_type(self.relay_password.text()).strip()
     host = unicode_type(self.relay_host.text()).strip()
     enc_method = ('TLS' if self.relay_tls.isChecked() else 'SSL'
             if self.relay_ssl.isChecked() else 'NONE')
     if host:
         # Validate input
         if ((username and not password) or (not username and password)):
             error_dialog(self, _('Bad configuration'),
                         _('You must either set both the username <b>and</b> password for '
                         'the mail server or no username and no password at all.')).exec_()
             return False
         if not (username and password) and not question_dialog(
                 self, _('Are you sure?'),
                 _('No username and password set for mailserver. Most '
                   ' mailservers need a username and password. Are you sure?')):
             return False
     conf = smtp_prefs()
     conf.set('from_', from_)
     conf.set('relay_host', host if host else None)
     conf.set('relay_port', self.relay_port.value())
     conf.set('relay_username', username if username else None)
     conf.set('relay_password', as_hex_unicode(password))
     conf.set('encryption', enc_method)
     return True
Example #8
0
def windows_repair(library_path=None):
    import subprocess
    from calibre.utils.serialize import json_dumps, json_loads
    from polyglot.binary import as_hex_unicode, from_hex_bytes
    if library_path:
        library_path = as_hex_unicode(json_dumps(library_path))
        winutil.prepare_for_restart()
        os.environ['CALIBRE_REPAIR_CORRUPTED_DB'] = environ_item(library_path)
        subprocess.Popen([sys.executable])
    else:
        try:
            app = Application([])
            from calibre.gui2.dialogs.restore_library import repair_library_at
            library_path = json_loads(
                from_hex_bytes(os.environ.pop('CALIBRE_REPAIR_CORRUPTED_DB')))
            done = repair_library_at(library_path, wait_time=4)
        except Exception:
            done = False
            error_dialog(
                None,
                _('Failed to repair library'),
                _('Could not repair library. Click "Show details" for more information.'
                  ),
                det_msg=traceback.format_exc(),
                show=True)
        if done:
            subprocess.Popen([sys.executable])
        app.quit()
Example #9
0
 def env(self):
     if ispy3:
         env = os.environ.copy()
     else:
         # We use this inefficient method of copying the environment variables
         # because of non ascii env vars on windows. See https://bugs.launchpad.net/bugs/811191
         env = {}
         for key in os.environ:
             try:
                 val = os.environ[key]
                 if isinstance(val, unicode_type):
                     # On windows subprocess cannot handle unicode env vars
                     try:
                         val = val.encode(filesystem_encoding)
                     except ValueError:
                         val = val.encode('utf-8')
                 if isinstance(key, unicode_type):
                     key = key.encode('ascii')
                 env[key] = val
             except:
                 pass
     env[native_string_type('CALIBRE_WORKER')] = environ_item('1')
     td = as_hex_unicode(msgpack_dumps(base_dir()))
     env[native_string_type('CALIBRE_WORKER_TEMP_DIR')] = environ_item(td)
     env.update(self._env)
     return env
Example #10
0
 def set_email_settings(self, to_set):
     from_ = unicode_type(self.email_from.text()).strip()
     if to_set and not from_:
         error_dialog(self, _('Bad configuration'),
                      _('You must set the From email address')).exec_()
         return False
     username = unicode_type(self.relay_username.text()).strip()
     password = unicode_type(self.relay_password.text()).strip()
     host = unicode_type(self.relay_host.text()).strip()
     enc_method = ('TLS' if self.relay_tls.isChecked() else 'SSL'
             if self.relay_ssl.isChecked() else 'NONE')
     if host:
         # Validate input
         if ((username and not password) or (not username and password)):
             error_dialog(self, _('Bad configuration'),
                         _('You must either set both the username <b>and</b> password for '
                         'the mail server or no username and no password at all.')).exec_()
             return False
         if not (username and password) and not question_dialog(
                 self, _('Are you sure?'),
                 _('No username and password set for mailserver. Most '
                   ' mailservers need a username and password. Are you sure?')):
             return False
     conf = smtp_prefs()
     conf.set('from_', from_)
     conf.set('relay_host', host if host else None)
     conf.set('relay_port', self.relay_port.value())
     conf.set('relay_username', username if username else None)
     conf.set('relay_password', as_hex_unicode(password))
     conf.set('encryption', enc_method)
     return True
Example #11
0
 def env(self):
     if ispy3:
         env = os.environ.copy()
     else:
         # We use this inefficient method of copying the environment variables
         # because of non ascii env vars on windows. See https://bugs.launchpad.net/bugs/811191
         env = {}
         for key in os.environ:
             try:
                 val = os.environ[key]
                 if isinstance(val, unicode_type):
                     # On windows subprocess cannot handle unicode env vars
                     try:
                         val = val.encode(filesystem_encoding)
                     except ValueError:
                         val = val.encode('utf-8')
                 if isinstance(key, unicode_type):
                     key = key.encode('ascii')
                 env[key] = val
             except:
                 pass
     env[native_string_type('CALIBRE_WORKER')] = environ_item('1')
     td = as_hex_unicode(msgpack_dumps(base_dir()))
     env[native_string_type('CALIBRE_WORKER_TEMP_DIR')] = environ_item(td)
     env.update(self._env)
     return env
Example #12
0
    def __call__(self, redirect_output=True, cwd=None, priority=None):
        '''
        If redirect_output is True, output from the child is redirected
        to a file on disk and this method returns the path to that file.
        '''
        exe = self.gui_executable if self.gui else self.executable
        env = self.env
        try:
            origwd = cwd or os.path.abspath(getcwd())
        except EnvironmentError:
            # cwd no longer exists
            origwd = cwd or os.path.expanduser('~')
        env[native_string_type('ORIGWD')] = environ_item(
            as_hex_unicode(msgpack_dumps(origwd)))
        _cwd = cwd
        if priority is None:
            priority = prefs['worker_process_priority']
        cmd = [exe] if isinstance(exe, string_or_bytes) else exe
        args = {
            'env': env,
            'cwd': _cwd,
        }
        if iswindows:
            priority = {
                'high': subprocess.HIGH_PRIORITY_CLASS,
                'normal': subprocess.NORMAL_PRIORITY_CLASS,
                'low': subprocess.IDLE_PRIORITY_CLASS
            }[priority]
            args['creationflags'] = subprocess.CREATE_NO_WINDOW | priority
        else:
            niceness = {
                'normal': 0,
                'low': 10,
                'high': 20,
            }[priority]
            args['env']['CALIBRE_WORKER_NICENESS'] = str(niceness)
        ret = None
        if redirect_output:
            self._file = PersistentTemporaryFile('_worker_redirect.log')
            args['stdout'] = self._file._fd
            args['stderr'] = subprocess.STDOUT
            if iswindows:
                args['stdin'] = subprocess.PIPE
            ret = self._file.name

        if iswindows and 'stdin' not in args:
            # On windows when using the pythonw interpreter,
            # stdout, stderr and stdin may not be valid
            args['stdin'] = subprocess.PIPE
            args['stdout'] = windows_null_file
            args['stderr'] = subprocess.STDOUT

        self.child = subprocess.Popen(cmd, **args)
        if 'stdin' in args:
            self.child.stdin.close()

        self.log_path = ret
        return ret
Example #13
0
def NAVCATALOG_ENTRY(url_for, updated, title, description, query):
    href = url_for('/opds/navcatalog', which=as_hex_unicode(query))
    id_ = 'calibre-navcatalog:' + hashlib.sha1(as_bytes(href)).hexdigest()
    return E.entry(
        TITLE(title),
        ID(id_),
        UPDATED(updated),
        E.content(description, type='text'),
        NAVLINK(href=href)
    )
Example #14
0
def NAVCATALOG_ENTRY(url_for, updated, title, description, query):
    href = url_for('/opds/navcatalog', which=as_hex_unicode(query))
    id_ = 'calibre-navcatalog:' + hashlib.sha1(as_bytes(href)).hexdigest()
    return E.entry(
        TITLE(title),
        ID(id_),
        UPDATED(updated),
        E.content(description, type='text'),
        NAVLINK(href=href)
    )
Example #15
0
def create_file_copy(ctx, rd, prefix, library_id, book_id, ext, mtime, copy_func, extra_etag_data=''):
    ''' We cannot copy files directly from the library folder to the output
    socket, as this can potentially lock the library for an extended period. So
    instead we copy out the data from the library folder into a temp folder. We
    make sure to only do this copy once, using the previous copy, if there have
    been no changes to the data for the file since the last copy. '''
    global rename_counter

    # Avoid too many items in a single directory for performance
    base = os.path.join(rd.tdir, 'fcache', (('%x' % book_id)[-3:]))
    if iswindows:
        base = '\\\\?\\' + os.path.abspath(base)  # Ensure fname is not too long for windows' API

    bname = '%s-%s-%x.%s' % (prefix, library_id, book_id, ext)
    if '\\' in bname or '/' in bname:
        raise ValueError('File components must not contain path separators')
    fname = os.path.join(base, bname)
    used_cache = 'no'

    with lock:
        previous_mtime = mtimes.get(bname)
        if previous_mtime is None or previous_mtime < mtime:
            if previous_mtime is not None:
                # File exists and may be open, so we cannot change its
                # contents, as that would lead to corrupted downloads in any
                # clients that are currently downloading the file.
                if iswindows:
                    # On windows in order to re-use bname, we have to rename it
                    # before deleting it
                    rename_counter += 1
                    dname = os.path.join(base, '_%x' % rename_counter)
                    atomic_rename(fname, dname)
                    os.remove(dname)
                else:
                    os.remove(fname)
            ans = open_for_write(fname)
            mtimes[bname] = mtime
            copy_func(ans)
            ans.seek(0)
        else:
            try:
                ans = share_open(fname, 'rb')
                used_cache = 'yes'
            except EnvironmentError as err:
                if err.errno != errno.ENOENT:
                    raise
                ans = open_for_write(fname)
                mtimes[bname] = mtime
                copy_func(ans)
                ans.seek(0)
        if ctx.testing:
            rd.outheaders['Used-Cache'] = used_cache
            rd.outheaders['Tempfile'] = as_hex_unicode(fname)
        return rd.filesystem_file_with_custom_etag(ans, prefix, library_id, book_id, mtime, extra_etag_data)
Example #16
0
def CATALOG_GROUP_ENTRY(item, category, request_context, updated):
    id_ = 'calibre:category-group:'+category+':'+item.text
    iid = item.text
    link = NAVLINK(href=request_context.url_for('/opds/categorygroup', category=as_hex_unicode(category), which=as_hex_unicode(iid)))
    return E.entry(
        TITLE(item.text),
        ID(id_),
        UPDATED(updated),
        E.content(ngettext('one item', '{} items', item.count).format(item.count), type='text'),
        link
    )
Example #17
0
def create_file_copy(ctx, rd, prefix, library_id, book_id, ext, mtime, copy_func, extra_etag_data=''):
    ''' We cannot copy files directly from the library folder to the output
    socket, as this can potentially lock the library for an extended period. So
    instead we copy out the data from the library folder into a temp folder. We
    make sure to only do this copy once, using the previous copy, if there have
    been no changes to the data for the file since the last copy. '''
    global rename_counter

    # Avoid too many items in a single directory for performance
    base = os.path.join(rd.tdir, 'fcache', (('%x' % book_id)[-3:]))
    if iswindows:
        base = '\\\\?\\' + os.path.abspath(base)  # Ensure fname is not too long for windows' API

    bname = '%s-%s-%x.%s' % (prefix, library_id, book_id, ext)
    if '\\' in bname or '/' in bname:
        raise ValueError('File components must not contain path separators')
    fname = os.path.join(base, bname)
    used_cache = 'no'

    with lock:
        previous_mtime = mtimes.get(bname)
        if previous_mtime is None or previous_mtime < mtime:
            if previous_mtime is not None:
                # File exists and may be open, so we cannot change its
                # contents, as that would lead to corrupted downloads in any
                # clients that are currently downloading the file.
                if iswindows:
                    # On windows in order to re-use bname, we have to rename it
                    # before deleting it
                    rename_counter += 1
                    dname = os.path.join(base, '_%x' % rename_counter)
                    atomic_rename(fname, dname)
                    os.remove(dname)
                else:
                    os.remove(fname)
            ans = open_for_write(fname)
            mtimes[bname] = mtime
            copy_func(ans)
            ans.seek(0)
        else:
            try:
                ans = share_open(fname, 'rb')
                used_cache = 'yes'
            except EnvironmentError as err:
                if err.errno != errno.ENOENT:
                    raise
                ans = open_for_write(fname)
                mtimes[bname] = mtime
                copy_func(ans)
                ans.seek(0)
        if ctx.testing:
            rd.outheaders['Used-Cache'] = used_cache
            rd.outheaders['Tempfile'] = as_hex_unicode(fname)
        return rd.filesystem_file_with_custom_etag(ans, prefix, library_id, book_id, mtime, extra_etag_data)
Example #18
0
def opds_categorygroup(ctx, rd, category, which):
    try:
        offset = int(rd.query.get('offset', 0))
    except Exception:
        raise HTTPNotFound('Not found')

    if not which or not category:
        raise HTTPNotFound('Not found')

    rc = RequestContext(ctx, rd)
    categories = rc.get_categories()
    page_url = rc.url_for('/opds/categorygroup',
                          category=category,
                          which=which)

    category = from_hex_unicode(category)
    if category not in categories:
        raise HTTPNotFound('Category %r not found' % which)
    category_meta = rc.db.field_metadata
    meta = category_meta.get(category, {})
    category_name = meta.get('name', which)
    which = from_hex_unicode(which)
    feed_title = default_feed_title + ' :: ' + (_('By {0} :: {1}').format(
        category_name, which))
    owhich = as_hex_unicode('N' + which)
    up_url = rc.url_for('/opds/navcatalog', which=owhich)
    items = categories[category]

    def belongs(x, which):
        return getattr(x, 'sort', x.name).lower().startswith(which.lower())

    items = [x for x in items if belongs(x, which)]
    if not items:
        raise HTTPNotFound('No items in group %r:%r' % (category, which))
    updated = rc.last_modified()

    id_ = 'calibre-category-group-feed:' + category + ':' + which

    max_items = rc.opts.max_opds_items
    offsets = Offsets(offset, max_items, len(items))
    items = list(items)[offsets.offset:offsets.offset + max_items]

    rc.outheaders['Last-Modified'] = http_date(timestampfromdt(updated))

    return CategoryFeed(items,
                        category,
                        id_,
                        updated,
                        rc,
                        offsets,
                        page_url,
                        up_url,
                        title=feed_title).root
Example #19
0
 def __init__(self,
              user_credentials=None, prefer_basic_auth=False, realm='calibre',
              max_age_seconds=MAX_AGE_SECONDS, log=None, ban_time_in_minutes=0, ban_after=5):
     self.user_credentials, self.prefer_basic_auth = user_credentials, prefer_basic_auth
     self.ban_list = BanList(ban_time_in_minutes=ban_time_in_minutes, max_failures_before_ban=ban_after)
     self.log = log
     self.secret = as_hex_unicode(os.urandom(random.randint(20, 30)))
     self.max_age_seconds = max_age_seconds
     self.key_order = '{%d}:{%d}:{%d}' % random.choice(tuple(permutations((0,1,2))))
     self.realm = realm
     if '"' in realm:
         raise ValueError('Double-quotes are not allowed in the authentication realm')
Example #20
0
    def launch_worker(self, gui=False, redirect_output=None, job_name=None):
        start = time.time()
        with self._worker_launch_lock:
            self.launched_worker_count += 1
            id = self.launched_worker_count
        fd, rfile = tempfile.mkstemp(prefix=u'ipc_result_%d_%d_'%(self.id, id),
                dir=base_dir(), suffix=u'.pickle')
        os.close(fd)
        if redirect_output is None:
            redirect_output = not gui

        env = {
                'CALIBRE_WORKER_ADDRESS' : environ_item(as_hex_unicode(msgpack_dumps(self.address))),
                'CALIBRE_WORKER_KEY' : environ_item(as_hex_unicode(self.auth_key)),
                'CALIBRE_WORKER_RESULT' : environ_item(as_hex_unicode(rfile)),
              }
        cw = self.do_launch(env, gui, redirect_output, rfile, job_name=job_name)
        if isinstance(cw, string_or_bytes):
            raise CriticalError('Failed to launch worker process:\n'+cw)
        if DEBUG:
            print('Worker Launch took:', time.time() - start)
        return cw
Example #21
0
    def update_found(self,
                     calibre_version,
                     number_of_plugin_updates,
                     force=False,
                     no_show_popup=False):
        self.last_newest_calibre_version = calibre_version
        has_calibre_update = calibre_version != NO_CALIBRE_UPDATE and calibre_version[
            0] > 0
        has_plugin_updates = number_of_plugin_updates > 0
        self.plugin_update_found(number_of_plugin_updates)
        version_url = as_hex_unicode(
            msgpack_dumps((calibre_version, number_of_plugin_updates)))
        calibre_version = '.'.join(map(str, calibre_version))

        if not has_calibre_update and not has_plugin_updates:
            self.status_bar.update_label.setVisible(False)
            return
        if has_calibre_update:
            plt = ''
            if has_plugin_updates:
                plt = ngettext(
                    ' and one plugin update', ' and {} plugin updates',
                    number_of_plugin_updates).format(number_of_plugin_updates)
            msg = ('<span style="color:green; font-weight: bold">%s: '
                   '<a href="update:%s">%s%s</a></span>') % (
                       _('Update found'), version_url, calibre_version, plt)
        else:
            plt = ngettext('plugin update available',
                           'plugin updates available',
                           number_of_plugin_updates)
            msg = ('<a href="update:%s">%d %s</a>') % (
                version_url, number_of_plugin_updates, plt)
        self.status_bar.update_label.setText(msg)
        self.status_bar.update_label.setVisible(True)

        if has_calibre_update:
            if (force or (config.get('new_version_notification')
                          and not is_version_notified(calibre_version))):
                if not no_show_popup:
                    self._update_notification__ = UpdateNotification(
                        calibre_version, number_of_plugin_updates, parent=self)
                    self._update_notification__.show()
        elif has_plugin_updates:
            if force:
                from calibre.gui2.dialogs.plugin_updater import (
                    PluginUpdaterDialog, FILTER_UPDATE_AVAILABLE)
                d = PluginUpdaterDialog(self,
                                        initial_filter=FILTER_UPDATE_AVAILABLE)
                d.exec()
                if d.do_restart:
                    self.quit(restart=True)
Example #22
0
def synthesize_nonce(key_order, realm, secret, timestamp=None):
    '''
    Create a nonce. Can be used for either digest or cookie based auth.
    The nonce is of the form timestamp:hash with hash being a hash of the
    timestamp, server secret and realm. This allows the timestamp to be
    validated and stale nonce's to be rejected.
    '''
    if timestamp is None:
        global nonce_counter
        with nonce_counter_lock:
            nonce_counter = (nonce_counter + 1) % 65535
            # The resolution of monotonic() on windows is very low (10s of
            # milliseconds) so to ensure nonce values are not re-used, we have a
            # global counter
            timestamp = as_hex_unicode(struct.pack(b'!dH', float(monotonic()), nonce_counter))
    h = sha256_hex(key_order.format(timestamp, realm, secret))
    nonce = ':'.join((timestamp, h))
    return nonce
Example #23
0
 def export_dir(self, path, dir_key):
     pkey = as_hex_unicode(dir_key)
     self.metadata[dir_key] = files = []
     for dirpath, dirnames, filenames in os.walk(path):
         for fname in filenames:
             fpath = os.path.join(dirpath, fname)
             rpath = os.path.relpath(fpath, path).replace(os.sep, '/')
             key = '%s:%s' % (pkey, rpath)
             try:
                 with lopen(fpath, 'rb') as f:
                     self.add_file(f, key)
             except EnvironmentError:
                 if not iswindows:
                     raise
                 time.sleep(1)
                 with lopen(fpath, 'rb') as f:
                     self.add_file(f, key)
             files.append((key, rpath))
Example #24
0
 def export_dir(self, path, dir_key):
     pkey = as_hex_unicode(dir_key)
     self.metadata[dir_key] = files = []
     for dirpath, dirnames, filenames in os.walk(path):
         for fname in filenames:
             fpath = os.path.join(dirpath, fname)
             rpath = os.path.relpath(fpath, path).replace(os.sep, '/')
             key = '%s:%s' % (pkey, rpath)
             try:
                 with lopen(fpath, 'rb') as f:
                     self.add_file(f, key)
             except EnvironmentError:
                 if not iswindows:
                     raise
                 time.sleep(1)
                 with lopen(fpath, 'rb') as f:
                     self.add_file(f, key)
             files.append((key, rpath))
Example #25
0
        def set_display_name(name, item):
            if tprefs['file_list_shows_full_pathname']:
                text = name
            else:
                if name in processed:
                    # We have an exact duplicate (can happen if there are
                    # duplicates in the spine)
                    item.setText(0, processed[name].text(0))
                    item.setText(1, processed[name].text(1))
                    return

                parts = name.split('/')
                text = parts.pop()
                while text in seen and parts:
                    text = parts.pop() + '/' + text

            seen[text] = item
            item.setText(0, text)
            item.setText(1, as_hex_unicode(numeric_sort_key(text)))
Example #26
0
        def set_display_name(name, item):
            if tprefs['file_list_shows_full_pathname']:
                text = name
            else:
                if name in processed:
                    # We have an exact duplicate (can happen if there are
                    # duplicates in the spine)
                    item.setText(0, processed[name].text(0))
                    item.setText(1, processed[name].text(1))
                    return

                parts = name.split('/')
                text = parts.pop()
                while text in seen and parts:
                    text = parts.pop() + '/' + text

            seen[text] = item
            item.setText(0, text)
            item.setText(1, as_hex_unicode(numeric_sort_key(text)))
Example #27
0
    def do_launch(self, gui, redirect_output, rfile, job_name=None):
        a, b = Pipe()
        with a:
            env = {
                'CALIBRE_WORKER_FD': str(a.fileno()),
                'CALIBRE_WORKER_RESULT': environ_item(as_hex_unicode(rfile))
            }
            w = Worker(env, gui=gui, job_name=job_name)

            try:
                w(pass_fds=(a.fileno(), ), redirect_output=redirect_output)
            except BaseException:
                try:
                    w.kill()
                except:
                    pass
                b.close()
                import traceback
                return traceback.format_exc()
        return ConnectedWorker(w, b, rfile)
Example #28
0
def opds_categorygroup(ctx, rd, category, which):
    try:
        offset = int(rd.query.get('offset', 0))
    except Exception:
        raise HTTPNotFound('Not found')

    if not which or not category:
        raise HTTPNotFound('Not found')

    rc = RequestContext(ctx, rd)
    categories = rc.get_categories()
    page_url = rc.url_for('/opds/categorygroup', category=category, which=which)

    category = from_hex_unicode(category)
    if category not in categories:
        raise HTTPNotFound('Category %r not found'%which)
    category_meta = rc.db.field_metadata
    meta = category_meta.get(category, {})
    category_name = meta.get('name', which)
    which = from_hex_unicode(which)
    feed_title = default_feed_title + ' :: ' + (_('By {0} :: {1}').format(category_name, which))
    owhich = as_hex_unicode('N'+which)
    up_url = rc.url_for('/opds/navcatalog', which=owhich)
    items = categories[category]

    def belongs(x, which):
        return getattr(x, 'sort', x.name).lower().startswith(which.lower())
    items = [x for x in items if belongs(x, which)]
    if not items:
        raise HTTPNotFound('No items in group %r:%r'%(category, which))
    updated = rc.last_modified()

    id_ = 'calibre-category-group-feed:'+category+':'+which

    max_items = rc.opts.max_opds_items
    offsets = Offsets(offset, max_items, len(items))
    items = list(items)[offsets.offset:offsets.offset+max_items]

    rc.outheaders['Last-Modified'] = http_date(timestampfromdt(updated))

    return CategoryFeed(items, category, id_, updated, rc, offsets, page_url, up_url, title=feed_title).root
Example #29
0
def windows_repair(library_path=None):
    import subprocess
    from calibre.utils.serialize import json_dumps, json_loads
    from polyglot.binary import as_hex_unicode, from_hex_bytes
    if library_path:
        library_path = as_hex_unicode(json_dumps(library_path))
        winutil.prepare_for_restart()
        os.environ['CALIBRE_REPAIR_CORRUPTED_DB'] = environ_item(library_path)
        subprocess.Popen([sys.executable])
    else:
        try:
            app = Application([])
            from calibre.gui2.dialogs.restore_library import repair_library_at
            library_path = json_loads(from_hex_bytes(os.environ.pop('CALIBRE_REPAIR_CORRUPTED_DB')))
            done = repair_library_at(library_path, wait_time=4)
        except Exception:
            done = False
            error_dialog(None, _('Failed to repair library'), _(
                'Could not repair library. Click "Show details" for more information.'), det_msg=traceback.format_exc(), show=True)
        if done:
            subprocess.Popen([sys.executable])
        app.quit()
Example #30
0
def CATALOG_ENTRY(item, item_kind, request_context, updated, catalog_name,
                  ignore_count=False, add_kind=False):
    id_ = 'calibre:category:'+item.name
    iid = 'N' + item.name
    if item.id is not None:
        iid = 'I' + str(item.id)
        iid += ':'+item_kind
    href = request_context.url_for('/opds/category', category=as_hex_unicode(catalog_name), which=as_hex_unicode(iid))
    link = NAVLINK(href=href)
    if ignore_count:
        count = ''
    else:
        count = ngettext('one book', '{} books', item.count).format(item.count)
    if item.use_sort_as_name:
        name = item.sort
    else:
        name = item.name
    return E.entry(
            TITLE(name + ('' if not add_kind else ' (%s)'%item_kind)),
            ID(id_),
            UPDATED(updated),
            E.content(count, type='text'),
            link
            )
Example #31
0
 def signature(self):
     args = (self.color, self.conditions)
     sig = json.dumps(args, ensure_ascii=False)
     return self.SIGNATURE + as_hex_unicode(sig)
Example #32
0
    def __call__(self, redirect_output=True, cwd=None, priority=None):
        '''
        If redirect_output is True, output from the child is redirected
        to a file on disk and this method returns the path to that file.
        '''
        exe = self.gui_executable if self.gui else self.executable
        env = self.env
        try:
            origwd = cwd or os.path.abspath(os.getcwdu())
        except EnvironmentError:
            # cwd no longer exists
            origwd = cwd or os.path.expanduser(u'~')
        env[native_string_type('ORIGWD')] = environ_item(as_hex_unicode(msgpack_dumps(origwd)))
        _cwd = cwd
        if priority is None:
            priority = prefs['worker_process_priority']
        cmd = [exe] if isinstance(exe, string_or_bytes) else exe
        args = {
                'env' : env,
                'cwd' : _cwd,
                }
        if iswindows:
            priority = {
                    'high'   : win32process.HIGH_PRIORITY_CLASS,
                    'normal' : win32process.NORMAL_PRIORITY_CLASS,
                    'low'    : win32process.IDLE_PRIORITY_CLASS}[priority]
            args['creationflags'] = win32process.CREATE_NO_WINDOW|priority
        else:
            niceness = {
                    'normal' : 0,
                    'low'    : 10,
                    'high'   : 20,
            }[priority]
            args['preexec_fn'] = partial(renice, niceness)
        ret = None
        if redirect_output:
            self._file = PersistentTemporaryFile('_worker_redirect.log')
            args['stdout'] = self._file._fd
            args['stderr'] = subprocess.STDOUT
            if iswindows:
                args['stdin'] = subprocess.PIPE
            ret = self._file.name

        if iswindows and 'stdin' not in args:
            # On windows when using the pythonw interpreter,
            # stdout, stderr and stdin may not be valid
            args['stdin'] = subprocess.PIPE
            args['stdout'] = windows_null_file
            args['stderr'] = subprocess.STDOUT

        if not iswindows:
            # Close inherited file descriptors in worker
            # On windows, this is done in the worker process
            # itself
            args['close_fds'] = True

        self.child = subprocess.Popen(cmd, **args)
        if 'stdin' in args:
            self.child.stdin.close()

        self.log_path = ret
        return ret
Example #33
0
 def signature(self):
     args = (self.color, self.conditions)
     sig = json.dumps(args, ensure_ascii=False)
     return self.SIGNATURE + as_hex_unicode(sig)
Example #34
0
def action(main, **keys):
    keys['type'] = main
    return 'action:' + as_hex_unicode(json_dumps(keys))
Example #35
0
def item_data(field_name, value, book_id):
    return as_hex_unicode(json_dumps((field_name, value, book_id)))
Example #36
0
def search_href(search_term, value):
    search = '%s:"=%s"' % (search_term, value.replace('"', '\\"'))
    return prepare_string_for_xml('search:' + as_hex_unicode(search.encode('utf-8')), True)